From d4c4840b119ca972efc4875fdd90daf1a8479e53 Mon Sep 17 00:00:00 2001 From: Fly Dev Date: Mon, 23 Jun 2025 14:09:53 +0000 Subject: [PATCH] add comprehensive tests for DataExtended module --- test/aprs/data_extended_test.exs | 318 +++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 test/aprs/data_extended_test.exs diff --git a/test/aprs/data_extended_test.exs b/test/aprs/data_extended_test.exs new file mode 100644 index 0000000..70ae744 --- /dev/null +++ b/test/aprs/data_extended_test.exs @@ -0,0 +1,318 @@ +defmodule Aprs.DataExtendedTest do + use Aprs.DataCase, async: true + + alias Aprs.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[:aprs_messaging] + 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 + 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