From 3efce27e01fcb442f0ec7dc3af587745510fdc19 Mon Sep 17 00:00:00 2001 From: Zsolt Laky Date: Mon, 15 Mar 2021 17:05:15 +0100 Subject: [PATCH] Leave module loaded state as it was --- CHANGELOG.md | 4 ++++ src/meck_proc.erl | 20 ++++++++++++++++---- test/meck_tests.erl | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b8ae59..e2e5d34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ The format is based on [Keep a Changelog], and this project adheres to ## [Unreleased] +### Added + +- Leave module loaded state as it was [\#228](https://github.com/eproxus/meck/pull/228) + ## [0.9.2] - 2021-03-06 ### Fixed diff --git a/src/meck_proc.erl b/src/meck_proc.erl index 2640236..b1500c6 100644 --- a/src/meck_proc.erl +++ b/src/meck_proc.erl @@ -61,7 +61,8 @@ passthrough = false :: boolean(), reload :: {Compiler::pid(), {From::pid(), Tag::any()}} | undefined, - trackers = [] :: [tracker()]}). + trackers = [] :: [tracker()], + restore = false :: boolean()}). -record(tracker, {opt_func :: '_' | atom(), args_matcher :: meck_args_matcher:args_matcher(), @@ -211,6 +212,7 @@ validate_options([UnknownOption|_]) -> erlang:error({bad_arg, UnknownOption}). %% @hidden init([Mod, Options]) -> validate_options(Options), + Restore = code:is_loaded(Mod) =/= false, Exports = normal_exports(Mod), WasSticky = case proplists:get_bool(unstick, Options) of true -> {module, Mod} = code:ensure_loaded(Mod), @@ -237,7 +239,8 @@ init([Mod, Options]) -> was_sticky = WasSticky, merge_expects = MergeExpects, passthrough = Passthrough, - history = History}} + history = History, + restore = Restore}} catch exit:{error_loading_module, Mod, sticky_directory} -> {stop, {module_is_sticky, Mod}} @@ -344,11 +347,20 @@ handle_info(_Info, S) -> %% @hidden terminate(_Reason, #state{mod = Mod, original = OriginalState, - was_sticky = WasSticky}) -> + was_sticky = WasSticky, restore = Restore}) -> BackupCover = export_original_cover(Mod, OriginalState), cleanup(Mod), restore_original(Mod, OriginalState, WasSticky, BackupCover), - ok. + case Restore andalso false =:= code:is_loaded(Mod) of + true -> + % We make a best effort to reload the module here. Since this runs + % in a terminating process there is nothing we can do to recover if + % the loading fails. + _ = code:load_file(Mod), + ok; + _ -> + ok + end. %% @hidden code_change(_OldVsn, S, _Extra) -> {ok, S}. diff --git a/test/meck_tests.erl b/test/meck_tests.erl index 616730c..946ba7b 100644 --- a/test/meck_tests.erl +++ b/test/meck_tests.erl @@ -928,6 +928,20 @@ unload_all_test() -> ?assertEqual(lists:sort(Mods), lists:sort(meck:unload())), [?assertEqual(false, code:is_loaded(M)) || M <- Mods]. +reload_module_test() -> + false = code:purge(meck_test_module), + ?assertEqual({module, meck_test_module}, code:load_file(meck_test_module)), + ok = meck:new(meck_test_module), + ?assertEqual(ok, meck:unload(meck_test_module)), + ?assertMatch({file, _}, code:is_loaded(meck_test_module)), + false = code:purge(meck_test_module), + true = code:delete(meck_test_module), + ?assertEqual(false, code:is_loaded(meck_test_module)), + ok = meck:new(meck_test_module), + ?assertMatch({file, _}, code:is_loaded(meck_test_module)), + ?assertEqual(ok, meck:unload(meck_test_module)), + ?assertEqual(false, code:is_loaded(meck_test_module)). + original_no_file_test() -> {ok, Mod, Beam} = compile:forms([{attribute, 1, module, meck_not_on_disk}]), {module, Mod} = code:load_binary(Mod, "", Beam), -- 2.42.0.windows.2