defmodule MicrowavepropWeb.SkewtSvgTest do use ExUnit.Case, async: true alias MicrowavepropWeb.SkewtSvg @profile [ %{"pres" => 1013.0, "hght" => 100.0, "tmpc" => 25.0, "dwpc" => 18.0}, %{"pres" => 925.0, "hght" => 800.0, "tmpc" => 18.0, "dwpc" => 14.0}, %{"pres" => 850.0, "hght" => 1500.0, "tmpc" => 12.0, "dwpc" => 9.0}, %{"pres" => 700.0, "hght" => 3000.0, "tmpc" => 0.0, "dwpc" => -5.0}, %{"pres" => 500.0, "hght" => 5500.0, "tmpc" => -15.0, "dwpc" => -25.0}, %{"pres" => 300.0, "hght" => 9000.0, "tmpc" => -45.0, "dwpc" => -65.0} ] describe "render/1" do test "produces a valid root with the expected viewBox" do svg = @profile |> SkewtSvg.render() |> IO.iodata_to_binary() assert svg =~ ~r|]*viewBox="0 0 820 640"| assert String.ends_with?(svg, "") end test "draws temperature and dewpoint polylines" do svg = @profile |> SkewtSvg.render() |> IO.iodata_to_binary() assert svg =~ ~s|class="temp-line"| assert svg =~ ~s|class="dew-line"| end test "tolerates Rust-style atom-keyed levels" do rust_profile = [ %{pres_mb: 1013.0, hght_m: 100.0, tmpc: 25.0, dwpc: 18.0}, %{pres_mb: 850.0, hght_m: 1500.0, tmpc: 12.0, dwpc: 9.0}, %{pres_mb: 500.0, hght_m: 5500.0, tmpc: -15.0, dwpc: -25.0} ] svg = rust_profile |> SkewtSvg.render() |> IO.iodata_to_binary() assert svg =~ ~s|class="temp-line"| end test "renders without trace polylines on an empty profile" do svg = [] |> SkewtSvg.render() |> IO.iodata_to_binary() # The style block always defines the trace classes; only the # polyline elements should be missing for an empty profile. assert svg =~ " 1000.0, "hght" => 100.0, "tmpc" => 20.0, "dwpc" => 10.0}, %{"pres" => 500.0, "hght" => 5000.0, "tmpc" => -10.0, "dwpc" => nil} ] svg = partial |> SkewtSvg.render() |> IO.iodata_to_binary() # Temperature line must still draw both points. assert svg =~ ~s|class="temp-line"| # Dewpoint line will only contain the bottom point and renders as # nothing (single-point polyline) — that's fine, the test asserts # the renderer didn't crash. assert svg =~ "" end end describe "coordinate transforms" do test "pressure_y is monotonically decreasing as pressure decreases" do y1000 = SkewtSvg.pressure_y(1000) y500 = SkewtSvg.pressure_y(500) y100 = SkewtSvg.pressure_y(100) assert y1000 > y500 assert y500 > y100 end test "temperature_x at the bottom edge: warmer = further right" do cold = SkewtSvg.temperature_x(-20, SkewtSvg.pressure_y(1000)) warm = SkewtSvg.temperature_x(20, SkewtSvg.pressure_y(1000)) assert warm > cold end test "temperature_x is skewed: same temperature shifts right as pressure decreases" do bottom = SkewtSvg.temperature_x(0, SkewtSvg.pressure_y(1000)) top = SkewtSvg.temperature_x(0, SkewtSvg.pressure_y(300)) # Skew-T isotherms lean lower-left → upper-right, so the same # 0 °C plotted at 300 mb sits to the right of 0 °C at 1000 mb. assert top > bottom end end end