1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1999-2011. 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: %% 21: -module(exception_SUITE). 22: 23: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, 24: init_per_testcase/2,end_per_testcase/2, 25: init_per_suite/1,end_per_suite/1, 26: badmatch/1,pending_errors/1,nil_arith/1, 27: stacktrace/1,nested_stacktrace/1,raise/1,gunilla/1,per/1]). 28: 29: -export([bad_guy/2]). 30: 31: -include_lib("test_server/include/test_server.hrl"). 32: 33: suite() -> [{ct_hooks,[ts_install_cth]}]. 34: 35: %% Filler. 36: %% 37: %% 38: %% 39: %% 40: %% This is line 40. 41: even(N) when is_integer(N), N > 1, (N rem 2) == 0 -> 42: odd(N-1)++[N]. 43: 44: odd(N) when is_integer(N), N > 1, (N rem 2) == 1 -> 45: even(N-1)++[N]. 46: 47: 48: all() -> 49: cases(). 50: 51: groups() -> 52: []. 53: 54: init_per_group(_GroupName, Config) -> 55: Config. 56: 57: end_per_group(_GroupName, Config) -> 58: Config. 59: 60: 61: cases() -> 62: [badmatch, pending_errors, nil_arith, stacktrace, 63: nested_stacktrace, raise, gunilla, per]. 64: 65: -define(try_match(E), 66: catch ?MODULE:bar(), 67: {'EXIT', {{badmatch, nomatch}, _}} = (catch E = nomatch)). 68: 69: init_per_testcase(_Case, Config) -> 70: test_lib:interpret(?MODULE), 71: Dog = test_server:timetrap(?t:minutes(1)), 72: [{watchdog,Dog}|Config]. 73: 74: end_per_testcase(_Case, Config) -> 75: Dog = ?config(watchdog, Config), 76: ?t:timetrap_cancel(Dog), 77: ok. 78: 79: init_per_suite(Config) when is_list(Config) -> 80: ?line test_lib:interpret(?MODULE), 81: ?line true = lists:member(?MODULE, int:interpreted()), 82: Config. 83: 84: end_per_suite(Config) when is_list(Config) -> 85: ok. 86: 87: %% Test that deliberately bad matches are reported correctly. 88: 89: badmatch(Config) when is_list(Config) -> 90: ?line ?try_match(a), 91: ?line ?try_match(42), 92: ?line ?try_match({a, b, c}), 93: ?line ?try_match([]), 94: ?line ?try_match(1.0), 95: ok. 96: 97: %% Test various exceptions, in the presence of a previous error suppressed 98: %% in a guard. 99: pending_errors(Config) when is_list(Config) -> 100: ?line pending(e_badmatch, {badmatch, b}), 101: ?line pending(x, function_clause), 102: ?line pending(e_case, {case_clause, xxx}), 103: ?line pending(e_if, if_clause), 104: ?line pending(e_badarith, badarith), 105: ?line pending(e_undef, undef), 106: ?line pending(e_timeoutval, timeout_value), 107: ?line pending(e_badarg, badarg), 108: ?line pending(e_badarg_spawn, badarg), 109: ok. 110: 111: bad_guy(pe_badarith, Other) when Other+1 == 0 -> % badarith (suppressed) 112: ok; 113: bad_guy(pe_badarg, Other) when length(Other) > 0 -> % badarg (suppressed) 114: ok; 115: bad_guy(_, e_case) -> 116: case id(xxx) of 117: ok -> ok 118: end; % case_clause 119: bad_guy(_, e_if) -> 120: if 121: a == b -> ok 122: end; % if_clause 123: bad_guy(_, e_badarith) -> 124: 1+b; % badarith 125: bad_guy(_, e_undef) -> 126: non_existing_module:foo(); % undef 127: bad_guy(_, e_timeoutval) -> 128: receive 129: after arne -> % timeout_value 130: ok 131: end; 132: bad_guy(_, e_badarg) -> 133: node(xxx); % badarg 134: bad_guy(_, e_badarg_spawn) -> 135: spawn({}, {}, {}); % badarg 136: bad_guy(_, e_badmatch) -> 137: a = id(b). % badmatch 138: 139: pending(Arg, Expected) -> 140: pending(pe_badarith, Arg, Expected), 141: pending(pe_badarg, Arg, Expected). 142: 143: pending(First, Second, Expected) -> 144: pending_catched(First, Second, Expected), 145: pending_exit_message([First, Second], Expected). 146: 147: pending_catched(First, Second, Expected) -> 148: ok = io:format("Catching bad_guy(~p, ~p)", [First, Second]), 149: case catch bad_guy(First, Second) of 150: {'EXIT', Reason} -> 151: pending(Reason, bad_guy, [First, Second], Expected); 152: Other -> 153: test_server:fail({not_exit, Other}) 154: end. 155: 156: pending_exit_message(Args, Expected) -> 157: ok = io:format("Trapping EXITs from spawn_link(~p, ~p, ~p)", 158: [?MODULE, bad_guy, Args]), 159: process_flag(trap_exit, true), 160: Pid = spawn_link(?MODULE, bad_guy, Args), 161: receive 162: {'EXIT', Pid, Reason} -> 163: pending(Reason, bad_guy, Args, Expected); 164: Other -> 165: test_server:fail({unexpected_message, Other}) 166: after 10000 -> 167: test_server:fail(timeout) 168: end, 169: process_flag(trap_exit, false). 170: 171: pending({badarg, [{erlang,Bif,BifArgs,_},{?MODULE,Func,Arity,_}|_]}, 172: Func, Args, _Code) 173: when is_atom(Bif), is_list(BifArgs), length(Args) == Arity -> 174: ok; 175: pending({undef,[{non_existing_module,foo,[],_}|_]}, _, _, _) -> 176: ok; 177: pending({function_clause,[{?MODULE,Func,Args,_}|_]}, Func, Args, _Code) -> 178: ok; 179: pending({Code,[{?MODULE,Func,Arity,_}|_]}, Func, Args, Code) 180: when length(Args) == Arity -> 181: ok; 182: pending(Reason, _Function, _Args, _Code) -> 183: test_server:fail({bad_exit_reason,Reason}). 184: 185: %% Test that doing arithmetics on [] gives a badarith EXIT and not a crash. 186: 187: nil_arith(Config) when is_list(Config) -> 188: ?line ba_plus_minus_times([], []), 189: 190: ?line ba_plus_minus_times([], 0), 191: ?line ba_plus_minus_times([], 42), 192: ?line ba_plus_minus_times([], 38724978123478923784), 193: ?line ba_plus_minus_times([], 38.72), 194: 195: ?line ba_plus_minus_times(0, []), 196: ?line ba_plus_minus_times(334, []), 197: ?line ba_plus_minus_times(387249797813478923784, []), 198: ?line ba_plus_minus_times(344.22, []), 199: 200: ?line ba_div_rem([], []), 201: 202: ?line ba_div_rem([], 0), 203: ?line ba_div_rem([], 1), 204: ?line ba_div_rem([], 42), 205: ?line ba_div_rem([], 38724978123478923784), 206: ?line ba_div_rem(344.22, []), 207: 208: ?line ba_div_rem(0, []), 209: ?line ba_div_rem(1, []), 210: ?line ba_div_rem(334, []), 211: ?line ba_div_rem(387249797813478923784, []), 212: ?line ba_div_rem(344.22, []), 213: 214: ?line ba_div_rem(344.22, 0.0), 215: ?line ba_div_rem(1, 0.0), 216: ?line ba_div_rem(392873498733971, 0.0), 217: 218: ?line ba_bop([], []), 219: ?line ba_bop(0, []), 220: ?line ba_bop(42, []), 221: ?line ba_bop(-42342742987343, []), 222: ?line ba_bop(238.342, []), 223: ?line ba_bop([], 0), 224: ?line ba_bop([], -243), 225: ?line ba_bop([], 243), 226: ?line ba_bop([], 2438724982478933), 227: ?line ba_bop([], 3987.37), 228: 229: ?line ba_bnot([]), 230: ?line ba_bnot(23.33), 231: 232: ?line ba_shift([], []), 233: ?line ba_shift([], 0), 234: ?line ba_shift([], 4), 235: ?line ba_shift([], -4), 236: ?line ba_shift([], 2343333333333), 237: ?line ba_shift([], -333333333), 238: ?line ba_shift([], 234.00), 239: ?line ba_shift(23, []), 240: ?line ba_shift(0, []), 241: ?line ba_shift(-3433443433433323, []), 242: ?line ba_shift(433443433433323, []), 243: ?line ba_shift(343.93, []), 244: ok. 245: 246: ba_plus_minus_times(A, B) -> 247: io:format("~p + ~p", [A, B]), 248: {'EXIT', {badarith, _}} = (catch A + B), 249: io:format("~p - ~p", [A, B]), 250: {'EXIT', {badarith, _}} = (catch A - B), 251: io:format("~p * ~p", [A, B]), 252: {'EXIT', {badarith, _}} = (catch A * B). 253: 254: ba_div_rem(A, B) -> 255: io:format("~p / ~p", [A, B]), 256: {'EXIT', {badarith, _}} = (catch A / B), 257: io:format("~p div ~p", [A, B]), 258: {'EXIT', {badarith, _}} = (catch A div B), 259: io:format("~p rem ~p", [A, B]), 260: {'EXIT', {badarith, _}} = (catch A rem B). 261: 262: ba_bop(A, B) -> 263: io:format("~p band ~p", [A, B]), 264: {'EXIT', {badarith, _}} = (catch A band B), 265: io:format("~p bor ~p", [A, B]), 266: {'EXIT', {badarith, _}} = (catch A bor B), 267: io:format("~p bxor ~p", [A, B]), 268: {'EXIT', {badarith, _}} = (catch A bxor B). 269: 270: ba_shift(A, B) -> 271: io:format("~p bsl ~p", [A, B]), 272: {'EXIT', {badarith, _}} = (catch A bsl B), 273: io:format("~p bsr ~p", [A, B]), 274: {'EXIT', {badarith, _}} = (catch A bsr B). 275: 276: ba_bnot(A) -> 277: io:format("bnot ~p", [A]), 278: {'EXIT', {badarith, _}} = (catch bnot A). 279: 280: stacktrace(Conf) when is_list(Conf) -> 281: Tag = make_ref(), 282: ?line {_,Mref} = spawn_monitor(fun() -> exit({Tag,erlang:get_stacktrace()}) end), 283: ?line {Tag,[]} = receive {'DOWN',Mref,_,_,Info} -> Info end, 284: V = [make_ref()|self()], 285: ?line {value2,{caught1,badarg,[{erlang,abs,[V],_}|_]=St1}} = 286: stacktrace_1({'abs',V}, error, {value,V}), 287: ?line St1 = erase(stacktrace1), 288: ?line St1 = erase(stacktrace2), 289: ?line St1 = erlang:get_stacktrace(), 290: ?line {caught2,{error,badarith},[{?MODULE,my_add,2,_}|_]=St2} = 291: stacktrace_1({'div',{1,0}}, error, {'add',{0,a}}), 292: ?line [{?MODULE,my_div,2,_}|_] = erase(stacktrace1), 293: ?line St2 = erase(stacktrace2), 294: ?line St2 = erlang:get_stacktrace(), 295: ?line {caught2,{error,{try_clause,V}},[{?MODULE,stacktrace_1,3,_}|_]=St3} = 296: stacktrace_1({value,V}, error, {value,V}), 297: ?line St3 = erase(stacktrace1), 298: ?line St3 = erase(stacktrace2), 299: ?line St3 = erlang:get_stacktrace(), 300: ?line {caught2,{throw,V},[{?MODULE,foo,1,_}|_]=St4} = 301: stacktrace_1({value,V}, error, {throw,V}), 302: ?line [{?MODULE,stacktrace_1,3,_}|_] = erase(stacktrace1), 303: ?line St4 = erase(stacktrace2), 304: ?line St4 = erlang:get_stacktrace(), 305: ok. 306: 307: stacktrace_1(X, C1, Y) -> 308: erase(stacktrace1), 309: erase(stacktrace2), 310: try try foo(X) of 311: C1 -> value1 312: catch 313: C1:D1 -> {caught1,D1,erlang:get_stacktrace()} 314: after 315: put(stacktrace1, erlang:get_stacktrace()), 316: foo(Y) 317: end of 318: V2 -> {value2,V2} 319: catch 320: C2:D2 -> {caught2,{C2,D2},erlang:get_stacktrace()} 321: after 322: put(stacktrace2, erlang:get_stacktrace()) 323: end. 324: 325: 326: 327: nested_stacktrace(Conf) when is_list(Conf) -> 328: V = [{make_ref()}|[self()]], 329: ?line value1 = 330: nested_stacktrace_1({{value,{V,x1}},void,{V,x1}}, 331: {void,void,void}), 332: ?line {caught1, 333: [{?MODULE,my_add,2,_}|_], 334: value2, 335: [{?MODULE,my_add,2,_}|_]} = 336: nested_stacktrace_1({{'add',{V,x1}},error,badarith}, 337: {{value,{V,x2}},void,{V,x2}}), 338: ?line {caught1, 339: [{?MODULE,my_add,2,_}|_], 340: {caught2,[{erlang,abs,[V],_}|_]}, 341: [{erlang,abs,[V],_}|_]} = 342: nested_stacktrace_1({{'add',{V,x1}},error,badarith}, 343: {{'abs',V},error,badarg}), 344: ok. 345: 346: nested_stacktrace_1({X1,C1,V1}, {X2,C2,V2}) -> 347: try foo(X1) of 348: V1 -> value1 349: catch 350: C1:V1 -> 351: S1 = erlang:get_stacktrace(), 352: T2 = 353: try foo(X2) of 354: V2 -> value2 355: catch 356: C2:V2 -> {caught2,erlang:get_stacktrace()} 357: end, 358: {caught1,S1,T2,erlang:get_stacktrace()} 359: end. 360: 361: 362: 363: raise(Conf) when is_list(Conf) -> 364: ?line erase(raise), 365: ?line A = 366: try 367: ?line try foo({'div',{1,0}}) 368: catch 369: error:badarith -> 370: put(raise, A0 = erlang:get_stacktrace()), 371: ?line erlang:raise(error, badarith, A0) 372: end 373: catch 374: error:badarith -> 375: ?line A1 = erlang:get_stacktrace(), 376: ?line A1 = get(raise) 377: end, 378: ?line A = erlang:get_stacktrace(), 379: ?line A = get(raise), 380: ?line [{?MODULE,my_div,2,_}|_] = A, 381: %% 382: N = 8, % Must be even 383: ?line N = erlang:system_flag(backtrace_depth, N), 384: ?line try even(N) 385: catch error:function_clause -> ok 386: end, 387: ?line B = odd_even(N, []), 388: ?line B = erlang:get_stacktrace(), 389: %% 390: ?line C0 = odd_even(N+1, []), 391: ?line C = lists:sublist(C0, N), 392: ?line try odd(N+1) 393: catch error:function_clause -> ok 394: end, 395: ?line C = erlang:get_stacktrace(), 396: ?line try erlang:raise(error, function_clause, C0) 397: catch error:function_clause -> ok 398: end, 399: ?line C = erlang:get_stacktrace(), 400: ok. 401: 402: odd_even(N, R) when is_integer(N), N > 1 -> 403: odd_even(N-1, 404: [if (N rem 2) == 0 -> 405: {?MODULE,even,1,[{file,?MODULE_STRING++".erl"}, 406: {line,42}]}; 407: true -> 408: {?MODULE,odd,1,[{file,?MODULE_STRING++".erl"}, 409: {line,45}]} 410: end|R]); 411: odd_even(1, R) -> 412: [{?MODULE,odd,[1],[{file,?MODULE_STRING++".erl"}, 413: {line,44}]}|R]. 414: 415: foo({value,Value}) -> Value; 416: foo({'div',{A,B}}) -> 417: my_div(A, B); 418: foo({'add',{A,B}}) -> 419: my_add(A, B); 420: foo({'abs',X}) -> 421: my_abs(X); 422: foo({error,Error}) -> 423: erlang:error(Error); 424: foo({throw,Throw}) -> 425: erlang:throw(Throw); 426: foo({exit,Exit}) -> 427: erlang:exit(Exit); 428: foo({raise,{Class,Reason,Stacktrace}}) -> 429: erlang:raise(Class, Reason, Stacktrace). 430: %%foo(function_clause) -> % must not be defined! 431: 432: my_div(A, B) -> 433: A div B. 434: 435: my_add(A, B) -> 436: A + B. 437: 438: my_abs(X) -> abs(X). 439: 440: gunilla(Config) when is_list(Config) -> 441: ?line {throw,kalle} = gunilla_1(), 442: ?line [] = erlang:get_stacktrace(), 443: ok. 444: 445: gunilla_1() -> 446: try try arne() 447: after 448: pelle 449: end 450: catch 451: C:R -> 452: {C,R} 453: end. 454: 455: arne() -> 456: %% Empty stack trace used to cause change the error class to 'error'. 457: erlang:raise(throw, kalle, []). 458: 459: per(Config) when is_list(Config) -> 460: try 461: t1(0,pad,0), 462: t2(0,pad,0) 463: catch 464: error:badarith -> 465: ok 466: end. 467: 468: t1(_,X,_) -> 469: (1 bsl X) + 1. 470: 471: t2(_,X,_) -> 472: (X bsl 1) + 1. 473: 474: id(I) -> I.