1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1999-2013. All Rights Reserved.
    5: %% 
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %% 
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %% 
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: -module(match_spec_SUITE).
   21: 
   22: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   23: 	 init_per_group/2,end_per_group/2, not_run/1]).
   24: -export([test_1/1, test_2/1, test_3/1, bad_match_spec_bin/1,
   25: 	 trace_control_word/1, silent/1, silent_no_ms/1, silent_test/1,
   26: 	 ms_trace2/1, ms_trace3/1, boxed_and_small/1,
   27: 	 destructive_in_test_bif/1, guard_exceptions/1,
   28: 	 unary_plus/1, unary_minus/1, moving_labels/1]).
   29: -export([fpe/1]).
   30: -export([otp_9422/1]).
   31: -export([faulty_seq_trace/1, do_faulty_seq_trace/0]).
   32: -export([runner/2, loop_runner/3]).
   33: -export([f1/1, f2/2, f3/2, fn/1, fn/2, fn/3]).
   34: -export([do_boxed_and_small/0]).
   35: 
   36: % This test suite assumes that tracing in general works. What we test is
   37: % the match spec functionality.
   38: 
   39: -include_lib("test_server/include/test_server.hrl").
   40: 
   41: -export([init_per_testcase/2, end_per_testcase/2]).
   42: 
   43: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
   44:     Dog=?t:timetrap(?t:seconds(10)),
   45:     [{watchdog, Dog}|Config].
   46: 
   47: end_per_testcase(_Func, Config) ->
   48:     Dog=?config(watchdog, Config),
   49:     ?t:timetrap_cancel(Dog).
   50: 
   51: 
   52: suite() -> [{ct_hooks,[ts_install_cth]}].
   53: 
   54: all() -> 
   55:     case test_server:is_native(match_spec_SUITE) of
   56: 	false ->
   57: 	    [test_1, test_2, test_3, bad_match_spec_bin,
   58: 	     trace_control_word, silent, silent_no_ms, silent_test, ms_trace2,
   59: 	     ms_trace3, boxed_and_small, destructive_in_test_bif,
   60: 	     guard_exceptions, unary_plus, unary_minus, fpe,
   61: 	     moving_labels,
   62: 	     faulty_seq_trace,
   63: 	     otp_9422];
   64: 	true -> [not_run]
   65:     end.
   66: 
   67: groups() -> 
   68:     [].
   69: 
   70: init_per_suite(Config) ->
   71:     Config.
   72: 
   73: end_per_suite(_Config) ->
   74:     ok.
   75: 
   76: init_per_group(_GroupName, Config) ->
   77:     Config.
   78: 
   79: end_per_group(_GroupName, Config) ->
   80: 	Config.
   81: 
   82: 
   83: not_run(Config) when is_list(Config) ->
   84:     {skipped, "Native Code"}.
   85: 
   86: test_1(doc) ->
   87:     [""];
   88: test_1(suite) -> [];
   89: test_1(Config) when is_list(Config) ->
   90:     ?line tr(fun() -> ?MODULE:f1(a) end,
   91: 	     {?MODULE, f1, 1},
   92: 	     [],
   93: 	     [{call, {?MODULE, f1, [a]}}]),
   94: 
   95:     ?line tr(fun() -> ?MODULE:f2(a, a) end,
   96: 	     {?MODULE, f2, 2},
   97: 	     [{['$1','$1'],[{is_atom, '$1'}],[]}],
   98: 	     [{call, {?MODULE, f2, [a, a]}}]),
   99: 
  100:     ?line tr(fun() -> ?MODULE:f2(a, a) end,
  101: 	     {?MODULE, f2, 2},
  102: 	     [{['$1','$1'],[{is_atom, '$1'}],[{message, false}]}],
  103: 	     []),
  104: 
  105:     ?line tr(fun() -> ?MODULE:f2(a, a) end,
  106: 	     {?MODULE, f2, 2},
  107: 	     [{['$1','$1'],[{is_atom, '$1'}],[{message, 4711}]}],
  108: 	     [{call, {?MODULE, f2, [a, a]}, 4711}]),
  109: 
  110:     Ref = make_ref(),
  111:     ?line tr(fun() -> ?MODULE:f2(Ref, Ref) end,
  112: 	     {?MODULE, f2, 2},
  113: 	     [{[Ref,'$1'],[{is_reference, '$1'}],[{message, 4711}]}],
  114: 	     [{call, {?MODULE, f2, [Ref, Ref]}, 4711}]),
  115:     ?line tr(fun() -> ?MODULE:f2(Ref, Ref) end,
  116: 	     {?MODULE, f2, 2},
  117: 	     [{['$1',Ref],[{is_reference, '$1'}],[{message, 4711}]}],
  118: 	     [{call, {?MODULE, f2, [Ref, Ref]}, 4711}]),
  119: 
  120:     ?line tr(fun() -> ?MODULE:f2(a, a) end,
  121: 	     {?MODULE, f2, 2},
  122: 	     [{['$0','$0'],[{is_atom, '$0'}],[{message, 4711}]}],
  123: 	     [{call, {?MODULE, f2, [a, a]}, 4711}]),
  124: 
  125:     ?line tr(fun() -> ?MODULE:f2(a, b) end,
  126: 	     {?MODULE, f2, 2},
  127: 	     [{['_','_'],[],[]}],
  128: 	     [{call, {?MODULE, f2, [a, b]}}]),
  129: 
  130:     ?line tr(fun() -> ?MODULE:f2(a, b) end,
  131: 	     {?MODULE, f2, 2},
  132: 	     [{['_','_'],[],[{message, '$_'}]}],
  133: 	     [{call, {?MODULE, f2, [a, b]}, [a, b]}]),
  134: 
  135:     ?line tr(fun() -> ?MODULE:f2(a, '$_') end,
  136: 	     {?MODULE, f2, 2},
  137: 	     [{['$1','$_'],[{is_atom, '$1'}],[]}],
  138: 	     [{call, {?MODULE, f2, [a, '$_']}}]),
  139: 
  140:     ?line tr(fun() -> ?MODULE:f1({a}) end,
  141: 	     {?MODULE, f1, 1},
  142: 	     [{['$1'],[{'==', '$1', {const, {a}}}],[]}],
  143: 	     [{call, {?MODULE, f1, [{a}]}}]),
  144: 
  145:     ?line tr(fun() -> ?MODULE:f1({a}) end,
  146: 	     {?MODULE, f1, 1},
  147: 	     [{['$1'],[{'==', '$1', {{a}}}],[]}],
  148: 	     [{call, {?MODULE, f1, [{a}]}}]),
  149: 
  150: %% Undocumented, currently.
  151:     ?line tr(fun() -> ?MODULE:f2(a, a) end,
  152: 	     {?MODULE, f2, 2},
  153: 	     [{['$1','$1'],[{is_atom, '$1'}],[{message, 4711},
  154: 					      {message, true}]}],
  155: 	     [{call, {?MODULE, f2, [a, a]}}]),
  156: 
  157:     ?line tr(fun() -> ?MODULE:f2(a, a) end,
  158: 	     {?MODULE, f2, 2},
  159: 	     [{['$1','$1'],[{is_atom, '$1'}],[{message, 4711},
  160: 					      {message, false}]}],
  161: 	     []),
  162: 
  163:     ?line tr(fun() -> ?MODULE:f2(a, a) end,
  164: 	     {?MODULE, f2, 2},
  165: 	     [{['$1','$1'],[{is_atom, '$1'}],[kakalorum]}],
  166: 	     [{call, {?MODULE, f2, [a, a]}}]),
  167: 
  168: %    case tr0(fun() -> ?MODULE:f2(a, a) end,
  169: %	     {?MODULE, f2, 2},
  170: %	     [{['$1','$1'],[{is_atom, '$1'}],[{message, {process_dump}}]}]) of
  171: %	[{trace, _, call, {?MODULE, f2, [a, a]}, Bin}] ->
  172: %	    erlang:display(binary_to_list(Bin))
  173: %    end,
  174: 
  175: % Error cases
  176:     ?line errchk([{['$1','$1'],[{is_atom, '$1'}],[{banka, kanin}]}]),
  177: 
  178:     ok.
  179: 
  180: test_2(doc) ->
  181:     [""];
  182: test_2(suite) -> [];
  183: test_2(Config) when is_list(Config) ->
  184:     ?line tr(fun() -> ?MODULE:f2(a, a) end,
  185: 	     {?MODULE, f2, 2},
  186: 	     [{['$1','$1'],[{is_atom, '$1'}],[{return_trace}]}],
  187: 	     [{call, {?MODULE, f2, [a, a]}},
  188: 	      {return_from, {?MODULE, f2, 2}, {a, a}}]),
  189:     ok.
  190: 
  191: test_3(doc) ->
  192:     ["Test the enable_trace/2 and caller/0 PAM instructions"];
  193: test_3(suite) -> [];
  194: test_3(Config) when is_list(Config) ->
  195:     ?line Fun1 = fun() -> 
  196: 		   register(fnoppelklopfer,self()),
  197: 		   ?MODULE:f2(a, b),
  198: 		   ?MODULE:f2(a, b) 
  199: 	   end,
  200:     ?line P1 = spawn(?MODULE, runner, [self(), Fun1]),
  201:     ?line Pat = [{['$1','$1'],[],[{message,
  202: 				   [{enable_trace, P1, call},{caller}]}]},
  203: 		 {['_','_'],[],[{message,
  204: 				 [{disable_trace, fnoppelklopfer, call}]}]}],
  205:     ?line Fun2 = fun() -> ?MODULE:f3(a, a) end,
  206:     ?line P2 = spawn(?MODULE, runner, [self(), Fun2]),
  207:     ?line erlang:trace(P2, true, [call]),
  208:     ?line erlang:trace_pattern({?MODULE, f2, 2}, Pat),
  209:     ?line collect(P2, [{trace, P2, call, {?MODULE, f2, [a, a]}, [true,
  210: 							     {?MODULE,f3,2}]}]),
  211:     ?line collect(P1, [{trace, P1, call, {?MODULE, f2, [a, b]}, [true]}]),
  212:     ?line ok.
  213: 
  214: otp_9422(doc) -> [];
  215: otp_9422(Config) when is_list(Config) ->
  216:     Laps = 10000,
  217:     ?line Fun1 = fun() -> otp_9422_tracee() end,
  218:     ?line P1 = spawn_link(?MODULE, loop_runner, [self(), Fun1, Laps]),
  219:     io:format("spawned ~p as tracee\n", [P1]),
  220: 
  221:     ?line erlang:trace(P1, true, [call, silent]),
  222: 
  223:     ?line Fun2 = fun() -> otp_9422_trace_changer() end,
  224:     ?line P2 = spawn_link(?MODULE, loop_runner, [self(), Fun2, Laps]),
  225:     io:format("spawned ~p as trace_changer\n", [P2]),
  226: 
  227:     start_collect(P1),
  228:     start_collect(P2),
  229: 
  230:     %%receive after 10*1000 -> ok end,
  231: 
  232:     stop_collect(P1),
  233:     stop_collect(P2, abort),
  234:     ok.
  235:     
  236: otp_9422_tracee() ->
  237:     ?MODULE:f1(a),
  238:     ?MODULE:f1(b),
  239:     ?MODULE:f1(c).
  240: 
  241: otp_9422_trace_changer() ->
  242:     Pat1 = [{[a], [], [{enable_trace, arity}]}],
  243:     ?line erlang:trace_pattern({?MODULE, f1, 1}, Pat1),
  244:     Pat2 = [{[b], [], [{disable_trace, arity}]}],
  245:     ?line erlang:trace_pattern({?MODULE, f1, 1}, Pat2).
  246: 
  247:     
  248:     
  249: 
  250: 
  251: bad_match_spec_bin(Config) when is_list(Config) ->
  252:     {'EXIT',{badarg,_}} = (catch ets:match_spec_run([1], <<>>)),
  253:     B0 = <<1,2>>,
  254:     {B,_} = split_binary(B0, 0),
  255:     {'EXIT',{badarg,_}} = (catch ets:match_spec_run([1], B)),
  256:     ok.
  257: 
  258: 
  259: 
  260: trace_control_word(doc) ->
  261:     ["Test the erlang:system_info(trace_control_word) and ",
  262:      "erlang:system_flag(trace_control_word, Value) BIFs, ", 
  263:      "as well as the get_tcw/0 and set_tcw/1 PAM instructions"];
  264: trace_control_word(suite) -> [];
  265: trace_control_word(Config) when is_list(Config) ->
  266:     ?line 32 = Bits = tcw_bits(),
  267:     ?line High = 1 bsl (Bits - 1),
  268:     ?line erlang:system_flag(trace_control_word, 17),
  269:     ?line tr(fun() -> ?MODULE:f1(a) end,
  270: 	     {?MODULE, f1, 1},
  271: 	     [{'_',[{'=:=', {get_tcw}, 17}],[]}],
  272: 	     [{call, {?MODULE, f1, [a]}}]),
  273:     ?line tr(fun() -> ?MODULE:f1(a) end,
  274: 	     {?MODULE, f1, 1},
  275: 	     [{'_',[{'=:=', {get_tcw}, 18}],[]}],
  276: 	     []),
  277:     ?line erlang:system_flag(trace_control_word, High),
  278:     ?line tr(fun() -> ?MODULE:f1(a) end,
  279: 	     {?MODULE, f1, 1},
  280: 	     [{'_',[{'=:=', {get_tcw}, High}],[]}],
  281: 	     [{call, {?MODULE, f1, [a]}}]),
  282:     ?line erlang:system_flag(trace_control_word, 0),
  283:     ?line tr(fun() -> 
  284: 		     ?MODULE:f1(a), 
  285: 		     ?MODULE:f1(start), 
  286: 		     ?MODULE:f1(b), 
  287: 		     ?MODULE:f1(c), 
  288: 		     ?MODULE:f1(high), 
  289: 		     ?MODULE:f1(d),
  290: 		     ?MODULE:f1(stop), 
  291: 		     ?MODULE:f1(e) 
  292: 	     end,
  293: 	     {?MODULE, f1, 1},
  294: 	     [{[start],
  295: 	       [],
  296: 	       [{message, {set_tcw, 17}}]},
  297: 	      {[stop],
  298: 	       [],
  299: 	       [{message, {set_tcw, 0}}]},
  300: 	      {[high],
  301: 	       [],
  302: 	       [{message, {set_tcw, High}}]},
  303: 	      {['_'],
  304: 	       [{'>', {get_tcw}, 0}],
  305: 	       [{set_tcw, {'+', 1, {get_tcw}}}, {message, {get_tcw}}] }],
  306: 	     [{call, {?MODULE, f1, [start]}, 0},
  307: 	      {call, {?MODULE, f1, [b]}, 18},
  308: 	      {call, {?MODULE, f1, [c]}, 19},
  309: 	      {call, {?MODULE, f1, [high]}, 19},
  310: 	      {call, {?MODULE, f1, [d]}, High + 1},
  311: 	      {call, {?MODULE, f1, [stop]}, High + 1}]),
  312:     ?line 0 = erlang:system_info(trace_control_word),
  313:     ok.
  314: 
  315: tcw_bits() ->
  316:     ?line tcw_bits(erlang:system_flag(trace_control_word, 0), 0, 0).
  317: 
  318: tcw_bits(Save, Prev, Bits) ->
  319:     ?line Curr = 1 bsl Bits,
  320:     ?line case catch erlang:system_flag(trace_control_word, Curr) of
  321: 	      {'EXIT' , {badarg, _}} ->
  322: 		  ?line Prev = erlang:system_flag(trace_control_word, Save),
  323: 		  Bits;
  324: 	      Prev ->
  325: 		  ?line Curr = erlang:system_info(trace_control_word),
  326: 		  tcw_bits(Save, Curr, Bits+1)
  327: 	  end.
  328: 
  329: 
  330: 
  331: silent(doc) ->
  332:     ["Test the erlang:trace(_, _, [silent]) flag ",
  333:      "as well as the silent/0 PAM instruction"];
  334: silent(suite) -> [];
  335: silent(Config) when is_list(Config) ->
  336:     %% Global call trace
  337:     ?line tr(fun() -> 
  338: 		     ?MODULE:f1(a),     % No trace - not active
  339: 		     ?MODULE:f1(miss),  % No trace - no activation
  340: 		     ?MODULE:f1(b),     % No trace - still not active
  341: 		     ?MODULE:f1(start), % Trace    - activation
  342: 		     ?MODULE:f1(c),     % Trace    - active
  343: 		     f1(d),             % No trace - local call
  344: 		     ?MODULE:f1(miss),  % Trace    - no inactivation
  345: 		     ?MODULE:f1(e),     % Trace    - still active
  346: 		     ?MODULE:f1(stop),  % No trace - inactivation
  347: 		     ?MODULE:f1(f)      % No trace - not active
  348: 	     end,
  349: 	     {?MODULE, f1, 1},
  350: 	     [call, silent],
  351: 	     [{[start],
  352: 	       [],
  353: 	       [{silent, false}, {message, start}]},
  354: 	      {[stop],
  355: 	       [],
  356: 	       [{silent, true}, {message, stop}]},
  357: 	      {[miss],
  358: 	       [],
  359: 	       [{silent, neither_true_nor_false}, {message, miss}]},
  360: 	      {['$1'],
  361: 	       [],
  362: 	       [{message, '$1'}] }],
  363: 	     [global],
  364: 	     [{call, {?MODULE, f1, [start]}, start},
  365: 	      {call, {?MODULE, f1, [c]}, c},
  366: 	      {call, {?MODULE, f1, [miss]}, miss},
  367: 	      {call, {?MODULE, f1, [e]}, e} ]),
  368:     %% Local call trace
  369:     ?line tr(fun() -> 
  370: 		     ?MODULE:f1(a),     % No trace - not active
  371: 		     f1(b),             % No trace - not active
  372: 		     ?MODULE:f1(start), % Trace    - activation
  373: 		     ?MODULE:f1(c),     % Trace    - active
  374: 		     f1(d),             % Trace    - active
  375: 		     f1(stop),          % No trace - inactivation
  376: 		     ?MODULE:f1(e),     % No trace - not active
  377: 		     f1(f)              % No trace - not active
  378: 	     end,
  379: 	     {?MODULE, f1, 1},
  380: 	     [call, silent],
  381: 	     [{[start],
  382: 	       [],
  383: 	       [{silent, false}, {message, start}]},
  384: 	      {[stop],
  385: 	       [],
  386: 	       [{silent, true}, {message, stop}]},
  387: 	      {['$1'],
  388: 	       [],
  389: 	       [{message, '$1'}] }],
  390: 	     [local],
  391: 	     [{call, {?MODULE, f1, [start]}, start},
  392: 	      {call, {?MODULE, f1, [c]}, c},
  393: 	      {call, {?MODULE, f1, [d]}, d} ]),
  394:     ok.
  395: 
  396: silent_no_ms(doc) ->
  397:     ["Test the erlang:trace(_, _, [silent]) flag without match specs"];
  398: silent_no_ms(suite) -> [];
  399: silent_no_ms(Config) when is_list(Config) ->
  400:     %% Global call trace
  401:     %%
  402:     %% Trace f2/2 and erlang:integer_to_list/1 without match spec
  403:     %% and use match spec on f1/1 to control silent flag.
  404:     ?line tr(
  405: 	    fun () -> 
  406: 		    ?MODULE:f1(a),
  407: 		    ?MODULE:f2(b, c),
  408: 		    _ = erlang:integer_to_list(id(1)),
  409: 		    ?MODULE:f3(d, e),
  410: 		    ?MODULE:f1(start),
  411: 		    ?MODULE:f2(f, g),
  412: 		    _ = erlang:integer_to_list(id(2)),
  413: 		    ?MODULE:f3(h, i),
  414: 		    ?MODULE:f1(stop),
  415: 		    ?MODULE:f2(j, k),
  416: 		    _ = erlang:integer_to_list(id(3)),
  417: 		    ?MODULE:f3(l, m)
  418: 	    end,
  419: 	    fun (Tracee) ->
  420: 		    ?line 1 = 
  421: 			erlang:trace(Tracee, true, 
  422: 				     [call,silent,return_to]),
  423: 		    ?line 1 =
  424: 			erlang:trace_pattern(
  425: 			  {?MODULE,f2,2}, 
  426: 			  [], 
  427: 			  [global]),
  428: 		    ?line 1 = 
  429: 			erlang:trace_pattern(
  430: 			  {erlang,integer_to_list,1}, 
  431: 			  [], 
  432: 			  [global]),
  433: 		    ?line 1 = 
  434: 			erlang:trace_pattern(
  435: 			  {?MODULE,f1,1},
  436: 			  [{[start],[],[{silent,false}]},
  437: 			   {[stop],[],[{silent,true}]}],
  438: 			  [global]),
  439: 		    %%
  440: 		    %% Expected: (no return_to for global call trace)
  441: 		    %%
  442: 		    ?line
  443: 			[{trace,Tracee,call,{?MODULE,f1,[start]}},
  444: 			 {trace,Tracee,call,{?MODULE,f2,[f,g]}},
  445: 		         {trace,Tracee,call,{erlang,integer_to_list,[2]}},
  446: 			 {trace,Tracee,call,{?MODULE,f2,[h,i]}}]
  447: 	    end),
  448:     %% Local call trace
  449:     %%
  450:     %% Trace f2/2 and erlang:integer_to_list/1 without match spec
  451:     %% and use match spec on f1/1 to control silent flag.
  452:     ?line tr(
  453: 	    fun () -> 
  454: 		    ?MODULE:f1(a),
  455: 		    ?MODULE:f2(b, c),
  456: 		    _ = erlang:integer_to_list(id(1)),
  457: 		    ?MODULE:f3(d, e),
  458: 		    ?MODULE:f1(start),
  459: 		    ?MODULE:f2(f, g),
  460: 		    _ = erlang:integer_to_list(id(2)),
  461: 		    ?MODULE:f3(h, i),
  462: 		    ?MODULE:f1(stop),
  463: 		    ?MODULE:f2(j, k),
  464: 		    _ = erlang:integer_to_list(id(3)),
  465: 		    ?MODULE:f3(l, m)
  466: 	    end,
  467: 	    fun (Tracee) ->
  468: 		    ?line 1 =
  469: 			erlang:trace(Tracee, true, 
  470: 				     [call,silent,return_to]),
  471: 		    ?line 1 = 
  472: 			erlang:trace_pattern(
  473: 			  {?MODULE,f2,2}, 
  474: 			  [], 
  475: 			  [local]),
  476: 		    ?line 1 = 
  477: 			erlang:trace_pattern(
  478: 			  {erlang,integer_to_list,1}, 
  479: 			  [], 
  480: 			  [local]),
  481: 		    ?line 1 =
  482: 			erlang:trace_pattern(
  483: 			  {?MODULE,f1,1},
  484: 			  [{[start],[],[{silent,false}]},
  485: 			   {[stop],[],[{silent,true}]}],
  486: 			  [local]),
  487: 		    %%
  488: 		    %% Expected:
  489: 		    %%
  490: 		    ?line
  491: 			[{trace,Tracee,call,{?MODULE,f1,[start]}},
  492: 			 {trace,Tracee,return_to,
  493: 			  {?MODULE,'-silent_no_ms/1-fun-2-',0}},
  494: 			 {trace,Tracee,call,{?MODULE,f2,[f,g]}},
  495: 			 {trace,Tracee,return_to,
  496: 			  {?MODULE,'-silent_no_ms/1-fun-2-',0}},
  497: 		         {trace,Tracee,call,{erlang,integer_to_list,[2]}},
  498: 			 {trace,Tracee,return_to,
  499: 			  {?MODULE,'-silent_no_ms/1-fun-2-',0}},
  500: 			 {trace,Tracee,call,{?MODULE,f2,[h,i]}},
  501: 			 {trace,Tracee,return_to,{?MODULE,f3,2}}]
  502: 	    end).
  503: 
  504: silent_test(doc) ->
  505:     ["Test that match_spec_test does not activate silent"];
  506: silent_test(_Config) ->
  507:     {flags,[]} = erlang:trace_info(self(),flags),
  508:     erlang:match_spec_test([],[{'_',[],[{silent,true}]}],trace),
  509:     {flags,[]} = erlang:trace_info(self(),flags).
  510: 
  511: 
  512: ms_trace2(doc) ->
  513:     ["Test the match spec functions {trace/2}"];
  514: ms_trace2(suite) -> [];
  515: ms_trace2(Config) when is_list(Config) ->
  516:     Tracer = self(),
  517:     %% Meta trace init
  518:     %%
  519:     %% Trace global f1/1, local f2/2, global erlang:integer_to_list/1
  520:     %% without match spec. Use match spec functions
  521:     %% {trace/2} to control trace through fn/2,3.
  522:     ?line tr(
  523: 	    fun () -> 
  524: 		    ?MODULE:f1(a),
  525: 		    ?MODULE:f2(b, c),
  526: 		    _ = erlang:integer_to_list(id(1)),
  527: 		    ?MODULE:f3(d, e),
  528: 		    fn([all], [call,return_to,{tracer,Tracer}]),
  529: 		    ?MODULE:f1(f),
  530: 		    f2(g, h),
  531: 		    f1(i),
  532: 		    _ = erlang:integer_to_list(id(2)),
  533: 		    ?MODULE:f3(j, k),
  534: 		    fn([call,return_to], []),
  535: 		    ?MODULE:f1(l),
  536: 		    ?MODULE:f2(m, n),
  537: 		    _ = erlang:integer_to_list(id(3)),
  538: 		    ?MODULE:f3(o, p)
  539: 	    end,
  540: 	    fun (Tracee) ->
  541: 		    ?line 1 = 
  542: 			erlang:trace(Tracee, false, [all]),
  543: 		    ?line 1 =
  544: 			erlang:trace_pattern(
  545: 			  {?MODULE,f1,1}, 
  546: 			  [], 
  547: 			  [global]),
  548: 		    ?line 1 =
  549: 			erlang:trace_pattern(
  550: 			  {?MODULE,f2,2}, 
  551: 			  [], 
  552: 			  [local]),
  553: 		    ?line 1 = 
  554: 			erlang:trace_pattern(
  555: 			  {erlang,integer_to_list,1}, 
  556: 			  [], 
  557: 			  [global]),
  558: 		    ?line 3 = 
  559: 			erlang:trace_pattern(
  560: 			  {?MODULE,fn,'_'},
  561: 			  [{['$1','$2'],[],
  562: 			    [{trace,'$1','$2'},{message,ms_trace2}]}],
  563: 			  [meta]),
  564: 		    %%
  565: 		    %% Expected: (no return_to for global call trace)
  566: 		    %%
  567: 		    ?line Origin = {match_spec_SUITE,'-ms_trace2/1-fun-0-',1},
  568: 		    ?line
  569: 			[{trace_ts,Tracee,call,
  570: 			  {?MODULE,fn,
  571: 			   [[all],[call,return_to,{tracer,Tracer}]]},
  572: 			  ms_trace2},
  573: 			 {trace,Tracee,call,{?MODULE,f1,[f]}},
  574: 			 {trace,Tracee,call,{?MODULE,f2,[g,h]}},
  575: 			 {trace,Tracee,return_to,Origin},
  576: 		         {trace,Tracee,call,{erlang,integer_to_list,[2]}},
  577: 			 {trace,Tracee,call,{?MODULE,f2,[j,k]}},
  578: 			 {trace,Tracee,return_to,{?MODULE,f3,2}},
  579: 			 {trace_ts,Tracee,call,
  580: 			  {?MODULE,fn,
  581: 			   [[call,return_to],[]]},
  582: 			  ms_trace2}]
  583: 	    end),
  584:     ok.
  585: 
  586: 
  587: 
  588: ms_trace3(doc) ->
  589:     ["Test the match spec functions {trace/3}"];
  590: ms_trace3(suite) -> [];
  591: ms_trace3(Config) when is_list(Config) ->
  592:     TraceeName = 'match_spec_SUITE:ms_trace3',
  593:     Tracer = self(),
  594:     %% Meta trace init
  595:     %%
  596:     %% Trace global f1/1, local f2/2, global erlang:integer_to_list/1
  597:     %% without match spec. Use match spec functions
  598:     %% {trace/2} to control trace through fn/2,3.
  599:     Tag = make_ref(),
  600:     Controller =
  601: 	spawn_link(
  602: 	  fun () ->
  603: 		  receive 
  604: 		      {Tracee,Tag,start} ->
  605: 			  fn(TraceeName, [all], 
  606: 			     [call,return_to,send,'receive',
  607: 			      {tracer,Tracer}]),
  608: 			  Tracee ! {self(),Tag,started},
  609: 			  receive {Tracee,Tag,stop_1} -> ok end,
  610: 			  fn(Tracee, [call,return_to], []),
  611: 			  Tracee ! {self(),Tag,stopped_1},
  612: 			  receive {Tracee,Tag,stop_2} -> ok end,
  613: 			  fn(Tracee, [all], []),
  614: 			  Tracee ! {self(),Tag,stopped_2}
  615: 		  end
  616: 	  end),
  617:     ?line tr(
  618: 	    fun () -> %% Action
  619: 		    register(TraceeName, self()),
  620: 		    ?MODULE:f1(a),
  621: 		    ?MODULE:f2(b, c),
  622: 		    _ = erlang:integer_to_list(id(1)),
  623: 		    ?MODULE:f3(d, e),
  624: 		    Controller ! {self(),Tag,start},
  625: 		    receive {Controller,Tag,started} -> ok end,
  626: 		    ?MODULE:f1(f),
  627: 		    f2(g, h),
  628: 		    f1(i),
  629: 		    _ = erlang:integer_to_list(id(2)),
  630: 		    ?MODULE:f3(j, k),
  631: 		    Controller ! {self(),Tag,stop_1},
  632: 		    receive {Controller,Tag,stopped_1} -> ok end,
  633: 		    ?MODULE:f1(l),
  634: 		    ?MODULE:f2(m, n),
  635: 		    _ = erlang:integer_to_list(id(3)),
  636: 		    ?MODULE:f3(o, p),
  637: 		    Controller ! {self(),Tag,stop_2},
  638: 		    receive {Controller,Tag,stopped_2} -> ok end,
  639: 		    ?MODULE:f1(q),
  640: 		    ?MODULE:f2(r, s),
  641: 		    _ = erlang:integer_to_list(id(4)),
  642: 		    ?MODULE:f3(t, u)
  643: 	    end,
  644: 	    
  645: 	    fun (Tracee) -> %% Startup
  646: 		    ?line 1 = 
  647: 			erlang:trace(Tracee, false, [all]),
  648: 		    ?line 1 =
  649: 			erlang:trace_pattern(
  650: 			  {?MODULE,f1,1}, 
  651: 			  [], 
  652: 			  [global]),
  653: 		    ?line 1 =
  654: 			erlang:trace_pattern(
  655: 			  {?MODULE,f2,2}, 
  656: 			  [], 
  657: 			  [local]),
  658: 		    ?line 1 = 
  659: 			erlang:trace_pattern(
  660: 			  {erlang,integer_to_list,1}, 
  661: 			  [], 
  662: 			  [global]),
  663: 		    ?line 3 = 
  664: 			erlang:trace_pattern(
  665: 			  {?MODULE,fn,'_'},
  666: 			  [{['$1','$2','$3'],[],
  667: 			    [{trace,'$1','$2','$3'},{message,Tag}]}],
  668: 			  [meta]),
  669: 		    %%
  670: 		    %% Expected: (no return_to for global call trace)
  671: 		    %%
  672: 		    ?line Origin = {match_spec_SUITE,'-ms_trace3/1-fun-1-',2},
  673: 		    ?line
  674: 			[{trace_ts,Controller,call,
  675: 			  {?MODULE,fn,[TraceeName,[all],
  676: 				       [call,return_to,send,'receive',
  677: 					{tracer,Tracer}]]},
  678: 			  Tag},
  679: 			 {trace,Tracee,'receive',{Controller,Tag,started}},
  680: 			 {trace,Tracee,call,{?MODULE,f1,[f]}},
  681: 			 {trace,Tracee,call,{?MODULE,f2,[g,h]}},
  682: 			 {trace,Tracee,return_to,Origin},
  683: 		         {trace,Tracee,call,{erlang,integer_to_list,[2]}},
  684: 			 {trace,Tracee,call,{?MODULE,f2,[j,k]}},
  685: 			 {trace,Tracee,return_to,{?MODULE,f3,2}},
  686: 			 {trace,Tracee,send,{Tracee,Tag,stop_1},Controller},
  687: 			 {trace_ts,Controller,call,
  688: 			  {?MODULE,fn,[Tracee,[call,return_to],[]]},
  689: 			  Tag},
  690: 			 {trace_ts,Controller,call,
  691: 			  {?MODULE,fn,[Tracee,[all],[]]},
  692: 			  Tag}]
  693: 	    end),
  694:     ok.
  695: 
  696: 
  697: 
  698: destructive_in_test_bif(doc) ->
  699:     ["Test that destructive operations in test bif does not really happen"];
  700: destructive_in_test_bif(suite) -> [];
  701: destructive_in_test_bif(Config) when is_list(Config) ->
  702:     ?line {ok,OldToken,_,_} = erlang:match_spec_test
  703: 				([],
  704: 				 [{'_',[],[{message,{get_seq_token}}]}],trace),
  705:     ?line {ok,_,_,_} = erlang:match_spec_test
  706: 			 ([],
  707: 			  [{'_',[],[{message,{set_seq_token, label, 1}}]}],
  708: 			  trace),
  709:     ?line {ok,OldToken,_,_} = erlang:match_spec_test
  710: 				([],
  711: 				 [{'_',[],[{message,{get_seq_token}}]}],trace),
  712:     ?line {ok, OldTCW,_,_} = erlang:match_spec_test
  713: 			       ([],[{'_',[],[{message,{get_tcw}}]}],trace),
  714:     ?line {ok,OldTCW,_,_} = erlang:match_spec_test
  715: 			      ([],
  716: 			       [{'_',[],[{message,{set_tcw, OldTCW+1}}]}],
  717: 			       trace),
  718:     ?line {ok, OldTCW,_,_} = erlang:match_spec_test
  719: 			       ([],[{'_',[],[{message,{get_tcw}}]}],trace),
  720:     ok.
  721: 
  722: boxed_and_small(doc) ->
  723:     ["Test that the comparision between boxed and small does not crash emulator"];
  724: boxed_and_small(suite) -> [];
  725: boxed_and_small(Config) when is_list(Config) ->
  726:     ?line {ok, Node} = start_node(match_spec_suite_other),
  727:     ?line ok = rpc:call(Node,?MODULE,do_boxed_and_small,[]),
  728:     ?line stop_node(Node),
  729:     ok.
  730: 
  731: do_boxed_and_small() ->
  732:     {ok, false, _, _} = erlang:match_spec_test({0,3},[{{1.47,'_'},[],['$_']}],table),
  733:     {ok, false, _, _} = erlang:match_spec_test({0,3},[{{12345678901234567890,'_'},[],['$_']}],table),
  734:     {ok, false, _, _} = erlang:match_spec_test({0,3},[{{<<1,2,3,4>>,'_'},[],['$_']}],table),
  735:     {ok, false, _, _} = erlang:match_spec_test({0,3},[{{make_ref(),'_'},[],['$_']}],table),
  736:     ok.
  737: 
  738: faulty_seq_trace(doc) ->
  739:     ["Test that faulty seq_trace_call does not crash emulator"];
  740: faulty_seq_trace(suite) -> [];
  741: faulty_seq_trace(Config) when is_list(Config) ->
  742:     ?line {ok, Node} = start_node(match_spec_suite_other),
  743:     ?line ok = rpc:call(Node,?MODULE,do_faulty_seq_trace,[]),
  744:     ?line stop_node(Node),
  745:     ok.
  746: 
  747: do_faulty_seq_trace() ->
  748:     {ok,'EXIT',_,_} = erlang:match_spec_test([],[{'_',[],[{message,{set_seq_token,yxa,true}}]}],trace),
  749:     ok.
  750: 
  751: errchk(Pat) ->
  752:     case catch erlang:trace_pattern({?MODULE, f2, 2}, Pat) of
  753: 	{'EXIT', {badarg, _}} ->
  754: 	    ok;
  755: 	Other ->
  756: 	    test_server:fail({noerror, Other})
  757:     end.
  758: 
  759: unary_minus(suite) ->
  760:     [];
  761: unary_minus(doc) ->
  762:     ["Checks that unary minus works"];
  763: unary_minus(Config) when is_list(Config) ->
  764:     ?line {ok,true,[],[]} = erlang:match_spec_test
  765: 			      (5,
  766: 			       [{'$1',
  767: 				 [{'<',{'-','$1'},-4}],
  768: 				 [true]}],
  769: 			       table),
  770:     ?line {ok,false,[],[]} = erlang:match_spec_test
  771: 			      (5,
  772: 			       [{'$1',
  773: 				 [{'<',{'-','$1'},-6}],
  774: 				 [true]}],
  775: 			       table),
  776:     ?line {ok,true,[],[]} = erlang:match_spec_test
  777: 			      (5,
  778: 			       [{'$1',
  779: 				 [{'=:=',{'-','$1',2},3}],
  780: 				 [true]}],
  781: 			       table),
  782:     ?line {ok,false,[],[]} = erlang:match_spec_test
  783: 			      (hej,
  784: 			       [{'$1',
  785: 				 [{'=/=',{'-','$1'},0}],
  786: 				 [true]}],
  787: 			       table),
  788:     ok.
  789: unary_plus(suite) ->
  790:     [];
  791: unary_plus(doc) ->
  792:     ["Checks that unary plus works"];
  793: unary_plus(Config) when is_list(Config) ->
  794:     ?line {ok,true,[],[]} = erlang:match_spec_test
  795: 			      (5,
  796: 			       [{'$1',
  797: 				 [{'<',{'+','$1'},6}],
  798: 				 [true]}],
  799: 			       table),
  800:     ?line {ok,false,[],[]} = erlang:match_spec_test
  801: 			      (5,
  802: 			       [{'$1',
  803: 				 [{'<',{'+','$1'},4}],
  804: 				 [true]}],
  805: 			       table),
  806:     ?line {ok,true,[],[]} = erlang:match_spec_test
  807: 			      (5,
  808: 			       [{'$1',
  809: 				 [{'=:=',{'+','$1',2},7}],
  810: 				 [true]}],
  811: 			       table),
  812:     ?line {ok,false,[],[]} = erlang:match_spec_test
  813: 			      (hej,
  814: 			       [{'$1',
  815: 				 [{'=/=',{'+','$1'},0}],
  816: 				 [true]}],
  817: 			       table),
  818:     ok.
  819: 
  820: 
  821:     
  822: 
  823: guard_exceptions(suite) ->
  824:     [];
  825: guard_exceptions(doc) ->
  826:     ["Checks that exceptions in guards are handled correctly"];
  827: guard_exceptions(Config) when is_list(Config) ->
  828:     ?line {ok,false,[],[]} = erlang:match_spec_test
  829: 			       (5,
  830: 				[{'$1',
  831: 				  [{'or',{is_integer,'$1'},{'or','$1','$1'}}],
  832: 				  [true]}],
  833: 				table),
  834:     ?line {ok,true,[],[]} = erlang:match_spec_test
  835: 			       (5,
  836: 				[{'$1',
  837: 				  [{'orelse',{is_integer,'$1'},
  838: 				    {'or','$1','$1'}}],
  839: 				  [true]}],
  840: 				table),
  841:     ?line {ok,false,[],[]} = erlang:match_spec_test
  842: 			       (5,
  843: 				[{'$1',
  844: 				  [{'orelse',{'or','$1',true},
  845: 				    {is_integer,'$1'}}],
  846: 				  [true]}],
  847: 				table),
  848:     ?line {ok,false,[],[]} = erlang:match_spec_test
  849: 			       (5,
  850: 				[{'$1',
  851: 				  [{'or',{is_integer,'$1'},
  852: 				    {'orelse','$1',true}}],
  853: 				  [true]}],
  854: 				table),
  855:     ?line {ok,true,[],[]} = erlang:match_spec_test
  856: 			       (5,
  857: 				[{'$1',
  858: 				  [{'or',{is_integer,'$1'},
  859: 				    {'orelse',true,'$1'}}],
  860: 				  [true]}],
  861: 				table),
  862:     ?line {ok,true,[],[]} = erlang:match_spec_test
  863: 			       (5,
  864: 				[{'$1',
  865: 				  [{'or',{is_integer,'$1'},
  866: 				    {'andalso',false,'$1'}}],
  867: 				  [true]}],
  868: 				table),
  869:     ?line {ok,false,[],[]} = erlang:match_spec_test
  870: 			       (5,
  871: 				[{'$1',
  872: 				  [{'or',{is_integer,'$1'},
  873: 				    {'andalso','$1',false}}],
  874: 				  [true]}],
  875: 				table),
  876: 
  877:     ?line {ok,false,[],[]} = erlang:match_spec_test
  878: 			       (5,
  879: 				[{'$1',
  880: 				  [{'or',{is_integer,'$1'},
  881: 				    {'andalso','$1',false}}],
  882: 				  [true]}],
  883: 				table),
  884: 
  885:     ok.
  886: 
  887: fpe(suite) ->
  888:     [];
  889: fpe(doc) ->
  890:     ["Checks floating point exceptions in match-specs"];
  891: fpe(Config) when is_list(Config) ->
  892:     MS = [{{'$1'},[],[{'/','$1',0}]}],
  893:     case catch (['EXIT','EXIT'] = 
  894: 		ets:match_spec_run([{1},{2}],ets:match_spec_compile(MS))) of 
  895: 	{'EXIT',_} -> test_server:fail({error, 
  896: 					"Floating point exceptions faulty"});
  897: 	_ -> ok 
  898:     end.
  899: 
  900: moving_labels(Config) when is_list(Config) ->
  901:     %% Force an andalso/orelse construction to be moved by placing it
  902:     %% in a tuple followed by a constant term. Labels should still
  903:     %% point at their correct target.
  904:     %% 
  905:     Ms = [{{'$1','$2'},[],[{{ok,{'andalso','$1','$2'},[1,2,3]}}]}],
  906:     ?line {ok,{ok,false,[1,2,3]},[],[]} =
  907: 	erlang:match_spec_test({true,false}, Ms, table),
  908: 
  909:     Ms2 = [{{'$1','$2'},[],[{{ok,{'orelse','$1','$2'},[1,2,3]}}]}],
  910:     ?line {ok,{ok,true,[1,2,3]},[],[]} =
  911: 	erlang:match_spec_test({true,false}, Ms2, table),
  912: 
  913:     ok.
  914:     
  915: tr(Fun, MFA, Pat, Expected) ->
  916:     tr(Fun, MFA, [call], Pat, [global], Expected).
  917: 
  918: tr(Fun, MFA, TraceFlags, Pat, PatFlags, Expected0) ->
  919:     tr(Fun,
  920:        fun(P) ->
  921: 	       erlang:trace(P, true, TraceFlags),
  922: 	       erlang:trace_pattern(MFA, Pat, PatFlags),
  923: 	       lists:map(
  924: 		 fun(X) -> 
  925: 			 list_to_tuple([trace, P | tuple_to_list(X)])
  926: 		 end,
  927: 		 Expected0)
  928:        end).
  929: 
  930: tr(RunFun, ControlFun) ->
  931:     P = spawn(?MODULE, runner, [self(), RunFun]),
  932:     collect(P, ControlFun(P)).
  933: 
  934: collect(P, TMs) ->
  935:     start_collect(P),
  936:     collect(TMs),
  937:     stop_collect(P).
  938: 
  939: collect([]) ->
  940:     receive
  941: 	M ->
  942: 	    ?t:format("Got unexpected: ~p~n", [M]),
  943: 	    flush({got_unexpected,M})
  944:     after 17 ->
  945: 	    ok
  946:     end;
  947: collect([TM | TMs]) ->
  948:     ?t:format(        "Expecting:      ~p~n", [TM]),
  949:     receive
  950: 	M ->
  951: 	    case if element(1, M) == trace_ts ->
  952: 			 list_to_tuple(lists:reverse(
  953: 					 tl(lists:reverse(tuple_to_list(M)))));
  954: 		    true -> M
  955: 		 end of
  956: 		TM ->
  957: 		    ?t:format("Got:            ~p~n", [M]),
  958: 		    collect(TMs);
  959: 		_ ->
  960: 		    ?t:format("Got unexpected: ~p~n", [M]),
  961: 		    flush({got_unexpected,M})
  962: 	    end
  963:     end.
  964: 
  965: flush(Reason) ->
  966:     receive
  967: 	M ->
  968: 	    ?t:format("In queue:       ~p~n", [M]),
  969: 	    flush(Reason)
  970:     after 17 ->
  971: 	    ?t:fail(Reason)
  972:     end.
  973: 
  974: start_collect(P) ->
  975:     P ! {go, self()}.
  976: 
  977: stop_collect(P) ->
  978:     stop_collect(P, done).
  979: stop_collect(P, Order) ->
  980:     P ! {Order, self()},
  981:     receive
  982: 	{gone, P} ->
  983: 	    ok
  984:     end.
  985: 
  986: 
  987: runner(Collector, Fun) ->
  988:     receive
  989: 	{go, Collector} ->
  990: 	    go
  991:     end,
  992:     Fun(),
  993:     receive
  994: 	{done, Collector} ->
  995: 	    Collector ! {gone, self()}
  996:     end.
  997: 
  998: loop_runner(Collector, Fun, Laps) ->
  999:     receive
 1000: 	{go, Collector} ->
 1001: 	    go
 1002:     end,
 1003:     loop_runner_cont(Collector, Fun, 0, Laps).
 1004: 
 1005: loop_runner_cont(_Collector, _Fun, Laps, Laps) ->
 1006:     receive
 1007: 	{done, Collector} ->
 1008: 	    io:format("loop_runner ~p exit after ~p laps\n", [self(), Laps]),
 1009: 	    Collector ! {gone, self()}
 1010:     end;
 1011: loop_runner_cont(Collector, Fun, N, Laps) ->
 1012:     Fun(),
 1013:     receive
 1014: 	{abort, Collector} ->
 1015: 	    io:format("loop_runner ~p aborted after ~p of ~p laps\n", [self(), N+1, Laps]),
 1016: 	    Collector ! {gone, self()}
 1017:     after 0 ->
 1018: 	    loop_runner_cont(Collector, Fun, N+1, Laps)
 1019:     end.
 1020: 
 1021: 
 1022: f1(X) ->
 1023:     {X}.
 1024: 
 1025: f2(X, Y) ->
 1026:     {X, Y}.
 1027: 
 1028: f3(X,Y) ->
 1029:     ?MODULE:f2(X,Y),
 1030:     ok.
 1031: 
 1032: fn(X) ->
 1033:     [X].
 1034: fn(X, Y) ->
 1035:     [X, Y].
 1036: fn(X, Y, Z) ->
 1037:     [X, Y, Z].
 1038: 
 1039: id(X) ->
 1040:     X.
 1041: 
 1042: start_node(Name) ->
 1043:     Pa = filename:dirname(code:which(?MODULE)),
 1044:     Cookie = atom_to_list(erlang:get_cookie()),
 1045:     test_server:start_node(Name, slave, 
 1046: 			   [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]).
 1047: 
 1048: stop_node(Node) ->
 1049:     test_server:stop_node(Node).