-module(mockth). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/mockth.gleam"). -export([validate/1, history/1, unload_all/0, mocked/0, unload/1, expect/3, with_mock/4]). -export_type([history/0, mock_error/0]). -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(" A module for mocking functions in Erlang modules - wrapper around [meck](https://github.com/eproxus/meck).\n"). -type history() :: {history, gleam@erlang@process:pid_(), binary(), binary(), list(gleam@dynamic:dynamic_())}. -type mock_error() :: {no_function_error, binary()} | {no_module_error, binary()} | no_expect_error. -file("src/mockth.gleam", 64). ?DOC( " Validate the state of the mock module(s).\n" " Validation can detect:\n" " - When a function was called with the wrong argument types (function_clause)\n" " - When an exception was thrown\n" " - When an exception was thrown and expected (via meck:exception/2), which still results in true being returned\n" "\n" " Validation cannot detect:\n" " - When you didn't call a function\n" " - When you called a function with the wrong number of arguments (undef)\n" " - When you called an undefined function (undef)\n" ). -spec validate(binary()) -> boolean(). validate(Module) -> Mod = erlang:binary_to_atom(Module), meck:validate(Mod). -file("src/mockth.gleam", 107). ?DOC( " Returns the history of calls to the mocked module.\n" " Don't support exception handling.\n" ). -spec history(binary()) -> {ok, list(history())} | {error, mock_error()}. history(Module) -> _pipe = erlang:binary_to_atom(Module), _pipe@1 = meck:history(_pipe), _pipe@2 = gleam@list:map( _pipe@1, fun(Histoy) -> {Pid, Mfa, _} = Histoy, {Module@1, Function, Arguments} = Mfa, Module@2 = erlang:atom_to_binary(Module@1), Function@1 = erlang:atom_to_binary(Function), {history, Pid, Module@2, Function@1, Arguments} end ), {ok, _pipe@2}. -file("src/mockth.gleam", 159). -spec module_atoms_to_strings(list(gleam@erlang@atom:atom_())) -> list(binary()). module_atoms_to_strings(Module_atoms) -> _pipe = Module_atoms, gleam@list:map(_pipe, fun erlang:atom_to_binary/1). -file("src/mockth.gleam", 74). ?DOC( " The function returns the list of mocked modules that were unloaded in the process.\n" " Unloads all mocked modules from memory.\n" ). -spec unload_all() -> list(binary()). unload_all() -> _pipe = meck:unload(), module_atoms_to_strings(_pipe). -file("src/mockth.gleam", 94). ?DOC(" Returns the currently mocked modules.\n"). -spec mocked() -> list(binary()). mocked() -> _pipe = meck:mocked(), module_atoms_to_strings(_pipe). -file("src/mockth.gleam", 164). -spec is_ok_atom(gleam@erlang@atom:atom_()) -> {ok, boolean()} | {error, mock_error()}. is_ok_atom(A) -> Ok = erlang:binary_to_atom(<<"ok"/utf8>>), case Ok =:= A of true -> {ok, true}; false -> {error, no_expect_error} end. -file("src/mockth.gleam", 84). ?DOC( " Unload a mocked module or a list of mocked modules.\n" " This will purge and delete the module(s) from the Erlang virtual machine. If the mocked module(s) replaced an existing module, this module will still be in the Erlang load path and can be loaded manually or when called.\n" ). -spec unload(binary()) -> {ok, boolean()} | {error, mock_error()}. unload(Module) -> _pipe = erlang:binary_to_atom(Module), _pipe@1 = meck:unload(_pipe), is_ok_atom(_pipe@1). -file("src/mockth.gleam", 172). -spec load_expect_atoms(binary(), binary()) -> {gleam@erlang@atom:atom_(), gleam@erlang@atom:atom_()}. load_expect_atoms(Module, Function) -> Module@1 = erlang:binary_to_atom(Module), Function@1 = erlang:binary_to_atom(Function), {Module@1, Function@1}. -file("src/mockth.gleam", 39). ?DOC( " Mock a function.\n" " The function `fun` should return the value that the function will return when called.\n" " ```gleam\n" " pub fn expect1_test() {\n" " let assert Ok(_) =\n" " mockth.expect(\"gleam@function\", \"identity\", fn(_) { \"hello\" })\n" "\n" " mockth.validate(\"gleam@function\")\n" " |> should.equal(True)\n" "\n" " mockth.mocked()\n" " |> should.equal([\"gleam@function\"])\n" "\n" " function.identity(\"world\")\n" " |> should.equal(\"hello\")\n" " }\n" ). -spec expect(binary(), binary(), any()) -> {ok, boolean()} | {error, mock_error()}. expect(Module, Function, Fun) -> {Module@1, Function@1} = load_expect_atoms(Module, Function), _pipe = meck:expect(Module@1, Function@1, Fun), is_ok_atom(_pipe). -file("src/mockth.gleam", 139). ?DOC( " Utility function to set up mocks with the `use` sugar.\n" "\n" " ```gleam\n" " pub fn with_mock_test() {\n" " use mock <- mockth.with_mock(\n" " module: \"gleam@function\",\n" " function: \"identity\",\n" " replacement: fn(_) { \"hello\" },\n" " )\n" "\n" " function.identity(\"world\")\n" " |> should.equal(\"hello\")\n" "\n" " // the mocked module is available here as `mocks`\n" " // for example to be able to call `mockth.history` with it.\n" " }\n" " ```\n" ). -spec with_mock(binary(), binary(), any(), fun((binary()) -> any())) -> list(binary()). with_mock(Module, Function, Fun, F) -> case expect(Module, Function, Fun) of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"mockth"/utf8>>, function => <<"with_mock"/utf8>>, line => 145, value => _assert_fail, start => 4475, 'end' => 4523, pattern_start => 4486, pattern_end => 4491}) end, _pipe = validate(Module), gleeunit@should:be_true(_pipe), _pipe@1 = mocked(), _pipe@2 = gleam@list:contains(_pipe@1, Module), gleeunit@should:be_true(_pipe@2), F(Module), unload_all().