192 lines
5.8 KiB
Elixir
192 lines
5.8 KiB
Elixir
defmodule Aprs.EncodingUtilsTest do
|
|
use ExUnit.Case
|
|
|
|
alias Aprs.EncodingUtils
|
|
alias Aprs.Packet
|
|
|
|
doctest Aprs.EncodingUtils
|
|
|
|
describe "sanitize_string/1" do
|
|
test "returns valid UTF-8 strings unchanged" do
|
|
assert EncodingUtils.sanitize_string("Hello World") == "Hello World"
|
|
assert EncodingUtils.sanitize_string("Café") == "Café"
|
|
assert EncodingUtils.sanitize_string("你好") == "你好"
|
|
end
|
|
|
|
test "handles nil input" do
|
|
assert EncodingUtils.sanitize_string(nil) == nil
|
|
end
|
|
|
|
test "handles non-binary input" do
|
|
assert EncodingUtils.sanitize_string(123) == 123
|
|
assert EncodingUtils.sanitize_string(:atom) == :atom
|
|
end
|
|
|
|
test "sanitizes invalid UTF-8 sequences" do
|
|
# Binary with invalid UTF-8 bytes (0xD3 and 0xD1 from the error)
|
|
invalid_binary = <<85, 78, 73, 211, 78, 32, 80, 65, 78, 65, 77, 69, 209, 65>>
|
|
result = EncodingUtils.sanitize_string(invalid_binary)
|
|
|
|
# Should be a valid UTF-8 string
|
|
assert String.valid?(result)
|
|
|
|
# Should contain some recognizable text
|
|
assert String.contains?(result, "UNI")
|
|
assert String.contains?(result, "PANAME")
|
|
end
|
|
|
|
test "handles mixed valid and invalid UTF-8" do
|
|
# "Hello" + invalid byte + "World"
|
|
mixed_binary = <<72, 101, 108, 108, 111, 211, 87, 111, 114, 108, 100>>
|
|
result = EncodingUtils.sanitize_string(mixed_binary)
|
|
|
|
assert String.valid?(result)
|
|
assert String.starts_with?(result, "Hello")
|
|
assert String.ends_with?(result, "World")
|
|
end
|
|
end
|
|
|
|
describe "sanitize_packet/1" do
|
|
test "sanitizes information_field" do
|
|
invalid_info = <<72, 101, 108, 108, 111, 211, 87, 111, 114, 108, 100>>
|
|
|
|
packet = %Packet{
|
|
id: "test-id",
|
|
sender: "TEST-1",
|
|
path: "TCPIP*",
|
|
destination: "APX100",
|
|
information_field: invalid_info,
|
|
data_type: :position,
|
|
base_callsign: "TEST",
|
|
ssid: "1",
|
|
data_extended: %{comment: "Valid comment"}
|
|
}
|
|
|
|
sanitized = EncodingUtils.sanitize_packet(packet)
|
|
|
|
assert String.valid?(sanitized.information_field)
|
|
assert String.contains?(sanitized.information_field, "Hello")
|
|
assert String.contains?(sanitized.information_field, "World")
|
|
end
|
|
|
|
test "sanitizes comment in data_extended" do
|
|
invalid_comment = <<85, 78, 73, 211, 78, 32, 80, 65, 78, 65, 77, 69, 209, 65>>
|
|
|
|
packet = %Packet{
|
|
id: "test-id",
|
|
sender: "TEST-1",
|
|
path: "TCPIP*",
|
|
destination: "APX100",
|
|
information_field: "Valid info",
|
|
data_type: :position,
|
|
base_callsign: "TEST",
|
|
ssid: "1",
|
|
data_extended: %{comment: invalid_comment}
|
|
}
|
|
|
|
sanitized = EncodingUtils.sanitize_packet(packet)
|
|
|
|
assert String.valid?(sanitized.data_extended.comment)
|
|
assert String.contains?(sanitized.data_extended.comment, "UNI")
|
|
end
|
|
|
|
test "handles packet with nil data_extended" do
|
|
packet = %Packet{
|
|
id: "test-id",
|
|
sender: "TEST-1",
|
|
path: "TCPIP*",
|
|
destination: "APX100",
|
|
information_field: "Valid info",
|
|
data_type: :position,
|
|
base_callsign: "TEST",
|
|
ssid: "1",
|
|
data_extended: nil
|
|
}
|
|
|
|
sanitized = EncodingUtils.sanitize_packet(packet)
|
|
|
|
assert sanitized.data_extended == nil
|
|
assert sanitized.information_field == "Valid info"
|
|
end
|
|
end
|
|
|
|
describe "sanitize_data_extended/1" do
|
|
test "handles nil input" do
|
|
assert EncodingUtils.sanitize_data_extended(nil) == nil
|
|
end
|
|
|
|
test "sanitizes comment field in map" do
|
|
invalid_comment = <<72, 101, 108, 108, 111, 211, 87, 111, 114, 108, 100>>
|
|
data_extended = %{comment: invalid_comment, latitude: 12.34, longitude: -56.78}
|
|
|
|
sanitized = EncodingUtils.sanitize_data_extended(data_extended)
|
|
|
|
assert String.valid?(sanitized.comment)
|
|
assert sanitized.latitude == 12.34
|
|
assert sanitized.longitude == -56.78
|
|
end
|
|
|
|
test "sanitizes message field in MicE struct" do
|
|
invalid_message = <<72, 101, 108, 108, 111, 211, 87, 111, 114, 108, 100>>
|
|
mic_e = %Parser.Types.MicE{message: invalid_message, lat_degrees: 40}
|
|
|
|
sanitized = EncodingUtils.sanitize_data_extended(mic_e)
|
|
|
|
assert String.valid?(sanitized.message)
|
|
assert sanitized.lat_degrees == 40
|
|
end
|
|
|
|
test "returns other data unchanged" do
|
|
data = %{some_field: "value", number: 42}
|
|
assert EncodingUtils.sanitize_data_extended(data) == data
|
|
end
|
|
end
|
|
|
|
describe "to_hex/1" do
|
|
test "converts binary to hex string" do
|
|
assert EncodingUtils.to_hex(<<72, 101, 108, 108, 111>>) == "48656C6C6F"
|
|
assert EncodingUtils.to_hex(<<0, 255>>) == "00FF"
|
|
assert EncodingUtils.to_hex(<<>>) == ""
|
|
end
|
|
|
|
test "handles invalid UTF-8 bytes" do
|
|
invalid_binary = <<85, 78, 73, 211, 78>>
|
|
result = EncodingUtils.to_hex(invalid_binary)
|
|
assert result == "554E49D34E"
|
|
end
|
|
end
|
|
|
|
describe "encoding_info/1" do
|
|
test "returns info for valid UTF-8 string" do
|
|
info = EncodingUtils.encoding_info("Hello")
|
|
assert info.valid_utf8 == true
|
|
assert info.byte_count == 5
|
|
assert info.char_count == 5
|
|
end
|
|
|
|
test "returns info for invalid UTF-8 binary" do
|
|
invalid_binary = <<72, 101, 211, 108, 111>>
|
|
info = EncodingUtils.encoding_info(invalid_binary)
|
|
|
|
assert info.valid_utf8 == false
|
|
assert info.byte_count == 5
|
|
assert info.invalid_at == 2
|
|
end
|
|
|
|
test "handles empty binary" do
|
|
info = EncodingUtils.encoding_info("")
|
|
assert info.valid_utf8 == true
|
|
assert info.byte_count == 0
|
|
assert info.char_count == 0
|
|
end
|
|
|
|
test "handles multi-byte UTF-8 characters" do
|
|
info = EncodingUtils.encoding_info("Café")
|
|
assert info.valid_utf8 == true
|
|
# 'é' takes 2 bytes
|
|
assert info.byte_count == 5
|
|
# but counts as 1 character
|
|
assert info.char_count == 4
|
|
end
|
|
end
|
|
end
|