Skip to content
Permalink
Browse files
Use compatible stack trace handling
Moved and cleaned up the stack trace handling to a shared header file.
Cleaned-up file is developed by me and taken from basho/riak_core [1],
based on this original code in Meck.

[1]: https://github.com/basho/riak_core/blob/b726b0b4c5bbef1a20b95d551d3e32f6dc8741b5/src/stacktrace.hrl
  • Loading branch information
eproxus committed May 14, 2020
1 parent 8c16751 commit 558e925b48ce257b12e381080c851dc49c87d7bb
Showing 3 changed files with 43 additions and 30 deletions.
@@ -0,0 +1,34 @@
%% Copied from basho/riak_core.
%%
%% Fix to make Erlang programs compile on both OTP20 and OTP21.
%%
%% Get the stack trace in a way that is backwards compatible. Luckily
%% OTP_RELEASE was introduced in the same version as the new preferred way of
%% getting the stack trace. A _catch_/2 macro is provided for consistency in
%% cases where the stack trace is not needed.
%%
%% Example use:
%% try f(...)
%% catch
%% ?_exception_(_, Reason, StackToken) ->
%% case Reason of
%% {fail, Error} -> ok;
%% _ -> {'EXIT', Reason, ?_get_stacktrace_(StackToken)}
%% end
%% end,

-ifdef(OTP_RELEASE). %% This implies 21 or higher
-define(_exception_(Class, Reason, StackToken), Class:Reason:StackToken).
-define(_get_stacktrace_(StackToken), StackToken).
-define(_current_stacktrace_(),
try
exit('$get_stacktrace')
catch
exit:'$get_stacktrace':__GetCurrentStackTrace ->
__GetCurrentStackTrace
end).
-else.
-define(_exception_(Class, Reason, _), Class:Reason).
-define(_get_stacktrace_(_), erlang:get_stacktrace()).
-define(_current_stacktrace_(), erlang:get_stacktrace()).
-endif.
@@ -24,6 +24,8 @@
%% Exported to be accessible from generated modules.
-export([exec/4]).

-include("meck.hrl").

%%%============================================================================
%%% Definitions
%%%============================================================================
@@ -168,29 +170,6 @@ exec(Pid, Mod, Func, Args) ->
apply(Mod, Func, Args)
end.

%% workaround for the removal of erlang:get_stacktrace/0 beginning
%% in Erlang 21.
%% There is no good solution if you want BOTH
%% a) be able to compile with both pre- and post-21 compilers
%% b) no warning (e.g. if you use warnings_as_errors)
%% this is one of(?) the less bad hacks.
%% `OTP_RELEASE' was introduced in 21, so if it is defined, we use post-21
%% behaviour, otherwise pre-21.
%% Note that in the EXCEPTION macro, you can match on Class and Reason,
%% but not on StackToken. I.e. this works;
%% ?EXCEPTION(throw,R,S)
%% but not this;
%% ?EXCEPTION(C,R,[])
%% StackToken is used to make the macros hygienic (i.e. to not leak variable
%% bindings)
-ifdef(OTP_RELEASE). %% this implies 21 or higher
-define(EXCEPTION(Class, Reason, StackToken), Class:Reason:StackToken).
-define(GET_STACK(StackToken), StackToken).
-else.
-define(EXCEPTION(Class, Reason, _), Class:Reason).
-define(GET_STACK(_), erlang:get_stacktrace()).
-endif.

-spec eval(Pid::pid(), Mod::atom(), Func::atom(), Args::[any()],
ResultSpec::any()) -> Result::any() | no_return().
eval(Pid, Mod, Func, Args, ResultSpec) ->
@@ -200,9 +179,9 @@ eval(Pid, Mod, Func, Args, ResultSpec) ->
meck_proc:add_history(Mod, Pid, Func, Args, Result),
Result
catch
?EXCEPTION(Class, Reason, StackToken) ->
?_exception_(Class, Reason, StackToken) ->
handle_exception(Pid, Mod, Func, Args,
Class, Reason, ?GET_STACK(StackToken))
Class, Reason, ?_get_stacktrace_(StackToken))
after
erase(?CURRENT_CALL)
end.
@@ -17,6 +17,7 @@
-module(meck_tests).

-include_lib("eunit/include/eunit.hrl").
-include("../src/meck.hrl").

-define(assertTerminated(MonitorRef, Reason, Timeout),
(fun() ->
@@ -207,11 +208,11 @@ stacktrace_(Mod) ->
Mod:test(),
throw(failed)
catch
error:test_error ->
?_exception_(error, test_error, StackToken) ->
?assert(lists:any(fun({M, test, []}) when M == Mod -> true;
({M, test, [],[]}) when M == Mod -> true;
(_) -> false
end, erlang:get_stacktrace()))
end, ?_get_stacktrace_(StackToken)))
end.

stacktrace_function_clause_(Mod) ->
@@ -220,13 +221,12 @@ stacktrace_function_clause_(Mod) ->
Mod:test(error),
throw(failed)
catch
error:function_clause ->
Stacktrace = erlang:get_stacktrace(),
?_exception_(error, function_clause, StackToken) ->
?assert(lists:any(
fun ({M, test, [error]}) when M == Mod -> true;
({M, test, [error], []}) when M == Mod -> true;
(_) -> false
end, Stacktrace))
end, ?_get_stacktrace_(StackToken)))
end.

call_undef_(Mod) ->

0 comments on commit 558e925

Please sign in to comment.