diff options
Diffstat (limited to 'lib/stdlib/test')
33 files changed, 1532 insertions, 886 deletions
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index d4ab674486..e366c2b755 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -30,6 +30,7 @@ MODULES= \ erl_lint_SUITE \ erl_pp_SUITE \ erl_scan_SUITE \ + error_logger_h_SUITE \ escript_SUITE \ ets_SUITE \ ets_tough_SUITE \ diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl index cca9b967d5..f750145ef0 100644 --- a/lib/stdlib/test/base64_SUITE.erl +++ b/lib/stdlib/test/base64_SUITE.erl @@ -30,7 +30,8 @@ %% Test cases must be exported. -export([base64_encode/1, base64_decode/1, base64_otp_5635/1, base64_otp_6279/1, big/1, illegal/1, mime_decode/1, - mime_decode_to_string/1, roundtrip/1]). + mime_decode_to_string/1, + roundtrip_1/1, roundtrip_2/1, roundtrip_3/1, roundtrip_4/1]). init_per_testcase(_, Config) -> Dog = test_server:timetrap(?t:minutes(4)), @@ -50,10 +51,11 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [base64_encode, base64_decode, base64_otp_5635, base64_otp_6279, big, illegal, mime_decode, mime_decode_to_string, - roundtrip]. + {group, roundtrip}]. groups() -> - []. + [{roundtrip, [parallel], + [roundtrip_1, roundtrip_2, roundtrip_3, roundtrip_4]}]. init_per_suite(Config) -> Config. @@ -242,21 +244,33 @@ mime_decode_to_string(Config) when is_list(Config) -> %%------------------------------------------------------------------------- -roundtrip(Config) when is_list(Config) -> - Sizes = lists:seq(1, 255) ++ lists:seq(2400-5, 2440), - roundtrip_1(Sizes, []). +roundtrip_1(Config) when is_list(Config) -> + do_roundtrip(1). -roundtrip_1([NextSize|Sizes], Current) -> +roundtrip_2(Config) when is_list(Config) -> + do_roundtrip(2). + +roundtrip_3(Config) when is_list(Config) -> + do_roundtrip(3). + +roundtrip_4(Config) when is_list(Config) -> + do_roundtrip(4). + +do_roundtrip(Offset) -> + Sizes = lists:seq(Offset, 255, 4) ++ lists:seq(2400-6+Offset, 2440, 4), + do_roundtrip_1(Sizes, []). + +do_roundtrip_1([NextSize|Sizes], Current) -> Len = length(Current), io:format("~p", [Len]), - do_roundtrip(Current), + do_roundtrip_2(Current), Next = random_byte_list(NextSize - Len, Current), - roundtrip_1(Sizes, Next); -roundtrip_1([], Last) -> + do_roundtrip_1(Sizes, Next); +do_roundtrip_1([], Last) -> io:format("~p", [length(Last)]), - do_roundtrip(Last). + do_roundtrip_2(Last). -do_roundtrip(List) -> +do_roundtrip_2(List) -> Bin = list_to_binary(List), Base64Bin = base64:encode(List), Base64Bin = base64:encode(Bin), @@ -326,7 +340,7 @@ interleaved_ws_roundtrip_1([], Base64List, Bin, List) -> random_byte_list(0, Acc) -> Acc; random_byte_list(N, Acc) -> - random_byte_list(N-1, [random:uniform(255)|Acc]). + random_byte_list(N-1, [rand:uniform(255)|Acc]). make_big_binary(N) -> list_to_binary(mbb(N, [])). diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl index 70c946bdb9..8a2df2bf85 100644 --- a/lib/stdlib/test/binary_module_SUITE.erl +++ b/lib/stdlib/test/binary_module_SUITE.erl @@ -536,6 +536,12 @@ do_interesting(Module) -> ?line [<<3>>,<<6>>] = Module:split(<<1,2,3,4,5,6,7,8>>, [<<1>>,<<2>>,<<4>>,<<5>>,<<7>>,<<8>>], [global,trim_all]), + [<<>>] = binary:split(<<>>, <<",">>, []), + [] = binary:split(<<>>, <<",">>, [trim]), + [] = binary:split(<<>>, <<",">>, [trim_all]), + [] = binary:split(<<>>, <<",">>, [global,trim]), + [] = binary:split(<<>>, <<",">>, [global,trim_all]), + ?line badarg = ?MASK_ERROR( Module:replace(<<1,2,3,4,5,6,7,8>>, [<<4,5>>,<<7>>,<<8>>],<<99>>, @@ -710,7 +716,7 @@ do_interesting(Module) -> encode_decode(doc) -> ["test binary:encode_unsigned/1,2 and binary:decode_unsigned/1,2"]; encode_decode(Config) when is_list(Config) -> - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line ok = encode_decode_loop({1,200},1000), % Need to be long enough % to create offheap binaries ok. @@ -817,7 +823,7 @@ copy(Config) when is_list(Config) -> ?line badarg = ?MASK_ERROR(binary:copy(<<1,2,3>>, 16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), ?line <<>> = binary:copy(<<>>,10000), - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line ok = random_copy(3000), ?line erts_debug:set_internal_state(available_internal_state,true), ?line io:format("oldlimit: ~p~n", @@ -855,7 +861,7 @@ random_copy(0) -> ok; random_copy(N) -> Str = random_string({0,N}), - Num = random:uniform(N div 10+1), + Num = rand:uniform(N div 10+1), A = ?MASK_ERROR(binary:copy(Str,Num)), B = ?MASK_ERROR(binref:copy(Str,Num)), C = ?MASK_ERROR(binary:copy(make_unaligned(Str),Num)), @@ -896,7 +902,7 @@ bin_to_list(Config) when is_list(Config) -> ?line [5] = lists:nthtail(byte_size(X)-1,LX), ?line [0,5] = lists:nthtail(byte_size(X)-2,LX), ?line [0,5] = lists:nthtail(byte_size(Y)-2,LY), - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line ok = random_bin_to_list(5000), ok. @@ -963,7 +969,7 @@ parts(Config) when is_list(Config) -> ?line badarg = ?MASK_ERROR(binary:part(Simple,{-1,0})), ?line badarg = ?MASK_ERROR(binary:part(Simple,{7,2})), ?line <<8>> = binary:part(Simple,{7,1}), - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line random_parts(5000), ok. @@ -987,15 +993,15 @@ random_parts(N) -> random_parts(0,_) -> []; random_parts(X,N) -> - Pos = random:uniform(N), - Len = random:uniform((Pos * 12) div 10), + Pos = rand:uniform(N), + Len = rand:uniform((Pos * 12) div 10), [{Pos,Len} | random_parts(X-1,N)]. random_ref_comp(doc) -> ["Test pseudorandomly generated cases against reference imlementation"]; random_ref_comp(Config) when is_list(Config) -> put(success_counter,0), - random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), Nr = {1,40}, Hr = {30,1000}, I1 = 1500, @@ -1025,7 +1031,7 @@ random_ref_sr_comp(doc) -> ["Test pseudorandomly generated cases against reference imlementation of split and replace"]; random_ref_sr_comp(Config) when is_list(Config) -> put(success_counter,0), - random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), Nr = {1,40}, Hr = {30,1000}, I1 = 1500, @@ -1043,7 +1049,7 @@ random_ref_fla_comp(doc) -> ["Test pseudorandomly generated cases against reference imlementation of split and replace"]; random_ref_fla_comp(Config) when is_list(Config) -> ?line put(success_counter,0), - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line do_random_first_comp(5000,{1,1000}), ?line do_random_last_comp(5000,{1,1000}), ?line do_random_at_comp(5000,{1,1000}), @@ -1377,24 +1383,24 @@ one_random(N) -> random_number({Min,Max}) -> % Min and Max are *length* of number in % decimal positions - X = random:uniform(Max - Min + 1) + Min - 1, - list_to_integer([one_random_number(random:uniform(10)) || _ <- lists:seq(1,X)]). + X = rand:uniform(Max - Min + 1) + Min - 1, + list_to_integer([one_random_number(rand:uniform(10)) || _ <- lists:seq(1,X)]). random_length({Min,Max}) -> - random:uniform(Max - Min + 1) + Min - 1. + rand:uniform(Max - Min + 1) + Min - 1. random_string({Min,Max}) -> - X = random:uniform(Max - Min + 1) + Min - 1, - list_to_binary([one_random(random:uniform(68)) || _ <- lists:seq(1,X)]). + X = rand:uniform(Max - Min + 1) + Min - 1, + list_to_binary([one_random(rand:uniform(68)) || _ <- lists:seq(1,X)]). random_substring({Min,Max},Hay) -> - X = random:uniform(Max - Min + 1) + Min - 1, + X = rand:uniform(Max - Min + 1) + Min - 1, Y = byte_size(Hay), Z = if X > Y -> Y; true -> X end, PMax = Y - Z, - Pos = random:uniform(PMax + 1) - 1, + Pos = rand:uniform(PMax + 1) - 1, <<_:Pos/binary,Res:Z/binary,_/binary>> = Hay, Res. diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 7f5e06524a..e061e16e4c 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -53,7 +53,7 @@ simultaneous_open/1, insert_new/1, repair_continuation/1, otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1, otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1, - otp_8923/1, otp_9282/1, otp_11245/1, otp_11709/1]). + otp_8923/1, otp_9282/1, otp_11245/1, otp_11709/1, otp_13229/1]). -export([dets_dirty_loop/0]). @@ -110,7 +110,8 @@ all() -> many_clients, otp_4906, otp_5402, simultaneous_open, insert_new, repair_continuation, otp_5487, otp_6206, otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898, - otp_8899, otp_8903, otp_8923, otp_9282, otp_11245, otp_11709 + otp_8899, otp_8903, otp_8923, otp_9282, otp_11245, otp_11709, + otp_13229 ]. groups() -> @@ -3988,6 +3989,18 @@ otp_11709(Config) when is_list(Config) -> _ = file:delete(File), ok. +otp_13229(doc) -> + ["OTP-13229. open_file() exits with badarg when given binary file name."]; +otp_13229(_Config) -> + F = <<"binfile.tab">>, + try dets:open_file(name, [{file, F}]) of + R -> + exit({open_succeeded, R}) + catch + error:badarg -> + ok + end. + %% %% Parts common to several test cases %% diff --git a/lib/stdlib/test/dict_SUITE.erl b/lib/stdlib/test/dict_SUITE.erl index 648154ebbe..aff73b176d 100644 --- a/lib/stdlib/test/dict_SUITE.erl +++ b/lib/stdlib/test/dict_SUITE.erl @@ -108,7 +108,7 @@ iterate_1(M) -> M(empty, []). iterate_2(M) -> - random:seed(1, 2, 42), + rand:seed(exsplus, {1,2,42}), iter_tree(M, 1000). iter_tree(_M, 0) -> @@ -117,7 +117,7 @@ iter_tree(M, N) -> L = [{I, I} || I <- lists:seq(1, N)], T = M(from_list, L), L = lists:reverse(iterate_tree(M, T)), - R = random:uniform(N), + R = rand:uniform(N), KV = lists:reverse(iterate_tree_from(M, R, T)), KV = [P || P={K,_} <- L, K >= R], iter_tree(M, N-1). @@ -156,7 +156,7 @@ test_all(Tester) -> spawn_tester(M, Tester) -> Parent = self(), spawn_link(fun() -> - random:seed(1, 2, 42), + rand:seed(exsplus, {1,2,42}), S = Tester(M), Res = {M(size, S),lists:sort(M(to_list, S))}, Parent ! {result,self(),Res} @@ -194,12 +194,12 @@ rnd_list_1(0, Acc) -> Acc; rnd_list_1(N, Acc) -> Key = atomic_rnd_term(), - Value = random:uniform(100), + Value = rand:uniform(100), rnd_list_1(N-1, [{Key,Value}|Acc]). atomic_rnd_term() -> - case random:uniform(3) of - 1 -> list_to_atom(integer_to_list($\s+random:uniform(94))++"rnd"); - 2 -> random:uniform(); - 3 -> random:uniform(50)-37 + case rand:uniform(3) of + 1 -> list_to_atom(integer_to_list($\s+rand:uniform(94))++"rnd"); + 2 -> rand:uniform(); + 3 -> rand:uniform(50)-37 end. diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index 4e5df661b3..4c007e76ad 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -27,7 +27,7 @@ pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1, otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8503/1, otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1, - otp_11728/1, encoding/1]). + otp_11728/1, encoding/1, extends/1]). -export([epp_parse_erl_form/2]). @@ -70,7 +70,7 @@ all() -> not_circular, skip_header, otp_6277, otp_7702, otp_8130, overload_mac, otp_8388, otp_8470, otp_8503, otp_8562, otp_8665, otp_8911, otp_10302, otp_10820, otp_11728, - encoding]. + encoding, extends]. groups() -> [{upcase_mac, [], [upcase_mac_1, upcase_mac_2]}, @@ -621,6 +621,10 @@ otp_8130(Config) when is_list(Config) -> " 2 end,\n" " 7),\n" " {2,7} =\n" + " ?M1(begin 1 = fun _Name () -> 1 end(),\n" + " 2 end,\n" + " 7),\n" + " {2,7} =\n" " ?M1(begin 1 = fun t0/0(),\n" " 2 end,\n" " 7),\n" @@ -645,6 +649,9 @@ otp_8130(Config) when is_list(Config) -> " ?M1(begin yes = try 1 of 1 -> yes after foo end,\n" " 2 end,\n" " 7),\n" + " {[42],7} =\n" + " ?M1([42],\n" + " 7),\n" "ok.\n">>, ok}, @@ -728,11 +735,16 @@ otp_8130(Config) when is_list(Config) -> {errors,[{{2,2},epp,{include,lib,"$apa/foo.hrl"}}],[]}}, - {otp_8130_c9, + {otp_8130_c9a, <<"-define(S, ?S).\n" "t() -> ?S.\n">>, {errors,[{{2,9},epp,{circular,'S', none}}],[]}}, + {otp_8130_c9b, + <<"-define(S(), ?S()).\n" + "t() -> ?S().\n">>, + {errors,[{{2,9},epp,{circular,'S', 0}}],[]}}, + {otp_8130_c10, <<"\n-file.">>, {errors,[{{2,2},epp,{bad,file}}],[]}}, @@ -799,6 +811,10 @@ otp_8130(Config) when is_list(Config) -> <<"\n-include(\"no such file.erl\").\n">>, {errors,[{{2,2},epp,{include,file,"no such file.erl"}}],[]}}, + {otp_8130_c25, + <<"\n-define(A.\n">>, + {errors,[{{2,2},epp,{bad,define}}],[]}}, + {otp_8130_7, <<"-record(b, {b}).\n" "-define(A, {{a,#b.b.\n" @@ -826,14 +842,14 @@ otp_8130(Config) when is_list(Config) -> "-define(a, 3.14).\n" "t() -> ?a.\n"), ?line {ok,Epp} = epp:open(File, []), - ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE', - 'MACHINE','MODULE','MODULE_STRING'] = macs(Epp), + PreDefMacs = macs(Epp), + ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE', + 'MACHINE','MODULE','MODULE_STRING'] = PreDefMacs, ?line {ok,[{'-',_},{atom,_,file}|_]} = epp:scan_erl_form(Epp), ?line {ok,[{'-',_},{atom,_,module}|_]} = epp:scan_erl_form(Epp), ?line {ok,[{atom,_,t}|_]} = epp:scan_erl_form(Epp), ?line {eof,_} = epp:scan_erl_form(Epp), - ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE', - 'MACHINE','MODULE','MODULE_STRING',a] = macs(Epp), + [a] = macs(Epp) -- PreDefMacs, ?line epp:close(Epp), %% escript @@ -1476,6 +1492,20 @@ encoding(Config) when is_list(Config) -> epp_parse_file(ErlFile, [{default_encoding,utf8},extra]), ok. +extends(Config) -> + Cs = [{extends_c1, + <<"-extends(some.other.module).\n">>, + {errors,[{1,erl_parse,["syntax error before: ","'.'"]}],[]}}], + [] = compile(Config, Cs), + + Ts = [{extends_1, + <<"-extends(some_other_module).\n" + "t() -> {?BASE_MODULE,?BASE_MODULE_STRING}.\n">>, + {some_other_module,"some_other_module"}}], + + [] = run(Config, Ts), + ok. + check(Config, Tests) -> eval_tests(Config, fun check_test/2, Tests). @@ -1504,15 +1534,17 @@ eval_tests(Config, Fun, Tests) -> check_test(Config, Test) -> Filename = "epp_test.erl", - ?line PrivDir = ?config(priv_dir, Config), - ?line File = filename:join(PrivDir, Filename), - ?line ok = file:write_file(File, Test), - ?line case epp:parse_file(File, [PrivDir], []) of - {ok,Forms} -> - [E || E={error,_} <- Forms]; - {error,Error} -> - Error - end. + PrivDir = ?config(priv_dir, Config), + File = filename:join(PrivDir, Filename), + ok = file:write_file(File, Test), + case epp:parse_file(File, [PrivDir], []) of + {ok,Forms} -> + Errors = [E || E={error,_} <- Forms], + call_format_error([E || {error,E} <- Errors]), + Errors; + {error,Error} -> + Error + end. compile_test(Config, Test0) -> Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0], @@ -1528,8 +1560,11 @@ compile_test(Config, Test0) -> warnings(File, Ws) -> case lists:append([W || {F, W} <- Ws, F =:= File]) of - [] -> []; - L -> {warnings, L} + [] -> + []; + L -> + call_format_error(L), + {warnings, L} end. compile_file(File, Opts) -> @@ -1540,12 +1575,20 @@ compile_file(File, Opts) -> end. errs([{File,Es}|L], File) -> + call_format_error(Es), Es ++ errs(L, File); errs([_|L], File) -> errs(L, File); errs([], _File) -> []. +%% Smoke test and coverage of format_error/1. +call_format_error([{_,M,E}|T]) -> + _ = M:format_error(E), + call_format_error(T); +call_format_error([]) -> + ok. + epp_parse_file(File, Opts) -> case epp:parse_file(File, Opts) of {ok, Forms} -> diff --git a/lib/stdlib/test/erl_anno_SUITE.erl b/lib/stdlib/test/erl_anno_SUITE.erl index 66b02151a0..0369455846 100644 --- a/lib/stdlib/test/erl_anno_SUITE.erl +++ b/lib/stdlib/test/erl_anno_SUITE.erl @@ -34,7 +34,7 @@ init_per_testcase/2, end_per_testcase/2]). -export([new/1, is_anno/1, generated/1, end_location/1, file/1, - line/1, location/1, record/1, text/1, bad/1, neg_line/1]). + line/1, location/1, record/1, text/1, bad/1]). -export([parse_abstract/1, mapfold_anno/1]). @@ -43,7 +43,7 @@ all() -> groups() -> [{anno, [], [new, is_anno, generated, end_location, file, - line, location, record, text, bad, neg_line]}, + line, location, record, text, bad]}, {parse, [], [parse_abstract, mapfold_anno]}]. suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -229,74 +229,6 @@ bad(_Config) -> (catch erl_anno:record(bad)), % 1st arg not opaque ok. -neg_line(doc) -> - ["Test negative line numbers (OTP 18)"]; -neg_line(_Config) -> - neg_line1(false), - neg_line1(true), - ok. - -neg_line1(TextToo) -> - Minus8_0 = erl_anno:new(-8), - Plus8_0 = erl_anno:new(8), - Minus8C_0 = erl_anno:new({-8, 17}), - Plus8C_0 = erl_anno:new({8, 17}), - - [Minus8, Plus8, Minus8C, Plus8C] = - [case TextToo of - true -> - erl_anno:set_text("foo", A); - false -> - A - end || A <- [Minus8_0, Plus8_0, Minus8C_0, Plus8C_0]], - - tst(-3, erl_anno:set_location(3, Minus8)), - tst(-3, erl_anno:set_location(-3, Plus8)), - tst(-3, erl_anno:set_location(-3, Minus8)), - tst({-3,9}, erl_anno:set_location({3, 9}, Minus8)), - tst({-3,9}, erl_anno:set_location({-3, 9}, Plus8)), - tst({-3,9}, erl_anno:set_location({-3, 9}, Minus8)), - tst(-3, erl_anno:set_location(3, Minus8C)), - tst(-3, erl_anno:set_location(-3, Plus8C)), - tst(-3, erl_anno:set_location(-3, Minus8C)), - tst({-3,9}, erl_anno:set_location({3, 9}, Minus8C)), - tst({-3,9}, erl_anno:set_location({-3, 9}, Plus8C)), - tst({-3,9}, erl_anno:set_location({-3, 9}, Minus8C)), - - tst(-8, erl_anno:set_generated(true, Plus8)), - tst(-8, erl_anno:set_generated(true, Minus8)), - tst({-8,17}, erl_anno:set_generated(true, Plus8C)), - tst({-8,17}, erl_anno:set_generated(true, Minus8C)), - tst(8, erl_anno:set_generated(false, Plus8)), - tst(8, erl_anno:set_generated(false, Minus8)), - tst({8,17}, erl_anno:set_generated(false, Plus8C)), - tst({8,17}, erl_anno:set_generated(false, Minus8C)), - - tst(-3, erl_anno:set_line(3, Minus8)), - tst(-3, erl_anno:set_line(-3, Plus8)), - tst(-3, erl_anno:set_line(-3, Minus8)), - tst({-3,17}, erl_anno:set_line(3, Minus8C)), - tst({-3,17}, erl_anno:set_line(-3, Plus8C)), - tst({-3,17}, erl_anno:set_line(-3, Minus8C)), - ok. - -tst(Term, Anno) -> - ?format("Term: ~p\n", [Term]), - ?format("Anno: ~p\n", [Anno]), - case anno_to_term(Anno) of - Term -> - ok; - Else -> - case lists:keyfind(location, 1, Else) of - {location, Term} -> - ok; - _Else2 -> - ?format("Else2 ~p\n", [_Else2]), - io:format("expected ~p\n got ~p\n", [Term, Else]), - exit({Term, Else}) - end - end. - parse_abstract(doc) -> ["Test erl_parse:new_anno/1, erl_parse:anno_to_term/1" ", and erl_parse:anno_from_term/1"]; diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index b9c4ad0a46..c21c4e61ee 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2013. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -39,6 +39,7 @@ otp_7550/1, otp_8133/1, otp_10622/1, + otp_13228/1, funs/1, try_catch/1, eval_expr_5/1, @@ -83,7 +84,8 @@ all() -> pattern_expr, match_bin, guard_3, guard_4, guard_5, lc, simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543, otp_6787, otp_6977, otp_7550, - otp_8133, otp_10622, funs, try_catch, eval_expr_5, zero_width, + otp_8133, otp_10622, otp_13228, + funs, try_catch, eval_expr_5, zero_width, eep37, eep43]. groups() -> @@ -1042,6 +1044,13 @@ otp_10622(Config) when is_list(Config) -> ok. +otp_13228(doc) -> + ["OTP-13228. ERL-32: non-local function handler bug."]; +otp_13228(_Config) -> + LFH = {value, fun(foo, [io_fwrite]) -> worked end}, + EFH = {value, fun({io, fwrite}, [atom]) -> io_fwrite end}, + {value, worked, []} = parse_and_run("foo(io:fwrite(atom)).", LFH, EFH). + funs(doc) -> ["Simple cases, just to cover some code."]; funs(suite) -> @@ -1483,6 +1492,16 @@ eep43(Config) when is_list(Config) -> " #{ K1 := 1, K2 := 2, K3 := 3, {2,2} := 4} = Map " "end.", #{ 1 => 1, <<42:301>> => 2, {3,<<42:301>>} => 3, {2,2} => 4}), + check(fun () -> + X = key, + (fun(#{X := value}) -> true end)(#{X => value}) + end, + "begin " + " X = key, " + " (fun(#{X := value}) -> true end)(#{X => value}) " + "end.", + true), + error_check("[camembert]#{}.", {badmap,[camembert]}), error_check("[camembert]#{nonexisting:=v}.", {badmap,[camembert]}), error_check("#{} = 1.", {badmatch,1}), diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 0424e2b967..c5e2e5609d 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2015. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ too_many_arguments/1, basic_errors/1,bin_syntax_errors/1, predef/1, - maps/1,maps_type/1,otp_11851/1,otp_12195/1 + maps/1,maps_type/1,otp_11851/1,otp_11879/1,otp_13230/1 ]). % Default timetrap timeout (set in init_per_testcase). @@ -94,7 +94,7 @@ all() -> bif_clash, behaviour_basic, behaviour_multiple, otp_11861, otp_7550, otp_8051, format_warn, {group, on_load}, too_many_arguments, basic_errors, bin_syntax_errors, predef, - maps, maps_type, otp_11851, otp_12195]. + maps, maps_type, otp_11851, otp_11879, otp_13230]. groups() -> [{unused_vars_warn, [], @@ -1296,12 +1296,16 @@ unsized_binary_in_bin_gen_pattern(Config) when is_list(Config) -> Ts = [{unsized_binary_in_bin_gen_pattern, <<"t({bc,binary,Bin}) -> << <<X,Tail/binary>> || <<X,Tail/binary>> <= Bin >>; + t({bc,bytes,Bin}) -> + << <<X,Tail/binary>> || <<X,Tail/bytes>> <= Bin >>; t({bc,bits,Bin}) -> << <<X,Tail/bits>> || <<X,Tail/bits>> <= Bin >>; t({bc,bitstring,Bin}) -> << <<X,Tail/bits>> || <<X,Tail/bitstring>> <= Bin >>; t({lc,binary,Bin}) -> [ {X,Tail} || <<X,Tail/binary>> <= Bin ]; + t({lc,bytes,Bin}) -> + [ {X,Tail} || <<X,Tail/bytes>> <= Bin ]; t({lc,bits,Bin}) -> [ {X,Tail} || <<X,Tail/bits>> <= Bin ]; t({lc,bitstring,Bin}) -> @@ -1313,7 +1317,9 @@ unsized_binary_in_bin_gen_pattern(Config) when is_list(Config) -> {6,erl_lint,unsized_binary_in_bin_gen_pattern}, {8,erl_lint,unsized_binary_in_bin_gen_pattern}, {10,erl_lint,unsized_binary_in_bin_gen_pattern}, - {12,erl_lint,unsized_binary_in_bin_gen_pattern}], + {12,erl_lint,unsized_binary_in_bin_gen_pattern}, + {14,erl_lint,unsized_binary_in_bin_gen_pattern}, + {16,erl_lint,unsized_binary_in_bin_gen_pattern}], []}}], [] = run(Config, Ts), ok. @@ -3604,7 +3610,10 @@ bin_syntax_errors(Config) -> t(<<X/unit:8>>) -> X; t(<<X:7/float>>) -> X; t(<< <<_:8>> >>) -> ok; - t(<<(x ! y):8/integer>>) -> ok. + t(<<(x ! y):8/integer>>) -> ok; + t(X) -> + {<<X/binary-integer>>,<<X/signed-unsigned-integer>>, + <<X/little-big>>,<<X/unit:4-unit:8>>}. ">>, [], {error,[{1,erl_lint,illegal_bitsize}, @@ -3613,7 +3622,12 @@ bin_syntax_errors(Config) -> {4,erl_lint,{undefined_bittype,bad_type}}, {5,erl_lint,bittype_unit}, {7,erl_lint,illegal_pattern}, - {8,erl_lint,illegal_pattern}], + {8,erl_lint,illegal_pattern}, + {10,erl_lint,{bittype_mismatch,integer,binary,"type"}}, + {10,erl_lint,{bittype_mismatch,unsigned,signed,"sign"}}, + {11,erl_lint,{bittype_mismatch,8,4,"unit"}}, + {11,erl_lint,{bittype_mismatch,big,little,"endianness"}} + ], [{6,erl_lint,{bad_bitsize,"float"}}]}} ], [] = run(Config, Ts), @@ -3835,38 +3849,36 @@ otp_11851(Config) when is_list(Config) -> [] = run(Config, Ts), ok. -otp_12195(doc) -> - "OTP-12195: Check obsolete types (tailor made for OTP 18)."; -otp_12195(Config) when is_list(Config) -> - Ts = [{otp_12195_1, - <<"-export_type([r1/0]). - -type r1() :: erl_scan:line() - | erl_scan:column() - | erl_scan:location() - | erl_anno:line().">>, - [], - {warnings,[{2,erl_lint, - {deprecated_type,{erl_scan,line,0}, - "deprecated (will be removed in OTP 19); " - "use erl_anno:line() instead"}}, - {3,erl_lint, - {deprecated_type,{erl_scan,column,0}, - "deprecated (will be removed in OTP 19); use " - "erl_anno:column() instead"}}, - {4,erl_lint, - {deprecated_type,{erl_scan,location,0}, - "deprecated (will be removed in OTP 19); " - "use erl_anno:location() instead"}}]}}, - {otp_12195_2, - <<"-export_type([r1/0]). - -compile(nowarn_deprecated_type). - -type r1() :: erl_scan:line() - | erl_scan:column() - | erl_scan:location() - | erl_anno:line().">>, - [], - []}], - [] = run(Config, Ts), +otp_11879(doc) -> + "OTP-11879: The -spec f/a :: (As) -> B; syntax removed, " + "and is_subtype/2 deprecated"; +otp_11879(_Config) -> + Fs = [{attribute,0,file,{"file.erl",0}}, + {attribute,0,module,m}, + {attribute,1,spec, + {{f,1}, + [{type,2,'fun',[{type,3,product,[{var,4,'V1'}, + {var,5,'V1'}]}, + {type,6,integer,[]}]}]}}, + {attribute,20,callback, + {{cb,21}, + [{type,22,'fun',[{type,23,product,[{var,24,'V1'}, + {var,25,'V1'}]}, + {type,6,integer,[]}]}]}}], + {error,[{"file.erl", + [{1,erl_lint,{spec_fun_undefined,{f,1}}}, + {2,erl_lint,spec_wrong_arity}, + {22,erl_lint,callback_wrong_arity}]}], + []} = compile:forms(Fs, [return,report]), + ok. + +otp_13230(doc) -> + "OTP-13230: -deprecated without -module"; +otp_13230(Config) when is_list(Config) -> + Abstr = <<"-deprecated([{frutt,0,next_version}]).">>, + {errors,[{1,erl_lint,undefined_module}, + {1,erl_lint,{bad_deprecated,{frutt,0}}}], + []} = run_test2(Config, Abstr, []), ok. run(Config, Tests) -> @@ -3920,22 +3932,35 @@ run_test2(Conf, Test, Warnings0) -> %% is no reason to produce an output file since we are only %% interested in the errors and warnings. - %% Print warnings, call erl_lint:format_error/1. + %% Print warnings, call erl_lint:format_error/1. (But note that + %% the compiler will ignore failing calls to erl_lint:format_error/1.) compile:file(File, [binary,report|Opts]), case compile:file(File, [binary|Opts]) of - {ok, _M, Code, Ws} when is_binary(Code) -> warnings(File, Ws); - {error, [{File,Es}], []} -> {errors, Es, []}; - {error, [{File,Es}], [{File,Ws}]} -> {error, Es, Ws}; - {error, [{File,Es1},{File,Es2}], []} -> {errors2, Es1, Es2} + {ok, _M, Code, Ws} when is_binary(Code) -> + warnings(File, Ws); + {error, [{File,Es}], []} -> + {errors, call_format_error(Es), []}; + {error, [{File,Es}], [{File,Ws}]} -> + {error, call_format_error(Es), call_format_error(Ws)}; + {error, [{File,Es1},{File,Es2}], []} -> + {errors2, Es1, Es2} end. warnings(File, Ws) -> case lists:append([W || {F, W} <- Ws, F =:= File]) of - [] -> []; - L -> {warnings, L} + [] -> + []; + L -> + {warnings, call_format_error(L)} end. +call_format_error(L) -> + %% Smoke test of format_error/1 to make sure that no crashes + %% slip through. + _ = [Mod:format_error(Term) || {_,Mod,Term} <- L], + L. + fail() -> io:format("failed~n"), ?t:fail(). diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index 389fd059f6..8a128b3815 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -876,6 +876,9 @@ type_examples() -> {ex30,<<"-type t99() ::" "{t2(),'\\'t::4'(),t5(),t6(),t7(),t8(),t10(),t14()," "t15(),t20(),t21(), t22(),t25()}. ">>}, + %% Writing constraints as is_subtype(V, T) is not supported since + %% Erlang/OTP 19.0, but as long as the parser recognizes the + %% is_subtype(V, T) syntax, we need a few examples of the syntax. {ex31,<<"-spec t1(FooBar :: t99()) -> t99();" "(t2()) -> t2();" "('\\'t::4'()) -> '\\'t::4'() when is_subtype('\\'t::4'(), t24);" @@ -928,7 +931,9 @@ otp_8522(Config) when is_list(Config) -> ?line {ok, _} = compile:file(FileName, [{outdir,?privdir},debug_info]), BF = filename("otp_8522", Config), ?line {ok, A} = beam_lib:chunks(BF, [abstract_code]), - ?line 5 = count_atom(A, undefined), + %% OTP-12719: Since 'undefined' is no longer added by the Erlang + %% Parser, the number of 'undefined' is 4. It used to be 5. + ?line 4 = count_atom(A, undefined), ok. count_atom(A, A) -> @@ -960,6 +965,9 @@ maps_syntax(Config) when is_list(Config) -> "-compile(export_all).\n" "-type t1() :: map().\n" "-type t2() :: #{ atom() => integer(), atom() => float() }.\n" + "-type u() :: #{a => (I :: integer()) | (A :: atom()),\n" + " (X :: atom()) | (Y :: atom()) =>\n" + " (I :: integer()) | (A :: atom())}.\n" "-spec f1(t1()) -> 'true'.\n" "f1(M) when is_map(M) -> true.\n" "-spec f2(t2()) -> integer().\n" @@ -995,18 +1003,10 @@ otp_8567(Config) when is_list(Config) -> "t() ->\n" " 3.\n" "\n" - "-spec(t1/1 :: (ot()) -> ot1()).\n" - "t1(A) ->\n" - " A.\n" - "\n" "-spec(t2 (ot()) -> ot1()).\n" "t2(A) ->\n" " A.\n" "\n" - "-spec(otp_8567:t3/1 :: (ot()) -> ot1()).\n" - "t3(A) ->\n" - " A.\n" - "\n" "-spec(otp_8567:t4 (ot()) -> ot1()).\n" "t4(A) ->\n" " A.\n">>, @@ -1062,7 +1062,7 @@ otp_9147(Config) when is_list(Config) -> ?line {ok, Bin} = file:read_file(PFileName), %% The parentheses around "F1 :: a | b" are new (bugfix). ?line true = - lists:member("-record(undef,{f1 :: undefined | (F1 :: a | b)}).", + lists:member("-record(undef,{f1 :: F1 :: a | b}).", string:tokens(binary_to_list(Bin), "\n")), ok. diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl index 12ea3d128c..db669aae99 100644 --- a/lib/stdlib/test/erl_scan_SUITE.erl +++ b/lib/stdlib/test/erl_scan_SUITE.erl @@ -191,8 +191,7 @@ otp_7810(Config) when is_list(Config) -> ?line ok = more_chars(), ?line ok = more_options(), - ?line ok = attributes_info(), - ?line ok = set_attribute(), + ?line ok = anno_info(), ok. @@ -269,7 +268,7 @@ punctuations() -> comments() -> ?line test("a %%\n b"), - {ok,[],1} = erl_scan_string("%"), + ?line {ok,[],1} = erl_scan_string("%"), ?line test("a %%\n b"), {ok,[{atom,{1,1},a},{atom,{2,2},b}],{2,3}} = erl_scan_string("a %%\n b", {1,1}), @@ -338,7 +337,7 @@ base_integers() -> erl_scan:string(Str) end || {BS,S} <- [{"3","3"},{"15","f"}, {"12","c"}] ], - {ok,[{integer,1,239},{'@',1}],1} = erl_scan_string("16#ef@"), + ?line {ok,[{integer,1,239},{'@',1}],1} = erl_scan_string("16#ef@"), {ok,[{integer,{1,1},239},{'@',{1,6}}],{1,7}} = erl_scan_string("16#ef@", {1,1}, []), {ok,[{integer,{1,1},14},{atom,{1,5},g@}],{1,7}} = @@ -387,20 +386,15 @@ dots() -> R2 = erl_scan_string(S, {1,1}, []) end || {S, R, R2} <- Dot], - ?line {ok,[{dot,_}=T1],{1,2}} = erl_scan:string(".", {1,1}, text), - ?line [{column,1},{length,1},{line,1},{text,"."}] = - erl_scan:token_info(T1, [column, length, line, text]), - ?line {ok,[{dot,_}=T2],{1,3}} = erl_scan:string(".%", {1,1}, text), - ?line [{column,1},{length,1},{line,1},{text,"."}] = - erl_scan:token_info(T2, [column, length, line, text]), - ?line {ok,[{dot,_}=T3],{1,6}} = + {ok,[{dot,_}=T1],{1,2}} = erl_scan:string(".", {1,1}, text), + [1, 1, "."] = token_info(T1), + {ok,[{dot,_}=T2],{1,3}} = erl_scan:string(".%", {1,1}, text), + [1, 1, "."] = token_info(T2), + {ok,[{dot,_}=T3],{1,6}} = erl_scan:string(".% öh", {1,1}, text), - ?line [{column,1},{length,1},{line,1},{text,"."}] = - erl_scan:token_info(T3, [column, length, line, text]), - ?line {error,{{1,2},erl_scan,char},{1,3}} = - erl_scan:string(".$", {1,1}), - ?line {error,{{1,2},erl_scan,char},{1,4}} = - erl_scan:string(".$\\", {1,1}), + [1, 1, "."] = token_info(T3), + {error,{{1,2},erl_scan,char},{1,3}} = erl_scan:string(".$", {1,1}), + {error,{{1,2},erl_scan,char},{1,4}} = erl_scan:string(".$\\", {1,1}), test_string(". ", [{dot,{1,1}}]), test_string(". ", [{dot,{1,1}}]), @@ -413,18 +407,18 @@ dots() -> test_string(".a", [{'.',{1,1}},{atom,{1,2},a}]), test_string("%. \n. ", [{dot,{2,1}}]), - ?line {more,C} = erl_scan:tokens([], "%. ",{1,1}, return), + {more,C} = erl_scan:tokens([], "%. ",{1,1}, return), {done,{ok,[{comment,{1,1},"%. "}, {white_space,{1,4},"\n"}, {dot,{2,1}}], {2,3}}, ""} = erl_scan_tokens(C, "\n. ", {1,1}, return), % any loc, any options - ?line [test_string(S, R) || - {S, R} <- [{".$\n", [{'.',{1,1}},{char,{1,2},$\n}]}, - {"$\\\n", [{char,{1,1},$\n}]}, - {"'\\\n'", [{atom,{1,1},'\n'}]}, - {"$\n", [{char,{1,1},$\n}]}] ], + [test_string(S, R) || + {S, R} <- [{".$\n", [{'.',{1,1}},{char,{1,2},$\n}]}, + {"$\\\n", [{char,{1,1},$\n}]}, + {"'\\\n'", [{atom,{1,1},'\n'}]}, + {"$\n", [{char,{1,1},$\n}]}] ], ok. chars() -> @@ -540,8 +534,8 @@ eof() -> %% A dot followed by eof is special: ?line {more, C} = erl_scan:tokens([], "a.", 1), - {done,{ok,[{atom,1,a},{dot,1}],1},eof} = erl_scan_tokens(C,eof,1), - {ok,[{atom,1,foo},{dot,1}],1} = erl_scan_string("foo."), + ?line {done,{ok,[{atom,1,a},{dot,1}],1},eof} = erl_scan_tokens(C,eof,1), + ?line {ok,[{atom,1,foo},{dot,1}],1} = erl_scan_string("foo."), %% With column. {more, CCol} = erl_scan:tokens([], "a.", {1,1}), @@ -655,145 +649,72 @@ options() -> ok. more_options() -> - ?line {ok,[{atom,A1,foo}],{19,20}} = + {ok,[{atom,_,foo}=T1],{19,20}} = erl_scan:string("foo", {19,17},[]), - ?line [{column,17},{line,19}] = erl_scan:attributes_info(A1), - ?line {done,{ok,[{atom,A2,foo},{dot,_}],{19,22}},[]} = + {19,17} = erl_scan:location(T1), + {done,{ok,[{atom,_,foo}=T2,{dot,_}],{19,22}},[]} = erl_scan:tokens([], "foo. ", {19,17}, [bad_opt]), % type error - ?line [{column,17},{line,19}] = erl_scan:attributes_info(A2), - ?line {ok,[{atom,A3,foo}],{19,20}} = + {19,17} = erl_scan:location(T2), + {ok,[{atom,_,foo}=T3],{19,20}} = erl_scan:string("foo", {19,17},[text]), - ?line [{column,17},{length,3},{line,19},{text,"foo"}] = - erl_scan:attributes_info(A3), + {19,17} = erl_scan:location(T3), + "foo" = erl_scan:text(T3), - ?line {ok,[{atom,A4,foo}],1} = erl_scan:string("foo", 1, [text]), - ?line [{length,3},{line,1},{text,"foo"}] = erl_scan:attributes_info(A4), + {ok,[{atom,_,foo}=T4],1} = erl_scan:string("foo", 1, [text]), + 1 = erl_scan:line(T4), + 1 = erl_scan:location(T4), + "foo" = erl_scan:text(T4), ok. token_info() -> - ?line {ok,[T1],_} = erl_scan:string("foo", {1,18}, [text]), + {ok,[T1],_} = erl_scan:string("foo", {1,18}, [text]), {'EXIT',{badarg,_}} = - (catch {foo, erl_scan:token_info(T1, foo)}), % type error - ?line {line,1} = erl_scan:token_info(T1, line), - ?line {column,18} = erl_scan:token_info(T1, column), - ?line {length,3} = erl_scan:token_info(T1, length), - ?line {text,"foo"} = erl_scan:token_info(T1, text), - ?line [{category,atom},{column,18},{length,3},{line,1}, - {symbol,foo},{text,"foo"}] = - erl_scan:token_info(T1), - ?line [{length,3},{column,18}] = - erl_scan:token_info(T1, [length, column]), - ?line [{location,{1,18}}] = - erl_scan:token_info(T1, [location]), - ?line {category,atom} = erl_scan:token_info(T1, category), - ?line [{symbol,foo}] = erl_scan:token_info(T1, [symbol]), - - ?line {ok,[T2],_} = erl_scan:string("foo", 1, []), - ?line {line,1} = erl_scan:token_info(T2, line), - ?line undefined = erl_scan:token_info(T2, column), - ?line undefined = erl_scan:token_info(T2, length), - ?line undefined = erl_scan:token_info(T2, text), - ?line {location,1} = erl_scan:token_info(T2, location), - ?line [{category,atom},{line,1},{symbol,foo}] = erl_scan:token_info(T2), - ?line [{line,1}] = erl_scan:token_info(T2, [length, line]), - - ?line {ok,[T3],_} = erl_scan:string("=", 1, []), - ?line [{line,1}] = erl_scan:token_info(T3, [column, line]), - ?line {category,'='} = erl_scan:token_info(T3, category), - ?line [{symbol,'='}] = erl_scan:token_info(T3, [symbol]), + (catch {foo, erl_scan:category(foo)}), % type error + {'EXIT',{badarg,_}} = + (catch {foo, erl_scan:symbol(foo)}), % type error + atom = erl_scan:category(T1), + foo = erl_scan:symbol(T1), + + {ok,[T2],_} = erl_scan:string("foo", 1, []), + 1 = erl_scan:line(T2), + undefined = erl_scan:column(T2), + undefined = erl_scan:text(T2), + 1 = erl_scan:location(T2), + + {ok,[T3],_} = erl_scan:string("=", 1, []), + '=' = erl_scan:category(T3), + '=' = erl_scan:symbol(T3), ok. -attributes_info() -> - ?line {'EXIT',_} = - (catch {foo,erl_scan:attributes_info(foo)}), % type error - [{line,18}] = erl_scan:attributes_info(erl_anno:new(18)), - {location,19} = - erl_scan:attributes_info(erl_anno:new(19), location), - ?line {ok,[{atom,A0,foo}],_} = erl_scan:string("foo", 19, [text]), - ?line {location,19} = erl_scan:attributes_info(A0, location), - - ?line {ok,[{atom,A3,foo}],_} = erl_scan:string("foo", {1,3}, [text]), - ?line {line,1} = erl_scan:attributes_info(A3, line), - ?line {column,3} = erl_scan:attributes_info(A3, column), - ?line {location,{1,3}} = erl_scan:attributes_info(A3, location), - ?line {text,"foo"} = erl_scan:attributes_info(A3, text), - - ?line {ok,[{atom,A4,foo}],_} = erl_scan:string("foo", 2, [text]), - ?line {line,2} = erl_scan:attributes_info(A4, line), - ?line undefined = erl_scan:attributes_info(A4, column), - ?line {location,2} = erl_scan:attributes_info(A4, location), - ?line {text,"foo"} = erl_scan:attributes_info(A4, text), - - ?line {ok,[{atom,A5,foo}],_} = erl_scan:string("foo", {1,3}, []), - ?line {line,1} = erl_scan:attributes_info(A5, line), - ?line {column,3} = erl_scan:attributes_info(A5, column), - ?line {location,{1,3}} = erl_scan:attributes_info(A5, location), - ?line undefined = erl_scan:attributes_info(A5, text), - - ?line undefined = erl_scan:attributes_info([], line), % type error +anno_info() -> + {'EXIT',_} = + (catch {foo,erl_scan:line(foo)}), % type error + {ok,[{atom,_,foo}=T0],_} = erl_scan:string("foo", 19, [text]), + 19 = erl_scan:location(T0), + 19 = erl_scan:end_location(T0), + + {ok,[{atom,_,foo}=T3],_} = erl_scan:string("foo", {1,3}, [text]), + 1 = erl_scan:line(T3), + 3 = erl_scan:column(T3), + {1,3} = erl_scan:location(T3), + {1,6} = erl_scan:end_location(T3), + "foo" = erl_scan:text(T3), + + {ok,[{atom,_,foo}=T4],_} = erl_scan:string("foo", 2, [text]), + 2 = erl_scan:line(T4), + undefined = erl_scan:column(T4), + 2 = erl_scan:location(T4), + "foo" = erl_scan:text(T4), + + {ok,[{atom,_,foo}=T5],_} = erl_scan:string("foo", {1,3}, []), + 1 = erl_scan:line(T5), + 3 = erl_scan:column(T5), + {1,3} = erl_scan:location(T5), + undefined = erl_scan:text(T5), ok. -set_attribute() -> - F = fun(Line) -> -Line end, - Anno2 = erl_anno:new(2), - A0 = erl_scan:set_attribute(line, Anno2, F), - {line, -2} = erl_scan:attributes_info(A0, line), - ?line {ok,[{atom,A1,foo}],_} = erl_scan:string("foo", {9,17}), - ?line A2 = erl_scan:set_attribute(line, A1, F), - ?line {line,-9} = erl_scan:attributes_info(A2, line), - ?line {location,{-9,17}} = erl_scan:attributes_info(A2, location), - ?line [{line,-9},{column,17}] = - erl_scan:attributes_info(A2, [line,column,text]), - - F2 = fun(Line) -> {17,Line} end, - ?line Attr1 = erl_scan:set_attribute(line, 2, F2), - ?line {line,{17,2}} = erl_scan:attributes_info(Attr1, line), - ?line undefined = erl_scan:attributes_info(Attr1, column), - ?line {location,{17,2}} = % a bit mixed up - erl_scan:attributes_info(Attr1, location), - - ?line A3 = erl_scan:set_attribute(line, A1, F2), - ?line {line,{17,9}} = erl_scan:attributes_info(A3, line), - ?line {location,{{17,9},17}} = erl_scan:attributes_info(A3, location), - ?line [{line,{17,9}},{column,17}] = - erl_scan:attributes_info(A3, [line,column,text]), - - ?line {ok,[{atom,A4,foo}],_} = erl_scan:string("foo", {9,17}, [text]), - ?line A5 = erl_scan:set_attribute(line, A4, F), - ?line {line,-9} = erl_scan:attributes_info(A5, line), - ?line {location,{-9,17}} = erl_scan:attributes_info(A5, location), - ?line [{line,-9},{column,17},{text,"foo"}] = - erl_scan:attributes_info(A5, [line,column,text]), - - ?line {ok,[{atom,A6,foo}],_} = erl_scan:string("foo", 11, [text]), - ?line A7 = erl_scan:set_attribute(line, A6, F2), - %% Incompatible with pre 18: - %% {line,{17,11}} = erl_scan:attributes_info(A7, line), - {line,17} = erl_scan:attributes_info(A7, line), - ?line {location,{17,11}} = % mixed up - erl_scan:attributes_info(A7, location), - %% Incompatible with pre 18: - %% [{line,{17,11}},{text,"foo"}] = - %% erl_scan:attributes_info(A7, [line,column,text]), - [{line,17},{column,11},{text,"foo"}] = - erl_scan:attributes_info(A7, [line,column,text]), - - ?line {'EXIT',_} = - (catch {foo, erl_scan:set_attribute(line, [], F2)}), % type error - ?line {'EXIT',{badarg,_}} = - (catch {foo, erl_scan:set_attribute(column, [], F2)}), % type error - - Attr10 = erl_anno:new(8), - Attr20 = erl_scan:set_attribute(line, Attr10, - fun(L) -> {nos,'X',L} end), - %% OTP-9412 - Attr30 = erl_scan:set_attribute(line, Attr20, - fun({nos,_V,VL}) -> VL end), - 8 = erl_anno:to_term(Attr30), - ok. - column_errors() -> ?line {error,{{1,1},erl_scan,{string,$',""}},{1,3}} = % $' erl_scan:string("'\\",{1,1}), @@ -892,14 +813,13 @@ unicode() -> erl_scan_string(Qs, 1), {ok,[Q2],{1,9}} = erl_scan:string("$\\x{aaa}", {1,1}, [text]), - [{category,char},{column,1},{length,8}, - {line,1},{symbol,16#aaa},{text,Qs}] = - erl_scan:token_info(Q2), + [{category,char},{column,1},{line,1},{symbol,16#aaa},{text,Qs}] = + token_info_long(Q2), U1 = "\"\\x{aaa}\"", - {ok,[{string,A1,[2730]}],{1,10}} = erl_scan:string(U1, {1,1}, [text]), - [{line,1},{column,1},{text,"\"\\x{aaa}\""}] = - erl_scan:attributes_info(A1, [line, column, text]), + {ok,[{string,_,[2730]}=T1],{1,10}} = erl_scan:string(U1, {1,1}, [text]), + {1,1} = erl_scan:location(T1), + "\"\\x{aaa}\"" = erl_scan:text(T1), {ok,[{string,1,[2730]}],1} = erl_scan_string(U1, 1), U2 = "\"\\x41\\x{fff}\\x42\"", @@ -1012,16 +932,13 @@ otp_10302(Config) when is_list(Config) -> Qs = "$\\x{aaa}", {ok,[{char,1,2730}],1} = erl_scan_string(Qs, 1), {ok,[Q2],{1,9}} = erl_scan:string(Qs,{1,1},[text]), - [{category,char},{column,1},{length,8}, - {line,1},{symbol,16#aaa},{text,Qs}] = - erl_scan:token_info(Q2), - - Tags = [category, column, length, line, symbol, text], + [{category,char},{column,1},{line,1},{symbol,16#aaa},{text,Qs}] = + token_info_long(Q2), U1 = "\"\\x{aaa}\"", {ok,[T1],{1,10}} = erl_scan:string(U1, {1,1}, [text]), - [{category,string},{column,1},{length,9},{line,1}, - {symbol,[16#aaa]},{text,U1}] = erl_scan:token_info(T1, Tags), + [{category,string},{column,1},{line,1},{symbol,[16#aaa]},{text,U1}] = + token_info_long(T1), U2 = "\"\\x41\\x{fff}\\x42\"", {ok,[{string,1,[65,4095,66]}],1} = erl_scan_string(U2, 1), @@ -1353,9 +1270,7 @@ test_wsc([], []) -> ok; test_wsc([Token|Tokens], [Token2|Tokens2]) -> [Text, Text2] = [Text || - {text, Text} <- - [erl_scan:token_info(T, text) || - T <- [Token, Token2]]], + Text <- [erl_scan:text(T) || T <- [Token, Token2]]], Sz = erts_debug:size(Text), Sz2 = erts_debug:size({Text, Text2}), IsCompacted = Sz2 < 2*Sz+erts_debug:size({a,a}), @@ -1394,7 +1309,7 @@ all_same(L, Char) -> newlines_first([]) -> ok; newlines_first([Token|Tokens]) -> - {text,Text} = erl_scan:token_info(Token, text), + Text = erl_scan:text(Token), Nnls = length([C || C <- Text, C =:= $\n]), OK = case Text of [$\n|_] -> @@ -1414,7 +1329,7 @@ select_tokens(Tokens, Tags) -> lists:filter(fun(T) -> lists:member(element(1, T), Tags) end, Tokens). simplify([Token|Tokens]) -> - {line,Line} = erl_scan:token_info(Token, line), + Line = erl_scan:line(Token), [setelement(2, Token, erl_anno:new(Line)) | simplify(Tokens)]; simplify([]) -> []. @@ -1423,17 +1338,31 @@ get_text(Tokens) -> lists:flatten( [T || Token <- Tokens, - ({text,T} = erl_scan:token_info(Token, text)) =/= []]). + (T = erl_scan:text(Token)) =/= []]). test_decorated_tokens(String, Tokens) -> ToksAttrs = token_attrs(Tokens), test_strings(ToksAttrs, String, 1, 1). token_attrs(Tokens) -> - [{L,C,Len,T} || + [{L,C,length(T),T} || Token <- Tokens, - ([{line,L},{column,C},{length,Len},{text,T}] = - erl_scan:token_info(Token, [line,column,length,text])) =/= []]. + ([C,L,T] = token_info(Token)) =/= []]. + +token_info(T) -> + Column = erl_scan:column(T), + Line = erl_scan:line(T), + Text = erl_scan:text(T), + [Column, Line, Text]. + +token_info_long(T) -> + Column = erl_scan:column(T), + Line = erl_scan:line(T), + Text = erl_scan:text(T), + Category = erl_scan:category(T), + Symbol = erl_scan:symbol(T), + [{category,Category},{column,Column},{line,Line}, + {symbol,Symbol},{text,Text}]. test_strings([], _S, Line, Column) -> {Line,Column}; @@ -1514,8 +1443,7 @@ consistent_attributes([Ts | TsL]) -> L = [T || T <- Ts, is_integer(element(2, T))], case L of [] -> - TagsL = [[Tag || {Tag,_} <- - erl_scan:attributes_info(element(2, T))] || + TagsL = [[Tag || {Tag,_} <- defined(token_info_long(T))] || T <- Ts], case lists:usort(TagsL) of [_] -> @@ -1531,6 +1459,9 @@ consistent_attributes([Ts | TsL]) -> Ts end. +defined(L) -> + [{T,V} || {T,V} <- L, V =/= undefined]. + family_list(L) -> sofs:to_external(family(L)). diff --git a/lib/stdlib/test/error_logger_h_SUITE.erl b/lib/stdlib/test/error_logger_h_SUITE.erl new file mode 100644 index 0000000000..c82b1b62ef --- /dev/null +++ b/lib/stdlib/test/error_logger_h_SUITE.erl @@ -0,0 +1,406 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(error_logger_h_SUITE). +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2]). +-export([logfile/1,logfile_truncated/1,tty/1,tty_truncated/1]). + +%% Event handler exports. +-export([init/1,handle_event/2,terminate/2]). + +-include_lib("test_server/include/test_server.hrl"). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [logfile,logfile_truncated,tty,tty_truncated]. + +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +logfile(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + Log = filename:join(LogDir, "logfile.log"), + ok = filelib:ensure_dir(Log), + + Ev = event_templates(), + + do_one_logfile(Log, Ev, unlimited), + + Pa = "-pa " ++ filename:dirname(code:which(?MODULE)), + {ok,Node} = start_node(logfile, Pa), + error_logger:logfile({open,Log}), + ok = rpc:call(Node, erlang, apply, [fun gen_events/1,[Ev]]), + AtNode = iolist_to_binary(["** at node ",atom_to_list(Node)," **"]), + error_logger:logfile(close), + analyse_events(Log, Ev, [AtNode], unlimited), + + [] = [{X, file:pid2name(X)} || X <- processes(), Data <- [process_info(X, [current_function])], + Data =/= undefined, + element(1, element(2, lists:keyfind(current_function, 1, Data))) + =:= file_io_server, + file:pid2name(X) =:= {ok, Log}], + + test_server:stop_node(Node), + + cleanup(Log), + ok. + +logfile_truncated(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + Log = filename:join(LogDir, "logfile_truncated.log"), + ok = filelib:ensure_dir(Log), + + Ev = event_templates(), + + Depth = 20, + application:set_env(kernel, error_logger_format_depth, Depth), + try + do_one_logfile(Log, Ev, Depth) + after + application:unset_env(kernel, error_logger_format_depth) + end, + + cleanup(Log), + ok. + +do_one_logfile(Log, Ev, Depth) -> + error_logger:logfile({open,Log}), + gen_events(Ev), + error_logger:logfile(close), + analyse_events(Log, Ev, [], Depth). + +tty(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + Log = filename:join(LogDir, "tty.log"), + ok = filelib:ensure_dir(Log), + + Ev = event_templates(), + + do_one_tty(Log, Ev, unlimited), + + Pa = "-pa " ++ filename:dirname(code:which(?MODULE)), + {ok,Node} = start_node(logfile, Pa), + tty_log_open(Log), + ok = rpc:call(Node, erlang, apply, [fun gen_events/1,[Ev]]), + tty_log_close(), + AtNode = iolist_to_binary(["** at node ",atom_to_list(Node)," **"]), + analyse_events(Log, Ev, [AtNode], unlimited), + + test_server:stop_node(Node), + + cleanup(Log), + ok. + +tty_truncated(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + Log = filename:join(LogDir, "tty_truncated.log"), + ok = filelib:ensure_dir(Log), + + Ev = event_templates(), + + Depth = 20, + application:set_env(kernel, error_logger_format_depth, Depth), + try + do_one_tty(Log, Ev, Depth) + after + application:unset_env(kernel, error_logger_format_depth) + end, + + cleanup(Log), + ok. + +do_one_tty(Log, Ev, Depth) -> + tty_log_open(Log), + gen_events(Ev), + tty_log_close(), + analyse_events(Log, Ev, [], Depth). + +tty_log_open(Log) -> + {ok,Fd} = file:open(Log, [write]), + Depth = case application:get_env(kernel, error_logger_format_depth) of + {ok,D} -> D; + _ -> unlimited + end, + error_logger:add_report_handler(?MODULE, {Fd,Depth}), + Fd. + +tty_log_close() -> + error_logger:delete_report_handler(?MODULE), + ok. + +event_templates() -> + [{error_msg,["Pure error string\n",[]]}, + {error_msg,["Pure error string with error ~p\n",[]]}, + {error_msg,["Error string with ~p\n", [format]]}, + {error_msg,["Error string with bad format ~p\n", []]}, + + {error_report,[error_atom]}, + {error_report,["error string"]}, + {error_report,[[{error_tag,value},error_value]]}, + + {info_msg,["Pure info string\n",[]]}, + {info_msg,["Pure info string with error ~p\n",[]]}, + {info_msg,["Pure string with ~p\n", [format]]}, + {info_msg,["Pure string with bad format ~p\n", []]}, + + {info_report,[info_atom]}, + {info_report,["info string"]}, + {info_report,[[{info_tag,value},info_value]]}, + + {warning_msg,["Pure warning string\n",[]]}, + {warning_msg,["Pure warning string with error ~p\n",[]]}, + {warning_msg,["Warning string with ~p\n", [format]]}, + {warning_msg,["Warning string with bad format ~p\n", []]}, + + {warning_report,[warning_atom]}, + {warning_report,["warning string"]}, + {warning_report,[[{warning_tag,value},warning_value]]}, + + %% Bigger terms. + {error_msg,["fairly big: ~p\n",[lists:seq(1, 128)]]}, + {error_report,[list_to_tuple(lists:seq(1, 100))]}, + {error_report,[lists:seq(32, 126)]}, + {error_report,[[{tag,lists:seq(1, 64)}]]} + ]. + +gen_events(Ev) -> + io:format("node = ~p\n", [node()]), + io:format("group leader = ~p\n", [group_leader()]), + io:format("~p\n", [gen_event:which_handlers(error_logger)]), + call_error_logger(Ev), + + {Pid,Ref} = spawn_monitor(fun() -> error(ouch) end), + receive + {'DOWN',Ref,process,Pid,_} -> + ok + end, + + %% The following calls with a custom type will be ignored. + error_logger:error_report(ignored, value), + error_logger:warning_report(ignored, value), + error_logger:info_report(ignored, value), + receive after 100 -> ok end, + ok. + +analyse_events(Log, Ev, AtNode, Depth) -> + {ok,Bin} = file:read_file(Log), + + io:format("*** Contents of log file ***\n\n~s\n", [Bin]), + + Lines = binary:split(Bin, <<"\n">>, [global,trim_all]), + io:format("~p\n", [Lines]), + + Rest = match_output(Ev, Lines, AtNode, Depth), + io:format("~p\n", [Rest]), + + [] = match_emulator_error(Rest), + ok. + + +call_error_logger([{F,Args}|T]) -> + apply(error_logger, F, Args), + call_error_logger(T); +call_error_logger([]) -> ok. + + +match_emulator_error([Head,Second,Third,_|Lines]) -> + match_head(<<"ERROR">>, Head), + {match,[{0,_}]} = re:run(Second, + "^Error in process <\\d+[.]\\d+[.]\\d+> on " + "node [^ ]* with exit value:"), + {match,[{0,_}]} = re:run(Third, "^[{]ouch,"), + Lines. + +match_output([Item|T], Lines0, AtNode, Depth) -> + try match_item(Item, Lines0, AtNode, Depth) of + Lines -> + match_output(T, Lines, AtNode, Depth) + catch + C:E -> + Stk = erlang:get_stacktrace(), + io:format("ITEM: ~p", [Item]), + io:format("LINES: ~p", [Lines0]), + erlang:raise(C, E, Stk) + end; +match_output([], Lines, _, _) -> Lines. + +match_item(Item, Lines, AtNode, Depth) -> + case item_type(Item) of + {msg,Head,Args} -> + match_format(Head, Args, Lines, AtNode, Depth); + {report,Head,Args} -> + match_term(Head, Args, Lines, AtNode, Depth) + end. + +item_type({error_msg,Args}) -> + {msg,<<"ERROR">>,Args}; +item_type({info_msg,Args}) -> + {msg,<<"INFO">>,Args}; +item_type({warning_msg,Args}) -> + {msg,<<"WARNING">>,Args}; +item_type({error_report,Args}) -> + {report,<<"ERROR">>,Args}; +item_type({info_report,Args}) -> + {report,<<"INFO">>,Args}; +item_type({warning_report,Args}) -> + {report,<<"WARNING">>,Args}. + +match_format(Tag, [Format,Args], [Head|Lines], AtNode, Depth) -> + match_head(Tag, Head), + Bin = try dl_format(Depth, Format, Args) of + Str -> + iolist_to_binary(Str) + catch + _:_ -> + S = dl_format(Depth, "ERROR: ~p - ~p~n", [Format,Args]), + iolist_to_binary(S) + end, + Expected0 = binary:split(Bin, <<"\n">>, [global,trim]), + Expected = Expected0 ++ AtNode, + match_term_lines(Expected, Lines). + +match_term(Tag, [Arg], [Head|Lines], AtNode, Depth) -> + match_head(Tag, Head), + Expected0 = match_term_get_expected(Arg, Depth), + Expected = Expected0 ++ AtNode, + match_term_lines(Expected, Lines). + +match_term_get_expected(List, Depth) when is_list(List) -> + Bin = try iolist_to_binary(dl_format(Depth, "~s\n", [List])) of + Bin0 -> Bin0 + catch + _:_ -> + iolist_to_binary(format_rep(List, Depth)) + end, + binary:split(Bin, <<"\n">>, [global,trim]); +match_term_get_expected(Term, Depth) -> + S = dl_format(Depth, "~p\n", [Term]), + Bin = iolist_to_binary(S), + binary:split(Bin, <<"\n">>, [global,trim]). + +format_rep([{Tag,Data}|Rep], Depth) -> + [dl_format(Depth, " ~p: ~p\n", [Tag,Data])| + format_rep(Rep, Depth)]; +format_rep([Other|Rep], Depth) -> + [dl_format(Depth, " ~p\n", [Other])| + format_rep(Rep, Depth)]; +format_rep([], _Depth) -> []. + +match_term_lines([Line|T], [Line|Lines]) -> + match_term_lines(T, Lines); +match_term_lines([], Lines) -> Lines. + +match_head(Tag, Head) -> + Re = <<"^=",Tag/binary, + " REPORT==== \\d\\d?-[A-Z][a-z][a-z]-\\d{4}::" + "\\d\\d:\\d\\d:\\d\\d ===$">>, + {match,_} = re:run(Head, Re). + +start_node(Name, Args) -> + case test_server:start_node(Name, slave, [{args,Args}]) of + {ok,Node} -> + {ok,Node}; + Error -> + test_server:fail(Error) + end. + +cleanup(File) -> + %% The point of this test case is not to test file operations. + %% Therefore ignore any failures. + case file:delete(File) of + ok -> + ok; + {error,Error1} -> + io:format("file:delete(~s) failed with error ~p", + [File,Error1]) + end, + Dir = filename:dirname(File), + case file:del_dir(Dir) of + ok -> + ok; + {error,Error2} -> + io:format("file:del_dir(~s) failed with error ~p", + [Dir,Error2]) + end, + ok. + + +%% Depth-limited io_lib:format. Intentionally implemented here instead +%% of using io_lib:scan_format/2 to avoid using the same implementation +%% as in the error_logger handlers. + +dl_format(unlimited, Format, Args) -> + io_lib:format(Format, Args); +dl_format(Depth, Format0, Args0) -> + {Format,Args} = dl_format_1(Format0, Args0, Depth, [], []), + io_lib:format(Format, Args). + +dl_format_1("~p"++Fs, [A|As], Depth, Facc, Acc) -> + dl_format_1(Fs, As, Depth, [$P,$~|Facc], [Depth,A|Acc]); +dl_format_1("~w"++Fs, [A|As], Depth, Facc, Acc) -> + dl_format_1(Fs, As, Depth, [$W,$~|Facc], [Depth,A|Acc]); +dl_format_1("~s"++Fs, [A|As], Depth, Facc, Acc) -> + dl_format_1(Fs, As, Depth, [$s,$~|Facc], [A|Acc]); +dl_format_1([F|Fs], As, Depth, Facc, Aacc) -> + dl_format_1(Fs, As, Depth, [F|Facc], Aacc); +dl_format_1([], [], _, Facc, Aacc) -> + {lists:reverse(Facc),lists:reverse(Aacc)}. + +%%% +%%% Our own event handler. There is no way to intercept the output +%%% from error_logger_tty_h, but we can use the same code by +%%% calling error_logger_tty_h:write_event/2. +%%% + +init({_,_}=St) -> + {ok,St}. + +handle_event(Event, {Fd,Depth}=St) -> + case error_logger_tty_h:write_event(tag_event(Event), io_lib, Depth) of + ok -> + ok; + Str when is_list(Str) -> + io:put_chars(Fd, Str) + end, + {ok,St}. + +terminate(_Reason, {Fd,_}) -> + ok = file:close(Fd), + []. + +tag_event(Event) -> + {erlang:universaltime(),Event}. diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index ae431d66d9..3e63d19213 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -112,9 +112,8 @@ -define(m(A,B), ?line assert_eq(A,B)). init_per_testcase(Case, Config) -> - Seed = {S1,S2,S3} = random:seed0(), %now(), - random:seed(S1,S2,S3), - io:format("*** SEED: ~p ***\n", [Seed]), + rand:seed(exsplus), + io:format("*** SEED: ~p ***\n", [rand:export_seed()]), start_spawn_logger(), wait_for_test_procs(), %% Ensure previous case cleaned up Dog=test_server:timetrap(test_server:minutes(20)), @@ -731,10 +730,6 @@ chk_normal_tab_struct_size() -> % ?line ok % end. --define(DB_TREE_STACK_NEED,50). % The static stack for a tree, in halfword pointers are two internal words - % so the stack gets twice as big --define(DB_HASH_SIZEOF_EXTSEG,260). % The segment size in words, in halfword this will be twice as large. - adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = _Mem0) -> %% Adjust for 64-bit, smp, and os: %% Table struct size may differ. @@ -748,19 +743,7 @@ adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = _Mem0) -> % end, TabDiff = ?TAB_STRUCT_SZ, - Mem1 = {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}, - - case {erlang:system_info({wordsize,internal}),erlang:system_info({wordsize,external})} of - %% Halfword, corrections for regular pointers occupying two internal words. - {4,8} -> - {A1,B1,C1,D1} = Mem1, - {A1+4*ets:info(T1, size)+?DB_TREE_STACK_NEED, - B1+3*ets:info(T2, size)+?DB_HASH_SIZEOF_EXTSEG, - C1+3*ets:info(T3, size)+?DB_HASH_SIZEOF_EXTSEG, - D1+3*ets:info(T4, size)+?DB_HASH_SIZEOF_EXTSEG}; - _ -> - Mem1 - end. + {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}. t_whitebox(doc) -> ["Diverse whitebox testes"]; @@ -1346,7 +1329,7 @@ drop_match() -> ets_match(Tab,Expr) -> - case random:uniform(2) of + case rand:uniform(2) of 1 -> ets:match(Tab,Expr); _ -> @@ -1355,14 +1338,14 @@ ets_match(Tab,Expr) -> match_chunked(Tab,Expr) -> match_chunked_collect(ets:match(Tab,Expr, - random:uniform(1999) + 1)). + rand:uniform(1999) + 1)). match_chunked_collect('$end_of_table') -> []; match_chunked_collect({Results, Continuation}) -> Results ++ match_chunked_collect(ets:match(Continuation)). ets_match_object(Tab,Expr) -> - case random:uniform(2) of + case rand:uniform(2) of 1 -> ets:match_object(Tab,Expr); _ -> @@ -1371,7 +1354,7 @@ ets_match_object(Tab,Expr) -> match_object_chunked(Tab,Expr) -> match_object_chunked_collect(ets:match_object(Tab,Expr, - random:uniform(1999) + 1)). + rand:uniform(1999) + 1)). match_object_chunked_collect('$end_of_table') -> []; match_object_chunked_collect({Results, Continuation}) -> @@ -1383,19 +1366,15 @@ random_test() -> ?line ReadDir = get(where_to_read), ?line WriteDir = get(where_to_write), ?line (catch file:make_dir(WriteDir)), - ?line Seed = case file:consult(filename:join([ReadDir, - "preset_random_seed.txt"])) of - {ok,[X]} -> - X; - _ -> - {A,B,C} = erlang:timestamp(), - random:seed(A,B,C), - get(random_seed) - end, - put(random_seed,Seed), - ?line {ok, F} = file:open(filename:join([WriteDir, - "last_random_seed.txt"]), - [write]), + case file:consult(filename:join([ReadDir,"preset_random_seed.txt"])) of + {ok,[X]} -> + rand:seed(X); + _ -> + rand:seed(exsplus) + end, + Seed = rand:export_seed(), + {ok,F} = file:open(filename:join([WriteDir,"last_random_seed.txt"]), + [write]), io:format(F,"~p. ~n",[Seed]), file:close(F), io:format("Random seed ~p written to ~s, copy to ~s to rerun with " @@ -1417,7 +1396,7 @@ do_random_test() -> end, 5000), ?line io:format("~nData inserted~n"), ?line do_n_times(fun() -> - ?line I = random:uniform(25), + I = rand:uniform(25), ?line Key = create_random_string(I) ++ '_', ?line L1 = ets_match_object(OrdSet,{Key,'_'}), ?line L2 = lists:sort(ets_match_object(Set,{Key,'_'})), @@ -1977,7 +1956,7 @@ evil_update_counter(Config) when is_list(Config) -> gb_sets:module_info(), math:module_info(), ordsets:module_info(), - random:module_info(), + rand:module_info(), repeat_for_opts(evil_update_counter_do). @@ -2011,7 +1990,7 @@ evil_counter(I,Opts) -> 1 -> 16#12345678FFFFFFFF; 2 -> 16#7777777777FFFFFFFF863648726743 end, - Start = Start0 + random:uniform(100000), + Start = Start0 + rand:uniform(100000), ets:insert(T, {dracula,Start}), Iter = 40000, End = Start + Iter, @@ -4661,11 +4640,11 @@ create_random_string(0) -> []; create_random_string(OfLength) -> - C = case random:uniform(2) of + C = case rand:uniform(2) of 1 -> - (random:uniform($Z - $A + 1) - 1) + $A; + (rand:uniform($Z - $A + 1) - 1) + $A; _ -> - (random:uniform($z - $a + 1) - 1) + $a + (rand:uniform($z - $a + 1) - 1) + $a end, [C | create_random_string(OfLength - 1)]. @@ -4676,7 +4655,7 @@ create_random_tuple(OfLength) -> end,create_random_string(OfLength))). create_partly_bound_tuple(OfLength) -> - case random:uniform(2) of + case rand:uniform(2) of 1 -> create_partly_bound_tuple1(OfLength); _ -> @@ -4685,14 +4664,14 @@ create_partly_bound_tuple(OfLength) -> create_partly_bound_tuple1(OfLength) -> T0 = create_random_tuple(OfLength), - I = random:uniform(OfLength), + I = rand:uniform(OfLength), setelement(I,T0,'$1'). set_n_random_elements(T0,0,_,_) -> T0; set_n_random_elements(T0,N,OfLength,GenFun) -> - I = random:uniform(OfLength), + I = rand:uniform(OfLength), What = GenFun(I), case element(I,T0) of What -> @@ -4706,12 +4685,12 @@ make_dollar_atom(I) -> list_to_atom([$$] ++ integer_to_list(I)). create_partly_bound_tuple2(OfLength) -> T0 = create_random_tuple(OfLength), - I = random:uniform(OfLength - 1), + I = rand:uniform(OfLength - 1), set_n_random_elements(T0,I,OfLength,fun make_dollar_atom/1). create_partly_bound_tuple3(OfLength) -> T0 = create_random_tuple(OfLength), - I = random:uniform(OfLength - 1), + I = rand:uniform(OfLength - 1), set_n_random_elements(T0,I,OfLength,fun(_) -> '_' end). do_n_times(_,0) -> @@ -5074,11 +5053,12 @@ meta_wb_do(Opts) -> io:format("Colliding names = ~p\n",[Names]), F = fun(0,_,_) -> ok; - (N,Tabs,Me) -> Name1 = lists:nth(random:uniform(Len),Names), - Name2 = lists:nth(random:uniform(Len),Names), - Op = element(random:uniform(3),OpFuns), - NTabs = Op(Name1, Name2, Tabs, Opts), - Me(N-1,NTabs,Me) + (N,Tabs,Me) -> + Name1 = lists:nth(rand:uniform(Len), Names), + Name2 = lists:nth(rand:uniform(Len), Names), + Op = element(rand:uniform(3),OpFuns), + NTabs = Op(Name1, Name2, Tabs, Opts), + Me(N-1, NTabs, Me) end, F(Len*100, [], F), @@ -5344,7 +5324,7 @@ smp_insert(suite) -> []; smp_insert(Config) when is_list(Config) -> ets_new(smp_insert,[named_table,public,{write_concurrency,true}]), InitF = fun(_) -> ok end, - ExecF = fun(_) -> true = ets:insert(smp_insert,{random:uniform(10000)}) + ExecF = fun(_) -> true = ets:insert(smp_insert,{rand:uniform(10000)}) end, FiniF = fun(_) -> ok end, run_workers(InitF,ExecF,FiniF,100000), @@ -5595,10 +5575,10 @@ smp_select_delete(Config) when is_list(Config) -> Zeros = erlang:make_tuple(Mod,0), InitF = fun(_) -> Zeros end, ExecF = fun(Diffs0) -> - case random:uniform(20) of + case rand:uniform(20) of 1 -> Mod = 17, - Eq = random:uniform(Mod) - 1, + Eq = rand:uniform(Mod) - 1, Deleted = ets:select_delete(T, [{{'_', '$1'}, [{'=:=', {'rem', '$1', Mod}, Eq}], @@ -5607,7 +5587,7 @@ smp_select_delete(Config) when is_list(Config) -> element(Eq+1,Diffs0) - Deleted), Diffs1; _ -> - Key = random:uniform(10000), + Key = rand:uniform(10000), Eq = Key rem Mod, ?line case ets:insert_new(T,{Key,Key}) of true -> @@ -5811,7 +5791,7 @@ run_workers_do(InitF,ExecF,FiniF,Laps, Exclude) -> N when (N > Exclude) -> N - Exclude end, io:format("smp starting ~p workers\n",[NumOfProcs]), - Seeds = [{ProcN,random:uniform(9999)} || ProcN <- lists:seq(1,NumOfProcs)], + Seeds = [{ProcN,rand:uniform(9999)} || ProcN <- lists:seq(1,NumOfProcs)], Parent = self(), Pids = [my_spawn_link(fun()-> worker(Seed,InitF,ExecF,FiniF,Laps,Parent,NumOfProcs) end) || Seed <- Seeds], @@ -5822,7 +5802,7 @@ run_workers_do(InitF,ExecF,FiniF,Laps, Exclude) -> worker({ProcN,Seed}, InitF, ExecF, FiniF, Laps, Parent, NumOfProcs) -> io:format("smp worker ~p, seed=~p~n",[self(),Seed]), - random:seed(Seed,Seed,Seed), + rand:seed(exsplus, {Seed,Seed,Seed}), State1 = InitF([ProcN, NumOfProcs]), State2 = worker_loop(Laps, ExecF, State1), Result = FiniF(State2), diff --git a/lib/stdlib/test/ets_tough_SUITE.erl b/lib/stdlib/test/ets_tough_SUITE.erl index c6f24fc670..8a7f2b1ec2 100644 --- a/lib/stdlib/test/ets_tough_SUITE.erl +++ b/lib/stdlib/test/ets_tough_SUITE.erl @@ -92,7 +92,7 @@ ex1_sub(Config) -> ok. prep(Config) -> - random:seed(), + rand:seed(exsplus), put(dump_ticket,none), DumpDir = filename:join(?config(priv_dir,Config), "ets_tough"), file:make_dir(DumpDir), @@ -221,19 +221,19 @@ random_class() -> random_element(Classes). random_key() -> - random:uniform(8). + rand:uniform(8). random_value() -> - case random:uniform(5) of + case rand:uniform(5) of 1 -> ok; 2 -> {data,random_key()}; 3 -> {foo,bar,random_class()}; - 4 -> random:uniform(1000); + 4 -> rand:uniform(1000); 5 -> {recursive,random_value()} end. random_element(T) -> - I = random:uniform(tuple_size(T)), + I = rand:uniform(tuple_size(T)), element(I,T). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl index 01b798faef..c39ff842ee 100644 --- a/lib/stdlib/test/filelib_SUITE.erl +++ b/lib/stdlib/test/filelib_SUITE.erl @@ -318,7 +318,7 @@ same_lists(Expected0, Actual0, BaseDir) -> mkfiles([H|T], Dir) -> Name = filename:join(Dir, H), - Garbage = [31+random:uniform(95) || _ <- lists:seq(1, random:uniform(1024))], + Garbage = [31+rand:uniform(95) || _ <- lists:seq(1, rand:uniform(1024))], file:write_file(Name, Garbage), [Name|mkfiles(T, Dir)]; mkfiles([], _) -> []. diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl index fd47da8150..4372e77df9 100644 --- a/lib/stdlib/test/filename_SUITE.erl +++ b/lib/stdlib/test/filename_SUITE.erl @@ -97,20 +97,11 @@ absname(Config) when is_list(Config) -> ?line file:set_cwd(Cwd), ok; - Type -> - case Type of - {unix, _} -> - ?line ok = file:set_cwd("/usr"), - ?line "/usr/foo" = filename:absname(foo), - ?line "/usr/foo" = filename:absname("foo"), - ?line "/usr/../ebin" = filename:absname("../ebin"); - {ose, _} -> - ?line ok = file:set_cwd("/romfs"), - ?line "/romfs/foo" = filename:absname(foo), - ?line "/romfs/foo" = filename:absname("foo"), - ?line "/romfs/../ebin" = filename:absname("../ebin") - end, - + {unix, _} -> + ?line ok = file:set_cwd("/usr"), + ?line "/usr/foo" = filename:absname(foo), + ?line "/usr/foo" = filename:absname("foo"), + ?line "/usr/../ebin" = filename:absname("../ebin"), ?line file:set_cwd("/"), ?line "/foo" = filename:absname(foo), ?line "/foo" = filename:absname("foo"), @@ -494,18 +485,10 @@ absname_bin(Config) when is_list(Config) -> ?line file:set_cwd(Cwd), ok; - Type -> - case Type of - {unix,_} -> - ?line ok = file:set_cwd(<<"/usr">>), - ?line <<"/usr/foo">> = filename:absname(<<"foo">>), - ?line <<"/usr/../ebin">> = filename:absname(<<"../ebin">>); - {ose,_} -> - ?line ok = file:set_cwd(<<"/romfs">>), - ?line <<"/romfs/foo">> = filename:absname(<<"foo">>), - ?line <<"/romfs/../ebin">> = filename:absname(<<"../ebin">>) - end, - + {unix, _} -> + ?line ok = file:set_cwd(<<"/usr">>), + ?line <<"/usr/foo">> = filename:absname(<<"foo">>), + ?line <<"/usr/../ebin">> = filename:absname(<<"../ebin">>), ?line file:set_cwd(<<"/">>), ?line <<"/foo">> = filename:absname(<<"foo">>), ?line <<"/../ebin">> = filename:absname(<<"../ebin">>), diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl index 7a6fcba4e5..b019f98b69 100644 --- a/lib/stdlib/test/gen_event_SUITE.erl +++ b/lib/stdlib/test/gen_event_SUITE.erl @@ -412,7 +412,6 @@ notify(Config) when is_list(Config) -> ok end, ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:notify(my_dummy_handler, Event), ?line receive @@ -445,7 +444,6 @@ notify(Config) when is_list(Config) -> end, ?line ok = gen_event:notify(my_dummy_handler, {swap_event, {dummy1_h, 9}, swap}), - ?t:sleep(1000), ?line [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:notify(my_dummy_handler, Event), ?line receive @@ -485,7 +483,6 @@ notify(Config) when is_list(Config) -> ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]), ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:notify(my_dummy_handler, do_crash), @@ -496,7 +493,6 @@ notify(Config) when is_list(Config) -> ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]), ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:notify(my_dummy_handler, delete_event), @@ -529,7 +525,6 @@ sync_notify(Config) when is_list(Config) -> end, ?line ok = gen_event:sync_notify(my_dummy_handler, {swap_event, dummy1_h, swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:sync_notify(my_dummy_handler, Event), ?line receive @@ -562,7 +557,6 @@ sync_notify(Config) when is_list(Config) -> end, ?line ok = gen_event:sync_notify(my_dummy_handler, {swap_event, {dummy1_h, 9}, swap}), - ?t:sleep(1000), ?line [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:sync_notify(my_dummy_handler, Event), ?line receive @@ -603,7 +597,6 @@ sync_notify(Config) when is_list(Config) -> ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]), ?line ok = gen_event:sync_notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:sync_notify(my_dummy_handler, do_crash), @@ -615,7 +608,6 @@ sync_notify(Config) when is_list(Config) -> ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]), ?line ok = gen_event:sync_notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:sync_notify(my_dummy_handler, delete_event), @@ -789,7 +781,6 @@ info(Config) when is_list(Config) -> ok end, ?line my_dummy_handler ! {swap_info,dummy1_h,swap}, - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line my_dummy_handler ! Info, ?line receive @@ -821,7 +812,6 @@ info(Config) when is_list(Config) -> ok end, ?line my_dummy_handler ! {swap_info,{dummy1_h,2},swap}, - ?t:sleep(1000), ?line [{dummy1_h,2}] = gen_event:which_handlers(my_dummy_handler), ?line my_dummy_handler ! Info, ?line receive @@ -853,7 +843,6 @@ info(Config) when is_list(Config) -> ok end, ?line my_dummy_handler ! {swap_info,dummy1_h,swap}, - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line my_dummy_handler ! Info, ?line receive diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl index 41de016f8d..1cff990697 100644 --- a/lib/stdlib/test/id_transform_SUITE.erl +++ b/lib/stdlib/test/id_transform_SUITE.erl @@ -56,47 +56,26 @@ end_per_group(_GroupName, Config) -> id_transform(doc) -> "Test erl_id_trans."; id_transform(Config) when is_list(Config) -> - ?line File=filename:join([code:lib_dir(stdlib),"examples", - "erl_id_trans.erl"]), - ?line {ok,erl_id_trans,Bin}=compile:file(File,[binary]), - ?line {module,erl_id_trans}=code:load_binary(erl_id_trans,File,Bin), - ?line case test_server:purify_is_running() of - false -> - Dog = ct:timetrap(?t:hours(1)), - ?line Res = run_in_test_suite(), - ?t:timetrap_cancel(Dog), - Res; - true -> - {skip,"Purify (too slow)"} - end. + File = filename:join([code:lib_dir(stdlib),"examples", + "erl_id_trans.erl"]), + {ok,erl_id_trans,Bin} = compile:file(File,[binary]), + {module,erl_id_trans} = code:load_binary(erl_id_trans, File, Bin), + case test_server:purify_is_running() of + false -> + Dog = ct:timetrap(?t:hours(1)), + Res = run_in_test_suite(), + ?t:timetrap_cancel(Dog), + Res; + true -> + {skip,"Valgrind (too slow)"} + end. run_in_test_suite() -> - LibDir = code:lib_dir(), SuperDir = filename:dirname(filename:dirname(code:which(?MODULE))), TestDirs = filelib:wildcard(filename:join([SuperDir,"*_test"])), - {All,Res} = case LibDir of - "/clearcase/otp/erts/lib" -> - %% Only test_suites 'cause clearcase is too slow... - {false,run_list(TestDirs)}; - _ -> - {true,run_codepath_and(TestDirs)} - end, - Comment0 = case All of - true -> []; - false -> "Only testsuite directories traversed" - end, - case Res of - {error,Reason} when Comment0 =/= [] -> - {failed,Comment0++"; "++Reason}; - {error,Reason} -> - {failed,Reason}; - ok -> - {comment,Comment0} - end. - -run_codepath_and(DirList) -> AbsDirs = [filename:absname(X) || X <- code:get_path()], - run_list(ordsets:from_list([X || X <- AbsDirs] ++ DirList)). + Dirs = ordsets:from_list(AbsDirs ++ TestDirs), + run_list(Dirs). run_list(PathL) -> io:format("Where to search for beam files:\n~p\n", [PathL]), @@ -123,7 +102,7 @@ run_list(PathL) -> end, case length(SevereFailures) of 0 -> ok; - Len -> {error,integer_to_list(Len)++" failures"} + Len -> {failed,integer_to_list(Len)++" failures"} end. diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl index 5df09b6a79..0e897631ff 100644 --- a/lib/stdlib/test/io_SUITE.erl +++ b/lib/stdlib/test/io_SUITE.erl @@ -29,10 +29,11 @@ manpage/1, otp_6708/1, otp_7084/1, otp_7421/1, io_lib_collect_line_3_wb/1, cr_whitespace_in_string/1, io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1, - printable_range/1, + printable_range/1, bad_printable_range/1, io_lib_print_binary_depth_one/1, otp_10302/1, otp_10755/1, otp_10836/1, io_lib_width_too_small/1, - io_with_huge_message_queue/1, format_string/1]). + io_with_huge_message_queue/1, format_string/1, + maps/1, coverage/1]). -export([pretty/2]). @@ -70,10 +71,10 @@ all() -> manpage, otp_6708, otp_7084, otp_7421, io_lib_collect_line_3_wb, cr_whitespace_in_string, io_fread_newlines, otp_8989, io_lib_fread_literal, - printable_range, + printable_range, bad_printable_range, io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836, io_lib_width_too_small, io_with_huge_message_queue, - format_string]. + format_string, maps, coverage]. groups() -> []. @@ -2062,8 +2063,6 @@ printable_range(Suite) when is_list(Suite) -> [{args, " +pclatin1 -pa " ++ Pa}]), unicode = rpc:call(UNode,io,printable_range,[]), latin1 = rpc:call(LNode,io,printable_range,[]), - {error, _} = test_server:start_node(printable_range_unnicode, slave, - [{args, " +pcunnicode -pa " ++ Pa}]), PrettyOptions = [{column,1}, {line_length,109}, {depth,30}, @@ -2071,48 +2070,69 @@ printable_range(Suite) when is_list(Suite) -> {record_print_fun, fun(_,_) -> no end}, {encoding,unicode}], - 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib_pretty,print, - [{hello, [1024,1025]}, - PrettyOptions]))), - 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib_pretty,print, - [{hello, [1024,1025]}, - PrettyOptions]))), - 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib_pretty,print, - [{hello, [1024,1025]}, - PrettyOptions]))), - 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib_pretty,print, - [{hello, <<1024/utf8,1025/utf8>>}, - PrettyOptions]))), - 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib_pretty,print, - [{hello, <<1024/utf8,1025/utf8>>}, - PrettyOptions]))), - 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib_pretty,print, - [{hello, <<1024/utf8,1025/utf8>>}, - PrettyOptions]))), + PrintableControls = "\t\v\b\f\e\r\n", + + 1025 = print_max(UNode, [{hello, [1024,1025]}, + PrettyOptions]), + 125 = print_max(LNode, [{hello, [1024,1025]}, + PrettyOptions]), + 125 = print_max(DNode, [{hello, [1024,1025]}, + PrettyOptions]), + 1025 = print_max(UNode, [{hello, <<1024/utf8,1025/utf8>>}, + PrettyOptions]), + 125 = print_max(LNode, [{hello, <<1024/utf8,1025/utf8>>}, + PrettyOptions]), + 125 = print_max(DNode, [{hello, <<1024/utf8,1025/utf8>>}, + PrettyOptions]), + $v = print_max(UNode, [PrintableControls,PrettyOptions]), + $v = print_max(LNode, [PrintableControls,PrettyOptions]), + $v = print_max(DNode, [PrintableControls,PrettyOptions]), + 16#10FFFF = print_max(UNode, + [<<16#10FFFF/utf8,"\t\v\b\f\e\r\n">>, + PrettyOptions]), + $> = print_max(LNode, + [<<16#10FFFF/utf8,"\t\v\b\f\e\r\n">>, + PrettyOptions]), + $> = print_max(DNode, + [<<16#10FFFF/utf8,"\t\v\b\f\e\r\n">>, + PrettyOptions]), - 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib,format, - ["~tp",[{hello, [1024,1025]}]]))), - 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib,format, - ["~tp",[{hello, [1024,1025]}]]))), - 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib,format, - ["~tp",[{hello, [1024,1025]}]]))), - 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib,format, - ["~tp", - [{hello, - <<1024/utf8,1025/utf8>>}]]))), - 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib,format, - ["~tp", - [{hello, - <<1024/utf8,1025/utf8>>}]]))), - 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib,format, - ["~tp", - [{hello, - <<1024/utf8,1025/utf8>>}]]))), + 1025 = format_max(UNode, ["~tp", [{hello, [1024,1025]}]]), + 125 = format_max(LNode, ["~tp", [{hello, [1024,1025]}]]), + 125 = format_max(DNode, ["~tp", [{hello, [1024,1025]}]]), + 1025 = format_max(UNode, ["~tp", [{hello, <<1024/utf8,1025/utf8>>}]]), + 125 = format_max(LNode, ["~tp", [{hello, <<1024/utf8,1025/utf8>>}]]), + 125 = format_max(DNode, ["~tp", [{hello, <<1024/utf8,1025/utf8>>}]]), + + $\e = format_max(UNode, ["~ts", [PrintableControls]]), + $\e = format_max(LNode, ["~ts", [PrintableControls]]), + $\e = format_max(DNode, ["~ts", [PrintableControls]]), + test_server:stop_node(UNode), test_server:stop_node(LNode), test_server:stop_node(DNode), ok. +print_max(Node, Args) -> + rpc_call_max(Node, io_lib_pretty, print, Args). + +format_max(Node, Args) -> + rpc_call_max(Node, io_lib, format, Args). + +rpc_call_max(Node, M, F, Args) -> + lists:max(lists:flatten(rpc:call(Node, M, F, Args))). + +%% Make sure that a bad specification for a printable range is rejected. +bad_printable_range(Config) when is_list(Config) -> + Cmd = lists:concat([lib:progname()," +pcunnnnnicode -run erlang halt"]), + case os:cmd(Cmd) of + "bad range of printable characters" ++ _ -> + ok; + String -> + io:format("~s\n", [String]), + ?t:fail() + end. + io_lib_print_binary_depth_one(doc) -> "Test binaries printed with a depth of one behave correctly"; io_lib_print_binary_depth_one(Suite) when is_list(Suite) -> @@ -2225,7 +2245,7 @@ compile_file(File, Text, Config) -> after ok %file:delete(Fname) end. -io_lib_width_too_small(Config) -> +io_lib_width_too_small(_Config) -> "**" = lists:flatten(io_lib:format("~2.3w", [3.14])), "**" = lists:flatten(io_lib:format("~2.5w", [3.14])), ok. @@ -2271,8 +2291,113 @@ writes(N, F1) -> file:write(F1, "hello\n"), writes(N - 1, F1). -format_string(Config) -> +format_string(_Config) -> %% All but padding is tested by fmt/2. "xxxxxxsssx" = fmt("~10.4.xs", ["sss"]), "xxxxxxsssx" = fmt("~10.4.*s", [$x, "sss"]), ok. + +maps(_Config) -> + %% Note that order in which a map is printed is arbitrary. In + %% practice, small maps (non-HAMT) are printed in key order, but + %% the breakpoint for creating big maps (HAMT) is lower in the + %% debug-compiled run-time system than in the optimized run-time + %% system. + %% + %% Therefore, play it completely safe by not assuming any order + %% in a map with more than one element. + + "#{}" = fmt("~w", [#{}]), + "#{a=>b}" = fmt("~w", [#{a=>b}]), + re_fmt(<<"#\\{(a=>b|c=>d),[.][.][.]=>[.][.][.]\\}">>, + "~W", [#{a=>b,c=>d},2]), + re_fmt(<<"#\\{(a=>b|c=>d|e=>f),[.][.][.]=>[.][.][.],[.][.][.]\\}">>, + "~W", [#{a=>b,c=>d,e=>f},2]), + + "#{}" = fmt("~p", [#{}]), + "#{a => b}" = fmt("~p", [#{a=>b}]), + "#{...}" = fmt("~P", [#{a=>b},1]), + re_fmt(<<"#\\{(a => b|c => d),[.][.][.]\\}">>, + "~P", [#{a=>b,c=>d},2]), + re_fmt(<<"#\\{(a => b|c => d|e => f),[.][.][.]\\}">>, + "~P", [#{a=>b,c=>d,e=>f},2]), + + List = [{I,I*I} || I <- lists:seq(1, 20)], + Map = maps:from_list(List), + + "#{...}" = fmt("~P", [Map,1]), + + %% Print a map and parse it back to a map. + S = fmt("~p\n", [Map]), + io:format("~p\n", [S]), + Map = parse_map(S), + + %% Smoke test of a map as key. + MapAsKey = #{Map => "value"}, + io:format("~s\n", [fmt("~p", [MapAsKey])]), + ok. + +re_fmt(Pattern, Format, Args) -> + S = list_to_binary(fmt(Format, Args)), + case re:run(S, Pattern, [{capture,none}]) of + nomatch -> + io:format("Pattern: ~s", [Pattern]), + io:format("Result: ~s", [S]), + ?t:fail(); + match -> + ok + end. + +%% Parse a map consisting of integer keys and values. +parse_map(S0) -> + S1 = parse_expect(S0, "#{"), + {M,S2} = parse_map_1(S1), + S = parse_expect(S2, "}"), + S = "", + M. + +parse_map_1(S0) -> + {Key,S1} = parse_number(S0), + S2 = parse_expect(S1, "=>"), + {Val,S3} = parse_number(S2), + case S3 of + ","++S4 -> + S5 = parse_skip_ws(S4), + {Map,S} = parse_map_1(S5), + {Map#{Key=>Val},S}; + S -> + {#{Key=>Val},S} + end. + +parse_number(S) -> + parse_number(S, none). + +parse_number([C|S], Acc0) when $0 =< C, C =< $9 -> + Acc = case Acc0 of + none -> 0; + _ when is_integer(Acc0) -> Acc0 + end, + parse_number(S, Acc*10+C-$0); +parse_number(S, Acc) -> + {Acc,parse_skip_ws(S)}. + +parse_expect([H|T1], [H|T2]) -> + parse_expect(T1, T2); +parse_expect(S, []) -> + parse_skip_ws(S). + +parse_skip_ws([C|S]) when C =< $\s -> + parse_skip_ws(S); +parse_skip_ws(S) -> + S. + +%% Cover the last uncovered lines for completeness. +coverage(_Config) -> + S1 = io_lib_pretty:print({a,term}, fun(_, _) -> no end), + io:format("~s\n", [S1]), + + %% The tuple of arity three will be ignored. + S2 = io_lib_pretty:print(lists:seq(1, 100), [{depth,1,1}]), + io:format("~s\n", [S2]), + + ok. diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl index 1337b7dde2..811c7ed7bb 100644 --- a/lib/stdlib/test/io_proto_SUITE.erl +++ b/lib/stdlib/test/io_proto_SUITE.erl @@ -1378,47 +1378,43 @@ rtnode(C,N) -> rtnode(Commands,Nodename,ErlPrefix) -> rtnode(Commands,Nodename,ErlPrefix,[]). rtnode(Commands,Nodename,ErlPrefix,Extra) -> - ?line case get_progs() of - {error,_Reason} -> - ?line {skip,"No runerl present"}; - {RunErl,ToErl,Erl} -> - ?line case create_tempdir() of - {error, Reason2} -> - ?line {skip, Reason2}; - Tempdir -> - ?line SPid = - start_runerl_node(RunErl,ErlPrefix++ - "\\\""++Erl++"\\\"", - Tempdir,Nodename, Extra), - ?line CPid = start_toerl_server(ToErl,Tempdir), - ?line erase(getline_skipped), - ?line Res = - (catch get_and_put(CPid, Commands,1)), - ?line case stop_runerl_node(CPid) of - {error,_} -> - ?line CPid2 = - start_toerl_server - (ToErl,Tempdir), - ?line erase(getline_skipped), - ?line ok = get_and_put - (CPid2, - [{putline,[7]}, - {sleep, - timeout(short)}, - {putline,""}, - {getline," -->"}, - {putline,"s"}, - {putline,"c"}, - {putline,""}],1), - ?line stop_runerl_node(CPid2); - _ -> - ?line ok - end, - ?line wait_for_runerl_server(SPid), - ?line ok = ?RM_RF(Tempdir), - ?line ok = Res - end - end. + case get_progs() of + {error,_Reason} -> + {skip,"No runerl present"}; + {RunErl,ToErl,Erl} -> + case create_tempdir() of + {error, Reason2} -> + {skip, Reason2}; + Tempdir -> + SPid = start_runerl_node(RunErl, ErlPrefix++ + "\\\""++Erl++"\\\"", + Tempdir, Nodename, Extra), + CPid = start_toerl_server(ToErl, Tempdir), + put(getline_skipped, []), + Res = (catch get_and_put(CPid, Commands, 1)), + case stop_runerl_node(CPid) of + {error,_} -> + CPid2 = start_toerl_server(ToErl, Tempdir), + put(getline_skipped, []), + ok = get_and_put + (CPid2, + [{putline,[7]}, + {sleep, + timeout(short)}, + {putline,""}, + {getline," -->"}, + {putline,"s"}, + {putline,"c"}, + {putline,""}], 1), + stop_runerl_node(CPid2); + _ -> + ok + end, + wait_for_runerl_server(SPid), + ok = ?RM_RF(Tempdir), + ok = Res + end + end. timeout(long) -> 2 * timeout(normal); @@ -1462,57 +1458,51 @@ get_and_put(CPid, [{sleep, X}|T],N) -> after X -> get_and_put(CPid,T,N+1) end; -get_and_put(CPid, [{getline, Match}|T],N) -> +get_and_put(CPid, [{getline_pred,Pred,Msg}|T]=T0, N) + when is_function(Pred) -> ?dbg({getline, Match}), CPid ! {self(), {get_line, timeout(normal)}}, receive {get_line, timeout} -> error_logger:error_msg("~p: getline timeout waiting for \"~s\" " "(command number ~p, skipped: ~p)~n", - [?MODULE, Match,N,get(getline_skipped)]), + [?MODULE,Msg,N,get(getline_skipped)]), {error, timeout}; {get_line, Data} -> ?dbg({data,Data}), - case lists:prefix(Match, Data) of - true -> - erase(getline_skipped), + case Pred(Data) of + yes -> + put(getline_skipped, []), get_and_put(CPid, T,N+1); - false -> - case get(getline_skipped) of - undefined -> - put(getline_skipped,[Data]); - List -> - put(getline_skipped,List ++ [Data]) - end, - get_and_put(CPid, [{getline, Match}|T],N) + no -> + error_logger:error_msg("~p: getline match failure " + "\"~s\" " + "(command number ~p)\n", + [?MODULE,Msg,N]), + {error, no_match}; + maybe -> + List = get(getline_skipped), + put(getline_skipped, List ++ [Data]), + get_and_put(CPid, T0, N) end end; +get_and_put(CPid, [{getline, Match}|T],N) -> + ?dbg({getline, Match}), + F = fun(Data) -> + case lists:prefix(Match, Data) of + true -> yes; + false -> maybe + end + end, + get_and_put(CPid, [{getline_pred,F,Match}|T], N); get_and_put(CPid, [{getline_re, Match}|T],N) -> - ?dbg({getline_re, Match}), - CPid ! {self(), {get_line, timeout(normal)}}, - receive - {get_line, timeout} -> - error_logger:error_msg("~p: getline_re timeout waiting for \"~s\" " - "(command number ~p, skipped: ~p)~n", - [?MODULE, Match,N,get(getline_skipped)]), - {error, timeout}; - {get_line, Data} -> - ?dbg({data,Data}), - case re:run(Data, Match,[{capture,none}]) of - match -> - erase(getline_skipped), - get_and_put(CPid, T,N+1); - _ -> - case get(getline_skipped) of - undefined -> - put(getline_skipped,[Data]); - List -> - put(getline_skipped,List ++ [Data]) - end, - get_and_put(CPid, [{getline_re, Match}|T],N) - end - end; - + F = fun(Data) -> + case re:run(Data, Match, [{capture,none}]) of + match -> yes; + _ -> maybe + end + end, + get_and_put(CPid, [{getline_pred,F,Match}|T], N); get_and_put(CPid, [{putline_raw, Line}|T],N) -> ?dbg({putline_raw, Line}), CPid ! {self(), {send_line, Line}}, @@ -1801,10 +1791,22 @@ get_data_within(Port, Timeout, Acc) -> end. get_default_shell() -> + Match = fun(Data) -> + case lists:prefix("undefined", Data) of + true -> + yes; + false -> + case re:run(Data, "<\\d+[.]\\d+[.]\\d+>", + [{capture,none}]) of + match -> no; + _ -> maybe + end + end + end, try rtnode([{putline,""}, {putline, "whereis(user_drv)."}, - {getline, "undefined"}],[]), + {getline_pred, Match, "matching of user_drv pid"}], []), old catch _E:_R -> ?dbg({_E,_R}), diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl index e886a797f0..bd68c93779 100644 --- a/lib/stdlib/test/lists_SUITE.erl +++ b/lib/stdlib/test/lists_SUITE.erl @@ -38,13 +38,13 @@ % Test cases must be exported. -export([member/1, reverse/1, keymember/1, keysearch_keyfind/1, - keystore/1, keytake/1, + keystore/1, keytake/1, keyreplace/1, append_1/1, append_2/1, seq_loop/1, seq_2/1, seq_3/1, seq_2_e/1, seq_3_e/1, sublist_2/1, sublist_3/1, sublist_2_e/1, sublist_3_e/1, flatten_1/1, flatten_2/1, flatten_1_e/1, flatten_2_e/1, - dropwhile/1, + dropwhile/1, takewhile/1, sort_1/1, sort_stable/1, merge/1, rmerge/1, sort_rand/1, usort_1/1, usort_stable/1, umerge/1, rumerge/1,usort_rand/1, keymerge/1, rkeymerge/1, @@ -62,7 +62,7 @@ zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1, filter_partition/1, otp_5939/1, otp_6023/1, otp_6606/1, otp_7230/1, - suffix/1, subtract/1, droplast/1]). + suffix/1, subtract/1, droplast/1, hof/1]). %% Sort randomized lists until stopped. %% @@ -81,37 +81,51 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [{group, append}, reverse, member, keymember, - keysearch_keyfind, keystore, keytake, dropwhile, {group,sort}, - {group, usort}, {group, keysort}, {group, ukeysort}, - {group, funsort}, {group, ufunsort}, {group, sublist}, - {group, flatten}, {group, seq}, zip_unzip, zip_unzip3, - zipwith, zipwith3, filter_partition, {group, tickets}, - suffix, subtract]. + [{group, append}, + {group, key}, + {group,sort}, + {group, usort}, + {group, keysort}, + {group, ukeysort}, + {group, funsort}, + {group, ufunsort}, + {group, sublist}, + {group, flatten}, + {group, seq}, + {group, tickets}, + {group, zip}, + {group, misc}]. groups() -> - [{append, [], [append_1, append_2]}, - {usort, [], + [{append, [parallel], [append_1, append_2]}, + {usort, [parallel], [umerge, rumerge, usort_1, usort_rand, usort_stable]}, - {keysort, [], + {keysort, [parallel], [keymerge, rkeymerge, keysort_1, keysort_rand, keysort_i, keysort_stable, keysort_error]}, - {sort,[],[merge, rmerge, sort_1, sort_rand]}, - {ukeysort, [], + {key, [parallel], [keymember, keysearch_keyfind, keystore, + keytake, keyreplace]}, + {sort,[parallel],[merge, rmerge, sort_1, sort_rand]}, + {ukeysort, [parallel], [ukeymerge, rukeymerge, ukeysort_1, ukeysort_rand, ukeysort_i, ukeysort_stable, ukeysort_error]}, - {funsort, [], + {funsort, [parallel], [funmerge, rfunmerge, funsort_1, funsort_stable, funsort_error, funsort_rand]}, - {ufunsort, [], + {ufunsort, [parallel], [ufunmerge, rufunmerge, ufunsort_1, ufunsort_stable, ufunsort_error, ufunsort_rand]}, - {seq, [], [seq_loop, seq_2, seq_3, seq_2_e, seq_3_e]}, - {sublist, [], + {seq, [parallel], [seq_loop, seq_2, seq_3, seq_2_e, seq_3_e]}, + {sublist, [parallel], [sublist_2, sublist_3, sublist_2_e, sublist_3_e]}, - {flatten, [], + {flatten, [parallel], [flatten_1, flatten_2, flatten_1_e, flatten_2_e]}, - {tickets, [], [otp_5939, otp_6023, otp_6606, otp_7230]}]. + {tickets, [parallel], [otp_5939, otp_6023, otp_6606, otp_7230]}, + {zip, [parallel], [zip_unzip, zip_unzip3, zipwith, zipwith3]}, + {misc, [parallel], [reverse, member, dropwhile, takewhile, + filter_partition, suffix, subtract, + hof]} + ]. init_per_suite(Config) -> Config. @@ -345,6 +359,33 @@ dropwhile(Config) when is_list(Config) -> ok. +takewhile(Config) when is_list(Config) -> + F = fun(C) -> C =/= $@ end, + + [] = lists:takewhile(F, []), + [a] = lists:takewhile(F, [a]), + [a,b] = lists:takewhile(F, [a,b]), + [a,b,c] = lists:takewhile(F, [a,b,c]), + + [] = lists:takewhile(F, [$@]), + [] = lists:takewhile(F, [$@,$@]), + [a] = lists:takewhile(F, [a,$@]), + + [$k] = lists:takewhile(F, [$k,$@]), + [$k,$l] = lists:takewhile(F, [$k,$l,$@,$@]), + [a] = lists:takewhile(F, [a,$@,$@,$@]), + + [] = lists:takewhile(F, [$@,a,$@,b]), + [] = lists:takewhile(F, [$@,$@,a,$@,b]), + [] = lists:takewhile(F, [$@,$@,$@,a,$@,b]), + + Long = lists:seq(1, 1024), + Shorter = lists:seq(1, 400), + + Shorter = lists:takewhile(fun(E) -> E =< 400 end, Long), + + ok. + keystore(doc) -> ["OTP-XXX."]; keystore(suite) -> []; @@ -382,6 +423,17 @@ keytake(Config) when is_list(Config) -> ?line false = lists:keytake(4, 2, L), ok. +%% Test lists:keyreplace/4. +keyreplace(Config) when is_list(Config) -> + [{new,42}] = lists:keyreplace(k, 1, [{k,1}], {new,42}), + [atom,{new,a,b}] = lists:keyreplace(k, 1, [atom,{k,1}], {new,a,b}), + [a,{x,y,z}] = lists:keyreplace(a, 5, [a,{x,y,z}], {no,use}), + + %% Error cases. + {'EXIT',_} = (catch lists:keyreplace(k, 1, [], not_tuple)), + {'EXIT',_} = (catch lists:keyreplace(k, 0, [], {a,b})), + ok. + merge(doc) -> ["merge functions"]; merge(suite) -> []; merge(Config) when is_list(Config) -> @@ -1625,8 +1677,7 @@ check_stab(L, U, S, US, SS) -> %%% Element 3 in the tuple is the position of the tuple in the list. biglist(N) -> - {A, B, C} = get_seed(), - random:seed(A, B, C), + rand:seed(exsplus), biglist(N, []). biglist(0, L) -> @@ -1642,8 +1693,7 @@ biglist(N, L) -> %%% No sequence number. ubiglist(N) -> - {A, B, C} = get_seed(), - random:seed(A, B, C), + rand:seed(exsplus), ubiglist(N, []). ubiglist(0, L) -> @@ -1667,8 +1717,7 @@ urandom_tuple(N, I) -> %%% sequence number. bigfunlist(N) -> - {A, B, C} = get_seed(), - random:seed(A, B, C), + rand:seed(exsplus), bigfunlist_1(N). bigfunlist_1(N) when N < 30000 -> % Now (R8) max 32000 different pids. @@ -1702,21 +1751,13 @@ make_fun(Pid) -> fun_pid(Fun) -> erlang:fun_info(Fun, pid). -get_seed() -> - case random:seed() of - undefined -> - erlang:timestamp(); - Tuple -> - Tuple - end. - random_tuple(N, Seq) -> R1 = randint(N), R2 = randint(N), {R1, R2, Seq}. randint(N) -> - trunc(random:uniform() * N). + trunc(rand:uniform() * N). %% The first "duplicate" is kept. no_dups([]) -> @@ -1778,8 +1819,7 @@ sort_loop_1(Pid) -> end. sloop(N) -> - {A, B, C} = get_seed(), - random:seed(A, B, C), + rand:seed(exsplus), sloop(N, #state{}). sloop(N, S) -> @@ -2326,19 +2366,25 @@ sublist_3_e(Config) when is_list(Config) -> -define(flatten_error1(X), ?line {'EXIT', _} = (catch lists:flatten(X))). -define(flatten_error2(X,Y), ?line {'EXIT', _} = (catch lists:flatten(X,Y))). -flatten_1(doc) -> ["flatten/1"]; -flatten_1(suite) -> []; +%% Test lists:flatten/1,2 and lists:flatlength/1. flatten_1(Config) when is_list(Config) -> - ?line [] = lists:flatten([]), - ?line [1,2] = lists:flatten([1,2]), - ?line [1,2] = lists:flatten([1,[2]]), - ?line [1,2] = lists:flatten([[1],2]), - ?line [1,2] = lists:flatten([[1],[2]]), - ?line [1,2] = lists:flatten([[1,2]]), - ?line [a,b,c,d] = lists:flatten([[a],[b,c,[d]]]), + [] = lists_flatten([]), + [1,2] = lists_flatten([1,2]), + [1,2] = lists_flatten([1,[2]]), + [1,2] = lists_flatten([[1],2]), + [1,2] = lists_flatten([[1],[2]]), + [1,2] = lists_flatten([[1,2]]), + [a,b,c,d] = lists_flatten([[a],[b,c,[d]]]), ok. +lists_flatten(List) -> + Flat = lists:flatten(List), + Flat = lists:flatten(List, []), + Len = lists:flatlength(List), + Len = length(Flat), + Flat. + flatten_1_e(doc) -> ["flatten/1 error cases"]; flatten_1_e(suite) -> []; flatten_1_e(Config) when is_list(Config) -> @@ -2351,11 +2397,11 @@ flatten_1_e(Config) when is_list(Config) -> %%% clear-cut. Right now, I think that any term should be allowed. %%% But I also wish this function didn't exist at all. -flatten_2(doc) -> ["flatten/2"]; -flatten_2(suite) -> []; +%% Test lists:flatten/2. flatten_2(Config) when is_list(Config) -> - ?line [] = lists:flatten([]), - ?line [a] = lists:flatten([a]), + [] = lists:flatten([], []), + [a] = lists:flatten([a], []), + [a,b,c,[no,flatten]] = lists:flatten([[a,[b,c]]], [[no,flatten]]), ok. flatten_2_e(doc) -> ["flatten/2 error cases"]; @@ -2651,3 +2697,40 @@ droplast(Config) when is_list(Config) -> ?line {'EXIT', {function_clause, _}} = (catch lists:droplast(x)), ok. + +%% Briefly test the common high-order functions to ensure they +%% are covered. +hof(Config) when is_list(Config) -> + L = [1,2,3], + [1,4,9] = lists:map(fun(N) -> N*N end, L), + [1,4,5,6] = lists:flatmap(fun(1) -> [1]; + (2) -> []; + (3) -> [4,5,6] + end, L), + [{1,[a]},{2,[b]},{3,[c]}] = + lists:keymap(fun(A) -> [A] end, 2, [{1,a},{2,b},{3,c}]), + + [1,3] = lists:filter(fun(N) -> N rem 2 =:= 1 end, L), + FilterMapFun = fun(1) -> true; + (2) -> {true,42}; + (3) -> false + end, + [1,42] = lists:filtermap(FilterMapFun, L), + [1,42] = lists:zf(FilterMapFun, L), + + [3,2,1] = lists:foldl(fun(E, A) -> [E|A] end, [], L), + [1,2,3] = lists:foldr(fun(E, A) -> [E|A] end, [], L), + {[1,4,9],[3,2,1]} = lists:mapfoldl(fun(E, A) -> + {E*E,[E|A]} + end, [], L), + {[1,4,9],[1,2,3]} = lists:mapfoldr(fun(E, A) -> + {E*E,[E|A]} + end, [], L), + + true = lists:any(fun(N) -> N =:= 2 end, L), + false = lists:any(fun(N) -> N =:= 42 end, L), + + true = lists:all(fun(N) -> is_integer(N) end, L), + false = lists:all(fun(N) -> N rem 2 =:= 0 end, L), + + ok. diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl index 36f009eec6..f7a6a38138 100644 --- a/lib/stdlib/test/proc_lib_SUITE.erl +++ b/lib/stdlib/test/proc_lib_SUITE.erl @@ -28,7 +28,7 @@ init_per_group/2,end_per_group/2, crash/1, sync_start_nolink/1, sync_start_link/1, spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, - hibernate/1, stop/1]). + hibernate/1, stop/1, t_format/1]). -export([ otp_6345/1, init_dont_hang/1]). -export([hib_loop/1, awaken/1]). @@ -51,7 +51,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [crash, {group, sync_start}, spawn_opt, hibernate, - {group, tickets}, stop]. + {group, tickets}, stop, t_format]. groups() -> [{tickets, [], [otp_6345, init_dont_hang]}, @@ -80,77 +80,123 @@ end_per_group(_GroupName, Config) -> crash(Config) when is_list(Config) -> error_logger:add_report_handler(?MODULE, self()), - Pid = proc_lib:spawn(?MODULE, sp1, []), - Pid ! die, - ?line Report = receive - {crash_report, Pid, Report0} -> Report0 - after 2000 -> test_server:fail(no_crash_report) - end, - ?line proc_lib:format(Report), - ?line [PidRep, []] = Report, - ?line {value, {initial_call,{?MODULE,sp1,[]}}} = - lists:keysearch(initial_call, 1, PidRep), - Self = self(), - ?line {value, {ancestors,[Self]}} = - lists:keysearch(ancestors, 1, PidRep), - ?line {value, {error_info,{exit,die,_StackTrace1}}} = - lists:keysearch(error_info, 1, PidRep), - - F = fun sp1/0, - Pid1 = proc_lib:spawn(node(), F), - Pid1 ! die, - ?line [PidRep1, []] = receive - {crash_report, Pid1, Report1} -> Report1 - after 2000 -> test_server:fail(no_crash_report) - end, - ?line {value, {initial_call,{Fmod,Fname,[]}}} = - lists:keysearch(initial_call, 1, PidRep1), - ?line {module,Fmod} = erlang:fun_info(F, module), - ?line {name,Fname} = erlang:fun_info(F, name), - ?line {value, {ancestors,[Self]}} = - lists:keysearch(ancestors, 1, PidRep1), - ?line {value, {error_info,{exit,die,_StackTrace2}}} = - lists:keysearch(error_info, 1, PidRep1), - - Pid2 = proc_lib:spawn(?MODULE, sp2, []), - test_server:sleep(100), - ?line {?MODULE,sp2,[]} = proc_lib:initial_call(Pid2), - ?line {?MODULE,sp2,0} = proc_lib:translate_initial_call(Pid2), - Pid2 ! die, - ?line [Pid2Rep, [{neighbour, LinkRep}]] = - receive - {crash_report, Pid2, Report2} -> Report2 - after 2000 -> test_server:fail(no_crash_report) - end, - ?line {value, {initial_call,{?MODULE,sp2,[]}}} = - lists:keysearch(initial_call, 1, Pid2Rep), - ?line {value, {ancestors,[Self]}} = - lists:keysearch(ancestors, 1, Pid2Rep), - ?line {value, {error_info,{exit,die,_StackTrace3}}} = - lists:keysearch(error_info, 1, Pid2Rep), - ?line {value, {initial_call,{?MODULE,sp1,[]}}} = - lists:keysearch(initial_call, 1, LinkRep), - %% Make sure that we don't get a crash report if a process %% terminates with reason 'shutdown' or reason {shutdown,Reason}. - ?line process_flag(trap_exit, true), - ?line Pid3 = proc_lib:spawn_link(erlang, apply, - [fun() -> exit(shutdown) end,[]]), + process_flag(trap_exit, true), + Pid0 = proc_lib:spawn_link(erlang, apply, + [fun() -> exit(shutdown) end,[]]), + Pid1 = proc_lib:spawn_link(erlang, apply, + [fun() -> exit({shutdown,{a,b,c}}) end,[]]), + + receive {'EXIT',Pid0,shutdown} -> ok end, + receive {'EXIT',Pid1,{shutdown,{a,b,c}}} -> ok end, + process_flag(trap_exit, false), + %% We expect any unexpected messages to be caught below, + %% so we don't have explicitly wait some time to be sure. + + %% Spawn export function. + Pid2 = proc_lib:spawn(?MODULE, sp1, []), + Pid2 ! die, + Exp2 = [{initial_call,{?MODULE,sp1,[]}}, + {ancestors,[self()]}, + {error_info,{exit,die,{stacktrace}}}], + analyse_crash(Pid2, Exp2, []), - ?line Pid4 = proc_lib:spawn_link(erlang, apply, - [fun() -> exit({shutdown,{a,b,c}}) end,[]]), + %% Spawn fun. + F = fun sp1/0, + Pid3 = proc_lib:spawn(node(), F), + Pid3 ! die, + {module,?MODULE} = erlang:fun_info(F, module), + {name,Fname} = erlang:fun_info(F, name), + Exp3 = [{initial_call,{?MODULE,Fname,[]}}, + {ancestors,[self()]}, + {error_info,{exit,die,{stacktrace}}}], + analyse_crash(Pid3, Exp3, []), - ?line receive {'EXIT',Pid3,shutdown} -> ok end, - ?line receive {'EXIT',Pid4,{shutdown,{a,b,c}}} -> ok end, - ?line process_flag(trap_exit, false), + %% Spawn function with neighbour. + Pid4 = proc_lib:spawn(?MODULE, sp2, []), + test_server:sleep(100), + {?MODULE,sp2,[]} = proc_lib:initial_call(Pid4), + {?MODULE,sp2,0} = proc_lib:translate_initial_call(Pid4), + Pid4 ! die, + Exp4 = [{initial_call,{?MODULE,sp2,[]}}, + {ancestors,[self()]}, + {error_info,{exit,die,{stacktrace}}}], + Links4 = [[{initial_call,{?MODULE,sp1,[]}}, + {ancestors,[Pid4,self()]}]], + analyse_crash(Pid4, Exp4, Links4), + + %% Make sure that we still get a crash report if the + %% process dictionary have been tampered with. + + Pid5 = proc_lib:spawn(erlang, apply, + [fun() -> + erase(), + exit(abnormal) + end,[]]), + Exp5 = [{initial_call,absent}, + {ancestors,[]}, + {error_info,{exit,abnormal,{stacktrace}}}], + analyse_crash(Pid5, Exp5, []), + + error_logger:delete_report_handler(?MODULE), + ok. +analyse_crash(Pid, Expected0, ExpLinks) -> + Expected = [{pid,Pid}|Expected0], receive - Any -> - ?line ?t:fail({unexpected_message,Any}) - after 2000 -> - ok - end. + {crash_report, Pid, Report} -> + _ = proc_lib:format(Report), %Smoke test. + [Crash,Links] = Report, + analyse_crash_1(Expected, Crash), + analyse_links(ExpLinks, Links); + Unexpected -> + io:format("~p\n", [Unexpected]), + test_server:fail(unexpected_message) + after 5000 -> + test_server:fail(no_crash_report) + end. +analyse_links([H|Es], [{neighbour,N}|Links]) -> + analyse_crash_1(H, N), + analyse_links(Es, Links); +analyse_links([], []) -> + ok. + +analyse_crash_1([{Key,absent}|T], Report) -> + false = lists:keymember(Key, 1, Report), + analyse_crash_1(T, Report); +analyse_crash_1([{Key,Pattern}|T], Report) -> + case lists:keyfind(Key, 1, Report) of + false -> + io:format("~p", [Report]), + test_server:fail({missing_key,Key}); + {Key,Info} -> + try + match_info(Pattern, Info) + catch + no_match -> + io:format("key: ~p", [Key]), + io:format("pattern: ~p", [Pattern]), + io:format("actual: ~p", [Report]), + test_server:fail(no_match) + end, + analyse_crash_1(T, Report) + end; +analyse_crash_1([], _Report) -> + []. + +match_info(T, T) -> + ok; +match_info({stacktrace}, Stk) when is_list(Stk) -> + ok; +match_info([H1|T1], [H2|T2]) -> + match_info(H1, H2), + match_info(T1, T2); +match_info(Tuple1, Tuple2) when tuple_size(Tuple1) =:= tuple_size(Tuple2) -> + match_info(tuple_to_list(Tuple1), tuple_to_list(Tuple2)); +match_info(_, _) -> + throw(no_match). sync_start_nolink(Config) when is_list(Config) -> _Pid = spawn_link(?MODULE, sp5, [self()]), @@ -301,6 +347,7 @@ hibernate(Config) when is_list(Config) -> ?line {value,{initial_call,{?MODULE,hib_loop,[_]}}} = lists:keysearch(initial_call, 1, Report), + error_logger:delete_report_handler(?MODULE), ok. hib_loop(LoopData) -> @@ -364,7 +411,7 @@ init_dont_hang(Config) when is_list(Config) -> end. init_dont_hang_init(_Parent) -> - 1 = 2. + error(bad_init). %% Test proc_lib:stop/1,3 stop(_Config) -> @@ -448,10 +495,55 @@ stop(_Config) -> ok. system_terminate(crash,_Parent,_Deb,_State) -> - 1 = 2; + error({badmatch,2}); system_terminate(Reason,_Parent,_Deb,_State) -> exit(Reason). + +t_format(_Config) -> + error_logger:tty(false), + try + t_format() + after + error_logger:tty(true) + end, + ok. + +t_format() -> + error_logger:add_report_handler(?MODULE, self()), + Pid = proc_lib:spawn(fun t_format_looper/0), + HugeData = gb_sets:from_list(lists:seq(1, 100)), + Pid ! {die,HugeData}, + Report = receive + {crash_report, Pid, Report0} -> Report0 + end, + Usz = do_test_format(Report, unlimited), + Tsz = do_test_format(Report, 20), + + if + Tsz >= Usz -> + ?t:fail(); + true -> + ok + end, + + ok. + +do_test_format(Report, Depth) -> + io:format("*** Depth = ~p", [Depth]), + S0 = proc_lib:format(Report, latin1, Depth), + S = lists:flatten(S0), + io:put_chars(S), + length(S). + +t_format_looper() -> + receive + {die,Data} -> + exit(Data); + _ -> + t_format_looper() + end. + %%----------------------------------------------------------------- %% The error_logger handler used. %%----------------------------------------------------------------- diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index 72216bfa0d..52fdb69b73 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -74,6 +74,7 @@ otp_5644/1, otp_5195/1, otp_6038_bug/1, otp_6359/1, otp_6562/1, otp_6590/1, otp_6673/1, otp_6964/1, otp_7114/1, otp_7238/1, otp_7232/1, otp_7552/1, otp_6674/1, otp_7714/1, otp_11758/1, + otp_12946/1, manpage/1, @@ -143,7 +144,7 @@ groups() -> {tickets, [], [otp_5644, otp_5195, otp_6038_bug, otp_6359, otp_6562, otp_6590, otp_6673, otp_6964, otp_7114, otp_7232, - otp_7238, otp_7552, otp_6674, otp_7714, otp_11758]}, + otp_7238, otp_7552, otp_6674, otp_7714, otp_11758, otp_12946]}, {compat, [], [backward, forward]}]. init_per_suite(Config) -> @@ -7154,6 +7155,18 @@ otp_6674(Config) when is_list(Config) -> ?line run(Config, Ts). +otp_12946(doc) -> + ["Syntax error."]; +otp_12946(suite) -> []; +otp_12946(Config) when is_list(Config) -> + Text = + <<"-export([init/0]). + init() -> + ok. + y">>, + {errors,[{4,erl_parse,_}],[]} = compile_file(Config, Text, []), + ok. + manpage(doc) -> "Examples from qlc(3)."; manpage(suite) -> []; diff --git a/lib/stdlib/test/queue_SUITE.erl b/lib/stdlib/test/queue_SUITE.erl index c965a8b218..5165ac3a3a 100644 --- a/lib/stdlib/test/queue_SUITE.erl +++ b/lib/stdlib/test/queue_SUITE.erl @@ -470,7 +470,7 @@ oops(suite) -> oops(Config) when is_list(Config) -> ?line N = 3142, ?line Optab = optab(), - ?line Seed0 = random:seed0(), + ?line Seed0 = rand:seed(exsplus, {1,2,4}), ?line {Is,Seed} = random_list(N, tuple_size(Optab), Seed0, []), ?line io:format("~p ", [Is]), ?line QA = queue:new(), @@ -562,20 +562,20 @@ args([], _, Seed, R) -> args([q|Ts], [Q|Qs]=Qss, Seed, R) -> args(Ts, if Qs =:= [] -> Qss; true -> Qs end, Seed, [Q|R]); args([l|Ts], Qs, Seed0, R) -> - {N,Seed1} = random:uniform_s(17, Seed0), + {N,Seed1} = rand:uniform_s(17, Seed0), {L,Seed} = random_list(N, 4711, Seed1, []), args(Ts, Qs, Seed, [L|R]); args([t|Ts], Qs, Seed0, R) -> - {T,Seed} = random:uniform_s(4711, Seed0), + {T,Seed} = rand:uniform_s(4711, Seed0), args(Ts, Qs, Seed, [T|R]); args([n|Ts], Qs, Seed0, R) -> - {N,Seed} = random:uniform_s(17, Seed0), + {N,Seed} = rand:uniform_s(17, Seed0), args(Ts, Qs, Seed, [N|R]). random_list(0, _, Seed, R) -> {R,Seed}; random_list(N, M, Seed0, R) -> - {X,Seed} = random:uniform_s(M, Seed0), + {X,Seed} = rand:uniform_s(M, Seed0), random_list(N-1, M, Seed, [X|R]). call(Func, As) -> diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl index b03caebe91..03b5ce1a25 100644 --- a/lib/stdlib/test/rand_SUITE.erl +++ b/lib/stdlib/test/rand_SUITE.erl @@ -25,7 +25,9 @@ ]). -export([interval_int/1, interval_float/1, seed/1, - api_eq/1, reference/1, basic_stats/1, + api_eq/1, reference/1, + basic_stats_uniform_1/1, basic_stats_uniform_2/1, + basic_stats_normal/1, plugin/1, measure/1 ]). @@ -51,11 +53,13 @@ all() -> [seed, interval_int, interval_float, api_eq, reference, - basic_stats, + {group, basic_stats}, plugin, measure ]. -groups() -> []. +groups() -> + [{basic_stats, [parallel], + [basic_stats_uniform_1, basic_stats_uniform_2, basic_stats_normal]}]. init_per_suite(Config) -> Config. end_per_suite(_Config) -> ok. @@ -122,6 +126,9 @@ seed_1(Alg) -> false = (S1 =:= rand:seed_s(Alg)), %% Negative integers works _ = rand:seed_s(Alg, {-1,-1,-1}), + %% Check that export_seed/1 returns 'undefined' if there is no seed + erase(rand_seed), + undefined = rand:export_seed(), %% Other term do not work {'EXIT', _} = (catch rand:seed_s(foobar, os:timestamp())), @@ -291,14 +298,19 @@ gen(_, _, Acc) -> lists:reverse(Acc). %% The algorithms must have good properties to begin with %% -basic_stats(doc) -> ["Check that the algorithms generate sound values."]; -basic_stats(suite) -> []; -basic_stats(Config) when is_list(Config) -> - io:format("Testing uniform~n",[]), +%% Check that the algorithms generate sound values. + +basic_stats_uniform_1(Config) when is_list(Config) -> [basic_uniform_1(?LOOP, rand:seed_s(Alg), 0.0, array:new([{default, 0}])) || Alg <- algs()], + ok. + +basic_stats_uniform_2(Config) when is_list(Config) -> [basic_uniform_2(?LOOP, rand:seed_s(Alg), 0, array:new([{default, 0}])) || Alg <- algs()], + ok. + +basic_stats_normal(Config) when is_list(Config) -> io:format("Testing normal~n",[]), [basic_normal_1(?LOOP, rand:seed_s(Alg), 0, 0) || Alg <- algs()], ok. diff --git a/lib/stdlib/test/random_iolist.erl b/lib/stdlib/test/random_iolist.erl index 9a0f034e72..6da7da04de 100644 --- a/lib/stdlib/test/random_iolist.erl +++ b/lib/stdlib/test/random_iolist.erl @@ -36,7 +36,7 @@ run2(Iter,Fun1,Fun2) -> compare2(Iter,Fun1,Fun2). random_byte() -> - random:uniform(256) - 1. + rand:uniform(256) - 1. random_list(0,Acc) -> Acc; @@ -45,7 +45,7 @@ random_list(N,Acc) -> random_binary(N) -> B = list_to_binary(random_list(N,[])), - case {random:uniform(2),size(B)} of + case {rand:uniform(2),size(B)} of {2,M} when M > 1 -> S = M-1, <<_:3,C:S/binary,_:5>> = B, @@ -57,7 +57,7 @@ random_list(N) -> random_list(N,[]). front() -> - case random:uniform(10) of + case rand:uniform(10) of 10 -> false; _ -> @@ -65,7 +65,7 @@ front() -> end. any_type() -> - case random:uniform(10) of + case rand:uniform(10) of 1 -> list; 2 -> @@ -77,7 +77,7 @@ any_type() -> end. tail_type() -> - case random:uniform(5) of + case rand:uniform(5) of 1 -> list; 2 -> @@ -90,9 +90,9 @@ random_length(N) -> UpperLimit = 255, case N of M when M > UpperLimit -> - random:uniform(UpperLimit+1) - 1; + rand:uniform(UpperLimit+1) - 1; _ -> - random:uniform(N+1) - 1 + rand:uniform(N+1) - 1 end. random_iolist(0,Acc) -> @@ -139,7 +139,7 @@ random_iolist(N) -> standard_seed() -> - random:seed(1201,855653,380975). + rand:seed(exsplus, {1201,855653,380975}). do_comp(List,F1,F2) -> X = F1(List), diff --git a/lib/stdlib/test/random_unicode_list.erl b/lib/stdlib/test/random_unicode_list.erl index ecafe42318..3bc86a8430 100644 --- a/lib/stdlib/test/random_unicode_list.erl +++ b/lib/stdlib/test/random_unicode_list.erl @@ -85,7 +85,7 @@ int_to_utf32_little(I) -> id(I) -> I. random_char() -> - case random:uniform(16#10FFFF+1) - 1 of + case rand:uniform(16#10FFFF+1) - 1 of X when X >= 16#D800, X =< 16#DFFF -> random_char(); @@ -116,13 +116,13 @@ random_binary(N,Enc) -> int_to(Enc,X) end, L)), - case {random:uniform(3),size(B)} of + case {rand:uniform(3),size(B)} of {2,M} when M > 1 -> B2 = id(<<1:3,B/binary,1:5>>), <<_:3,C:M/binary,_:5>> = B2, C; {3,M} when M > 1 -> - X = random:uniform(M+1)-1, + X = rand:uniform(M+1)-1, <<B1:X/binary,B2/binary>> = B, [B1,B2]; _ -> @@ -132,7 +132,7 @@ random_list(N) -> random_list(N,[]). front() -> - case random:uniform(10) of + case rand:uniform(10) of 10 -> false; _ -> @@ -140,7 +140,7 @@ front() -> end. any_type() -> - case random:uniform(10) of + case rand:uniform(10) of 1 -> list; 2 -> @@ -152,7 +152,7 @@ any_type() -> end. tail_type() -> - case random:uniform(5) of + case rand:uniform(5) of 1 -> list; 2 -> @@ -165,9 +165,9 @@ random_length(N) -> UpperLimit = 255, case N of M when M > UpperLimit -> - random:uniform(UpperLimit+1) - 1; + rand:uniform(UpperLimit+1) - 1; _ -> - random:uniform(N+1) - 1 + rand:uniform(N+1) - 1 end. random_unicode_list(0,Acc,_Enc) -> @@ -214,7 +214,7 @@ random_unicode_list(N,Enc) -> standard_seed() -> - random:seed(1201,855653,380975). + rand:seed(exsplus, {1201,855653,380975}). do_comp(List,F1,F2) -> X = F1(List), diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl index b8c20d9745..d78d6153da 100644 --- a/lib/stdlib/test/re_SUITE.erl +++ b/lib/stdlib/test/re_SUITE.erl @@ -28,7 +28,7 @@ pcre_compile_workspace_overflow/1,re_infinite_loop/1, re_backwards_accented/1,opt_dupnames/1,opt_all_names/1,inspect/1, opt_no_start_optimize/1,opt_never_utf/1,opt_ucp/1, - match_limit/1,sub_binaries/1]). + match_limit/1,sub_binaries/1,copt/1]). -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -319,32 +319,26 @@ replace_return(doc) -> ["Tests return options of replace together with global searching"]; replace_return(Config) when is_list(Config) -> Dog = ?t:timetrap(?t:minutes(3)), - ?line {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")), - ?line <<"nasse">> = re:replace(<<"nisse">>,"i","a",[{return,binary}]), - ?line <<"ABCÅXABCXA">> = re:replace("ABC\305abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary}]), - - ?line [<<"ABCÅ">>, - <<"X">>, - <<"ABC">>, - <<"X">> | - <<"A">> ] = - re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,iodata}]), - ?line "ABCÅXABCXA" = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,list},unicode]), - ?line <<65,66,67,195,133,88,65,66,67,88,65>> = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary},unicode]), - ?line <<65,66,67,195,133,88,65,66,67,97,98,99,100,65>> = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[{return,binary},unicode]), - ?line <<"iXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\9X",[{return,binary}]), - ?line <<"jXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\10X",[{return,binary}]), - ?line <<"Xk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\11X",[{return,binary}]), - ?line <<"9X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g9X",[{return,binary}]), - ?line <<"0X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g10X",[{return,binary}]), - ?line <<"X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g11X",[{return,binary}]), - ?line <<"971">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{9}7",[{return,binary}]), - ?line <<"071">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{10}7",[{return,binary}]), - ?line <<"71">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{11}7",[{return,binary}]), - ?line "a\x{400}bcX" = re:replace("a\x{400}bcd","d","X",[global,{return,list},unicode]), - ?line <<"a",208,128,"bcX">> = re:replace("a\x{400}bcd","d","X",[global,{return,binary},unicode]), - ?line "a\x{400}bcd" = re:replace("a\x{400}bcd","Z","X",[global,{return,list},unicode]), - ?line <<"a",208,128,"bcd">> = re:replace("a\x{400}bcd","Z","X",[global,{return,binary},unicode]), + {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")), + ok = replacetest(<<"nisse">>,"i","a",[{return,binary}],<<"nasse">>), + ok = replacetest("ABC\305abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary}],<<"ABCÅXABCXA">>), + ok = replacetest("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,iodata}],[<<"ABCÅ">>,<<"X">>,<<"ABC">>,<<"X">>|<<"A">>]), + ok = replacetest("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,list},unicode],"ABCÅXABCXA"), + ok = replacetest("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary},unicode],<<65,66,67,195,133,88,65,66,67,88,65>>), + ok = replacetest("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[{return,binary},unicode],<<65,66,67,195,133,88,65,66,67,97,98,99,100,65>>), + ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\9X",[{return,binary}],<<"iXk">>), + ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\10X",[{return,binary}],<<"jXk">>), + ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\11X",[{return,binary}],<<"Xk">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g9X",[{return,binary}],<<"9X1">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g10X",[{return,binary}],<<"0X1">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g11X",[{return,binary}],<<"X1">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{9}7",[{return,binary}],<<"971">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{10}7",[{return,binary}],<<"071">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{11}7",[{return,binary}],<<"71">>), + ok = replacetest("a\x{400}bcd","d","X",[global,{return,list},unicode],"a\x{400}bcX"), + ok = replacetest("a\x{400}bcd","d","X",[global,{return,binary},unicode],<<"a",208,128,"bcX">>), + ok = replacetest("a\x{400}bcd","Z","X",[global,{return,list},unicode],"a\x{400}bcd"), + ok = replacetest("a\x{400}bcd","Z","X",[global,{return,binary},unicode],<<"a",208,128,"bcd">>), ?t:timetrap_cancel(Dog), ok. @@ -389,6 +383,35 @@ crtest(Subject,RE,Options,true,Result) -> error end. +replacetest(Subject,RE,Replacement,Options,Result) -> + Result = re:replace(Subject,RE,Replacement,Options), + {CompileOptions,ReplaceOptions} = lists:partition(fun copt/1, Options), + {ok,MP} = re:compile(RE,CompileOptions), + Result = re:replace(Subject,MP,Replacement,ReplaceOptions), + ok. + +splittest(Subject,RE,Options,Result) -> + Result = re:split(Subject,RE,Options), + {CompileOptions,SplitOptions} = lists:partition(fun copt/1, Options), + {ok,MP} = re:compile(RE,CompileOptions), + Result = re:split(Subject,MP,SplitOptions), + ok. + +copt(caseless) -> true; +copt(no_start_optimize) -> true; +copt(never_utf) -> true; +copt(ucp) -> true; +copt(dollar_endonly) -> true; +copt(dotall) -> true; +copt(extended) -> true; +copt(firstline) -> true; +copt(multiline) -> true; +copt(no_auto_capture) -> true; +copt(dupnames) -> true; +copt(ungreedy) -> true; +copt(unicode) -> true; +copt(_) -> false. + split_autogen(doc) -> ["Test split with autogenerated erlang module"]; split_autogen(Config) when is_list(Config) -> @@ -401,43 +424,23 @@ split_options(doc) -> ["Test special options to split."]; split_options(Config) when is_list(Config) -> Dog = ?t:timetrap(?t:minutes(1)), - ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]] = re:split("a b c ","( )",[group,trim]), - ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]] = re:split("a b c ","( )",[group,{parts,0}]), - ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]] = - re:split("a b c ","( )",[{parts,infinity},group]), - ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]] = - re:split("a b c ","( )",[group]), - ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>], - [<<"c">>,<<" ">>],[<<"d">>,<<" ">>]] = - re:split(" a b c d ","( +)",[group,trim]), - ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>], - [<<"c">>,<<" ">>],[<<"d">>,<<" ">>]] = - re:split(" a b c d ","( +)",[{parts,0},group]), - ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>], - [<<"c">>,<<" ">>],[<<"d">>,<<" ">>],[<<>>]] = - re:split(" a b c d ","( +)",[{parts,infinity},group]), - ?line [[<<"a">>,<<" ">>],[<<"b c d">>]] = - re:split("a b c d","( +)",[{parts,2},group]), - ?line [[[967]," "],["b c d"]] = - re:split([967]++" b c d","( +)", - [{parts,2},group,{return,list},unicode]), - ?line [[<<207,135>>,<<" ">>],[<<"b c d">>]] = - re:split([967]++" b c d","( +)", - [{parts,2},group,{return,binary},unicode]), - ?line {'EXIT',{badarg,_}} = - (catch re:split([967]++" b c d","( +)", - [{parts,2},group,{return,binary}])), - ?line {'EXIT',{badarg,_}} = - (catch re:split("a b c d","( +)",[{parts,-2}])), - ?line {'EXIT',{badarg,_}} = - (catch re:split("a b c d","( +)",[{parts,banan}])), - ?line {'EXIT',{badarg,_}} = - (catch re:split("a b c d","( +)",[{capture,all}])), - ?line {'EXIT',{badarg,_}} = - (catch re:split("a b c d","( +)",[{capture,[],binary}])), + ok = splittest("a b c ","( )",[group,trim],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]]), + ok = splittest("a b c ","( )",[group,{parts,0}],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]]), + ok = splittest("a b c ","( )",[{parts,infinity},group],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]]), + ok = splittest("a b c ","( )",[group],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]]), + ok = splittest(" a b c d ","( +)",[group,trim],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>]]), + ok = splittest(" a b c d ","( +)",[{parts,0},group],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>]]), + ok = splittest(" a b c d ","( +)",[{parts,infinity},group],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>],[<<>>]]), + ok = splittest("a b c d","( +)",[{parts,2},group],[[<<"a">>,<<" ">>],[<<"b c d">>]]), + ok = splittest([967]++" b c d","( +)",[{parts,2},group,{return,list},unicode],[[[967]," "],["b c d"]]), + ok = splittest([967]++" b c d","( +)",[{parts,2},group,{return,binary},unicode],[[<<207,135>>,<<" ">>],[<<"b c d">>]]), + {'EXIT',{badarg,_}} = (catch re:split([967]++" b c d","( +)",[{parts,2},group,{return,binary}])), + {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{parts,-2}])), + {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{parts,banan}])), + {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{capture,all}])), + {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{capture,[],binary}])), % Parts 0 is equal to no parts specification (implicit strip) - ?line ["a"," ","b"," ","c"," ","d"] = - re:split("a b c d","( *)",[{parts,0},{return,list}]), + ok = splittest("a b c d","( *)",[{parts,0},{return,list}],["a"," ","b"," ","c"," ","d"]), ?t:timetrap_cancel(Dog), ok. diff --git a/lib/stdlib/test/run_pcre_tests.erl b/lib/stdlib/test/run_pcre_tests.erl index 1fdc777470..b7d1df39b8 100644 --- a/lib/stdlib/test/run_pcre_tests.erl +++ b/lib/stdlib/test/run_pcre_tests.erl @@ -1083,7 +1083,7 @@ dumponesplit(F,{RE,Line,O,TS}) -> %% Generate replacement tests from indatafile, %% you will need perl on the machine gen_repl_test(OneFile) -> - random:seed(1219,687731,62804), + rand:seed(exsplus, {1219,687731,62804}), {ok,Bin} = file:read_file(OneFile), Lines = splitfile(0,Bin,1), Structured = stru(Lines), @@ -1237,15 +1237,15 @@ btr(_) -> ranchar() -> - case random:uniform(10) of + case rand:uniform(10) of 9 -> $&; 10 -> <<"\\1">>; N when N < 5 -> - random:uniform($Z-$A)+$A-1; + rand:uniform($Z-$A)+$A-1; M when M < 9 -> - random:uniform($z-$a)+$a-1 + rand:uniform($z-$a)+$a-1 end. ranstring() -> - iolist_to_binary([ranchar() || _ <- lists:duplicate(random:uniform(20),0) ]). + iolist_to_binary([ranchar() || _ <- lists:duplicate(rand:uniform(20),0) ]). diff --git a/lib/stdlib/test/select_SUITE.erl b/lib/stdlib/test/select_SUITE.erl index ead64ffc75..6796676179 100644 --- a/lib/stdlib/test/select_SUITE.erl +++ b/lib/stdlib/test/select_SUITE.erl @@ -212,11 +212,10 @@ init_random(Config) -> {ok,[X]} -> X; _ -> - {A,B,C} = erlang:timestamp(), - random:seed(A,B,C), - get(random_seed) + rand:seed(exsplus), + rand:export_seed() end, - put(random_seed,Seed), + rand:seed(Seed), {ok, F} = file:open(filename:join([WriteDir, "last_random_seed2.txt"]), [write]), io:format(F,"~p. ~n",[Seed]), @@ -224,11 +223,11 @@ init_random(Config) -> ok. create_random_key(N,Type) -> - gen_key(random:uniform(N),Type). + gen_key(rand:uniform(N),Type). create_pb_key(N,list) -> - X = random:uniform(N), - case random:uniform(4) of + X = rand:uniform(N), + case rand:uniform(4) of 3 -> {[X, X+1, '_'], fun([Z,Z1,P1]) -> [Z,Z1,P1] =:= [X,X+1,P1] end}; 2 -> {[X, '_', '_'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end}; @@ -237,14 +236,14 @@ create_pb_key(N,list) -> _ -> {[X, '$1', '$2'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end} end; create_pb_key(N, tuple) -> - X = random:uniform(N), - case random:uniform(2) of + X = rand:uniform(N), + case rand:uniform(2) of 1 -> {{X, X+1, '$1'},fun({Z,Z1,P1}) -> {Z,Z1,P1} =:= {X,X+1,P1} end}; _ -> {{X, '$1', '$2'},fun({Z,P1,P2}) -> {Z,P1,P2} =:= {X,P1,P2} end} end; create_pb_key(N, complex) -> - X = random:uniform(N), - case random:uniform(2) of + X = rand:uniform(N), + case rand:uniform(2) of 1 -> {{[X, X+1], '$1'}, fun({[Z,Z1],P1}) -> {[Z,Z1],P1} =:= {[X,X+1],P1} end}; _ -> {{[X, '$1'], '$2'},fun({[Z,P1],P2}) -> diff --git a/lib/stdlib/test/sets_SUITE.erl b/lib/stdlib/test/sets_SUITE.erl index 972a812072..e7fc5595a9 100644 --- a/lib/stdlib/test/sets_SUITE.erl +++ b/lib/stdlib/test/sets_SUITE.erl @@ -107,9 +107,9 @@ add_element_del([H|T], M, S, Del, []) -> add_element_del(T, M, M(add_element, {H,S}), Del, [H]); add_element_del([H|T], M, S0, Del, Inserted) -> S1 = M(add_element, {H,S0}), - case random:uniform(3) of + case rand:uniform(3) of 1 -> - OldEl = lists:nth(random:uniform(length(Inserted)), Inserted), + OldEl = lists:nth(rand:uniform(length(Inserted)), Inserted), S = M(del_element, {OldEl,S1}), add_element_del(T, M, S, [OldEl|Del], [H|Inserted]); _ -> @@ -438,7 +438,7 @@ iterate_1(M) -> M(empty, []). iterate_2(M) -> - random:seed(1, 2, 42), + rand:seed(exsplus, {1,2,42}), iter_set(M, 1000). iter_set(_M, 0) -> @@ -447,7 +447,7 @@ iter_set(M, N) -> L = [I || I <- lists:seq(1, N)], T = M(from_list, L), L = lists:reverse(iterate_set(M, T)), - R = random:uniform(N), + R = rand:uniform(N), S = lists:reverse(iterate_set(M, R, T)), S = [E || E <- L, E >= R], iter_set(M, N-1). @@ -481,7 +481,7 @@ sets_mods() -> test_all(Tester) -> Res = [begin - random:seed(1, 2, 42), + rand:seed(exsplus, {1,2,42}), S = Tester(M), {M(size, S),lists:sort(M(to_list, S))} end || M <- sets_mods()], @@ -492,7 +492,7 @@ test_all([{Low,High}|T], Tester) -> test_all([Sz|T], Tester) when is_integer(Sz) -> List = rnd_list(Sz), Res = [begin - random:seed(19, 2, Sz), + rand:seed(exsplus, {19,2,Sz}), S = Tester(List, M), {M(size, S),lists:sort(M(to_list, S))} end || M <- sets_mods()], @@ -512,10 +512,10 @@ rnd_list(Sz) -> rnd_list_1(Sz, []). atomic_rnd_term() -> - case random:uniform(3) of - 1 -> list_to_atom(integer_to_list($\s+random:uniform(94))++"rnd"); - 2 -> random:uniform(); - 3 -> random:uniform(50)-37 + case rand:uniform(3) of + 1 -> list_to_atom(integer_to_list($\s+rand:uniform(94))++"rnd"); + 2 -> rand:uniform(); + 3 -> rand:uniform(50)-37 end. rnd_list_1(0, Acc) -> Acc; @@ -543,7 +543,7 @@ remove_some(List0, P) -> end. remove_some([H|T], P, Acc) -> - case random:uniform() of + case rand:uniform() of F when F < P -> %Remove. remove_some(T, P, Acc); _ -> diff --git a/lib/stdlib/test/timer_SUITE.erl b/lib/stdlib/test/timer_SUITE.erl index 057d82fb65..10dcfad76f 100644 --- a/lib/stdlib/test/timer_SUITE.erl +++ b/lib/stdlib/test/timer_SUITE.erl @@ -80,8 +80,6 @@ report_result(Error) -> ?line test_server:fail(Error). big_test(N) -> C = start_collect(), system_time(), system_time(), system_time(), - random:seed(erlang:timestamp()), - random:uniform(100),random:uniform(100),random:uniform(100), big_loop(C, N, []), @@ -127,17 +125,17 @@ big_loop(C, N, Pids) -> after 0 -> %% maybe start an interval timer test - Pids1 = maybe_start_i_test(Pids, C, random:uniform(4)), + Pids1 = maybe_start_i_test(Pids, C, rand:uniform(4)), %% start 1-4 "after" tests - Pids2 = start_after_test(Pids1, C, random:uniform(4)), + Pids2 = start_after_test(Pids1, C, rand:uniform(4)), %%Pids2=Pids1, %% wait a little while - timer:sleep(random:uniform(200)*3), + timer:sleep(rand:uniform(200)*3), %% spawn zero, one or two nrev to get some load ;-/ - Pids3 = start_nrev(Pids2, random:uniform(100)), + Pids3 = start_nrev(Pids2, rand:uniform(100)), big_loop(C, N-1, Pids3) end. @@ -148,20 +146,20 @@ start_nrev(Pids, N) when N < 25 -> start_nrev(Pids, N) when N < 75 -> [spawn_link(timer_SUITE, do_nrev, [1])|Pids]; start_nrev(Pids, _N) -> - NrevPid1 = spawn_link(timer_SUITE, do_nrev, [random:uniform(1000)*10]), + NrevPid1 = spawn_link(timer_SUITE, do_nrev, [rand:uniform(1000)*10]), NrevPid2 = spawn_link(timer_SUITE, do_nrev, [1]), [NrevPid1,NrevPid2|Pids]. start_after_test(Pids, C, 1) -> - TO1 = random:uniform(100)*47, + TO1 = rand:uniform(100)*47, [s_a_t(C, TO1)|Pids]; start_after_test(Pids, C, 2) -> - TO1 = random:uniform(100)*47, - TO2 = TO1 div random:uniform(3) + 101, + TO1 = rand:uniform(100)*47, + TO2 = TO1 div rand:uniform(3) + 101, [s_a_t(C, TO1),s_a_t(C, TO2)|Pids]; start_after_test(Pids, C, N) -> - TO1 = random:uniform(100)*47, + TO1 = rand:uniform(100)*47, start_after_test([s_a_t(C, TO1)|Pids], C, N-1). s_a_t(C, TimeOut) -> @@ -187,8 +185,8 @@ a_t(C, TimeOut) -> maybe_start_i_test(Pids, C, 1) -> %% ok do it - TOI = random:uniform(53)*49, - CountI = random:uniform(10) + 3, % at least 4 times + TOI = rand:uniform(53)*49, + CountI = rand:uniform(10) + 3, % at least 4 times [spawn_link(timer_SUITE, i_t, [C, TOI, CountI])|Pids]; maybe_start_i_test(Pids, _C, _) -> Pids. diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl index 9d48d092cf..c275053691 100644 --- a/lib/stdlib/test/zip_SUITE.erl +++ b/lib/stdlib/test/zip_SUITE.erl @@ -556,9 +556,10 @@ unzip_to_binary(doc) -> unzip_to_binary(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), + WorkDir = filename:join(PrivDir, "unzip_to_binary"), + _ = file:make_dir(WorkDir), - delete_all_in(PrivDir), - file:set_cwd(PrivDir), + ok = file:set_cwd(WorkDir), Long = filename:join(DataDir, "abc.zip"), %% Unzip a zip file into a binary @@ -569,7 +570,7 @@ unzip_to_binary(Config) when is_list(Config) -> end, FBList), %% Make sure no files created in cwd - {ok,[]} = file:list_dir(PrivDir), + {ok,[]} = file:list_dir(WorkDir), ok. @@ -578,8 +579,10 @@ zip_to_binary(doc) -> zip_to_binary(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), - delete_all_in(PrivDir), - file:set_cwd(PrivDir), + WorkDir = filename:join(PrivDir, "zip_to_binary"), + _ = file:make_dir(WorkDir), + + file:set_cwd(WorkDir), FileName = "abc.txt", ZipName = "t.zip", FilePath = filename:join(DataDir, FileName), @@ -589,7 +592,7 @@ zip_to_binary(Config) when is_list(Config) -> {ok, {ZipName, ZipB}} = zip:zip(ZipName, [FileName], [memory]), %% Make sure no files created in cwd - {ok,[FileName]} = file:list_dir(PrivDir), + {ok,[FileName]} = file:list_dir(WorkDir), %% Zip to a file {ok, ZipName} = zip:zip(ZipName, [FileName]), @@ -696,11 +699,6 @@ do_delete_files([Item|Rest], Cnt) -> end, do_delete_files(Rest, Cnt + DelCnt). -delete_all_in(Dir) -> - {ok, Files} = file:list_dir(Dir), - delete_files(lists:map(fun(F) -> filename:join(Dir,F) end, - Files)). - compress_control(doc) -> ["Test control of which files that should be compressed"]; compress_control(suite) -> []; |