1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2001-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: -module(cover_SUITE). 20: 21: -export([all/0, init_per_testcase/2, end_per_testcase/2, 22: suite/0,groups/0,init_per_suite/1, end_per_suite/1, 23: init_per_group/2,end_per_group/2]). 24: 25: -export([start/1, compile/1, analyse/1, misc/1, stop/1, 26: distribution/1, reconnect/1, die_and_reconnect/1, 27: dont_reconnect_after_stop/1, stop_node_after_disconnect/1, 28: export_import/1, 29: otp_5031/1, eif/1, otp_5305/1, otp_5418/1, otp_6115/1, otp_7095/1, 30: otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1, 31: otp_10979_hanging_node/1, compile_beam_opts/1]). 32: 33: -include_lib("test_server/include/test_server.hrl"). 34: 35: %%---------------------------------------------------------------------- 36: %% The following directory structure is assumed: 37: %% cwd __________________________________________ 38: %% | \ \ \ \ \ \ \ 39: %% a b cc d f d1 compile_beam_____ otp_6115 40: %% | \ \ \ \ \ \ \ 41: %% e crypt v w x d f1 f2 42: %% | 43: %% y 44: %%---------------------------------------------------------------------- 45: 46: suite() -> [{ct_hooks,[ts_install_cth]}]. 47: 48: all() -> 49: case whereis(cover_server) of 50: undefined -> 51: [start, compile, analyse, misc, stop, 52: distribution, reconnect, die_and_reconnect, 53: dont_reconnect_after_stop, stop_node_after_disconnect, 54: export_import, otp_5031, eif, otp_5305, otp_5418, 55: otp_6115, otp_7095, otp_8188, otp_8270, otp_8273, 56: otp_8340, otp_10979_hanging_node, compile_beam_opts]; 57: _pid -> 58: {skip, 59: "It looks like the test server is running " 60: "cover. Can't run cover test."} 61: end. 62: 63: groups() -> 64: []. 65: 66: init_per_suite(Config) -> 67: Config. 68: 69: end_per_suite(_Config) -> 70: ok. 71: 72: init_per_group(_GroupName, Config) -> 73: Config. 74: 75: end_per_group(_GroupName, Config) -> 76: Config. 77: 78: init_per_testcase(TC, Config) when TC =:= misc; 79: TC =:= compile; 80: TC =:= analyse; 81: TC =:= distribution; 82: TC =:= otp_5031; 83: TC =:= stop -> 84: case code:which(crypto) of 85: Path when is_list(Path) -> 86: init_per_testcase(dummy_tc, Config); 87: _Else -> 88: {skip, "No crypto file to test with"} 89: end; 90: init_per_testcase(_TestCase, Config) -> 91: Config. 92: 93: end_per_testcase(TestCase, _Config) -> 94: case lists:member(TestCase,[start,compile,analyse,misc]) of 95: true -> ok; 96: false -> cover:stop() 97: end, 98: ok. 99: 100: start(suite) -> []; 101: start(Config) when is_list(Config) -> 102: ?line ok = file:set_cwd(?config(data_dir, Config)), 103: 104: ?line Files = lsfiles(), 105: ?line remove(files(Files, ".out")), 106: 107: ?line {ok, Pid} = cover:start(), 108: ?line {error, {already_started, Pid}} = cover:start(). 109: 110: compile(suite) -> []; 111: compile(Config) when is_list(Config) -> 112: ?line ok = file:set_cwd(?config(data_dir, Config)), 113: 114: ?line Result1 = cover:compile_directory(), 115: ?line SortedResult = lists:sort(Result1), 116: ?line {ok, CWD} = file:get_cwd(), 117: ?line Result2 = cover:compile_directory(CWD), 118: ?line SortedResult = lists:sort(Result2), 119: ?line [{error,_DFile},{ok,a},{ok,b},{ok,cc},{ok,f}] = SortedResult, 120: ?line [{ok,e}] = cover:compile_directory("d1"), 121: ?line {error,enoent} = cover:compile_directory("d2"), 122: 123: ?line {ok,a} = cover:compile(a), 124: ?line {ok,b} = compile:file(b), 125: ?line code:purge(b), 126: ?line {module,b} = code:load_file(b), 127: ?line {ok,d} = cover:compile("d.erl", [{d,'AGE',42}]), 128: ?line {error,_BBFile} = cover:compile(bb), 129: 130: ?line StdlibDir = code:lib_dir(stdlib), 131: ?line Lists = filename:join([StdlibDir, "src", "lists.erl"]), 132: ?line {error, Lists} = cover:compile(Lists), 133: 134: %% For compiling beam: using dummy files v,w,x,y and z 135: ?line file:set_cwd("compile_beam"), 136: ?line {ok,_} = compile:file(v,[debug_info,report]), 137: ?line {ok,_} = compile:file(w,[debug_info,report]), 138: ?line {ok,_} = compile:file(x), 139: ?line {ok,_} = compile:file("d/y",[debug_info,{outdir,"d"},report]), 140: ?line Key = "A Krypto Key", 141: CryptoWorks = crypto_works(), 142: case CryptoWorks of 143: false -> 144: {ok,_} = compile:file(crypt, [debug_info,report]), 145: {ok,crypt} = cover:compile_beam("crypt.beam"); 146: true -> 147: {ok,_} = compile:file(crypt, [{debug_info_key,Key},report]), 148: {error,{encrypted_abstract_code,_}} = 149: cover:compile_beam("crypt.beam"), 150: ok = beam_lib:crypto_key_fun(simple_crypto_fun(Key)), 151: {ok,crypt} = cover:compile_beam("crypt.beam") 152: end, 153: Path = filename:join([?config(data_dir, Config), "compile_beam", "v.erl"]), 154: ?line {ok,v} = cover:compile_beam(v), 155: {source,Path} = lists:keyfind(source, 1, v:module_info(compile)), 156: ?line {ok,w} = cover:compile_beam("w.beam"), 157: ?line {error,{no_abstract_code,"./x.beam"}} = cover:compile_beam(x), 158: ?line {error,{already_cover_compiled,no_beam_found,a}}=cover:compile_beam(a), 159: ?line {error,non_existing} = cover:compile_beam(z), 160: ?line [{ok,y}] = cover:compile_beam_directory("d"), 161: ?line Result3 = lists:sort(cover:compile_beam_directory()), 162: ?line [{error,{no_abstract_code,_XBeam}},{ok,crypt},{ok,v},{ok,w}] = Result3, 163: ?line {error,enoent} = cover:compile_beam_directory("d2"), 164: ?line decompile([v,w,y]), 165: ?line Files = lsfiles(), 166: ?line remove(files(Files, ".beam")). 167: 168: crypto_works() -> 169: try crypto:start() of 170: {error,{already_started,crypto}} -> true; 171: ok -> true 172: catch 173: error:_ -> 174: false 175: end. 176: 177: simple_crypto_fun(Key) -> 178: fun(init) -> ok; 179: ({debug_info, des3_cbc, crypt, _}) -> Key 180: end. 181: 182: analyse(suite) -> []; 183: analyse(Config) when is_list(Config) -> 184: ?line ok = file:set_cwd(?config(data_dir, Config)), 185: 186: ?line done = a:start(5), 187: 188: ?line {ok, {a,{17,2}}} = cover:analyse(a, coverage, module), 189: ?line {ok, [{{a,start,1},{6,0}}, 190: {{a,stop,1},{0,1}}, 191: {{a,pong,1},{1,0}}, 192: {{a,loop,3},{5,1}}, 193: {{a,trycatch,1},{4,0}}, 194: {{a,exit_kalle,0},{1,0}}]} = cover:analyse(a, coverage, function), 195: ?line {ok, [{{a,start,1,1},{6,0}}, 196: {{a,stop,1,1},{0,1}}, 197: {{a,pong,1,1},{1,0}}, 198: {{a,loop,3,1},{3,1}}, 199: {{a,loop,3,2},{2,0}}, 200: {{a,trycatch,1,1},{4,0}}, 201: {{a,exit_kalle,0,1},{1,0}}]} = cover:analyse(a, coverage, clause), 202: ?line {ok, [{{a,9},{1,0}}, 203: {{a,10},{1,0}}, 204: {{a,11},{1,0}}, 205: {{a,13},{1,0}}, 206: {{a,14},{1,0}}, 207: {{a,15},{1,0}}, 208: {{a,21},{0,1}}, 209: {{a,26},{1,0}}, 210: {{a,31},{1,0}}, 211: {{a,32},{1,0}}, 212: {{a,34},{1,0}}, 213: {{a,36},{0,1}}, 214: {{a,39},{1,0}}, 215: {{a,40},{1,0}}, 216: {{a,44},{1,0}}, 217: {{a,47},{1,0}}, 218: {{a,49},{1,0}}, 219: {{a,51},{1,0}}, 220: {{a,55},{1,0}}]} = cover:analyse(a, coverage, line), 221: 222: ?line {ok, {a,15}} = cover:analyse(a, calls, module), 223: ?line {ok, [{{a,start,1},1}, 224: {{a,stop,1},0}, 225: {{a,pong,1},5}, 226: {{a,loop,3},6}, 227: {{a,trycatch,1},2}, 228: {{a,exit_kalle,0},1}]} = cover:analyse(a, calls, function), 229: ?line {ok, [{{a,start,1,1},1}, 230: {{a,stop,1,1},0}, 231: {{a,pong,1,1},5}, 232: {{a,loop,3,1},5}, 233: {{a,loop,3,2},1}, 234: {{a,trycatch,1,1},2}, 235: {{a,exit_kalle,0,1},1}]} = cover:analyse(a, calls, clause), 236: ?line {ok, [{{a,9},1}, 237: {{a,10},1}, 238: {{a,11},1}, 239: {{a,13},1}, 240: {{a,14},1}, 241: {{a,15},1}, 242: {{a,21},0}, 243: {{a,26},5}, 244: {{a,31},5}, 245: {{a,32},5}, 246: {{a,34},5}, 247: {{a,36},0}, 248: {{a,39},1}, 249: {{a,40},1}, 250: {{a,44},2}, 251: {{a,47},1}, 252: {{a,49},1}, 253: {{a,51},2}, 254: {{a,55},1}]} = cover:analyse(a, calls, line), 255: 256: ?line {ok, [{{a,start,1},{6,0}}, 257: {{a,stop,1},{0,1}}, 258: {{a,pong,1},{1,0}}, 259: {{a,loop,3},{5,1}}, 260: {{a,trycatch,1},{4,0}}, 261: {{a,exit_kalle,0},{1,0}}]} = cover:analyse(a), 262: ?line {ok, {a,{17,2}}} = cover:analyse(a, module), 263: ?line {ok, [{{a,start,1},1}, 264: {{a,stop,1},0}, 265: {{a,pong,1},5}, 266: {{a,loop,3},6}, 267: {{a,trycatch,1},2}, 268: {{a,exit_kalle,0},1}]} = cover:analyse(a, calls), 269: 270: ?line {ok, "a.COVER.out"} = cover:analyse_to_file(a), 271: ?line {ok, "e.COVER.out"} = cover:analyse_to_file(e), 272: ?line {ok, "a.COVER.html"} = cover:analyse_to_file(a,[html]), 273: ?line {ok, "e.COVER.html"} = cover:analyse_to_file(e,[html]), 274: 275: %% analyse_to_file of file which is compiled from beam 276: ?line {ok,f} = compile:file(f,[debug_info]), 277: ?line code:purge(f), 278: ?line {module,f} = code:load_file(f), 279: ?line {ok,f} = cover:compile_beam(f), 280: ?line f:f2(), 281: ?line {ok, "f.COVER.out"} = cover:analyse_to_file(f), 282: 283: %% Source code can be found via source 284: ?line {ok,v} = compile:file("compile_beam/v",[debug_info]), 285: ?line code:purge(v), 286: ?line {module,v} = code:load_file(v), 287: ?line {ok,v} = cover:compile_beam(v), 288: {ok,"v.COVER.out"} = cover:analyse_to_file(v), 289: 290: %% Source code cannot be found 291: {ok,_} = file:copy("compile_beam/z.erl", "z.erl"), 292: {ok,z} = compile:file(z,[debug_info]), 293: code:purge(z), 294: {module,z} = code:load_file(z), 295: {ok,z} = cover:compile_beam(z), 296: ok = file:delete("z.erl"), 297: {error,no_source_code_found} = cover:analyse_to_file(z), 298: code:purge(z), 299: code:delete(z), 300: 301: ?line {error,{not_cover_compiled,b}} = cover:analyse(b), 302: ?line {error,{not_cover_compiled,g}} = cover:analyse(g), 303: ?line {error,{not_cover_compiled,b}} = cover:analyse_to_file(b), 304: ?line {error,{not_cover_compiled,g}} = cover:analyse_to_file(g). 305: 306: misc(suite) -> []; 307: misc(Config) when is_list(Config) -> 308: ?line ok = file:set_cwd(?config(data_dir, Config)), 309: 310: ?line [a,cc,crypt,d,e,f,v] = lists:sort(cover:modules()), 311: 312: ?line {ok,cc} = compile:file(cc), 313: ?line code:purge(cc), 314: ?line {module,cc} = code:load_file(cc), 315: ?line [a,crypt,d,e,f,v] = lists:sort(cover:modules()), 316: 317: ?line {file, _File} = cover:is_compiled(a), 318: ?line false = cover:is_compiled(b), 319: ?line false = cover:is_compiled(g), 320: 321: ?line ok = cover:reset(a), 322: ?line {ok, {a,{0,19}}} = cover:analyse(a, module), 323: ?line ok = cover:reset(). 324: 325: stop(suite) -> []; 326: stop(Config) when is_list(Config) -> 327: ?line ok = file:set_cwd(?config(data_dir, Config)), 328: 329: ?line cover_compiled = code:which(a), 330: ?line {ok,d} = compile:file(d, [{d,'AGE',42}]), 331: ?line code:purge(d), 332: ?line {module,d} = code:load_file(d), 333: ?line ok = cover:stop(), 334: ?line Beam = code:which(a), 335: ?line true = is_unloaded(Beam), 336: 337: ?line Files = lsfiles(), 338: ?line remove(files(Files, ".out")), 339: ?line remove(files(Files, ".html")), 340: ?line remove(files(Files, ".beam")). 341: 342: distribution(suite) -> []; 343: distribution(Config) when is_list(Config) -> 344: ?line DataDir = ?config(data_dir, Config), 345: ?line ok = file:set_cwd(DataDir), 346: 347: ?line {ok,N1} = ?t:start_node(cover_SUITE_distribution1,slave,[]), 348: ?line {ok,N2} = ?t:start_node(cover_SUITE_distribution2,slave,[]), 349: ?line {ok,N3} = ?t:start_node(cover_SUITE_distribution3,slave,[]), 350: ?line {ok,N4} = ?t:start_node(cover_SUITE_distribution4,slave,[]), 351: 352: %% Check that an already compiled module is loaded on new nodes 353: ?line {ok,f} = cover:compile(f), 354: ?line {ok,[_,_,_,_]} = cover:start(nodes()), 355: ?line cover_compiled = code:which(f), 356: ?line cover_compiled = rpc:call(N1,code,which,[f]), 357: ?line cover_compiled = rpc:call(N2,code,which,[f]), 358: ?line cover_compiled = rpc:call(N3,code,which,[f]), 359: ?line cover_compiled = rpc:call(N4,code,which,[f]), 360: 361: %% Check that a node cannot be started twice 362: ?line {ok,[]} = cover:start(N2), 363: 364: %% Check that the current node (i.e. the main node) is not started with 365: %% start/1 and not stopped with stop/1 366: ?line {ok,[]} = cover:start(node()), 367: ?line ok = cover:stop(node()), 368: ?line true = is_pid(whereis(cover_server)), 369: 370: %% Check that a new compiled module is loaded on all existing nodes 371: ?line compile:file("compile_beam/v",[debug_info]), 372: ?line {ok,v} = cover:compile_beam(v), 373: ?line cover_compiled = code:which(v), 374: ?line cover_compiled = rpc:call(N1,code,which,[v]), 375: ?line cover_compiled = rpc:call(N2,code,which,[v]), 376: ?line cover_compiled = rpc:call(N3,code,which,[v]), 377: ?line cover_compiled = rpc:call(N4,code,which,[v]), 378: 379: %% this is lost when the node is killed 380: ?line rpc:call(N3,f,f2,[]), 381: ?line rpc:call(N3,erlang,halt,[]), 382: 383: %% this should be visible in analyse 384: ?line rpc:call(N1,f,f1,[]), 385: 386: %% Check that data is collected from remote node when stopped 387: ?line ok = cover:stop(N1), 388: ?line N1Beam = rpc:call(N1,code,which,[f]), 389: ?line true = is_unloaded(N1Beam), 390: ?line check_f_calls(1,0), 391: 392: %% Call f:f1() again on another node and check that number of calls is 393: %% accumulated. 394: ?line f:f1(), 395: ?line check_f_calls(2,0), 396: 397: %% Check that reset works on all nodes 398: ?line f:f1(), 399: ?line rpc:call(N2,f,f1,[]), 400: ?line ok = cover:reset(f), 401: ?line check_f_calls(0,0), 402: 403: %% Check that data is collected from all nodes 404: ?line rpc:call(N2,f,f1,[]), 405: ?line f:f2(), 406: ?line check_f_calls(1,1), 407: 408: %% Check that same data is not fetched again (i.e. that analyse does 409: %% reset on the remote node(s)) 410: ?line check_f_calls(1,1), 411: 412: %% Another checn that data is not fetched twice, i.e. when flushed 413: %% then analyse should not add the same data again. 414: ?line rpc:call(N4,f,f2,[]), 415: ?line ok = cover:flush(N4), 416: ?line check_f_calls(1,2), 417: 418: %% Check that flush collects data so calls are not lost if node is killed 419: ?line rpc:call(N4,f,f2,[]), 420: ?line ok = cover:flush(N4), 421: ?line rpc:call(N4,erlang,halt,[]), 422: ?line check_f_calls(1,3), 423: 424: %% Check that stop() unloads on all nodes 425: ?line ok = cover:stop(), 426: ?line timer:sleep(100), %% Give nodes time to unload on slow machines. 427: ?line LocalBeam = code:which(f), 428: ?line N2Beam = rpc:call(N2,code,which,[f]), 429: ?line true = is_unloaded(LocalBeam), 430: ?line true = is_unloaded(N2Beam), 431: 432: %% Check that cover_server on remote node does not die if main node dies 433: ?line {ok,[N1]} = cover:start(N1), 434: ?line true = is_pid(N1Server = rpc:call(N1,erlang,whereis,[cover_server])), 435: ?line exit(whereis(cover_server),kill), 436: ?line timer:sleep(100), 437: ?line N1Server = rpc:call(N1,erlang,whereis,[cover_server]), 438: 439: %% Cleanup 440: ?line Files = lsfiles(), 441: ?line remove(files(Files, ".beam")), 442: ?line ?t:stop_node(N1), 443: ?line ?t:stop_node(N2). 444: 445: %% Test that a lost node is reconnected 446: reconnect(Config) -> 447: DataDir = ?config(data_dir, Config), 448: ok = file:set_cwd(DataDir), 449: 450: {ok,a} = compile:file(a), 451: {ok,b} = compile:file(b), 452: {ok,f} = compile:file(f), 453: 454: {ok,N1} = ?t:start_node(cover_SUITE_reconnect,peer, 455: [{args," -pa " ++ DataDir},{start_cover,false}]), 456: {ok,a} = cover:compile(a), 457: {ok,f} = cover:compile(f), 458: {ok,[N1]} = cover:start(nodes()), 459: 460: %% Some calls to check later 461: rpc:call(N1,f,f1,[]), 462: cover:flush(N1), 463: rpc:call(N1,f,f1,[]), 464: 465: %% This will cause a call to f:f2() when nodes()==[] on N1 466: rpc:cast(N1,f,call_f2_when_isolated,[]), 467: 468: %% Disconnect and check that node is removed from main cover node 469: net_kernel:disconnect(N1), 470: timer:sleep(500), % allow some to detect disconnect and for f:f2() call 471: [] = cover:which_nodes(), 472: 473: %% Do some add one module (b) and remove one module (a) 474: code:purge(a), 475: {module,a} = code:load_file(a), 476: {ok,b} = cover:compile(b), 477: cover_compiled = code:which(b), 478: 479: [] = cover:which_nodes(), 480: check_f_calls(1,0), % only the first call - before the flush 481: 482: %% Reconnect the node and check that b and f are cover compiled but not a 483: net_kernel:connect_node(N1), 484: timer:sleep(100), 485: [N1] = cover:which_nodes(), % we are reconnected 486: cover_compiled = rpc:call(N1,code,which,[b]), 487: cover_compiled = rpc:call(N1,code,which,[f]), 488: ABeam = rpc:call(N1,code,which,[a]), 489: false = (cover_compiled==ABeam), 490: 491: %% Ensure that we have: 492: %% * one f1 call from before the flush, 493: %% * one f1 call from after the flush but before disconnect 494: %% * one f2 call when disconnected 495: check_f_calls(2,1), 496: 497: cover:stop(), 498: ?t:stop_node(N1), 499: ok. 500: 501: %% Test that a lost node is reconnected - also if it has been dead 502: die_and_reconnect(Config) -> 503: DataDir = ?config(data_dir, Config), 504: ok = file:set_cwd(DataDir), 505: 506: {ok,f} = compile:file(f), 507: 508: NodeName = cover_SUITE_die_and_reconnect, 509: {ok,N1} = ?t:start_node(NodeName,peer, 510: [{args," -pa " ++ DataDir},{start_cover,false}]), 511: %% {ok,a} = cover:compile(a), 512: {ok,f} = cover:compile(f), 513: {ok,[N1]} = cover:start(nodes()), 514: 515: %% Some calls to check later 516: rpc:call(N1,f,f1,[]), 517: cover:flush(N1), 518: rpc:call(N1,f,f1,[]), 519: 520: %% Kill the node 521: rpc:call(N1,erlang,halt,[]), 522: [] = cover:which_nodes(), 523: 524: check_f_calls(1,0), % only the first call - before the flush 525: 526: %% Restart the node and check that cover reconnects 527: {ok,N1} = ?t:start_node(NodeName,peer, 528: [{args," -pa " ++ DataDir},{start_cover,false}]), 529: timer:sleep(100), 530: [N1] = cover:which_nodes(), % we are reconnected 531: cover_compiled = rpc:call(N1,code,which,[f]), 532: 533: %% One more call... 534: rpc:call(N1,f,f1,[]), 535: 536: %% Ensure that no more calls are counted 537: check_f_calls(2,0), 538: 539: cover:stop(), 540: ?t:stop_node(N1), 541: ok. 542: 543: %% Test that a stopped node is not marked as lost, i.e. that it is not 544: %% reconnected if it is restarted (OTP-10638) 545: dont_reconnect_after_stop(Config) -> 546: DataDir = ?config(data_dir, Config), 547: ok = file:set_cwd(DataDir), 548: 549: {ok,f} = compile:file(f), 550: 551: NodeName = cover_SUITE_dont_reconnect_after_stop, 552: {ok,N1} = ?t:start_node(NodeName,peer, 553: [{args," -pa " ++ DataDir},{start_cover,false}]), 554: {ok,f} = cover:compile(f), 555: {ok,[N1]} = cover:start(nodes()), 556: 557: %% A call to check later 558: rpc:call(N1,f,f1,[]), 559: 560: %% Stop cover on the node, then terminate the node 561: cover:stop(N1), 562: rpc:call(N1,erlang,halt,[]), 563: [] = cover:which_nodes(), 564: 565: check_f_calls(1,0), 566: 567: %% Restart the node and check that cover does not reconnect 568: {ok,N1} = ?t:start_node(NodeName,peer, 569: [{args," -pa " ++ DataDir},{start_cover,false}]), 570: timer:sleep(300), 571: [] = cover:which_nodes(), 572: Beam = rpc:call(N1,code,which,[f]), 573: false = (Beam==cover_compiled), 574: 575: %% One more call... 576: rpc:call(N1,f,f1,[]), 577: cover:flush(N1), 578: 579: %% Ensure that the last call is not counted 580: check_f_calls(1,0), 581: 582: cover:stop(), 583: ?t:stop_node(N1), 584: ok. 585: 586: %% Test that a node which is stopped while it is marked as lost is not 587: %% reconnected if it is restarted (OTP-10638) 588: stop_node_after_disconnect(Config) -> 589: DataDir = ?config(data_dir, Config), 590: ok = file:set_cwd(DataDir), 591: 592: {ok,f} = compile:file(f), 593: 594: NodeName = cover_SUITE_stop_node_after_disconnect, 595: {ok,N1} = ?t:start_node(NodeName,peer, 596: [{args," -pa " ++ DataDir},{start_cover,false}]), 597: {ok,f} = cover:compile(f), 598: {ok,[N1]} = cover:start(nodes()), 599: 600: %% A call to check later 601: rpc:call(N1,f,f1,[]), 602: 603: %% Flush the node, then terminate the node to make it marked as lost 604: cover:flush(N1), 605: rpc:call(N1,erlang,halt,[]), 606: 607: check_f_calls(1,0), 608: 609: %% Stop cover on node 610: cover:stop(N1), 611: 612: %% Restart the node and check that cover does not reconnect 613: {ok,N1} = ?t:start_node(NodeName,peer, 614: [{args," -pa " ++ DataDir},{start_cover,false}]), 615: timer:sleep(300), 616: [] = cover:which_nodes(), 617: Beam = rpc:call(N1,code,which,[f]), 618: false = (Beam==cover_compiled), 619: 620: %% One more call... 621: rpc:call(N1,f,f1,[]), 622: cover:flush(N1), 623: 624: %% Ensure that the last call is not counted 625: check_f_calls(1,0), 626: 627: cover:stop(), 628: ?t:stop_node(N1), 629: ok. 630: 631: export_import(suite) -> []; 632: export_import(Config) when is_list(Config) -> 633: ?line DataDir = ?config(data_dir, Config), 634: ?line ok = file:set_cwd(DataDir), 635: ?line PortCount = length(erlang:ports()), 636: 637: %% Export one module 638: ?line {ok,f} = cover:compile(f), 639: ?line f:f1(), 640: %% check that no info is written about where data comes from when no 641: %% files are imported 642: ?line ?t:capture_start(), 643: ?line check_f_calls(1,0), 644: ?line [] = ?t:capture_get(), 645: ?line ?t:capture_stop(), 646: ?line ok = cover:export("f_exported",f), 647: ?line check_f_calls(1,0), 648: ?line ok = cover:stop(), 649: 650: %% Check that same data exists after import and that info is written about 651: %% data comming from imported file 652: ?line ok = cover:import("f_exported"), 653: ?line ?t:capture_start(), 654: ?line check_f_calls(1,0), 655: ?line [Text1] = ?t:capture_get(), 656: ?line "Analysis includes data from imported files"++_ = lists:flatten(Text1), 657: ?line ?t:capture_stop(), 658: 659: %% Export all modules 660: ?line {ok,a} = cover:compile(a), 661: ?line ?t:capture_start(), 662: ?line ok = cover:export("all_exported"), 663: ?line [] = ?t:capture_get(), 664: % ?line "Export includes data from imported files"++_ = lists:flatten(Text2), 665: ?line ?t:capture_stop(), 666: ?line ok = cover:stop(), 667: ?line ok = cover:import("all_exported"), 668: ?line check_f_calls(1,0), 669: 670: %% Check that data is reset when module is compiled again, and that 671: %% warning is written when data is deleted for imported module. 672: ?line ?t:capture_start(), 673: ?line {ok,f} = cover:compile(f), 674: ?line timer:sleep(10), % capture needs some time 675: ?line [Text3] = ?t:capture_get(), 676: ?line "WARNING: Deleting data for module f imported from" ++ _ = 677: lists:flatten(Text3), 678: ?line ?t:capture_stop(), 679: ?line check_f_calls(0,0), 680: 681: %% Check that data is summed up when first compiled and then imported 682: %% The module which has been compiled (f) is loaded from the file 683: %% all_exported again (since it has been reset during cover compiling), 684: %% but the other module (a) is not loaded since it is already loaded 685: ?line f:f1(), 686: ?line f:f2(), 687: ?line ok = cover:import("f_exported"), 688: ?line ?t:capture_start(), 689: ?line ok = cover:import("all_exported"), 690: ?line [Text4] = ?t:capture_get(), % a is not loaded again 691: ?line "WARNING: Module a already imported from " ++ _ = lists:flatten(Text4), 692: ?line ?t:capture_stop(), 693: ?line check_f_calls(3,1), 694: 695: %% Check that warning is written when same file is imported twice, 696: %% and that data is not imported again 697: ?line ?t:capture_start(), 698: ?line ok = cover:import("all_exported"), 699: ?line [Text5,Text6] = ?t:capture_get(), 700: ?line "WARNING: Module f already imported from " ++ _ = lists:flatten(Text5), 701: ?line "WARNING: Module a already imported from " ++ _ = lists:flatten(Text6), 702: ?line ?t:capture_stop(), 703: ?line check_f_calls(3,1), 704: 705: %% Check that reset removes all data and that the file which has been 706: %% reset can be imported again with no warning 707: ?line cover:reset(f), 708: ?line check_f_calls(0,0), 709: ?line ?t:capture_start(), 710: ?line ok = cover:import("all_exported"), 711: ?line [Text7] = ?t:capture_get(), % warning only on mod a 712: ?line "WARNING: Module a already imported from " ++ _ = lists:flatten(Text7), 713: ?line ?t:capture_stop(), 714: ?line check_f_calls(1,0), 715: 716: %% same as above - only reset all 717: ?line cover:reset(), 718: ?line check_f_calls(0,0), 719: ?line ?t:capture_start(), 720: ?line ok = cover:import("all_exported"), 721: ?line [] = ?t:capture_get(), % no warnings 722: ?line ?t:capture_stop(), 723: ?line check_f_calls(1,0), 724: 725: %% Check no raw files are left open 726: ?line PortCount = length(erlang:ports()), 727: 728: %% Cleanup 729: ?line ok = cover:stop(), 730: ?line Files = lsfiles(), 731: ?line remove(["f_exported","all_exported"|files(Files, ".beam")]). 732: 733: 734: otp_5031(suite) -> []; 735: otp_5031(Config) when is_list(Config) -> 736: 737: Dog = ?t:timetrap(?t:seconds(10)), 738: 739: ?line {ok,N1} = ?t:start_node(cover_SUITE_distribution1,slave,[]), 740: ?line {ok,[N1]} = cover:start(N1), 741: ?line {error,not_main_node} = rpc:call(N1,cover,modules,[]), 742: ?line cover:stop(), 743: 744: ?t:timetrap_cancel(Dog), 745: ok. 746: 747: eif(doc) -> 748: ["Test the \'Exclude Included Functions\' functionality"]; 749: eif(suite) -> 750: []; 751: eif(Config) when is_list(Config) -> 752: ?line ok = file:set_cwd(filename:join(?config(data_dir, Config), 753: "included_functions")), 754: ?line {ok, cover_inc} = compile:file(cover_inc,[debug_info]), 755: ?line {ok, cover_inc} = cover:compile_beam(cover_inc), 756: 757: %% This function will cause an included function to be executed. 758: %% The analysis should only show the lines that actually exist 759: %% in cover_inc.beam - not the ones from the included file. 760: ?line cover_inc:func(), 761: ?line {ok, [_, _]} = cover:analyse(cover_inc, line), 762: ?line cover:stop(), 763: ok. 764: 765: otp_5305(suite) -> []; 766: otp_5305(Config) when is_list(Config) -> 767: ?line ok = file:set_cwd(?config(priv_dir, Config)), 768: 769: File = "t.erl", 770: Test = <<"-module(t). 771: -export([t/0]). 772: -include_lib(\"stdlib/include/ms_transform.hrl\"). 773: t() -> 774: ets:fun2ms(fun(X) -> X end). 775: ">>, 776: ?line ok = file:write_file(File, Test), 777: ?line {ok, t} = cover:compile(File), 778: ?line cover:stop(), 779: ?line ok = file:delete(File), 780: 781: ok. 782: 783: otp_5418(suite) -> []; 784: otp_5418(Config) when is_list(Config) -> 785: ?line ok = file:set_cwd(?config(priv_dir, Config)), 786: 787: File = "t.erl", 788: Test = <<"-module(t). 789: ">>, 790: ?line ok = file:write_file(File, Test), 791: ?line {ok, t} = cover:compile(File), 792: ?line {ok,{t,{0,0}}} = cover:analyse(t, module), 793: ?line cover:stop(), 794: ?line ok = file:delete(File), 795: 796: ok. 797: 798: otp_6115(Config) when is_list(Config) -> 799: ?line {ok, CWD} = file:get_cwd(), 800: ?line Dir = filename:join(?config(data_dir, Config), otp_6115), 801: ?line ok = file:set_cwd(Dir), 802: ?line {ok, f1} = compile:file(f1, [debug_info]), 803: ?line {ok, f2} = compile:file(f2, [debug_info]), 804: 805: %% Cover compile f1, but not f2 806: ?line {ok, f1} = cover:compile(f1), 807: 808: %% If f1 is cover compiled, a process P is started with a 809: %% reference to the fun created in start_fail/0, and cover:stop() is 810: %% called, then P should be killed. 811: %% This is because (the fun held by P) references the cover 812: %% compiled code which should be *unloaded* when cover:stop() is 813: %% called -- running cover compiled code when there is no cover 814: %% server and thus no ets tables to bump counters in, makes no 815: %% sense. 816: Pid1 = f1:start_a(), 817: Pid2 = f1:start_b(), 818: 819: %% Now stop cover 820: ?line cover:stop(), 821: 822: %% Ensure that f1 is loaded (and not cover compiled), and that 823: %% both Pid1 and Pid2 are dead. 824: case code:which(f1) of 825: Beam when is_list(Beam) -> 826: ok; 827: Other -> 828: ?line ?t:fail({"f1 is not reloaded", Other}) 829: end, 830: case process_info(Pid1) of 831: undefined -> 832: ok; 833: _PI1 -> 834: RefToOldP1 = erlang:check_process_code(Pid1, f1), 835: ?t:fail({"Pid1 still alive", RefToOldP1}) 836: end, 837: case process_info(Pid2) of 838: undefined -> 839: ok; 840: _PI2 -> 841: RefToOldP2 = erlang:check_process_code(Pid1, f2), 842: ?t:fail({"Pid2 still alive", RefToOldP2}) 843: end, 844: 845: ?line file:set_cwd(CWD), 846: ok. 847: 848: otp_7095(doc) -> 849: ["andalso/orelse"]; 850: otp_7095(suite) -> []; 851: otp_7095(Config) when is_list(Config) -> 852: ?line ok = file:set_cwd(?config(priv_dir, Config)), 853: 854: File = "t.erl", 855: Test = <<"-module(t). 856: -export([t/0]). 857: t() -> 858: t1(), 859: t2(), 860: t3(), 861: t4(), 862: t5(), 863: put(t6, 0), 864: 0 = t6(), 865: 1 = erase(t6), 866: t7(), 867: put(t8, 0), 868: {'EXIT',{{badarg,0},_}} = (catch t8()), 869: 1 = erase(t8), 870: t9(), 871: ok. 872: 873: t1() -> 874: false % 20 875: andalso 876: true. % 22 877: 878: t2() -> 879: true % 25 880: andalso 881: true. % 27 882: 883: t3() -> 884: false % 30 885: orelse 886: true. % 32 887: 888: t4() -> 889: true % 35 890: orelse 891: true. % 37 892: 893: t5() -> 894: true % 40 895: andalso 896: true % 42 897: andalso 898: false. % 44 899: 900: t6() -> 901: true andalso % 47 902: add_one(t6). % 48 903: 904: t7() -> 905: true % 51 906: andalso 907: false % 53 908: andalso 909: not_ok. % 55 910: 911: t8() -> 912: true % 58 913: andalso 914: true % 60 915: andalso 916: add_one(t8) % 62 917: andalso 918: false. % 64 919: 920: t9() -> 921: if % 67 922: true -> 923: true % 69 924: andalso 925: false % 71 926: end 927: orelse 928: case ok of % 74 929: true -> 930: a; % 76 931: _ -> 932: true % 78 933: end. 934: 935: add_one(T) -> 936: put(T, get(T) + 1). % 82 937: ">>, 938: ?line ok = file:write_file(File, Test), 939: ?line {ok, t} = cover:compile(File), 940: ?line ok = t:t(), 941: ?line {ok,[{{t,4},1},{{t,5},1},{{t,6},1},{{t,7},1},{{t,8},1},{{t,9},1}, 942: {{t,10},1},{{t,11},1},{{t,12},1},{{t,13},1},{{t,14},1}, 943: {{t,15},1},{{t,16},1},{{t,17},1}, 944: {{t,20},1},{{t,22},0}, 945: {{t,25},1},{{t,27},1}, 946: {{t,30},1},{{t,32},1}, 947: {{t,35},1},{{t,37},0}, 948: {{t,40},1},{{t,42},1},{{t,44},1}, 949: {{t,47},1},{{t,48},1}, 950: {{t,51},1},{{t,53},1},{{t,55},0}, 951: {{t,58},1},{{t,60},1},{{t,62},1},{{t,64},0}, 952: {{t,67},1},{{t,69},1},{{t,71},1},{{t,74},1}, 953: {{t,76},0},{{t,78},1}, 954: {{t,82},2}]} = cover:analyse(t, calls, line), 955: ?line cover:stop(), 956: ?line ok = file:delete(File), 957: 958: ok. 959: 960: otp_8270(doc) -> 961: ["OTP-8270. Bug."]; 962: otp_8270(suite) -> []; 963: otp_8270(Config) when is_list(Config) -> 964: ?line DataDir = ?config(data_dir, Config), 965: ?line ok = file:set_cwd(DataDir), 966: 967: ?line PrivDir = ?config(priv_dir, Config), 968: 969: As = [{args," -pa " ++ PrivDir}], 970: ?line {ok,N1} = ?t:start_node(cover_n1,slave,As), 971: ?line {ok,N2} = ?t:start_node(cover_n2,slave,As), 972: ?line {ok,N3} = ?t:start_node(cover_n3,slave,As), 973: 974: timer:sleep(500), 975: cover:start(nodes()), 976: 977: Test = << 978: "-module(m).\n" 979: "-compile(export_all).\n" 980: "t() -> t(0).\n" 981: "l() ->\n" 982: " catch ets:tab2list(cover_internal_data_table).\n" 983: "t(Sz) ->\n" 984: " case ets:info(cover_internal_data_table, size) of\n" 985: " Sz ->\n" 986: " m:t(Sz); % Not a local call! Newly loaded code is entered.\n" 987: " NSz ->\n" 988: " % error_logger:info_msg(\"~p: ~p ~p change~n L1 ~p~n\", \n" 989: " % [node(), Sz, NSz, l()]),\n" 990: " m:t(NSz)\n" 991: " end.\n">>, 992: ?line _File = c_mod(m, Test, Config), 993: Fun = fun m:t/0, 994: ?line Pid1 = spawn(Fun), 995: ?line Pid2 = spawn(N1, Fun), 996: ?line Pid3 = spawn(N2, Fun), 997: ?line Pid4 = spawn(N3, Fun), 998: 999: ?line {ok, m} = cover:compile_beam(m), 1000: 1001: timer:sleep(1000), 1002: 1003: ?line Info = erlang:process_info(Pid1), 1004: ?line N1_info = rpc:call(N1, erlang, process_info, [Pid2]), 1005: ?line N2_info = rpc:call(N2, erlang, process_info, [Pid3]), 1006: ?line N3_info = rpc:call(N3, erlang, process_info, [Pid4]), 1007: 1008: ?line true = is_list(Info), 1009: ?line {N1,true} = {N1,is_list(N1_info)}, 1010: ?line {N2,true} = {N2,is_list(N2_info)}, 1011: ?line {N3,true} = {N3,is_list(N3_info)}, 1012: 1013: ?line ?t:stop_node(N1), 1014: ?line ?t:stop_node(N2), 1015: ?line ?t:stop_node(N3), 1016: ok. 1017: 1018: otp_8273(doc) -> 1019: ["OTP-8273. Bug."]; 1020: otp_8273(suite) -> []; 1021: otp_8273(Config) when is_list(Config) -> 1022: Test = <<"-module(t). 1023: -export([t/0]). 1024: t() -> 1025: foo = true andalso foo, 1026: bar = false orelse bar, 1027: ok. 1028: ">>, 1029: ?line File = cc_mod(t, Test, Config), 1030: ?line ok = t:t(), 1031: ?line cover:stop(), 1032: ?line ok = file:delete(File), 1033: 1034: ok. 1035: 1036: otp_8340(doc) -> 1037: ["OTP-8340. Bug."]; 1038: otp_8340(suite) -> []; 1039: otp_8340(Config) when is_list(Config) -> 1040: ?line [{{t,1},1},{{t,2},1},{{t,4},1}] = 1041: analyse_expr(<<"<< \n" 1042: " <<3:2, \n" 1043: " SeqId:62>> \n" 1044: " || SeqId <- [64] >>">>, Config), 1045: 1046: ok. 1047: 1048: otp_8188(doc) -> 1049: ["Clauses on the same line."]; 1050: otp_8188(suite) -> []; 1051: otp_8188(Config) when is_list(Config) -> 1052: %% This example covers the bug report: 1053: Test = <<"-module(t). 1054: -export([test/1]). 1055: 1056: -define(FOOBAR(X), 1057: case X of 1058: ok -> true; 1059: _ -> false 1060: end). 1061: 1062: test(X)-> 1063: _Res = 1064: ?FOOBAR(X). 1065: ">>, 1066: ?line File = cc_mod(t, Test, Config), 1067: ?line false = t:test(nok), 1068: ?line {ok,[{{t,11},1},{{t,12},1}]} = cover:analyse(t, calls, line), 1069: ?line cover:stop(), 1070: ?line ok = file:delete(File), 1071: 1072: %% Bit string comprehensions are now traversed; 1073: %% the handling of list comprehensions has been improved: 1074: comprehension_8188(Config), 1075: 1076: %% Variants of the reported bug: 1077: bug_8188(Config), 1078: ok. 1079: 1080: bug_8188(Cf) -> 1081: ?line [{{t,1},1},{{t,2},1},{{t,3},1}] = 1082: analyse_expr(<<"A = 3,\n" % 1 1083: " case A of\n" % 1 1084: " 2 -> two; 3 -> three end, A + 2">>, % 1 1085: Cf), 1086: 1087: ?line [{{t,1},1}, 1088: {{t,2},0}, 1089: {{t,3},1}, 1090: {{t,4},1}, 1091: {{t,5},1}, 1092: {{t,6},0}, 1093: {{t,7},1}, 1094: {{t,9},2}] = 1095: analyse_expr(<<"case two() of\n" % 1 1096: " 1 -> 2;\n" % 0 1097: " _ -> begin 3 end\n" % 1 1098: " +\n" % 1 1099: " begin 4 end end, case two() of\n" % 1 1100: " 1 -> a;\n" % 0 1101: " 2 -> b; 3 -> c\n" % 1 1102: " end.\n" 1103: "two() -> 2">>, Cf), % 2 1104: 1105: ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, 1106: {{t,4},1}, {{t,5},1}, {{t,6},0}] = 1107: analyse_expr(<<" self() ! 1,\n" 1108: " receive \n" 1109: " X=1 -> a;\n" 1110: " X=2 -> b end, case X of \n" 1111: " 1 -> a;\n" 1112: " 2 -> b\n" 1113: " end">>, Cf), 1114: 1115: T0 = <<"t1(X) ->\n " 1116: "case X of\n" 1117: " 1 -> A=a,B=A,B; % bump Li\n" 1118: " 2 -> b; 3 -> case X of % 2 -> b shall bump Li\n" 1119: " 3 -> a; % bump Li\n" 1120: " 2 -> b end; 4 -> d end, case X of % Li\n" 1121: " 1 -> a;\n" 1122: " 2 -> b; 3 -> c;\n" 1123: " 4 -> d\n" 1124: " end">>, 1125: 1126: T1 = [<<"a = t1(1). ">>,T0], 1127: ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},0}, 1128: {{t,5},0}, {{t,6},1}, {{t,7},1}, {{t,8},0}, {{t,9},0}] = 1129: analyse_expr(T1, Cf), 1130: 1131: T2 = [<<"b = t1(2). ">>,T0], 1132: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, 1133: {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}, {{t,9},0}] = 1134: analyse_expr(T2, Cf), 1135: 1136: T3 = [<<"c = t1(3). ">>,T0], 1137: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, 1138: {{t,5},1}, {{t,6},1}, {{t,7},0}, {{t,8},1}, {{t,9},0}] = 1139: analyse_expr(T3, Cf), 1140: 1141: T4 = [<<"d = t1(4). ">>,T0], 1142: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},0}, 1143: {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},0}, {{t,9},1}] = 1144: analyse_expr(T4, Cf), 1145: 1146: ?line [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},1},{{t,5},1}] = 1147: analyse_expr( 1148: <<"2 = x3(1). " 1149: "x3(X) ->\n" 1150: " case X of \n" 1151: " 1 -> case X of\n" 1152: " 1 -> a, Y = 2;\n" 1153: " 2 -> b, Y = 3 end, Y; 2 -> Y = 4 end, Y">>, Cf), 1154: 1155: ?line [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},1}] = 1156: analyse_expr( 1157: <<"1 = x4(1). " 1158: "x4(X) ->\n" 1159: " case X of\n" 1160: " 1 -> case X of\n" 1161: " 1 -> Y = 1 end, case X of 1 -> Y = 1 end, Y end">>, 1162: Cf), 1163: 1164: T10 = <<"t1(X) ->\n" 1165: "if\n" 1166: " X =:= 1 -> a;\n" 1167: " X =:= 2 -> b; X =:= 3 -> c end, case X of \n" 1168: " 1 -> a;\n" 1169: " 2 -> b; 3 -> c end, case X of\n" 1170: " 1 -> a;\n" 1171: " 2 -> b; 3 -> c\n" 1172: " end">>, 1173: T11 = [<<"a = t1(1). ">>,T10], 1174: ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},1}, 1175: {{t,5},1}, {{t,6},1}, {{t,7},1}, {{t,8},0}] = 1176: analyse_expr(T11, Cf), 1177: 1178: T12 = [<<"b = t1(2). ">>,T10], 1179: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, 1180: {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = 1181: analyse_expr(T12, Cf), 1182: 1183: T13 = [<<"c = t1(3). ">>,T10], 1184: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, 1185: {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = 1186: analyse_expr(T13, Cf), 1187: 1188: T20 = <<"t1(X) ->\n" 1189: "case X of\n" 1190: " 1 -> a;\n" 1191: " 2 -> b; 3 -> case X of\n" 1192: " 1 -> a;\n" 1193: " 2 -> b; 3 -> c end end, case X of\n" 1194: " 1 -> a;\n" 1195: " 2 -> b; 3 -> c\n" 1196: " end">>, 1197: 1198: T21 = [<<"a = t1(1). ">>,T20], 1199: ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},0}, 1200: {{t,5},0}, {{t,6},1}, {{t,7},1}, {{t,8},0}] = 1201: analyse_expr(T21, Cf), 1202: 1203: T22 = [<<"b = t1(2). ">>,T20], 1204: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, 1205: {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = 1206: analyse_expr(T22, Cf), 1207: 1208: T23 = [<<"c = t1(3). ">>,T20], 1209: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, 1210: {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = 1211: analyse_expr(T23, Cf), 1212: 1213: T30 = << 1214: "t1(X) ->\n" 1215: "case X of\n" 1216: " 1 -> a;\n" 1217: " 2 -> b; 3 -> case X of 1 -> a; 2 -> b; 3 -> c end end, case X of\n" 1218: " 1 -> a;\n" 1219: " 2 -> b; 3 -> c\n" 1220: " end\n">>, 1221: 1222: T31 = [<<"a = t1(1). ">>,T30], 1223: ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, 1224: {{t,4},1}, {{t,5},1}, {{t,6},0}] = 1225: analyse_expr(T31, Cf), 1226: 1227: T32 = [<<"b = t1(2). ">>,T30], 1228: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, 1229: {{t,4},1}, {{t,5},0}, {{t,6},1}] = 1230: analyse_expr(T32, Cf), 1231: 1232: T33 = [<<"c = t1(3). ">>,T30], 1233: ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, 1234: {{t,4},1}, {{t,5},0}, {{t,6},1}] = 1235: analyse_expr(T33, Cf), 1236: 1237: %% 'try' now traverses the body as a body... 1238: ?line [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},0},{{t,6},1}] = 1239: analyse_expr(<<"try \n" 1240: " B = 2, \n" 1241: " C = erlang:error(foo), \n" 1242: " {B,C} \n" 1243: "catch _:_ -> \n" 1244: " foo \n" 1245: "end">>, Cf), 1246: 1247: %% receive after: 1248: ?line [{{t,1},1},{{t,2},0},{{t,3},1}] = 1249: analyse_expr(<<"receive \n" 1250: " X=1 -> a; \n" 1251: " X=2 -> b after begin 10 end -> X=3 end">>, Cf), 1252: ?line [{{t,1},1},{{t,2},0},{{t,3},1}] = 1253: analyse_expr(<<"receive \n" 1254: " X=1 -> a; \n" 1255: " X=2 -> b after 10 -> begin X=3 end end">>, Cf), 1256: ok. 1257: 1258: comprehension_8188(Cf) -> 1259: ?line [{{t,1},1}] = 1260: analyse_expr(<<"[begin X end || X <- [1,2,3], X > 1]">>, Cf), 1261: ?line [{{t,1},1},{{t,2},1}] = 1262: analyse_expr(<<"[begin X end || \n" 1263: " X <- [1,2,3], X > 1]">>, Cf), 1264: ?line [{{t,1},1},{{t,2},1},{{t,3},3}] = 1265: analyse_expr(<<"[begin X end || \n " 1266: " X <- [1,2,3], \n " 1267: " X > 1]">>, Cf), 1268: ?line [{{t,1},1},{{t,3},1},{{t,4},3}] = 1269: analyse_expr(<<"[begin X end || \n " 1270: " X <- \n " 1271: " [1,2,3], \n " 1272: " X > 1]">>, Cf), 1273: ?line [{{t,1},1},{{t,2},2}] = 1274: analyse_expr(<<"[ \n " 1275: " X || X <- [1,2,3], X > 1]">>, Cf), 1276: ?line [{{t,1},1},{{t,2},2},{{t,3},3}] = 1277: analyse_expr(<<"[ \n" 1278: " X || X <- [1,2,3], \n" 1279: " X > 1]">>, Cf), 1280: ?line [{{t,1},1},{{t,2},1},{{t,3},2}] = 1281: analyse_expr(<<"[ \n " 1282: " X || X <- [1,2,3], X > 1, \n" 1283: " X > 2]">>, Cf), 1284: 1285: ?line [{{t,1},1}, 1286: {{t,3},2}, 1287: {{t,5},1}, 1288: {{t,7},1}, 1289: {{t,8},0}, 1290: {{t,12},3}, 1291: {{t,15},2}, 1292: {{t,17},2}, 1293: {{t,18},1}] = 1294: analyse_expr(<<"[ \n" % 1 1295: " begin\n" 1296: " X * 2\n" % 2 1297: " end ||\n" 1298: " X <- [1,\n" % 1 1299: " case two() of\n" 1300: " 2 -> 2;\n" % 1 1301: " _ -> two\n" % 0 1302: " end,\n" 1303: " 3],\n" 1304: " begin\n" 1305: " math:sqrt(X) > 1.0\n" % 3 1306: " end,\n" 1307: " begin\n" 1308: " true\n" % 2 1309: " end,\n" 1310: " true]. \n" % 2 1311: " two() -> 2">>, Cf), % 1 1312: 1313: ?line [{{t,1},1}, 1314: {{t,2},2}, 1315: {{t,3},1}, 1316: {{t,5},1}, 1317: {{t,6},0}, 1318: {{t,9},3}, 1319: {{t,10},2}, 1320: {{t,11},2}, 1321: {{t,12},1}] = 1322: analyse_expr(<<"[ \n" 1323: " X * 2 || \n" % 2 1324: " X <- [1,\n" % 1 1325: " case two() of\n" 1326: " 2 -> 2;\n" % 1 1327: " _ -> two\n" % 0 1328: " end,\n" 1329: " 3],\n" 1330: " math:sqrt(X) > 1.0,\n" % 3 1331: " true,\n" % 2 1332: " true]. \n" % 2 1333: " two() -> 2">>, Cf), % 1 1334: 1335: ?line [{{t,1},1}, 1336: {{t,2},2}, 1337: {{t,3},1}, 1338: {{t,4},1}, 1339: {{t,5},0}, 1340: {{t,8},1}, 1341: {{t,9},0}, 1342: {{t,12},3}, 1343: {{t,13},2}, 1344: {{t,14},2}] = 1345: analyse_expr(<<"<< \n" % 1 1346: " << (X*2) >> || \n" % 2 1347: " <<X>> <= << (case two() of\n" 1348: " 2 -> 1;\n" % 1 1349: " _ -> 2\n" % 0 1350: " end)/integer,\n" 1351: " (case two() of \n" 1352: " 2 -> 2;\n" % 1 1353: " _ -> two\n" % 0 1354: " end)/integer,\n" 1355: " 3 >>, \n" 1356: " math:sqrt(X) > 1.0,\n" % 3 1357: " true >>.\n" % 2 1358: "two() -> 2">>, Cf), 1359: 1360: ?line [{{t,1},1}, 1361: {{t,2},4}, 1362: {{t,4},1}, 1363: {{t,6},1}, 1364: {{t,7},0}, 1365: {{t,10},3}, 1366: {{t,11},2}, 1367: {{t,12},4}, 1368: {{t,13},1}] = 1369: analyse_expr(<<"<< \n" % 1 1370: " << (2)\n" % 4 1371: " :(8) >> || \n" 1372: " <<X>> <= << 1,\n" % 1 1373: " (case two() of \n" 1374: " 2 -> 2;\n" % 1 1375: " _ -> two\n" % 0 1376: " end)/integer,\n" 1377: " 3 >>, \n" 1378: " math:sqrt(X) > 1.0,\n" % 3 1379: " <<_>> <= << 1, 2 >>,\n" % 2 1380: " true >>.\n" % 4 1381: "two() -> 2">>, Cf), % 1 1382: 1383: ok. 1384: 1385: otp_10979_hanging_node(_Config) -> 1386: 1387: P1 = processes(), 1388: 1389: cover:stop(non_existing_node), 1390: cover:stop(), 1391: 1392: P2 = processes(), 1393: 1394: case P2--P1 of 1395: [] -> 1396: ok; 1397: New -> 1398: [io:format("New: ~p, ~p~n",[P,process_info(P)]) || P<-New], 1399: ct:fail(hanging_process) 1400: end, 1401: 1402: ok. 1403: 1404: compile_beam_opts(doc) -> 1405: ["Take compiler options from beam in cover:compile_beam"]; 1406: compile_beam_opts(suite) -> []; 1407: compile_beam_opts(Config) when is_list(Config) -> 1408: {ok, Cwd} = file:get_cwd(), 1409: ok = file:set_cwd(?config(priv_dir, Config)), 1410: IncDir = filename:join(?config(data_dir, Config), 1411: "included_functions"), 1412: File = filename:join([?config(data_dir, Config), "otp_11439", "t.erl"]), 1413: %% use all compiler options allowed by cover:filter_options 1414: %% i and d don't make sense when compiling from beam though 1415: {ok, t} = 1416: compile:file(File, [{i, IncDir}, 1417: {d, 'BOOL'}, 1418: {d, 'MACRO', macro_defined}, 1419: export_all, 1420: debug_info, 1421: return_errors]), 1422: Exports = 1423: [{func1,0}, 1424: {macro, 0}, 1425: {exported,0}, 1426: {nonexported,0}, 1427: {module_info,0}, 1428: {module_info,1}], 1429: Exports = t:module_info(exports), 1430: {ok, t} = cover:compile_beam("t"), 1431: Exports = t:module_info(exports), 1432: cover:stop(), 1433: ok = file:delete("t.beam"), 1434: ok = file:set_cwd(Cwd), 1435: ok. 1436: 1437: %%--Auxiliary------------------------------------------------------------ 1438: 1439: analyse_expr(Expr, Config) -> 1440: Binary = [<<"-module(t). " 1441: "-export([t/0]). " 1442: "t() -> ">>, Expr, <<".\n">>], 1443: File = cc_mod(t, Binary, Config), 1444: t:t(), 1445: {ok, Result} = cover:analyse(t, calls, line), 1446: ok = file:delete(File), 1447: Result. 1448: 1449: cc_mod(M, Binary, Config) -> 1450: {ok, Dir} = file:get_cwd(), 1451: PrivDir = ?config(priv_dir, Config), 1452: ok = file:set_cwd(PrivDir), 1453: File = atom_to_list(M) ++ ".erl", 1454: try 1455: ok = file:write_file(File, Binary), 1456: {ok, M} = cover:compile(File), 1457: filename:join(PrivDir, File) 1458: after file:set_cwd(Dir) 1459: end. 1460: 1461: c_mod(M, Binary, Config) -> 1462: {ok, Dir} = file:get_cwd(), 1463: PrivDir = ?config(priv_dir, Config), 1464: ok = file:set_cwd(PrivDir), 1465: File = atom_to_list(M) ++ ".erl", 1466: try 1467: ok = file:write_file(File, Binary), 1468: {ok, M} = compile:file(File, [debug_info]), 1469: code:purge(M), 1470: AbsFile = filename:rootname(File, ".erl"), 1471: code:load_abs(AbsFile, M), 1472: filename:join(PrivDir, File) 1473: after file:set_cwd(Dir) 1474: end. 1475: 1476: lsfiles() -> 1477: {ok, CWD} = file:get_cwd(), 1478: lsfiles(CWD). 1479: 1480: lsfiles(Dir) -> 1481: {ok, Files} = file:list_dir(Dir), 1482: Files. 1483: 1484: files(Files, Ext) -> 1485: lists:filter(fun(File) -> 1486: case filename:extension(File) of 1487: Ext -> true; 1488: _ -> false 1489: end 1490: end, 1491: Files). 1492: 1493: remove([File|Files]) -> 1494: ok = file:delete(File), 1495: remove(Files); 1496: remove([]) -> 1497: ok. 1498: 1499: decompile([Mod|Mods]) -> 1500: code:purge(Mod), 1501: code:delete(Mod), 1502: decompile(Mods); 1503: decompile([]) -> 1504: ok. 1505: 1506: is_unloaded(What) -> 1507: if 1508: is_list(What) -> true; 1509: What==non_existing -> true; 1510: true -> false 1511: end. 1512: 1513: check_f_calls(F1,F2) -> 1514: {ok,[{{f,f1,0},F1},{{f,f2,0},F2}|_]} = cover:analyse(f,calls,function).