-module(aion@testing@mock). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/aion/testing/mock.gleam"). -export([activity/3, child/6]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Typed activity and child-workflow mock registries for `aion/testing`.\n" "\n" " Tests register activity mocks against an `Activity(i, o)` value so the\n" " handler is statically checked against the same input and output types that\n" " `workflow.run` will use, and child doubles against the input/output/error\n" " codecs that `workflow.spawn_and_wait` will use. The test-only FFI double\n" " stores a type-erased wrapper in process-scoped state and intercepts\n" " activity dispatch and child spawn by name.\n" ). -file("src/aion/testing/mock.gleam", 82). -spec activity_error_to_raw(aion@error:activity_error()) -> binary(). activity_error_to_raw(Activity_error) -> case Activity_error of {retryable, Message, _} -> <<"retryable:"/utf8, Message/binary>>; {terminal, Message@1, _} -> <<"terminal:"/utf8, Message@1/binary>>; {activity_decode_failed, Decode_error} -> <<"terminal:activity decode failed: "/utf8, (erlang:element(2, Decode_error))/binary>>; {activity_timed_out, {timed_out, Message@2}} -> <<"timeout:"/utf8, Message@2/binary>>; {activity_cancelled, {cancelled, Reason}} -> <<"cancelled:"/utf8, Reason/binary>>; {activity_non_deterministic, {non_determinism_violation, Message@3}} -> <<"non_determinism:"/utf8, Message@3/binary>>; {activity_engine_failure, Message@4} -> Message@4 end. -file("src/aion/testing/mock.gleam", 19). ?DOC( " Register a typed activity mock for the current process.\n" "\n" " A handler whose input or output type does not match the supplied activity will\n" " fail at `gleam build`, before the workflow test can run.\n" ). -spec activity( FKW, aion@activity:activity(FKX, FKY), fun((FKX) -> {ok, FKY} | {error, aion@error:activity_error()}) ) -> {ok, FKW} | {error, aion@error:engine_error()}. activity(Env, Activity_value, Handler) -> Input_codec = aion@activity:input_codec(Activity_value), Output_codec = aion@activity:output_codec(Activity_value), Name = aion@activity:name(Activity_value), Raw_handler = fun(Raw_input) -> case (erlang:element(3, Input_codec))(Raw_input) of {ok, Typed_input} -> case Handler(Typed_input) of {ok, Typed_output} -> {ok, (erlang:element(2, Output_codec))(Typed_output)}; {error, Activity_error} -> {error, activity_error_to_raw(Activity_error)} end; {error, Decode_error} -> {error, <<"terminal:mock input decode failed: "/utf8, (erlang:element(2, Decode_error))/binary>>} end end, case aion_flow_ffi:testing_register_activity_mock(Name, Raw_handler) of {ok, _} -> {ok, Env}; {error, Raw_error} -> {error, {engine_failure, Raw_error}} end. -file("src/aion/testing/mock.gleam", 54). ?DOC( " Register a typed child-workflow double for the current test process.\n" "\n" " `workflow.spawn_and_wait(name, ...)` calls with the same `name` execute\n" " `handler` synchronously and record its typed result as the child terminal:\n" " `Ok` is decoded by the parent's output codec and a typed `Error` surfaces\n" " as `error.ChildWorkflowFailed`. Registering the child module's real\n" " `execute` function as the handler runs the full child workflow body —\n" " including its own activity dispatches against this process's activity\n" " mocks — inside the parent test.\n" ). -spec child( FLF, binary(), aion@codec:codec(FLG), aion@codec:codec(FLI), aion@codec:codec(FLK), fun((FLG) -> {ok, FLI} | {error, FLK}) ) -> {ok, FLF} | {error, aion@error:engine_error()}. child( Env, Name, Child_input_codec, Child_output_codec, Child_error_codec, Handler ) -> Raw_handler = fun(Raw_input) -> case (erlang:element(3, Child_input_codec))(Raw_input) of {ok, Typed_input} -> case Handler(Typed_input) of {ok, Typed_output} -> {ok, <<"ok:"/utf8, ((erlang:element(2, Child_output_codec))( Typed_output ))/binary>>}; {error, Workflow_error} -> {ok, <<"error:"/utf8, ((erlang:element(2, Child_error_codec))( Workflow_error ))/binary>>} end; {error, Decode_error} -> {error, <<"child mock input decode failed: "/utf8, (erlang:element(2, Decode_error))/binary>>} end end, case aion_flow_ffi:testing_register_child_mock(Name, Raw_handler) of {ok, _} -> {ok, Env}; {error, Raw_error} -> {error, {engine_failure, Raw_error}} end.