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(fun_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: good_call/1,bad_apply/1,bad_fun_call/1,badarity/1, 27: ext_badarity/1,otp_6061/1,external/1]). 28: 29: %% Internal exports. 30: -export([nothing/0,call_me/1]). 31: 32: -include_lib("test_server/include/test_server.hrl"). 33: 34: suite() -> [{ct_hooks,[ts_install_cth]}]. 35: 36: all() -> 37: cases(). 38: 39: groups() -> 40: []. 41: 42: init_per_group(_GroupName, Config) -> 43: Config. 44: 45: end_per_group(_GroupName, Config) -> 46: Config. 47: 48: 49: cases() -> 50: [good_call, bad_apply, bad_fun_call, badarity, 51: ext_badarity, otp_6061, external]. 52: 53: init_per_testcase(_Case, Config) -> 54: test_lib:interpret(?MODULE), 55: Dog = test_server:timetrap(?t:minutes(1)), 56: [{watchdog,Dog}|Config]. 57: 58: end_per_testcase(_Case, Config) -> 59: Dog = ?config(watchdog, Config), 60: ?t:timetrap_cancel(Dog), 61: ok. 62: 63: init_per_suite(Config) when is_list(Config) -> 64: ?line test_lib:interpret(?MODULE), 65: ?line true = lists:member(?MODULE, int:interpreted()), 66: Config. 67: 68: end_per_suite(Config) when is_list(Config) -> 69: ok. 70: 71: good_call(Config) when is_list(Config) -> 72: ?line F = fun() -> ok end, 73: ?line ok = F(), 74: ?line FF = fun ?MODULE:nothing/0, 75: ?line ok = FF(), 76: ok. 77: 78: bad_apply(doc) -> 79: "Test that the correct EXIT code is returned for all types of bad funs."; 80: bad_apply(suite) -> []; 81: bad_apply(Config) when is_list(Config) -> 82: ?line bad_apply_fc(42, [0]), 83: ?line bad_apply_fc(xx, [1]), 84: ?line bad_apply_fc({}, [2]), 85: ?line bad_apply_fc({1}, [3]), 86: ?line bad_apply_fc({1,2,3}, [4]), 87: ?line bad_apply_fc({1,2,3}, [5]), 88: ?line bad_apply_fc({1,2,3,4}, [6]), 89: ?line bad_apply_fc({1,2,3,4,5,6}, [7]), 90: ?line bad_apply_fc({1,2,3,4,5}, [8]), 91: ?line bad_apply_badarg({1,2}, [9]), 92: ok. 93: 94: bad_apply_fc(Fun, Args) -> 95: Res = (catch apply(Fun, Args)), 96: erlang:garbage_collect(), 97: erlang:yield(), 98: case Res of 99: {'EXIT',{{badfun,Fun},_Where}} -> 100: ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res]); 101: Other -> 102: ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res]), 103: ?t:fail({bad_result,Other}) 104: end. 105: 106: bad_apply_badarg(Fun, Args) -> 107: Res = (catch apply(Fun, Args)), 108: erlang:garbage_collect(), 109: erlang:yield(), 110: case Res of 111: {'EXIT',{{badfun,Fun},_Where}} -> 112: ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res]); 113: Other -> 114: ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res]), 115: ?t:fail({bad_result, Other}) 116: end. 117: 118: bad_fun_call(doc) -> 119: "Try directly calling bad funs."; 120: bad_fun_call(suite) -> []; 121: bad_fun_call(Config) when is_list(Config) -> 122: ?line bad_call_fc(42), 123: ?line bad_call_fc(xx), 124: ?line bad_call_fc({}), 125: ?line bad_call_fc({1}), 126: ?line bad_call_fc({1,2,3}), 127: ?line bad_call_fc({1,2,3}), 128: ?line bad_call_fc({1,2,3,4}), 129: ?line bad_call_fc({1,2,3,4,5,6}), 130: ?line bad_call_fc({1,2,3,4,5}), 131: ?line bad_call_fc({1,2}), 132: ok. 133: 134: bad_call_fc(Fun) -> 135: Args = [some,stupid,args], 136: Res = (catch Fun(Args)), 137: case Res of 138: {'EXIT',{{badfun,Fun},_Where}} -> 139: ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]); 140: Other -> 141: ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]), 142: ?t:fail({bad_result,Other}) 143: end. 144: 145: %% Call and apply valid external funs with wrong number of arguments. 146: 147: badarity(Config) when is_list(Config) -> 148: ?line Fun = fun() -> ok end, 149: ?line Stupid = {stupid,arguments}, 150: ?line Args = [some,{stupid,arguments},here], 151: 152: %% Simple call. 153: 154: ?line Res = (catch Fun(some, Stupid, here)), 155: erlang:garbage_collect(), 156: erlang:yield(), 157: case Res of 158: {'EXIT',{{badarity,{Fun,Args}},[_|_]}} -> 159: ?line ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]); 160: _ -> 161: ?line ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]), 162: ?line ?t:fail({bad_result,Res}) 163: end, 164: 165: %% Apply. 166: 167: ?line Res2 = (catch apply(Fun, Args)), 168: erlang:garbage_collect(), 169: erlang:yield(), 170: case Res2 of 171: {'EXIT',{{badarity,{Fun,Args}},[_|_]}} -> 172: ?line ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res2]); 173: _ -> 174: ?line ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res2]), 175: ?line ?t:fail({bad_result,Res2}) 176: end, 177: ok. 178: 179: %% Call and apply valid external funs with wrong number of arguments. 180: 181: ext_badarity(Config) when is_list(Config) -> 182: ?line Fun = fun ?MODULE:nothing/0, 183: ?line Stupid = {stupid,arguments}, 184: ?line Args = [some,{stupid,arguments},here], 185: 186: %% Simple call. 187: 188: ?line Res = (catch Fun(some, Stupid, here)), 189: erlang:garbage_collect(), 190: erlang:yield(), 191: case Res of 192: {'EXIT',{{badarity,{Fun,Args}},_}} -> 193: ?line ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]); 194: _ -> 195: ?line ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]), 196: ?line ?t:fail({bad_result,Res}) 197: end, 198: 199: %% Apply. 200: 201: ?line Res2 = (catch apply(Fun, Args)), 202: erlang:garbage_collect(), 203: erlang:yield(), 204: case Res2 of 205: {'EXIT',{{badarity,{Fun,Args}},_}} -> 206: ?line ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res2]); 207: _ -> 208: ?line ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res2]), 209: ?line ?t:fail({bad_result,Res2}) 210: end, 211: ok. 212: 213: nothing() -> 214: ok. 215: 216: otp_6061(suite) -> 217: []; 218: otp_6061(doc) -> 219: ["Test handling of fun expression referring to uninterpreted code"]; 220: otp_6061(Config) when is_list(Config) -> 221: 222: ?line OrigFlag = process_flag(trap_exit, true), 223: 224: ?line Self = self(), 225: ?line Pid = spawn_link(fun() -> test_otp_6061(Self) end), 226: 227: receive 228: working -> 229: ?line ok; 230: not_working -> 231: ?line ?t:fail(not_working); 232: {'EXIT', Pid, Reason} -> 233: ?line ?t:fail({crash, Reason}) 234: after 235: 5000 -> 236: ?line ?t:fail(timeout) 237: end, 238: 239: ?line process_flag(trap_exit, OrigFlag), 240: 241: ok. 242: 243: test_otp_6061(Starter) -> 244: Passes = [2], 245: PassesF = [fun() -> Starter ! not_working end, 246: fun() -> Starter ! working end, 247: fun() -> Starter ! not_working end], 248: lists:foreach(fun(P)->(lists:nth(P,PassesF))() end,Passes). 249: 250: -define(APPLY(M, F, A), (fun(Fun) -> {ok,{a,b}} = Fun({a,b}) end)(fun M:F/A)). 251: -define(APPLY2(M, F, A), 252: (fun(Map) -> 253: Id = fun(I) -> I end, 254: List = [x,y], 255: List = Map(Id, List), 256: {type,external} = erlang:fun_info(Map, type) 257: end)(fun M:F/A)). 258: 259: external(Config) when is_list(Config) -> 260: Mod = id(?MODULE), 261: Func = id(call_me), 262: Arity = id(1), 263: 264: ?APPLY(?MODULE, call_me, 1), 265: ?APPLY(?MODULE, call_me, Arity), 266: ?APPLY(?MODULE, Func, 1), 267: ?APPLY(?MODULE, Func, Arity), 268: ?APPLY(Mod, call_me, 1), 269: ?APPLY(Mod, call_me, Arity), 270: ?APPLY(Mod, Func, 1), 271: ?APPLY(Mod, Func, Arity), 272: 273: ListsMod = id(lists), 274: ListsMap = id(map), 275: ListsArity = id(2), 276: 277: ?APPLY2(lists, map, 2), 278: ?APPLY2(lists, map, ListsArity), 279: ?APPLY2(lists, ListsMap, 2), 280: ?APPLY2(lists, ListsMap, ListsArity), 281: ?APPLY2(ListsMod, map, 2), 282: ?APPLY2(ListsMod, map, ListsArity), 283: ?APPLY2(ListsMod, ListsMap, 2), 284: ?APPLY2(ListsMod, ListsMap, ListsArity), 285: 286: ok. 287: 288: call_me(I) -> 289: {ok,I}. 290: 291: id(I) -> 292: I.