#!/usr/bin/env elixir # Test script for network packagers # Usage: elixir test_network_packagers.exs defmodule NetworkPackagerTest do @moduledoc """ Test script to verify VISA and MasterCard packagers work correctly """ alias DaProductApp.MercuryISO8583.Packagers.{ISOMsg} alias DaProductApp.MercuryISO8583.Packagers.NetworkPackagers.{VisaPackager, MasterCardPackager} def run_tests do IO.puts("=== Network Packager Test Suite ===\n") test_visa_packager() test_mastercard_packager() test_routing_logic() IO.puts("\n=== All tests completed ===") end def test_visa_packager do IO.puts("Testing VISA Packager...") # Create a test purchase transaction visa_message = %ISOMsg{ mti: "0200", fields: %{ "2" => "4111111111111111", # VISA PAN "3" => "000000", # Processing code - purchase "4" => "000000010000", # Transaction amount - $100.00 "7" => "0110123456", # Transmission date/time "11" => "123456", # STAN "12" => "123456", # Local time "13" => "1101", # Local date "22" => "012", # POS entry mode "25" => "00", # POS condition code "32" => "123456", # Acquiring institution ID "37" => "123456789012", # Retrieval reference number "41" => "TERM0001", # Terminal ID "42" => "MERCHANT00001", # Merchant ID "49" => "840" # Currency code - USD }, dirty: false, max_field: 128 } case VisaPackager.pack(visa_message) do {:ok, packed_data} -> IO.puts(" ✓ VISA pack successful, #{byte_size(packed_data)} bytes") case VisaPackager.unpack(packed_data) do {:ok, unpacked_message} -> IO.puts(" ✓ VISA unpack successful") verify_message_fields(visa_message, unpacked_message, "VISA") {:error, reason} -> IO.puts(" ✗ VISA unpack failed: #{inspect(reason)}") end {:error, reason} -> IO.puts(" ✗ VISA pack failed: #{inspect(reason)}") end IO.puts("") end def test_mastercard_packager do IO.puts("Testing MasterCard Packager...") # Create a test purchase transaction mc_message = %ISOMsg{ mti: "0200", fields: %{ "2" => "5555555555554444", # MasterCard PAN "3" => "000000", # Processing code - purchase "4" => "000000050000", # Transaction amount - $500.00 "7" => "0110123456", # Transmission date/time "11" => "654321", # STAN "12" => "123456", # Local time "13" => "1101", # Local date "22" => "012", # POS entry mode "25" => "00", # POS condition code "32" => "654321", # Acquiring institution ID "37" => "210987654321", # Retrieval reference number "41" => "TERM0002", # Terminal ID "42" => "MERCHANT00002", # Merchant ID "48" => "TEST_EBCDIC_DATA", # Special EBCDIC subfield data "49" => "840" # Currency code - USD }, dirty: false, max_field: 128 } case MasterCardPackager.pack(mc_message) do {:ok, packed_data} -> IO.puts(" ✓ MasterCard pack successful, #{byte_size(packed_data)} bytes") case MasterCardPackager.unpack(packed_data) do {:ok, unpacked_message} -> IO.puts(" ✓ MasterCard unpack successful") verify_message_fields(mc_message, unpacked_message, "MasterCard") {:error, reason} -> IO.puts(" ✗ MasterCard unpack failed: #{inspect(reason)}") end {:error, reason} -> IO.puts(" ✗ MasterCard pack failed: #{inspect(reason)}") end IO.puts("") end def test_routing_logic do IO.puts("Testing BIN-based routing logic...") test_cases = [ {"4111111111111111", :visa, "VISA card"}, {"5555555555554444", :mastercard, "MasterCard"}, {"2223000048400011", :mastercard, "MasterCard 2-series"}, {"378282246310005", :amex, "American Express"}, {"6011111111111117", :discover, "Discover"}, {"1234567890123456", :unknown, "Unknown card type"} ] Enum.each(test_cases, fn {pan, expected_network, description} -> detected_network = determine_network_by_pan(pan) if detected_network == expected_network do IO.puts(" ✓ #{description}: #{pan} → #{detected_network}") else IO.puts(" ✗ #{description}: #{pan} → expected #{expected_network}, got #{detected_network}") end end) IO.puts("") end # Helper functions defp verify_message_fields(original, unpacked, network_name) do # Check that critical fields match critical_fields = ["2", "3", "4", "11", "37", "41", "42"] all_match = Enum.all?(critical_fields, fn field -> original_value = get_field_value(original, field) unpacked_value = get_field_value(unpacked, field) original_value == unpacked_value end) if all_match do IO.puts(" ✓ #{network_name} field verification passed") else IO.puts(" ✗ #{network_name} field verification failed") # Show mismatches Enum.each(critical_fields, fn field -> original_value = get_field_value(original, field) unpacked_value = get_field_value(unpacked, field) if original_value != unpacked_value do IO.puts(" Field #{field}: #{inspect(original_value)} → #{inspect(unpacked_value)}") end end) end end defp get_field_value(%ISOMsg{fields: fields}, field) do Map.get(fields, field) end defp determine_network_by_pan(pan) when is_binary(pan) and byte_size(pan) >= 4 do case pan do # VISA - starts with 4 "4" <> _ -> :visa # MasterCard - starts with 5 or 2221-2720 "5" <> _ -> :mastercard "2221" <> _ -> :mastercard "2222" <> _ -> :mastercard "2223" <> _ -> :mastercard "2224" <> _ -> :mastercard "2225" <> _ -> :mastercard "2226" <> _ -> :mastercard "2227" <> _ -> :mastercard # American Express - starts with 34 or 37 "34" <> _ -> :amex "37" <> _ -> :amex # Discover - starts with 6011, 644-649, 65 "6011" <> _ -> :discover "644" <> _ -> :discover "645" <> _ -> :discover "65" <> _ -> :discover _ -> :unknown end end defp determine_network_by_pan(_), do: :unknown end # Run the tests NetworkPackagerTest.run_tests()