diff options
Diffstat (limited to 'lib/debugger/test/int_eval_SUITE.erl')
-rw-r--r-- | lib/debugger/test/int_eval_SUITE.erl | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/lib/debugger/test/int_eval_SUITE.erl b/lib/debugger/test/int_eval_SUITE.erl new file mode 100644 index 0000000000..19b006e750 --- /dev/null +++ b/lib/debugger/test/int_eval_SUITE.erl @@ -0,0 +1,277 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(int_eval_SUITE). + +%% Purpose: Deeper test of the evaluator. + +-export([all/1,init_per_testcase/2, fin_per_testcase/2, + bifs_outside_erlang/1, spawning/1, applying/1, + catch_and_throw/1, external_call/1, test_module_info/1, + apply_interpreted_fun/1, apply_uninterpreted_fun/1, + interpreted_exit/1, otp_8310/1]). + +%% Helpers. +-export([applier/3]). + +-define(IM, my_int_eval_module). + +-include("test_server.hrl"). + +all(suite) -> + [bifs_outside_erlang,spawning,applying,catch_and_throw, + external_call,test_module_info, + apply_interpreted_fun,apply_uninterpreted_fun, + interpreted_exit, otp_8310]. + +init_per_testcase(_Case, Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {module,?IM} = int:i(filename:join(DataDir, ?IM)), + ?line ok = io:format("Interpreted modules: ~p",[int:interpreted()]), + {ok, Dog} = timer:apply_after(timer:minutes(1), + erlang, exit, [self(), kill]), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + ok = io:format("Interpreted modules: ~p", [int:interpreted()]), + Dog = ?config(watchdog, Config), + timer:cancel(Dog), + ok. + +bifs_outside_erlang(doc) -> + "Test that BIFs outside the erlang module are correctly evaluated."; +bifs_outside_erlang(suite) -> + []; +bifs_outside_erlang(Config) when is_list(Config) -> + Fun = fun() -> + Id = ?IM:ets_new(), + Self = self(), + ok = io:format("Self: ~p", [Self]), + Info = ets:info(Id), + {owner,Self} = lists:nth(2, Info), + %% Was + %% {owner,Self} = element(2, Info), + %% in R10B. + ?IM:ets_delete(Id), + ok + end, + ?line ok = spawn_eval(Fun), + ok. + +spawning(doc) -> + "Try evalutate spawn_link/3."; +spawning(suite) -> + []; +spawning(Config) when is_list(Config) -> + ?line ok = spawn_eval(fun() -> ?IM:spawn_test() end). + +applying(doc) -> + "Try various sorts of applies."; +applying(suite) -> + []; +applying(Config) when is_list(Config) -> + Fun = fun({number,X}, {number,Y}) -> X+Y end, + ?line ok = spawn_eval(fun() -> ?IM:apply_test(Fun) end). + +catch_and_throw(doc) -> + "Test catch and throw/1."; +catch_and_throw(suite) -> + []; +catch_and_throw(Config) when is_list(Config) -> + {a,ball} = spawn_eval(fun() -> ok = ?IM:catch_a_ball(), + catch ?IM:throw_a_ball() end), + + %% Throw and catch without any extra outer catch. + + ?line process_flag(trap_exit, true), + ?line Pid1 = spawn_link(fun() -> exit(?IM:catch_a_ball()) end), + receive + {'EXIT',Pid1,ok} -> ok; + {'EXIT',Pid1,Bad1} -> ?line ?t:fail({bad_message,Bad1}) + after 5000 -> + ?line ?t:fail(timeout) + end, + + + %% Throw without catch. + + ?line Pid2 = spawn_link(fun() -> ?IM:throw_a_ball() end), + receive + {'EXIT',Pid2,{{nocatch,{a,ball}},[_|_]}} -> ok; + {'EXIT',Pid2,Bad2} -> ?line ?t:fail({bad_message,Bad2}) + after 5000 -> + ?line ?t:fail(timeout) + end, + + ?line ok = ?IM:more_catch(fun(_) -> ?IM:exit_me() end), + ?line ok = ?IM:more_catch(fun(_) -> exit({unint, exit}) end), + ?line {a, ball} = ?IM:more_catch(fun(_) -> ?IM:throw_a_ball() end), + ?line {b, ball} = ?IM:more_catch(fun(_) -> throw({b,ball}) end), + + ExitInt = {'EXIT',{int,exit}}, + ExitU = {'EXIT',{unint,exit}}, + + ?line ExitInt = (catch ?IM:more_nocatch(fun(_) -> ?IM:exit_me() end)), + ?line ExitU = (catch ?IM:more_nocatch(fun(_) -> exit({unint, exit}) end)), + ?line {a, ball} = (catch {error, ?IM:more_nocatch(fun(_) -> ?IM:throw_a_ball() end)}), + ?line {b, ball} = (catch {error, ?IM:more_nocatch(fun(_) -> throw({b,ball}) end)}), + ok. + +external_call(doc) -> + "Test external calls."; +external_call(suite) -> + []; +external_call(Config) when is_list(Config) -> + ?line ok = spawn_eval(fun() -> ?IM:external_call_test({some,stupid,data}) end). + +test_module_info(doc) -> + "Test the module_info/0,1 functions."; +test_module_info(suite) -> + []; +test_module_info(Config) when is_list(Config) -> + ?line ModInfo = ?IM:module_info(), + ?line {value,{exports,Exp}} = lists:keysearch(exports, 1, ModInfo), + ?line {value,{attributes,Attr}} = lists:keysearch(attributes, 1, ModInfo), + ?line Exp = ?IM:module_info(exports), + ?line Attr = ?IM:module_info(attributes), + ?line {value,{stupid_attribute,[{a,b}]}} = + lists:keysearch(stupid_attribute, 1, Attr), + + %% Check exports using a list comprehension in the module itself. + + ?line ok = ?IM:check_exports(Exp), + + %% Call module_info/0,1 from the module itself. + + ?line ok = ?IM:check_module_info(ModInfo, Exp), + + ok. + +apply_interpreted_fun(doc) -> + "Apply a fun defined in interpreted code."; +apply_interpreted_fun(suite) -> []; +apply_interpreted_fun(Config) when is_list(Config) -> + + %% Called from uninterpreted code + ?line F1 = spawn_eval(fun() -> ?IM:give_me_a_fun_0() end), + ?line perfectly_alright = spawn_eval(fun() -> F1() end), + ?line ATerm = {a,term}, + ?line F2 = spawn_eval(fun() -> ?IM:give_me_a_fun_0(ATerm) end), + ?line {ok,ATerm} = spawn_eval(fun() -> F2() end), + + %% Called from uninterpreted code, badarity + ?line {'EXIT',{{badarity,{F1,[snape]}},[{?MODULE,_,_}|_]}} = + spawn_eval(fun() -> F1(snape) end), + + %% Called from uninterpreted code, error in fun + ?line F3 = spawn_eval(fun() -> ?IM:give_me_a_bad_fun() end), + ?line {'EXIT',{snape,[{?IM,_FunName,_}|_]}} = + spawn_eval(fun() -> F3(snape) end), + + %% Called from within interpreted code + ?line perfectly_alright = spawn_eval(fun() -> ?IM:do_apply(F1) end), + + %% Called from within interpreted code, badarity + ?line {'EXIT',{{badarity,{F1,[snape]}},[{?IM,do_apply,_}|_]}} = + spawn_eval(fun() -> ?IM:do_apply(F1, snape) end), + + %% Called from within interpreted code, error in fun + ?line {'EXIT',{snape,[{?IM,_FunName,_}|_]}} = + spawn_eval(fun() -> ?IM:do_apply(F3, snape) end), + + %% Try some more complex funs. + ?line F4 = ?IM:give_me_a_fun_1(14, 42), + ?line {false,yes,yeah,false} = + F4({{1,nope},{14,yes},{42,yeah},{100,forget_it}}), + ?line [this_is_ok,me_too] = + F4([{-24,no_way},{15,this_is_ok},{1333,forget_me},{37,me_too}]), + + %% OTP-5837 + %% Try fun with guard containing variable bound in environment + ?line [yes,no,no,no] = ?IM:otp_5837(1), + + ok. + +apply_uninterpreted_fun(doc) -> + "Apply a fun defined outside interpreted code."; +apply_uninterpreted_fun(suite) -> []; +apply_uninterpreted_fun(Config) when is_list(Config) -> + + ?line F1 = fun(snape) -> + erlang:error(snape); + (_Arg) -> + perfectly_alright + end, + + %% Ok + ?line perfectly_alright = + spawn_eval(fun() -> ?IM:do_apply(F1, any_arg) end), + + %% Badarity (evaluated in dbg_debugged, which calls erlang:apply/2) + ?line {'EXIT',{{badarity,{F1,[]}},[{erlang,apply,_}|_]}} = + spawn_eval(fun() -> ?IM:do_apply(F1) end), + + %% Error in fun + ?line {'EXIT',{snape,[{?MODULE,_FunName,_}|_]}} = + spawn_eval(fun() -> ?IM:do_apply(F1, snape) end), + + ok. + +%% +%% Try executing an interpreted exit/1 call. +%% + +interpreted_exit(Config) when is_list(Config) -> + ?line process_flag(trap_exit, true), + ?line Reason = make_ref(), + ?line Pid = spawn_link(fun() -> ?IM:please_call_exit(Reason) end), + ?line receive + {'EXIT',Pid,Reason} -> + ok; + {'EXIT',Pid,BadReason} -> + ?line ?t:fail({bad_message,BadReason}) + after 10000 -> + ?line ?t:fail(timeout) + end, + ok. + +otp_8310(doc) -> + "OTP-8310. Bugfixes lc/bc and andalso/orelse."; +otp_8310(Config) when is_list(Config) -> + ?line ok = ?IM:otp_8310(), + ok. + +applier(M, F, A) -> + Res = apply(M, F, A), + io:format("~p:~p(~p) => ~p\n", [M,F,A,Res]), + Res. + +%% +%% Evaluate in another process, to prevent the test_case process to become +%% interpreted. +%% + +spawn_eval(Fun) -> + Self = self(), + spawn_link(fun() -> Self ! (catch Fun()) end), + receive + Result -> + Result + end. |