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
Name: erlang-meck
Version: 0.8.13
Release: 1
Release: 2
BuildArch: noarch
Summary: A mocking library for Erlang
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
BuildRequires: erlang-hamcrest
BuildRequires: erlang-rebar
Patch0002: 0001-Add-introspection-of-which-modules-are-currently-moc.patch
%description
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
@ -34,5 +37,8 @@ modules, such as making sure no function is called in a way it should not.
%{erlang_appdir}/
%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
- package init