#!/usr/bin/env elixir # Test script to understand why ISOMsg.set fails # This will help us understand the root cause of the set_value issue Mix.install([ {:jason, "~> 1.3"} ]) defmodule TestISOSetBehavior do @moduledoc """ Test to understand why ISOMsg.set/3 is failing """ require Logger # Mock the structure of fields to understand the issue defmodule TestISOComponent do defstruct [:field_number, :value, :validated, :packager] def new(field_number, value \\ nil) do %__MODULE__{ field_number: field_number, value: value, validated: false } end def set_value(%__MODULE__{} = component, value) do %{component | value: value, validated: false} end # This is what causes the original error - if the first argument is not a struct def set_value(not_a_struct, value) when not is_struct(not_a_struct) do raise FunctionClauseError, module: __MODULE__, function: :set_value, arity: 2, args: [not_a_struct, value] end def get_value(%__MODULE__{value: value}), do: value end defmodule TestISOMsg do defstruct [:mti, :fields] def new(mti) do %__MODULE__{mti: mti, fields: %{}} end def set(%__MODULE__{fields: fields} = msg, field_number, value) do Logger.info("Setting field #{field_number} to '#{value}'") # This is the logic from the real ISOMsg.set/3 component = case Map.get(fields, field_number) do nil -> Logger.info("Field #{field_number} is nil, creating new component") TestISOComponent.new(field_number, value) existing -> Logger.info("Field #{field_number} exists: #{inspect(existing)}") TestISOComponent.set_value(existing, value) # This is where it can fail! end updated_fields = Map.put(fields, field_number, component) %{msg | fields: updated_fields} end def get(%__MODULE__{fields: fields}, field_number) do case Map.get(fields, field_number) do nil -> nil component -> TestISOComponent.get_value(component) end end end def test_iso_set_behavior do Logger.info("=== Testing ISOMsg.set behavior ===") # Test 1: Normal case - set field on empty message Logger.info("\n--- Test 1: Setting field on empty message ---") msg1 = TestISOMsg.new("0200") msg2 = TestISOMsg.set(msg1, 24, "782") Logger.info("✅ Successfully set field 24 to '782'") Logger.info("Field 24 value: #{TestISOMsg.get(msg2, 24)}") # Test 2: Set same field again with same value Logger.info("\n--- Test 2: Setting same field with same value ---") try do msg3 = TestISOMsg.set(msg2, 24, "782") Logger.info("✅ Successfully set field 24 to '782' again") Logger.info("Field 24 value: #{TestISOMsg.get(msg3, 24)}") rescue exception -> Logger.error("❌ Failed to set same field with same value: #{inspect(exception)}") end # Test 3: What if the field contains a plain string instead of ISOComponent? Logger.info("\n--- Test 3: Field contains plain string (corrupted state) ---") corrupted_msg = %TestISOMsg{ mti: "0200", fields: %{24 => "782"} # Plain string instead of ISOComponent struct! } Logger.info("Corrupted message fields: #{inspect(corrupted_msg.fields)}") try do TestISOMsg.set(corrupted_msg, 24, "782") Logger.info("✅ Unexpectedly succeeded with corrupted field") rescue exception -> Logger.error("❌ Failed with corrupted field (plain string): #{inspect(exception)}") Logger.error("This explains the original error!") end Logger.info("\n=== Test completed ===") end end # Run the test TestISOSetBehavior.test_iso_set_behavior()