#!/usr/bin/env elixir # Test script for the enhanced header management system using real modules Mix.install([ {:jason, "~> 1.4"} ]) import Bitwise # Add the lib directory to the path Code.append_path("lib") Code.append_path("_build/dev/lib/da_product_app/ebin") # Load our modules Application.put_env(:logger, :level, :info) # Define our modules inline for testing (since we can't load from mix project in script) defmodule DaProductApp.MercuryISO8583.Headers.HeaderUtils do import Bitwise def hex_to_binary(hex_string) when is_binary(hex_string) do try do clean_hex = hex_string |> String.replace(~r/[^0-9A-Fa-f]/, "") |> String.upcase() padded_hex = if rem(String.length(clean_hex), 2) == 1 do "0" <> clean_hex else clean_hex end case Base.decode16(padded_hex) do {:ok, binary} -> {:ok, binary} :error -> {:error, :invalid_hex} end rescue _ -> {:error, :invalid_hex} end end def binary_to_hex(binary) when is_binary(binary) do Base.encode16(binary, case: :upper) end def bcd_to_binary(bcd_string) when is_binary(bcd_string) do try do padded = if rem(String.length(bcd_string), 2) == 1 do "0" <> bcd_string else bcd_string end binary = padded |> String.graphemes() |> Enum.chunk_every(2) |> Enum.map(fn [high, low] -> (String.to_integer(high) <<< 4) ||| String.to_integer(low) end) |> :binary.list_to_bin() {:ok, binary} rescue _ -> {:error, :invalid_bcd} end end def binary_to_bcd(binary) when is_binary(binary) do binary |> :binary.bin_to_list() |> Enum.map(fn byte -> high = (byte &&& 0xF0) >>> 4 low = byte &&& 0x0F "#{high}#{low}" end) |> Enum.join("") end def ascii_to_binary(ascii_string) when is_binary(ascii_string) do ascii_string end def binary_to_ascii(binary) when is_binary(binary) do binary end end defmodule DaProductApp.MercuryISO8583.Headers.BaseHeader do defstruct [:type, :encoding, :pattern, :length, :binary_pattern] def new(config) when is_map(config) do with {:ok, binary_pattern} <- convert_pattern_to_binary(config) do header = %__MODULE__{ type: config.type, encoding: config.encoding, pattern: config.pattern, length: config.length, binary_pattern: binary_pattern } {:ok, header} end end def matches?(header, data) when is_binary(data) do pattern_size = byte_size(header.binary_pattern) if byte_size(data) >= pattern_size do <> = data header_part == header.binary_pattern else false end end def extract_header(header, data) when is_binary(data) do pattern_size = byte_size(header.binary_pattern) if byte_size(data) >= pattern_size do <> = data if header_part == header.binary_pattern do {:ok, header_part, remaining} else {:error, :header_mismatch} end else {:error, :insufficient_data} end end defp convert_pattern_to_binary(%{encoding: :hex, pattern: pattern}) do DaProductApp.MercuryISO8583.Headers.HeaderUtils.hex_to_binary(pattern) end defp convert_pattern_to_binary(%{encoding: :bcd, pattern: pattern}) do DaProductApp.MercuryISO8583.Headers.HeaderUtils.bcd_to_binary(pattern) end defp convert_pattern_to_binary(%{encoding: :ascii, pattern: pattern}) do {:ok, pattern} end end defmodule DaProductApp.MercuryISO8583.Headers.HeaderFactory do alias DaProductApp.MercuryISO8583.Headers.BaseHeader def create_from_config(%{header: %{enabled: false}}) do {:ok, :no_header} end def create_from_config(%{header: header_config}) when is_map(header_config) do case header_config.enabled do true -> BaseHeader.new(header_config) false -> {:ok, :no_header} _ -> {:error, :invalid_header_config} end end def create_from_config(_) do {:ok, :no_header} end def extract_header(:no_header, data) do {:ok, nil, data} end def extract_header(header_instance, data) do BaseHeader.extract_header(header_instance, data) end end alias DaProductApp.MercuryISO8583.Headers.HeaderUtils alias DaProductApp.MercuryISO8583.Headers.BaseHeader alias DaProductApp.MercuryISO8583.Headers.HeaderFactory defmodule RealHeaderTestScript do @moduledoc """ Test script using the real header management modules. """ require Logger def run do IO.puts("๐Ÿงช Enhanced Header Management System - Real Module Tests") IO.puts("=" |> String.duplicate(60)) test_header_utils() test_base_header() test_header_factory() IO.puts("\n๐ŸŽฏ Test Summary Complete") end defp test_header_utils do IO.puts("\n๐Ÿ”ง Testing HeaderUtils...") # Test hex to binary conversion IO.puts("Testing hex_to_binary...") case HeaderUtils.hex_to_binary("6000782000") do {:ok, binary} -> hex_back = HeaderUtils.binary_to_hex(binary) if hex_back == "6000782000" do IO.puts("โœ… Hex conversion: PASS") else IO.puts("โŒ Hex conversion: FAIL - expected 6000782000, got #{hex_back}") end {:error, reason} -> IO.puts("โŒ Hex conversion: FAIL - #{reason}") end # Test BCD conversion IO.puts("Testing BCD conversion...") case HeaderUtils.bcd_to_binary("123456") do {:ok, binary} -> bcd_back = HeaderUtils.binary_to_bcd(binary) if bcd_back == "123456" do IO.puts("โœ… BCD conversion: PASS") else IO.puts("โŒ BCD conversion: FAIL - expected 123456, got #{bcd_back}") end {:error, reason} -> IO.puts("โŒ BCD conversion: FAIL - #{reason}") end # Test ASCII conversion IO.puts("Testing ASCII conversion...") test_ascii = "TEST" binary_ascii = HeaderUtils.ascii_to_binary(test_ascii) ascii_back = HeaderUtils.binary_to_ascii(binary_ascii) if ascii_back == test_ascii do IO.puts("โœ… ASCII conversion: PASS") else IO.puts("โŒ ASCII conversion: FAIL - expected #{test_ascii}, got #{ascii_back}") end # Test invalid hex IO.puts("Testing invalid hex handling...") case HeaderUtils.hex_to_binary("invalid_hex") do {:error, :invalid_hex} -> IO.puts("โœ… Invalid hex handling: PASS") {:ok, _} -> IO.puts("โŒ Invalid hex handling: FAIL - should have returned error") end end defp test_base_header do IO.puts("\n๐Ÿ—๏ธ Testing BaseHeader...") # Test header creation config = %{ type: :base1, encoding: :hex, pattern: "6000782000", length: 5, enabled: true } case BaseHeader.new(config) do {:ok, header} -> IO.puts("โœ… BaseHeader creation: PASS") # Test pattern matching test_data = <<0x60, 0x00, 0x78, 0x20, 0x00, 0x12, 0x34>> if BaseHeader.matches?(header, test_data) do IO.puts("โœ… BaseHeader pattern matching: PASS") else IO.puts("โŒ BaseHeader pattern matching: FAIL") end # Test header extraction case BaseHeader.extract_header(header, test_data) do {:ok, extracted, remaining} -> if byte_size(extracted) == 5 and byte_size(remaining) == 2 do IO.puts("โœ… BaseHeader extraction: PASS") else IO.puts("โŒ BaseHeader extraction: FAIL - wrong sizes") end {:error, reason} -> IO.puts("โŒ BaseHeader extraction: FAIL - #{reason}") end {:error, reason} -> IO.puts("โŒ BaseHeader creation: FAIL - #{reason}") end end defp test_header_factory do IO.puts("\n๐Ÿญ Testing HeaderFactory...") # Test configuration parsing listener_config = %{ port: 8583, header: %{ enabled: true, type: :base1, encoding: :hex, pattern: "6000782000", length: 5 } } case HeaderFactory.create_from_config(listener_config) do {:ok, header_instance} -> IO.puts("โœ… HeaderFactory configuration parsing: PASS") # Test header functionality test_data = <<0x60, 0x00, 0x78, 0x20, 0x00, 0x08, 0x00>> case HeaderFactory.extract_header(header_instance, test_data) do {:ok, header, message_data} -> if byte_size(header) == 5 and byte_size(message_data) == 2 do IO.puts("โœ… HeaderFactory extraction: PASS") else IO.puts("โŒ HeaderFactory extraction: FAIL - wrong sizes") end {:error, reason} -> IO.puts("โŒ HeaderFactory extraction: FAIL - #{reason}") end {:error, reason} -> IO.puts("โŒ HeaderFactory configuration: FAIL - #{reason}") end # Test disabled header disabled_config = %{ port: 5000, header: %{enabled: false} } case HeaderFactory.create_from_config(disabled_config) do {:ok, :no_header} -> IO.puts("โœ… HeaderFactory disabled header: PASS") other -> IO.puts("โŒ HeaderFactory disabled header: FAIL - #{inspect(other)}") end end end # Run the tests RealHeaderTestScript.run()