defmodule Aprsme.DataExtendedTest do use Aprsme.DataCase, async: true alias Aprsme.DataExtended describe "changeset/2" do test "valid changeset with all required fields" do attrs = %{ aprs_messaging: true, comment: "Test comment", data_type: "position", symbol_code: "/", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid? assert get_change(changeset, :aprs_messaging) == true assert get_change(changeset, :comment) == "Test comment" assert get_change(changeset, :data_type) == "position" assert get_change(changeset, :symbol_code) == "/" assert get_change(changeset, :symbol_table_id) == "/" end test "valid changeset with coordinates" do attrs = %{ aprs_messaging: false, comment: "Position report", data_type: "position", latitude: Decimal.new("40.123456"), longitude: Decimal.new("-74.654321"), symbol_code: "j", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid? assert get_change(changeset, :latitude) == Decimal.new("40.123456") assert get_change(changeset, :longitude) == Decimal.new("-74.654321") end test "valid changeset with string coordinates gets converted to decimal" do attrs = %{ aprs_messaging: false, comment: "Position report", data_type: "position", latitude: "40.123456", longitude: "-74.654321", symbol_code: "j", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid? assert get_change(changeset, :latitude) == Decimal.new("40.123456") assert get_change(changeset, :longitude) == Decimal.new("-74.654321") end test "valid changeset with only required fields (no coordinates)" do attrs = %{ aprs_messaging: false, comment: "Status update", data_type: "status", symbol_code: ">", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid? refute get_change(changeset, :latitude) refute get_change(changeset, :longitude) end test "invalid changeset missing required fields" do attrs = %{} changeset = DataExtended.changeset(%DataExtended{}, attrs) refute changeset.valid? errors = errors_on(changeset) assert "can't be blank" in errors[:comment] assert "can't be blank" in errors[:data_type] assert "can't be blank" in errors[:symbol_code] assert "can't be blank" in errors[:symbol_table_id] end test "invalid changeset with empty required fields" do attrs = %{ aprs_messaging: nil, comment: "", data_type: "", symbol_code: "", symbol_table_id: "" } changeset = DataExtended.changeset(%DataExtended{}, attrs) refute changeset.valid? errors = errors_on(changeset) assert "can't be blank" in errors[:comment] assert "can't be blank" in errors[:data_type] assert "can't be blank" in errors[:symbol_code] assert "can't be blank" in errors[:symbol_table_id] end test "changeset with only latitude provided (should be invalid)" do attrs = %{ aprs_messaging: false, comment: "Partial position", data_type: "position", latitude: "40.123456", symbol_code: "j", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid? # When only latitude is provided, it should still be valid # The validation logic only requires a field if it's present in changes assert get_change(changeset, :latitude) == Decimal.new("40.123456") refute get_change(changeset, :longitude) end test "changeset with only longitude provided (should be invalid)" do attrs = %{ aprs_messaging: false, comment: "Partial position", data_type: "position", longitude: "-74.654321", symbol_code: "j", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid? # When only longitude is provided, it should still be valid assert get_change(changeset, :longitude) == Decimal.new("-74.654321") refute get_change(changeset, :latitude) end test "changeset handles boolean aprs_messaging properly" do # Test true attrs_true = %{ aprs_messaging: true, comment: "Message enabled", data_type: "message", symbol_code: ">", symbol_table_id: "/" } changeset_true = DataExtended.changeset(%DataExtended{}, attrs_true) assert changeset_true.valid? assert get_change(changeset_true, :aprs_messaging) == true # Test false attrs_false = %{ aprs_messaging: false, comment: "Message disabled", data_type: "status", symbol_code: ">", symbol_table_id: "/" } changeset_false = DataExtended.changeset(%DataExtended{}, attrs_false) assert changeset_false.valid? assert get_change(changeset_false, :aprs_messaging) == false || changeset_false.data.aprs_messaging == false end test "changeset with various symbol codes and table IDs" do test_cases = [ {"/", "/", "Primary table, house symbol"}, {"\\", "j", "Alternate table, jeep symbol"}, {">", "/", "Primary table, car symbol"}, {"[", "\\", "Alternate table, human symbol"} ] for {symbol_code, symbol_table_id, description} <- test_cases do attrs = %{ aprs_messaging: false, comment: description, data_type: "position", symbol_code: symbol_code, symbol_table_id: symbol_table_id } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid?, "Failed for #{description}" assert get_change(changeset, :symbol_code) == symbol_code assert get_change(changeset, :symbol_table_id) == symbol_table_id end end test "changeset with various data types" do data_types = ["position", "status", "message", "weather", "telemetry", "object", "item"] for data_type <- data_types do attrs = %{ aprs_messaging: false, comment: "Testing #{data_type}", data_type: data_type, symbol_code: ">", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid?, "Failed for data_type: #{data_type}" assert get_change(changeset, :data_type) == data_type end end test "changeset with long comment" do long_comment = String.duplicate("A", 1000) attrs = %{ aprs_messaging: false, comment: long_comment, data_type: "status", symbol_code: ">", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) assert changeset.valid? assert get_change(changeset, :comment) == long_comment end test "changeset preserves existing data when updating" do existing_data = %DataExtended{ aprs_messaging: true, comment: "Original comment", data_type: "position", latitude: Decimal.new("30.0"), longitude: Decimal.new("-90.0"), symbol_code: "/", symbol_table_id: "/" } update_attrs = %{ comment: "Updated comment", latitude: "31.0" } changeset = DataExtended.changeset(existing_data, update_attrs) assert changeset.valid? assert get_change(changeset, :comment) == "Updated comment" assert get_change(changeset, :latitude) == Decimal.new("31.0") # Other fields should remain unchanged assert changeset.data.aprs_messaging == true assert changeset.data.data_type == "position" end end describe "validate_required_if_present/2" do test "validates field when it's present in changes" do attrs = %{ aprs_messaging: false, comment: "Test", data_type: "position", # Explicitly setting to nil should trigger validation latitude: nil, symbol_code: ">", symbol_table_id: "/" } changeset = DataExtended.changeset(%DataExtended{}, attrs) # This test verifies the private function behavior indirectly # If latitude is explicitly set to nil, it should still be valid # because the validation logic only requires non-nil values assert changeset.valid? end end describe "struct creation and defaults" do test "creates struct with default values" do data_extended = %DataExtended{} assert data_extended.aprs_messaging == false assert is_nil(data_extended.comment) assert is_nil(data_extended.data_type) assert is_nil(data_extended.latitude) assert is_nil(data_extended.longitude) assert is_nil(data_extended.symbol_code) assert is_nil(data_extended.symbol_table_id) end test "creates struct with explicit values" do data_extended = %DataExtended{ aprs_messaging: true, comment: "Test comment", data_type: "position", latitude: Decimal.new("40.0"), longitude: Decimal.new("-74.0"), symbol_code: "j", symbol_table_id: "/" } assert data_extended.aprs_messaging == true assert data_extended.comment == "Test comment" assert data_extended.data_type == "position" assert data_extended.latitude == Decimal.new("40.0") assert data_extended.longitude == Decimal.new("-74.0") assert data_extended.symbol_code == "j" assert data_extended.symbol_table_id == "/" end end end