Add introspection of which modules are currently mocked

Signed-off-by: liubo <liubo1@xfusion.com>
This commit is contained in:
liubo 2023-12-05 18:34:46 +08:00
parent 9d8e545fdf
commit c814454989
2 changed files with 138 additions and 1 deletions

View File

@ -0,0 +1,131 @@
From 1ed7933038d709faae7d7fa8152e2c07ad2d6e50 Mon Sep 17 00:00:00 2001
From: Filipe Cristovao <filipe.cristovao@klarna.com>
Date: Tue, 12 May 2020 22:13:51 +0200
Subject: [PATCH] Add introspection of which modules are currently mocked
There's already an `meck:expects/[1,2]`, allowing introspection into
what kind of expectations are set.
This allows one to also check which modules is meck handling at any
point.
Introduced a `foldl_mocks` internal function to reuse the same logic
for both `unload/0` and `mocked/0`
---
src/meck.erl | 47 ++++++++++++++++++++++++++-------------------
test/meck_tests.erl | 21 ++++++++++++++++++++
2 files changed, 48 insertions(+), 20 deletions(-)
diff --git a/src/meck.erl b/src/meck.erl
index 9f4efc2..8eb0365 100644
--- a/src/meck.erl
+++ b/src/meck.erl
@@ -54,6 +54,7 @@
-export([wait/4]).
-export([wait/5]).
-export([wait/6]).
+-export([mocked/0]).
%% Syntactic sugar
-export([loop/1]).
@@ -460,7 +461,15 @@ history(Mod, OptCallerPid)
-spec unload() -> Unloaded when
Unloaded :: [Mod],
Mod :: atom().
-unload() -> lists:foldl(fun unload_if_mocked/2, [], registered()).
+unload() ->
+ foldl_mocks(fun(Mod, Acc) ->
+ try
+ unload(Mod),
+ [Mod | Acc]
+ catch error:{not_mocked, Mod} ->
+ Acc
+ end
+ end, []).
%% @doc Unload a mocked module or a list of mocked modules.
%%
@@ -723,6 +732,11 @@ capture(Occur, Mod, Func, OptArgsSpec, ArgNum, OptCallerPid) ->
capture(Occur, Mod, Func, OptArgsSpec, ArgNum) ->
meck_history:capture(Occur, '_', Mod, Func, OptArgsSpec, ArgNum).
+%% @doc Returns the currently mocked modules.
+-spec mocked() -> list(atom()).
+mocked() ->
+ foldl_mocks(fun(M, Acc) -> [M | Acc] end, []).
+
%%%============================================================================
%%% Internal functions
%%%============================================================================
@@ -732,25 +746,18 @@ wait_for_exit(Mod) ->
MonitorRef = erlang:monitor(process, meck_util:proc_name(Mod)),
receive {'DOWN', MonitorRef, _Type, _Object, _Info} -> ok end.
--spec unload_if_mocked(Mod::atom() | string(), Unloaded::[atom()]) ->
- NewUnloaded::[atom()].
-unload_if_mocked(Mod, Unloaded) when is_atom(Mod) ->
- unload_if_mocked(atom_to_list(Mod), Unloaded);
-unload_if_mocked(ModName, Unloaded) when length(ModName) > 5 ->
- case lists:split(length(ModName) - 5, ModName) of
- {Name, "_meck"} ->
- Mocked = erlang:list_to_existing_atom(Name),
- try
- unload(Mocked)
- catch error:{not_mocked, Mocked} ->
- ok
- end,
- [Mocked | Unloaded];
- _Else ->
- Unloaded
- end;
-unload_if_mocked(_P, Unloaded) ->
- Unloaded.
+-spec foldl_mocks(Fun, AccIn) -> AccOut when
+ Fun :: fun((Elem :: module(), AccIn) -> AccOut),
+ AccIn :: term(),
+ AccOut :: term().
+foldl_mocks(Fun, Acc0) when is_function(Fun, 2) ->
+ lists:foldl(fun(Mod, Acc) ->
+ ModName = atom_to_list(Mod),
+ case lists:split(max(length(ModName) - 5, 0), ModName) of
+ {Name, "_meck"} -> Fun(erlang:list_to_existing_atom(Name), Acc);
+ _Else -> Acc
+ end
+ end, Acc0, erlang:registered()).
-spec check_expect_result(ok | {error, Reason::any()}) -> ok.
check_expect_result(ok) -> ok;
diff --git a/test/meck_tests.erl b/test/meck_tests.erl
index f17223c..988ded7 100644
--- a/test/meck_tests.erl
+++ b/test/meck_tests.erl
@@ -1547,6 +1547,27 @@ wait_purge_expired_tracker_test() ->
%% Clean
meck:unload().
+mocked_test() ->
+ %% At start, no modules should be mocked:
+ [] = meck:mocked(),
+
+ %% Mocking a new module adds it to the list of mocked modules:
+ meck:new(mocked_test, [non_strict]),
+ [mocked_test] = meck:mocked(),
+
+ %% Mocking with implicit `meck:new` also adds to the list of mocked modules:
+ meck:expect(meck_test_module, c, 2, ok),
+ [meck_test_module, mocked_test] = lists:sort(meck:mocked()),
+
+ meck:new([foo, bar], [non_strict]),
+ [bar, foo, meck_test_module, mocked_test] = lists:sort(meck:mocked()),
+
+ ok = meck:unload([foo, meck_test_module]),
+ [bar, mocked_test] = lists:sort(meck:mocked()),
+
+ meck:unload(),
+ %% After unload all, no modules should be mocked again
+ [] = meck:mocked().
meck_passthrough_test_() ->
{foreach, fun setup_passthrough/0, fun teardown/1,
--
2.42.0.windows.2

View File

@ -2,7 +2,7 @@
%global upstream eproxus %global upstream eproxus
Name: erlang-meck Name: erlang-meck
Version: 0.8.13 Version: 0.8.13
Release: 1 Release: 2
BuildArch: noarch BuildArch: noarch
Summary: A mocking library for Erlang Summary: A mocking library for Erlang
License: ASL 2.0 License: ASL 2.0
@ -11,6 +11,9 @@ Source0: https://github.com/eproxus/meck/archive/%{version}/meck-%{version}.tar.
Patch1: erlang-meck-0001-Workaround-for-Rebar-2.x.patch Patch1: erlang-meck-0001-Workaround-for-Rebar-2.x.patch
BuildRequires: erlang-hamcrest BuildRequires: erlang-hamcrest
BuildRequires: erlang-rebar BuildRequires: erlang-rebar
Patch0002: 0001-Add-introspection-of-which-modules-are-currently-moc.patch
%description %description
With meck you can easily mock modules in Erlang. Since meck is intended to be With meck you can easily mock modules in Erlang. Since meck is intended to be
used in testing, you can also perform some basic validations on the mocked used in testing, you can also perform some basic validations on the mocked
@ -34,5 +37,8 @@ modules, such as making sure no function is called in a way it should not.
%{erlang_appdir}/ %{erlang_appdir}/
%changelog %changelog
* Tue Dec 5 2023 liubo <liubo1@xfusion.com> - 0.8.13-2
- Add introspection of which modules are currently mocked
* Sat Aug 29 2020 yaokai <yaokai13@huawei.com> - 0.8.13-1 * Sat Aug 29 2020 yaokai <yaokai13@huawei.com> - 0.8.13-1
- package init - package init