require_relative "test_helper" require "maptool/overpass_pois" # No real network calls — to_geojson is pure (canned Overpass response -> # GeoJSON), and that's the part worth protecting from regressions. fetch() # itself is a thin Net::HTTP.post_form + JSON.parse wrapper, same as # LiveTrackClient's own fetch_html, not independently tested for the same # reason that one isn't. class OverpassPoisTest < Minitest::Test def test_to_geojson_converts_matching_node_elements response = { "elements" => [ { "type" => "node", "lat" => 48.1, "lon" => 17.2, "tags" => { "amenity" => "drinking_water" } }, { "type" => "node", "lat" => 48.3, "lon" => 17.4, "tags" => { "amenity" => "toilets", "name" => "Rest area" } }, ], } geojson = Maptool::OverpassPois.to_geojson(response) assert_equal "FeatureCollection", geojson["type"] assert_equal 2, geojson["features"].size water = geojson["features"].find { |f| f["properties"]["category"] == "Drinking water" } assert_equal [17.2, 48.1], water["geometry"]["coordinates"] assert_equal "Drinking water", water["properties"]["name"], "falls back to the category when the node has no name tag" assert_equal "amenity_drinking_water", water["properties"]["icon"] assert_equal "#2e86de", water["properties"]["color"] end def test_to_geojson_assigns_icons_to_shop_categories response = { "elements" => [ { "type" => "node", "lat" => 1, "lon" => 1, "tags" => { "shop" => "supermarket" } }, { "type" => "node", "lat" => 2, "lon" => 2, "tags" => { "shop" => "convenience" } }, ], } icons = Maptool::OverpassPois.to_geojson(response)["features"].map { |f| f["properties"]["icon"] } assert_equal %w[shop_supermarket shop_convenience], icons end def test_to_geojson_builds_a_description_from_recognized_tags response = { "elements" => [ { "type" => "node", "lat" => 48.1, "lon" => 17.2, "tags" => { "amenity" => "toilets", "opening_hours" => "24/7", "operator" => "Town Council", "website" => "https://example.com" }, }, ], } description = Maptool::OverpassPois.to_geojson(response)["features"].first["properties"]["description"] assert_equal "Opening hours: 24/7\nOperator: Town Council\nhttps://example.com", description end def test_to_geojson_strips_embedded_newlines_from_tag_values response = { "elements" => [ { "type" => "node", "lat" => 48.1, "lon" => 17.2, "tags" => { "amenity" => "toilets", "operator" => "Acme Co\nhttps://evil.example" }, }, ], } description = Maptool::OverpassPois.to_geojson(response)["features"].first["properties"]["description"] assert_equal "Operator: Acme Co https://evil.example", description, "an embedded newline must not inject a second, independently-rendered line" end def test_to_geojson_omits_description_when_no_recognized_tags_are_present response = { "elements" => [{ "type" => "node", "lat" => 48.1, "lon" => 17.2, "tags" => { "amenity" => "toilets" } }] } refute Maptool::OverpassPois.to_geojson(response)["features"].first["properties"].key?("description") end def test_to_geojson_uses_the_node_name_when_present response = { "elements" => [{ "type" => "node", "lat" => 48.3, "lon" => 17.4, "tags" => { "amenity" => "toilets", "name" => "Rest area" } }] } feature = Maptool::OverpassPois.to_geojson(response)["features"].first assert_equal "Rest area", feature["properties"]["name"] end def test_to_geojson_skips_ways_and_relations response = { "elements" => [{ "type" => "way", "tags" => { "amenity" => "drinking_water" } }] } assert_empty Maptool::OverpassPois.to_geojson(response)["features"] end def test_to_geojson_skips_nodes_matching_no_known_category response = { "elements" => [{ "type" => "node", "lat" => 48.1, "lon" => 17.2, "tags" => { "amenity" => "restaurant" } }] } assert_empty Maptool::OverpassPois.to_geojson(response)["features"] end def test_lpg_matches_either_fuel_stations_with_the_lpg_tag_or_gas_bottle_shops response = { "elements" => [ { "type" => "node", "lat" => 1, "lon" => 1, "tags" => { "amenity" => "fuel", "fuel:lpg" => "yes" } }, { "type" => "node", "lat" => 2, "lon" => 2, "tags" => { "shop" => "gas" } }, { "type" => "node", "lat" => 3, "lon" => 3, "tags" => { "amenity" => "fuel" } }, # no lpg tag - not a match ], } categories = Maptool::OverpassPois.to_geojson(response)["features"].map { |f| f["properties"]["category"] } assert_equal ["LPG refill", "LPG refill"], categories end def test_build_query_includes_the_bbox_and_every_category_filter query = Maptool::OverpassPois.build_query([48.0, 17.0, 49.0, 18.0]) assert_includes query, "48.0,17.0,49.0,18.0" assert_includes query, %(["amenity"="drinking_water"]) assert_includes query, %(["natural"="spring"]) end end