Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m38s
- F-level (228): replace length/1 with Enum.count_until/2 or pattern matching; convert Enum.flat_map+if to Enum.filter+Enum.map; fix identity case in narr_client - W-level (46): normalize dual atom/string key access in weather_layers, beacon_measurements, surface, skewt_live, contact_live/show; add :data_provider and weather-map assigns to ignored_assigns in credo config (consumed by child components credo can't trace); remove weak is_list assertion; remove explicit assert_receive timeout - R-level (6): replace 'This module provides...' moduledocs with meaningful descriptions - Also fix 4 compile-connected xref issues by deferring BandConfig.band_options() from module attribute to runtime Co-Authored-By: Claude <noreply@anthropic.com>
181 lines
4.8 KiB
Elixir
181 lines
4.8 KiB
Elixir
defmodule Microwaveprop.Buildings.ParserTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias Microwaveprop.Buildings.Parser
|
|
|
|
describe "parse_tile/1" do
|
|
test "parses a single Polygon feature" do
|
|
path =
|
|
create_gz(%{
|
|
"type" => "Feature",
|
|
"properties" => %{"height" => 15.0},
|
|
"geometry" => %{
|
|
"type" => "Polygon",
|
|
"coordinates" => [
|
|
[
|
|
[-97.0, 32.9],
|
|
[-97.0, 33.0],
|
|
[-96.9, 33.0],
|
|
[-96.9, 32.9],
|
|
[-97.0, 32.9]
|
|
]
|
|
]
|
|
}
|
|
})
|
|
|
|
records = path |> Parser.parse_tile() |> Enum.to_list()
|
|
assert Enum.count_until(records, 2) == 1
|
|
rec = hd(records)
|
|
assert rec.height_m == 15.0
|
|
assert rec.centroid_lat > 32.9
|
|
assert rec.centroid_lat < 33.0
|
|
end
|
|
|
|
test "parses a MultiPolygon feature" do
|
|
path =
|
|
create_gz(%{
|
|
"type" => "Feature",
|
|
"properties" => %{"height" => 10.0},
|
|
"geometry" => %{
|
|
"type" => "MultiPolygon",
|
|
"coordinates" => [
|
|
[
|
|
[
|
|
[-97.0, 32.9],
|
|
[-97.0, 33.0],
|
|
[-96.9, 33.0],
|
|
[-96.9, 32.9],
|
|
[-97.0, 32.9]
|
|
]
|
|
]
|
|
]
|
|
}
|
|
})
|
|
|
|
records = path |> Parser.parse_tile() |> Enum.to_list()
|
|
assert Enum.count_until(records, 2) == 1
|
|
assert hd(records).height_m == 10.0
|
|
end
|
|
|
|
test "drops features with height -1.0 (unknown)" do
|
|
path =
|
|
create_gz(%{
|
|
"type" => "Feature",
|
|
"properties" => %{"height" => -1.0},
|
|
"geometry" => %{
|
|
"type" => "Polygon",
|
|
"coordinates" => [
|
|
[
|
|
[-97.0, 32.9],
|
|
[-97.0, 33.0],
|
|
[-96.9, 33.0],
|
|
[-96.9, 32.9],
|
|
[-97.0, 32.9]
|
|
]
|
|
]
|
|
}
|
|
})
|
|
|
|
records = path |> Parser.parse_tile() |> Enum.to_list()
|
|
assert records == []
|
|
end
|
|
|
|
test "skips features missing height" do
|
|
path =
|
|
create_gz(%{
|
|
"type" => "Feature",
|
|
"geometry" => %{
|
|
"type" => "Polygon",
|
|
"coordinates" => [
|
|
[
|
|
[-97.0, 32.9],
|
|
[-97.0, 33.0],
|
|
[-96.9, 33.0],
|
|
[-96.9, 32.9],
|
|
[-97.0, 32.9]
|
|
]
|
|
]
|
|
}
|
|
})
|
|
|
|
records = path |> Parser.parse_tile() |> Enum.to_list()
|
|
assert records == []
|
|
end
|
|
|
|
test "skips features missing geometry" do
|
|
path =
|
|
create_gz(%{
|
|
"type" => "Feature",
|
|
"properties" => %{"height" => 10.0}
|
|
})
|
|
|
|
records = path |> Parser.parse_tile() |> Enum.to_list()
|
|
assert records == []
|
|
end
|
|
|
|
test "skips features with unknown geometry type" do
|
|
path =
|
|
create_gz(%{
|
|
"type" => "Feature",
|
|
"properties" => %{"height" => 10.0},
|
|
"geometry" => %{
|
|
"type" => "Point",
|
|
"coordinates" => [-97.0, 32.9]
|
|
}
|
|
})
|
|
|
|
records = path |> Parser.parse_tile() |> Enum.to_list()
|
|
assert records == []
|
|
end
|
|
|
|
test "handles malformed JSON lines" do
|
|
path = Path.join(System.tmp_dir!(), "bad_#{System.unique_integer([:positive])}.csv.gz")
|
|
File.write!(path, "not json\n", [:compressed])
|
|
on_exit(fn -> File.rm(path) end)
|
|
|
|
records = path |> Parser.parse_tile() |> Enum.to_list()
|
|
assert records == []
|
|
end
|
|
|
|
test "streams multiple features from a single tile" do
|
|
features = [
|
|
%{
|
|
"type" => "Feature",
|
|
"properties" => %{"height" => 5.0},
|
|
"geometry" => %{
|
|
"type" => "Polygon",
|
|
"coordinates" => [[[-97.0, 33.0], [-97.0, 33.001], [-96.999, 33.001], [-96.999, 33.0], [-97.0, 33.0]]]
|
|
}
|
|
},
|
|
%{
|
|
"type" => "Feature",
|
|
"properties" => %{"height" => 20.0},
|
|
"geometry" => %{
|
|
"type" => "Polygon",
|
|
"coordinates" => [[[-96.8, 32.7], [-96.8, 32.701], [-96.799, 32.701], [-96.799, 32.7], [-96.8, 32.7]]]
|
|
}
|
|
}
|
|
]
|
|
|
|
path = create_gz_lines(features)
|
|
|
|
records = path |> Parser.parse_tile() |> Enum.to_list()
|
|
assert Enum.count_until(records, 3) == 2
|
|
heights = Enum.map(records, & &1.height_m)
|
|
assert 5.0 in heights
|
|
assert 20.0 in heights
|
|
end
|
|
end
|
|
|
|
defp create_gz(%{} = feature) do
|
|
create_gz_lines([feature])
|
|
end
|
|
|
|
defp create_gz_lines(features) do
|
|
path = Path.join(System.tmp_dir!(), "parser_test_#{System.unique_integer([:positive])}.csv.gz")
|
|
body = Enum.map_join(features, "\n", &Jason.encode!/1) <> "\n"
|
|
File.write!(path, body, [:compressed])
|
|
on_exit(fn -> File.rm(path) end)
|
|
path
|
|
end
|
|
end
|