diff options
Diffstat (limited to 'lib/stdlib/test')
-rw-r--r-- | lib/stdlib/test/Makefile | 2 | ||||
-rw-r--r-- | lib/stdlib/test/binary_module_SUITE.erl | 1323 | ||||
-rw-r--r-- | lib/stdlib/test/binref.erl | 588 | ||||
-rw-r--r-- | lib/stdlib/test/dummy1_h.erl | 15 | ||||
-rw-r--r-- | lib/stdlib/test/epp_SUITE.erl | 142 | ||||
-rw-r--r-- | lib/stdlib/test/erl_lint_SUITE.erl | 235 | ||||
-rw-r--r-- | lib/stdlib/test/erl_pp_SUITE.erl | 216 | ||||
-rw-r--r-- | lib/stdlib/test/erl_scan_SUITE.erl | 213 | ||||
-rw-r--r-- | lib/stdlib/test/escript_SUITE.erl | 406 | ||||
-rw-r--r-- | lib/stdlib/test/ets_SUITE.erl | 71 | ||||
-rw-r--r-- | lib/stdlib/test/gen_event_SUITE.erl | 59 | ||||
-rw-r--r-- | lib/stdlib/test/gen_fsm_SUITE.erl | 67 | ||||
-rw-r--r-- | lib/stdlib/test/gen_server_SUITE.erl | 115 | ||||
-rw-r--r-- | lib/stdlib/test/io_proto_SUITE.erl | 1 | ||||
-rw-r--r-- | lib/stdlib/test/qlc_SUITE.erl | 15 | ||||
-rw-r--r-- | lib/stdlib/test/re_SUITE.erl | 26 | ||||
-rw-r--r-- | lib/stdlib/test/timer_simple_SUITE.erl | 18 | ||||
-rw-r--r-- | lib/stdlib/test/zip_SUITE.erl | 78 |
18 files changed, 3228 insertions, 362 deletions
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index 9beac93eb8..3bbd9ce318 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -9,6 +9,8 @@ MODULES= \ array_SUITE \ base64_SUITE \ beam_lib_SUITE \ + binary_module_SUITE \ + binref \ c_SUITE \ calendar_SUITE \ dets_SUITE \ diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl new file mode 100644 index 0000000000..16ed9a2c26 --- /dev/null +++ b/lib/stdlib/test/binary_module_SUITE.erl @@ -0,0 +1,1323 @@ +-module(binary_module_SUITE). + +-export([all/1, interesting/1,random_ref_comp/1,random_ref_sr_comp/1, + random_ref_fla_comp/1,parts/1, bin_to_list/1, list_to_bin/1, + copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1]). + +-export([random_number/1, make_unaligned/1]). + + + +%%-define(STANDALONE,1). + +-ifdef(STANDALONE). + +-define(line,erlang:display({?MODULE,?LINE}),). + +-else. + +-include("test_server.hrl"). +-export([init_per_testcase/2, fin_per_testcase/2]). +% Default timetrap timeout (set in init_per_testcase). +% Some of these testcases are really heavy... +-define(default_timeout, ?t:minutes(20)). + +-endif. + + + +-ifdef(STANDALONE). +-export([run/0]). + +run() -> + [ apply(?MODULE,X,[[]]) || X <- all(suite) ]. + +-else. + +init_per_testcase(_Case, Config) -> + ?line Dog = ?t:timetrap(?default_timeout), + [{watchdog, Dog} | Config]. + +fin_per_testcase(_Case, Config) -> + ?line Dog = ?config(watchdog, Config), + ?line test_server:timetrap_cancel(Dog), + ok. +-endif. + +all(suite) -> [interesting,random_ref_fla_comp,random_ref_sr_comp, + random_ref_comp,parts,bin_to_list, list_to_bin, copy, + referenced,guard,encode_decode,badargs,longest_common_trap]. + +-define(MASK_ERROR(EXPR),mask_error((catch (EXPR)))). + + +badargs(doc) -> + ["Tests various badarg exceptions in the module"]; +badargs(Config) when is_list(Config) -> + ?line badarg = ?MASK_ERROR(binary:compile_pattern([<<1,2,3:3>>])), + ?line badarg = ?MASK_ERROR(binary:compile_pattern([<<1,2,3>>|<<1,2>>])), + ?line badarg = ?MASK_ERROR(binary:compile_pattern(<<1,2,3:3>>)), + ?line badarg = ?MASK_ERROR(binary:compile_pattern(<<>>)), + ?line badarg = ?MASK_ERROR(binary:match(<<1,2,3:3>>,<<1>>)), + ?line badarg = ?MASK_ERROR(binary:matches(<<1,2,3:3>>,<<1>>)), + ?line badarg = ?MASK_ERROR(binary:match(<<1,2,3>>,<<1>>, + [{scope,{0,1},1}])), + ?line badarg = ?MASK_ERROR(binary:match(<<1,2,3>>,<<1>>, + [{scape,{0,1}}])), + ?line badarg = ?MASK_ERROR(binary:match(<<1,2,3>>,<<1>>, + [{scope,{0,1,1}}])), + ?line badarg = ?MASK_ERROR(binary:match(<<1,2,3>>,<<1>>,[{scope,0,1}])), + ?line badarg = ?MASK_ERROR(binary:match(<<1,2,3>>,<<1>>,[{scope,[0,1]}])), + ?line badarg = ?MASK_ERROR(binary:match(<<1,2,3>>,<<1>>, + [{scope,{0.1,1}}])), + ?line badarg = ?MASK_ERROR(binary:match(<<1,2,3>>,<<1>>, + [{scope,{1,1.1}}])), + ?line badarg = + ?MASK_ERROR( + binary:match(<<1,2,3>>,<<1>>, + [{scope,{16#FF, + 16#FFFFFFFFFFFFFFFF}}])), + ?line badarg = + ?MASK_ERROR( + binary:match(<<1,2,3>>,<<1>>, + [{scope,{16#FFFFFFFFFFFFFFFF, + -16#7FFFFFFFFFFFFFFF-1}}])), + ?line badarg = + ?MASK_ERROR( + binary:match(<<1,2,3>>,<<1>>, + [{scope,{16#FFFFFFFFFFFFFFFF, + 16#7FFFFFFFFFFFFFFF}}])), + ?line badarg = + ?MASK_ERROR( + binary:part(<<1,2,3>>,{16#FF, + 16#FFFFFFFFFFFFFFFF})), + ?line badarg = + ?MASK_ERROR( + binary:part(<<1,2,3>>,{16#FFFFFFFFFFFFFFFF, + -16#7FFFFFFFFFFFFFFF-1})), + ?line badarg = + ?MASK_ERROR( + binary:part(<<1,2,3>>,{16#FFFFFFFFFFFFFFFF, + 16#7FFFFFFFFFFFFFFF})), + ?line badarg = + ?MASK_ERROR( + binary:part(make_unaligned(<<1,2,3>>),{1,1,1})), + ?line badarg = + ?MASK_ERROR( + binary_part(make_unaligned(<<1,2,3>>),{1,1,1})), + ?line badarg = + ?MASK_ERROR( + binary_part(make_unaligned(<<1,2,3>>),{16#FFFFFFFFFFFFFFFF, + -16#7FFFFFFFFFFFFFFF-1})), + ?line badarg = + ?MASK_ERROR( + binary_part(make_unaligned(<<1,2,3>>),{16#FF, + 16#FFFFFFFFFFFFFFFF})), + ?line badarg = + ?MASK_ERROR( + binary_part(make_unaligned(<<1,2,3>>),{16#FFFFFFFFFFFFFFFF, + 16#7FFFFFFFFFFFFFFF})), + ?line badarg = + ?MASK_ERROR( + binary_part(make_unaligned(<<1,2,3>>),{16#FFFFFFFFFFFFFFFFFF, + -16#7FFF})), + ?line badarg = + ?MASK_ERROR( + binary_part(make_unaligned(<<1,2,3>>),{16#FF, + -16#7FFF})), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3>>,{16#FF, + 16#FFFFFFFFFFFFFFFF})), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3>>,{16#FFFFFFFFFFFFFFFF, + -16#7FFFFFFFFFFFFFFF-1})), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3>>,{16#FFFFFFFFFFFFFFFF, + 16#7FFFFFFFFFFFFFFF})), + ?line [1,2,3] = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3>>)), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3>>,[])), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3>>,{1,2,3})), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3>>,{1.0,1})), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3>>,{1,1.0})), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3:3>>,{1,1})), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list(<<1,2,3:3>>)), + ?line badarg = + ?MASK_ERROR( + binary:bin_to_list([1,2,3])), + + ?line nomatch = + ?MASK_ERROR(binary:match(<<1,2,3>>,<<1>>,[{scope,{0,0}}])), + ?line badarg = + ?MASK_ERROR(binary:match(<<1,2,3>>,{bm,<<>>},[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR(binary:match(<<1,2,3>>,[],[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR(binary:match(<<1,2,3>>,{ac,<<>>},[{scope,{0,1}}])), + ?line {bm,BMMagic} = binary:compile_pattern([<<1,2,3>>]), + ?line {ac,ACMagic} = binary:compile_pattern([<<1,2,3>>,<<4,5>>]), + ?line badarg = + ?MASK_ERROR(binary:match(<<1,2,3>>,{bm,ACMagic},[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR(binary:match(<<1,2,3>>,{ac,BMMagic},[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR( + binary:match(<<1,2,3>>, + {bm,ets:match_spec_compile([{'_',[],['$_']}])}, + [{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR( + binary:match(<<1,2,3>>, + {ac,ets:match_spec_compile([{'_',[],['$_']}])}, + [{scope,{0,1}}])), + ?line nomatch = + ?MASK_ERROR(binary:matches(<<1,2,3>>,<<1>>,[{scope,{0,0}}])), + ?line badarg = + ?MASK_ERROR(binary:matches(<<1,2,3>>,{bm,<<>>},[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR(binary:matches(<<1,2,3>>,[],[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR(binary:matches(<<1,2,3>>,{ac,<<>>},[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR(binary:matches(<<1,2,3>>,{bm,ACMagic},[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR(binary:matches(<<1,2,3>>,{ac,BMMagic},[{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR( + binary:matches(<<1,2,3>>, + {bm,ets:match_spec_compile([{'_',[],['$_']}])}, + [{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR( + binary:matches(<<1,2,3>>, + {ac,ets:match_spec_compile([{'_',[],['$_']}])}, + [{scope,{0,1}}])), + ?line badarg = + ?MASK_ERROR(binary:longest_common_prefix( + [<<0:10000,1,2,4,1:3>>, + <<0:10000,1,2,3>>])), + ?line badarg = + ?MASK_ERROR(binary:longest_common_suffix( + [<<0:10000,1,2,4,1:3>>, + <<0:10000,1,2,3>>])), + ?line badarg = + ?MASK_ERROR(binary:encode_unsigned(-1)), + ?line badarg = + ?MASK_ERROR( + binary:encode_unsigned(-16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), + ?line badarg = + ?MASK_ERROR( + binary:first(<<1,2,4,1:3>>)), + ?line badarg = + ?MASK_ERROR( + binary:first([1,2,4])), + ?line badarg = + ?MASK_ERROR( + binary:last(<<1,2,4,1:3>>)), + ?line badarg = + ?MASK_ERROR( + binary:last([1,2,4])), + ?line badarg = + ?MASK_ERROR( + binary:at(<<1,2,4,1:3>>,2)), + ?line badarg = + ?MASK_ERROR( + binary:at(<<>>,2)), + ?line badarg = + ?MASK_ERROR( + binary:at([1,2,4],2)), + ok. + +longest_common_trap(doc) -> + ["Whitebox test to force special trap conditions in longest_common_{prefix,suffix}"]; +longest_common_trap(Config) when is_list(Config) -> + ?line erts_debug:set_internal_state(available_internal_state,true), + ?line io:format("oldlimit: ~p~n", + [erts_debug:set_internal_state(binary_loop_limit,10)]), + erlang:bump_reductions(10000000), + ?line _ = binary:longest_common_prefix( + [<<0:10000,1,2,4>>, + <<0:10000,1,2,3>>, + <<0:10000,1,3,3>>, + <<0:10000,1,2,4>>, + <<0:10000,1,2,4>>, + <<0:10000,1,2,3>>, + <<0:10000,1,3,3>>, + <<0:10000,1,2,3>>, + <<0:10000,1,3,3>>, + <<0:10000,1,2,4>>, + <<0:10000,1,2,4>>, + <<0:10000,1,2,3>>, + <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0:10000,1,3,3>>, + <<0:10000,1,2,4>>]), + ?line _ = binary:longest_common_prefix( + [<<0:10000,1,2,4>>, + <<0:10000,1,2,3>>, + <<0:10000,1,3,3>>, + <<0:10000,1,2,4>>, + <<0:10000,1,2,4>>, + <<0:10000,1,2,3>>, + <<0:10000,1,3,3>>, + <<0:10000,1,2,3>>, + <<0:10000,1,3,3>>, + <<0:10000,1,2,4>>, + <<0:10000,1,2,4>>, + <<0:10000,1,2,3>>, + <<0,0,0,0,0,0,0,0,0,0,0,0,0,0>>, + <<0:10000,1,2,4>>]), + erlang:bump_reductions(10000000), + ?line _ = binary:longest_common_suffix( + [<<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,3,3,0:10000,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>, + <<1,2,4,0:10000>>]), + ?line _ = binary:longest_common_suffix( + [<<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<1,2,4,0:10000>>, + <<0,0,0,0,0,0,0,0,0,0,0,0,0,0>>, + <<1,2,4,0:10000>>]), + Subj = subj(), + Len = byte_size(Subj), + ?line Len = binary:longest_common_suffix( + [Subj,Subj,Subj]), + ?line io:format("limit was: ~p~n", + [erts_debug:set_internal_state(binary_loop_limit, + default)]), + ?line erts_debug:set_internal_state(available_internal_state,false), + ok. + +subj() -> + Me = self(), + spawn(fun() -> + X0 = iolist_to_binary([ + "1234567890", + %lists:seq(16#21, 16#7e), + lists:duplicate(100, $x) + ]), + Me ! X0, + receive X -> X end + end), + X0 = receive A -> A end, + <<X1:32/binary,_/binary>> = X0, + Subject= <<X1/binary>>, + Subject. + + +interesting(doc) -> + ["Try some interesting patterns"]; +interesting(Config) when is_list(Config) -> + X = do_interesting(binary), + X = do_interesting(binref). + +do_interesting(Module) -> + ?line {0,4} = Module:match(<<"123456">>, + Module:compile_pattern([<<"12">>,<<"1234">>, + <<"23">>,<<"3">>, + <<"34">>,<<"456">>, + <<"45">>,<<"6">>])), + ?line [{0,4},{5,1}] = Module:matches(<<"123456">>, + Module:compile_pattern([<<"12">>,<<"1234">>, + <<"23">>,<<"3">>, + <<"34">>,<<"456">>, + <<"45">>,<<"6">>])), + ?line [{0,4}] = Module:matches(<<"123456">>, + Module:compile_pattern([<<"12">>,<<"1234">>, + <<"23">>,<<"3">>, + <<"34">>,<<"456">>, + <<"45">>])), + ?line [{0,2},{2,2}] = Module:matches(<<"123456">>, + Module:compile_pattern([<<"12">>, + <<"23">>,<<"3">>, + <<"34">>,<<"456">>, + <<"45">>])), + ?line {1,4} = Module:match(<<"123456">>, + Module:compile_pattern([<<"34">>,<<"34">>, + <<"12347">>,<<"2345">>])), + ?line [{1,4}] = Module:matches(<<"123456">>, + Module:compile_pattern([<<"34">>,<<"34">>, + <<"12347">>,<<"2345">>])), + ?line [{2,2}] = Module:matches(<<"123456">>, + Module:compile_pattern([<<"34">>,<<"34">>, + <<"12347">>,<<"2346">>])), + + ?line {0,4} = Module:match(<<"123456">>, + [<<"12">>,<<"1234">>, + <<"23">>,<<"3">>, + <<"34">>,<<"456">>, + <<"45">>,<<"6">>]), + ?line [{0,4},{5,1}] = Module:matches(<<"123456">>, + [<<"12">>,<<"1234">>, + <<"23">>,<<"3">>, + <<"34">>,<<"456">>, + <<"45">>,<<"6">>]), + ?line [{0,4}] = Module:matches(<<"123456">>, + [<<"12">>,<<"1234">>, + <<"23">>,<<"3">>, + <<"34">>,<<"456">>, + <<"45">>]), + ?line [{0,2},{2,2}] = Module:matches(<<"123456">>, + [<<"12">>, + <<"23">>,<<"3">>, + <<"34">>,<<"456">>, + <<"45">>]), + ?line {1,4} = Module:match(<<"123456">>, + [<<"34">>,<<"34">>, + <<"12347">>,<<"2345">>]), + ?line [{1,4}] = Module:matches(<<"123456">>, + [<<"34">>,<<"34">>, + <<"12347">>,<<"2345">>]), + ?line [{2,2}] = Module:matches(<<"123456">>, + [<<"34">>,<<"34">>, + <<"12347">>,<<"2346">>]), + ?line nomatch = Module:match(<<1,2,3,4>>,<<2>>,[{scope,{0,1}}]), + ?line {1,1} = Module:match(<<1,2,3,4>>,<<2>>,[{scope,{0,2}}]), + ?line nomatch = Module:match(<<1,2,3,4>>,<<2,3>>,[{scope,{0,2}}]), + ?line {1,2} = Module:match(<<1,2,3,4>>,<<2,3>>,[{scope,{0,3}}]), + ?line {1,2} = Module:match(<<1,2,3,4>>,<<2,3>>,[{scope,{0,4}}]), + ?line badarg = ?MASK_ERROR(Module:match(<<1,2,3,4>>,<<2,3>>, + [{scope,{0,5}}])), + ?line {1,2} = Module:match(<<1,2,3,4>>,<<2,3>>,[{scope,{4,-4}}]), + ?line {0,3} = Module:match(<<1,2,3,4>>,<<1,2,3>>,[{scope,{4,-4}}]), + ?line {0,4} = Module:match(<<1,2,3,4>>,<<1,2,3,4>>,[{scope,{4,-4}}]), + ?line badarg = ?MASK_ERROR(Module:match(<<1,2,3,4>>,<<1,2,3,4>>, + [{scope,{3,-4}}])), + ?line [] = Module:matches(<<1,2,3,4>>,<<2>>,[{scope,{0,1}}]), + ?line [{1,1}] = Module:matches(<<1,2,3,4>>,[<<2>>,<<3>>],[{scope,{0,2}}]), + ?line [] = Module:matches(<<1,2,3,4>>,<<2,3>>,[{scope,{0,2}}]), + ?line [{1,2}] = Module:matches(<<1,2,3,4>>,<<2,3>>,[{scope,{0,3}}]), + ?line [{1,2}] = Module:matches(<<1,2,3,4>>,<<2,3>>,[{scope,{0,4}}]), + ?line [{1,2}] = Module:matches(<<1,2,3,4>>,[<<2,3>>,<<4>>], + [{scope,{0,3}}]), + ?line [{1,2},{3,1}] = Module:matches(<<1,2,3,4>>,[<<2,3>>,<<4>>], + [{scope,{0,4}}]), + ?line badarg = ?MASK_ERROR(Module:matches(<<1,2,3,4>>,<<2,3>>, + [{scope,{0,5}}])), + ?line [{1,2}] = Module:matches(<<1,2,3,4>>,<<2,3>>,[{scope,{4,-4}}]), + ?line [{1,2},{3,1}] = Module:matches(<<1,2,3,4>>,[<<2,3>>,<<4>>], + [{scope,{4,-4}}]), + ?line [{0,3}] = Module:matches(<<1,2,3,4>>,<<1,2,3>>,[{scope,{4,-4}}]), + ?line [{0,4}] = Module:matches(<<1,2,3,4>>,<<1,2,3,4>>,[{scope,{4,-4}}]), + ?line badarg = ?MASK_ERROR(Module:matches(<<1,2,3,4>>,<<1,2,3,4>>, + [{scope,{3,-4}}])), + ?line badarg = ?MASK_ERROR(Module:matches(<<1,2,3,4>>,[<<1,2,3,4>>], + [{scope,{3,-4}}])), + ?line [<<1,2,3>>,<<6,7,8>>] = Module:split(<<1,2,3,4,5,6,7,8>>,<<4,5>>), + ?line [<<1,2,3>>,<<6,7,8>>] = Module:split(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>]), + ?line [<<1,2,3>>,<<6>>,<<8>>] = Module:split(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>],[global]), + ?line [<<1,2,3>>,<<6>>,<<>>,<<>>] = Module:split(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>], + [global]), + ?line [<<1,2,3>>,<<6>>] = Module:split(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>], + [global,trim]), + ?line [<<1,2,3,4,5,6,7,8>>] = Module:split(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>], + [global,trim,{scope,{0,4}}]), + ?line [<<1,2,3>>,<<6,7,8>>] = Module:split(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>], + [global,trim,{scope,{0,5}}]), + ?line badarg = ?MASK_ERROR( + Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<99>>, + [global,trim,{scope,{0,5}}])), + ?line <<1,2,3,99,6,7,8>> = Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<99>>,[]), + ?line <<1,2,3,99,6,99,99>> = Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<99>>, + [global]), + ?line <<1,2,3,99,6,7,8>> = Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<99>>, + [global,{scope,{0,5}}]), + ?line <<1,2,3,99,6,7,8>> = Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<99>>, + [global,{scope,{0,5}}]), + ?line <<1,2,3,99,6,7,8>> = Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<99>>, + [global,{scope,{0,5}}]), + ?line badarg = ?MASK_ERROR(Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<99>>, + [global,{scope,{0,5}}, + {insert,1}])), + ?line <<1,2,3,99,4,5,6,7,8>> = Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<99>>, + [global,{scope,{0,5}}, + {insert_replaced,1}]), + ?line <<1,2,3,9,4,5,9,6,7,8>> = Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>], + <<9,9>>, + [global,{scope,{0,5}}, + {insert_replaced,1}]), + ?line badarg = ?MASK_ERROR(Module:replace(<<1,2,3,4,5,6,7,8>>, + [<<4,5>>,<<7>>,<<8>>],<<>>, + [global,{scope,{0,5}}, + {insert_replaced,1}])), + ?line 2 = Module:longest_common_prefix([<<1,2,4>>,<<1,2,3>>]), + ?line 2 = Module:longest_common_prefix([<<1,2,4>>,<<1,2>>]), + ?line 1 = Module:longest_common_prefix([<<1,2,4>>,<<1>>]), + ?line 0 = Module:longest_common_prefix([<<1,2,4>>,<<>>]), + ?line 1 = Module:longest_common_prefix([<<1,2,4>>,<<1,2,3>>,<<1,3,3>>]), + ?line 1 = Module:longest_common_prefix([<<1,2,4>>,<<1,2,3>>,<<1,3,3>>,<<1,2,4>>]), + ?line 1251 = Module:longest_common_prefix([<<0:10000,1,2,4>>, + <<0:10000,1,2,3>>, + <<0:10000,1,3,3>>, + <<0:10000,1,2,4>>]), + ?line 12501 = Module:longest_common_prefix([<<0:100000,1,2,4>>, + <<0:100000,1,2,3>>, + <<0:100000,1,3,3>>, + <<0:100000,1,2,4>>]), + ?line 1251 = Module:longest_common_prefix( + [make_unaligned(<<0:10000,1,2,4>>), + <<0:10000,1,2,3>>, + make_unaligned(<<0:10000,1,3,3>>), + <<0:10000,1,2,4>>]), + ?line 12501 = Module:longest_common_prefix( + [<<0:100000,1,2,4>>, + make_unaligned(<<0:100000,1,2,3>>), + <<0:100000,1,3,3>>, + make_unaligned(<<0:100000,1,2,4>>)]), + ?line 1250001 = Module:longest_common_prefix([<<0:10000000,1,2,4>>, + <<0:10000000,1,2,3>>, + <<0:10000000,1,3,3>>, + <<0:10000000,1,2,4>>]), + if % Too cruel for the reference implementation + Module =:= binary -> + ?line erts_debug:set_internal_state(available_internal_state,true), + ?line io:format("oldlimit: ~p~n", + [erts_debug:set_internal_state( + binary_loop_limit,100)]), + ?line 1250001 = Module:longest_common_prefix( + [<<0:10000000,1,2,4>>, + <<0:10000000,1,2,3>>, + <<0:10000000,1,3,3>>, + <<0:10000000,1,2,4>>]), + ?line io:format("limit was: ~p~n", + [erts_debug:set_internal_state(binary_loop_limit, + default)]), + ?line erts_debug:set_internal_state(available_internal_state, + false); + true -> + ok + end, + ?line 1 = Module:longest_common_suffix([<<0:100000000,1,2,4,5>>, + <<0:100000000,1,2,3,5>>, + <<0:100000000,1,3,3,5>>, + <<0:100000000,1,2,4,5>>]), + ?line 1 = Module:longest_common_suffix([<<1,2,4,5>>, + <<0:100000000,1,2,3,5>>, + <<0:100000000,1,3,3,5>>, + <<0:100000000,1,2,4,5>>]), + ?line 1 = Module:longest_common_suffix([<<1,2,4,5,5>>,<<5,5>>, + <<0:100000000,1,3,3,5,5>>, + <<0:100000000,1,2,4,5>>]), + ?line 0 = Module:longest_common_suffix([<<1,2,4,5,5>>,<<5,5>>, + <<0:100000000,1,3,3,5,5>>, + <<0:100000000,1,2,4>>]), + ?line 2 = Module:longest_common_suffix([<<1,2,4,5,5>>,<<5,5>>, + <<0:100000000,1,3,3,5,5>>, + <<0:100000000,1,2,4,5,5>>]), + ?line 1 = Module:longest_common_suffix([<<1,2,4,5,5>>,<<5>>, + <<0:100000000,1,3,3,5,5>>, + <<0:100000000,1,2,4,5,5>>]), + ?line 0 = Module:longest_common_suffix([<<1,2,4,5,5>>,<<>>, + <<0:100000000,1,3,3,5,5>>, + <<0:100000000,1,2,4,5,5>>]), + ?line 0 = Module:longest_common_suffix([<<>>,<<0:100000000,1,3,3,5,5>>, + <<0:100000000,1,2,4,5,5>>]), + ?line 0 = Module:longest_common_suffix([<<>>,<<0:100000000,1,3,3,5,5>>, + <<0:100000000,1,2,4,5,5>>]), + ?line 2 = Module:longest_common_suffix([<<5,5>>,<<0:100000000,1,3,3,5,5>>, + <<0:100000000,1,2,4,5,5>>]), + ?line 2 = Module:longest_common_suffix([<<5,5>>,<<5,5>>,<<4,5,5>>]), + ?line 2 = Module:longest_common_suffix([<<5,5>>,<<5,5>>,<<5,5>>]), + ?line 3 = Module:longest_common_suffix([<<4,5,5>>,<<4,5,5>>,<<4,5,5>>]), + ?line 0 = Module:longest_common_suffix([<<>>]), + ?line badarg = ?MASK_ERROR(Module:longest_common_suffix([])), + ?line badarg = ?MASK_ERROR(Module:longest_common_suffix([apa])), + ?line badarg = ?MASK_ERROR(Module:longest_common_suffix([[<<>>]])), + ?line badarg = ?MASK_ERROR(Module:longest_common_suffix([[<<0>>, + <<1:9>>]])), + ?line 0 = Module:longest_common_prefix([<<>>]), + ?line badarg = ?MASK_ERROR(Module:longest_common_prefix([])), + ?line badarg = ?MASK_ERROR(Module:longest_common_prefix([apa])), + ?line badarg = ?MASK_ERROR(Module:longest_common_prefix([[<<>>]])), + ?line badarg = ?MASK_ERROR(Module:longest_common_prefix([[<<0>>, + <<1:9>>]])), + + ?line <<1:6,Bin:3/binary,_:2>> = <<1:6,1,2,3,1:2>>, + ?line <<1,2,3>> = Bin, + ?line 1 = Module:first(Bin), + ?line 1 = Module:first(<<1>>), + ?line 1 = Module:first(<<1,2,3>>), + ?line badarg = ?MASK_ERROR(Module:first(<<>>)), + ?line badarg = ?MASK_ERROR(Module:first(apa)), + ?line 3 = Module:last(Bin), + ?line 1 = Module:last(<<1>>), + ?line 3 = Module:last(<<1,2,3>>), + ?line badarg = ?MASK_ERROR(Module:last(<<>>)), + ?line badarg = ?MASK_ERROR(Module:last(apa)), + ?line 1 = Module:at(Bin,0), + ?line 1 = Module:at(<<1>>,0), + ?line 1 = Module:at(<<1,2,3>>,0), + ?line 2 = Module:at(<<1,2,3>>,1), + ?line 3 = Module:at(<<1,2,3>>,2), + ?line badarg = ?MASK_ERROR(Module:at(<<1,2,3>>,3)), + ?line badarg = ?MASK_ERROR(Module:at(<<1,2,3>>,-1)), + ?line badarg = ?MASK_ERROR(Module:at(<<1,2,3>>,apa)), + ?line "hejsan" = [ Module:at(<<"hejsan">>,I) || I <- lists:seq(0,5) ], + + ?line badarg = ?MASK_ERROR(Module:bin_to_list(<<1,2,3>>,3,-4)), + ?line [1,2,3] = ?MASK_ERROR(Module:bin_to_list(<<1,2,3>>,3,-3)), + + ?line badarg = ?MASK_ERROR(Module:decode_unsigned(<<1,2,1:2>>,big)), + ?line badarg = ?MASK_ERROR(Module:decode_unsigned(<<1,2,1:2>>,little)), + ?line badarg = ?MASK_ERROR(Module:decode_unsigned(apa)), + ?line badarg = ?MASK_ERROR(Module:decode_unsigned(125,little)), + ?line 0 = ?MASK_ERROR(Module:decode_unsigned(<<>>,little)), + ?line 0 = ?MASK_ERROR(Module:decode_unsigned(<<>>,big)), + ?line 0 = ?MASK_ERROR(Module:decode_unsigned(<<0>>,little)), + ?line 0 = ?MASK_ERROR(Module:decode_unsigned(<<0>>,big)), + ?line 0 = ?MASK_ERROR(Module:decode_unsigned(make_unaligned(<<0>>), + little)), + ?line 0 = ?MASK_ERROR(Module:decode_unsigned(make_unaligned(<<0>>),big)), + ?line badarg = ?MASK_ERROR(Module:encode_unsigned(apa)), + ?line badarg = ?MASK_ERROR(Module:encode_unsigned(125.3,little)), + ?line badarg = ?MASK_ERROR(Module:encode_unsigned({1},little)), + ?line badarg = ?MASK_ERROR(Module:encode_unsigned([1],little)), + ?line <<0>> = ?MASK_ERROR(Module:encode_unsigned(0,little)), + ?line <<0>> = ?MASK_ERROR(Module:encode_unsigned(0,big)), + ok. + +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}), + ?line ok = encode_decode_loop({1,200},1000), % Need to be long enough + % to create offheap binaries + ok. + +encode_decode_loop(_Range,0) -> + ok; +encode_decode_loop(Range, X) -> + ?line N = random_number(Range), + ?line A = binary:encode_unsigned(N), + ?line B = binary:encode_unsigned(N,big), + ?line C = binref:encode_unsigned(N), + ?line D = binref:encode_unsigned(N,big), + ?line E = binary:encode_unsigned(N,little), + ?line F = binref:encode_unsigned(N,little), + ?line G = binary:decode_unsigned(A), + ?line H = binary:decode_unsigned(A,big), + ?line I = binref:decode_unsigned(A), + ?line J = binary:decode_unsigned(E,little), + ?line K = binref:decode_unsigned(E,little), + ?line L = binary:decode_unsigned(make_unaligned(A)), + ?line M = binary:decode_unsigned(make_unaligned(E),little), + ?line PaddedBig = <<0:48,A/binary>>, + ?line PaddedLittle = <<E/binary,0:48>>, + ?line O = binary:decode_unsigned(PaddedBig), + ?line P = binary:decode_unsigned(make_unaligned(PaddedBig)), + ?line Q = binary:decode_unsigned(PaddedLittle,little), + ?line R = binary:decode_unsigned(make_unaligned(PaddedLittle),little), + ?line S = binref:decode_unsigned(PaddedLittle,little), + ?line T = binref:decode_unsigned(PaddedBig), + case (((A =:= B) and (B =:= C) and (C =:= D)) and + ((E =:= F)) and + ((N =:= G) and (G =:= H) and (H =:= I) and + (I =:= J) and (J =:= K) and (K =:= L) and (L =:= M)) and + ((M =:= O) and (O =:= P) and (P =:= Q) and (Q =:= R) and + (R =:= S) and (S =:= T)))of + true -> + encode_decode_loop(Range,X-1); + _ -> + io:format("Failed to encode/decode ~w~n(Results ~p)~n", + [N,[A,B,C,D,E,F,G,H,I,J,K,L,M,x,O,P,Q,R,S,T]]), + exit(mismatch) + end. + +guard(doc) -> + ["Smoke test of the guard BIFs binary_part/2,3"]; +guard(Config) when is_list(Config) -> + {comment, "Guard tests are run in emulator test suite"}. + +referenced(doc) -> + ["Test refernced_byte_size/1 bif."]; +referenced(Config) when is_list(Config) -> + ?line badarg = ?MASK_ERROR(binary:referenced_byte_size([])), + ?line badarg = ?MASK_ERROR(binary:referenced_byte_size(apa)), + ?line badarg = ?MASK_ERROR(binary:referenced_byte_size({})), + ?line badarg = ?MASK_ERROR(binary:referenced_byte_size(1)), + ?line A = <<1,2,3>>, + ?line B = binary:copy(A,1000), + ?line 3 = binary:referenced_byte_size(A), + ?line 3000 = binary:referenced_byte_size(B), + ?line <<_:8,C:2/binary>> = A, + ?line 3 = binary:referenced_byte_size(C), + ?line 2 = binary:referenced_byte_size(binary:copy(C)), + ?line <<_:7,D:2/binary,_:1>> = A, + ?line 2 = binary:referenced_byte_size(binary:copy(D)), + ?line 3 = binary:referenced_byte_size(D), + ?line <<_:8,E:2/binary,_/binary>> = B, + ?line 3000 = binary:referenced_byte_size(E), + ?line 2 = binary:referenced_byte_size(binary:copy(E)), + ?line <<_:7,F:2/binary,_:1,_/binary>> = B, + ?line 2 = binary:referenced_byte_size(binary:copy(F)), + ?line 3000 = binary:referenced_byte_size(F), + ok. + + + +list_to_bin(doc) -> + ["Test list_to_bin/1 bif"]; +list_to_bin(Config) when is_list(Config) -> + %% Just some smoke_tests first, then go nuts with random cases + ?line badarg = ?MASK_ERROR(binary:list_to_bin({})), + ?line badarg = ?MASK_ERROR(binary:list_to_bin(apa)), + ?line badarg = ?MASK_ERROR(binary:list_to_bin(<<"apa">>)), + F1 = fun(L) -> + ?MASK_ERROR(binref:list_to_bin(L)) + end, + F2 = fun(L) -> + ?MASK_ERROR(binary:list_to_bin(L)) + end, + ?line random_iolist:run(1000,F1,F2), + ok. + +copy(doc) -> + ["Test copy/1,2 bif's"]; +copy(Config) when is_list(Config) -> + ?line <<1,2,3>> = binary:copy(<<1,2,3>>), + ?line RS = random_string({1,10000}), + ?line RS = RS2 = binary:copy(RS), + ?line false = erts_debug:same(RS,RS2), + ?line <<>> = ?MASK_ERROR(binary:copy(<<1,2,3>>,0)), + ?line badarg = ?MASK_ERROR(binary:copy(<<1,2,3:3>>,2)), + ?line badarg = ?MASK_ERROR(binary:copy([],0)), + ?line <<>> = ?MASK_ERROR(binary:copy(<<>>,0)), + ?line badarg = ?MASK_ERROR(binary:copy(<<1,2,3>>,1.0)), + ?line badarg = ?MASK_ERROR(binary:copy(<<1,2,3>>, + 16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), + ?line <<>> = binary:copy(<<>>,10000), + ?line random:seed({1271,769940,559934}), + ?line ok = random_copy(3000), + ?line erts_debug:set_internal_state(available_internal_state,true), + ?line io:format("oldlimit: ~p~n", + [erts_debug:set_internal_state(binary_loop_limit,10)]), + ?line Subj = subj(), + ?line XX = binary:copy(Subj,1000), + ?line XX = binref:copy(Subj,1000), + ?line ok = random_copy(1000), + ?line kill_copy_loop(1000), + ?line io:format("limit was: ~p~n", + [erts_debug:set_internal_state(binary_loop_limit, + default)]), + ?line erts_debug:set_internal_state(available_internal_state,false), + ok. + +kill_copy_loop(0) -> + ok; +kill_copy_loop(N) -> + {Pid,Ref} = spawn_monitor(fun() -> + ok = random_copy(1000) + end), + receive + after 10 -> + ok + end, + exit(Pid,kill), + receive + {'DOWN',Ref,process,Pid,_} -> + kill_copy_loop(N-1) + after 1000 -> + exit(did_not_die) + end. + +random_copy(0) -> + ok; +random_copy(N) -> + Str = random_string({0,N}), + Num = random: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)), + case {(A =:= B), (B =:= C)} of + {true,true} -> + random_copy(N-1); + _ -> + io:format("Failed to pick copy ~s ~p times~n", + [Str,Num]), + io:format("A:~p,~nB:~p,~n,C:~p.~n", + [A,B,C]), + exit(mismatch) + end. + +bin_to_list(doc) -> + ["Test bin_to_list/1,2,3 bif's"]; +bin_to_list(Config) when is_list(Config) -> + %% Just some smoke_tests first, then go nuts with random cases + ?line X = <<1,2,3,4,0:1000000,5>>, + ?line Y = make_unaligned(X), + ?line LX = binary:bin_to_list(X), + ?line LX = binary:bin_to_list(X,0,byte_size(X)), + ?line LX = binary:bin_to_list(X,byte_size(X),-byte_size(X)), + ?line LX = binary:bin_to_list(X,{0,byte_size(X)}), + ?line LX = binary:bin_to_list(X,{byte_size(X),-byte_size(X)}), + ?line LY = binary:bin_to_list(Y), + ?line LY = binary:bin_to_list(Y,0,byte_size(Y)), + ?line LY = binary:bin_to_list(Y,byte_size(Y),-byte_size(Y)), + ?line LY = binary:bin_to_list(Y,{0,byte_size(Y)}), + ?line LY = binary:bin_to_list(Y,{byte_size(Y),-byte_size(Y)}), + ?line 1 = hd(LX), + ?line 5 = lists:last(LX), + ?line 1 = hd(LY), + ?line 5 = lists:last(LY), + ?line X = list_to_binary(LY), + ?line Y = list_to_binary(LY), + ?line X = list_to_binary(LY), + ?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}), + ?line ok = random_bin_to_list(5000), + ok. + +random_bin_to_list(0) -> + ok; +random_bin_to_list(N) -> + Str = random_string({1,N}), + Parts0 = random_parts(10,N), + Parts1 = Parts0 ++ [ {X+Y,-Y} || {X,Y} <- Parts0 ], + [ begin + try + true = ?MASK_ERROR(binary:bin_to_list(Str,Z)) =:= + ?MASK_ERROR(binref:bin_to_list(Str,Z)), + true = ?MASK_ERROR(binary:bin_to_list(Str,Z)) =:= + ?MASK_ERROR(binary:bin_to_list(make_unaligned(Str),Z)) + catch + _:_ -> + io:format("Error, Str = <<\"~s\">>.~nZ = ~p.~n", + [Str,Z]), + exit(badresult) + end + end || Z <- Parts1 ], + [ begin + try + true = ?MASK_ERROR(binary:bin_to_list(Str,A,B)) =:= + ?MASK_ERROR(binref:bin_to_list(Str,A,B)), + true = ?MASK_ERROR(binary:bin_to_list(Str,A,B)) =:= + ?MASK_ERROR(binary:bin_to_list(make_unaligned(Str),A,B)) + catch + _:_ -> + io:format("Error, Str = <<\"~s\">>.~nA = ~p.~nB = ~p.~n", + [Str,A,B]), + exit(badresult) + end + end || {A,B} <- Parts1 ], + random_bin_to_list(N-1). + +parts(doc) -> + ["Test the part/2,3 bif's"]; +parts(Config) when is_list(Config) -> + %% Some simple smoke tests to begin with + ?line Simple = <<1,2,3,4,5,6,7,8>>, + ?line <<1,2>> = binary:part(Simple,0,2), + ?line <<1,2>> = binary:part(Simple,{0,2}), + ?line Simple = binary:part(Simple,0,8), + ?line Simple = binary:part(Simple,{0,8}), + ?line badarg = ?MASK_ERROR(binary:part(Simple,0,9)), + ?line badarg = ?MASK_ERROR(binary:part(Simple,{0,9})), + ?line badarg = ?MASK_ERROR(binary:part(Simple,1,8)), + ?line badarg = ?MASK_ERROR(binary:part(Simple,{1,8})), + ?line badarg = ?MASK_ERROR(binary:part(Simple,{3,-4})), + ?line badarg = ?MASK_ERROR(binary:part(Simple,{3.0,1})), + ?line badarg = ?MASK_ERROR( + binary:part(Simple,{16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFF + ,1})), + ?line <<2,3,4,5,6,7,8>> = binary:part(Simple,{1,7}), + ?line <<2,3,4,5,6,7,8>> = binary:part(Simple,{8,-7}), + ?line Simple = binary:part(Simple,{8,-8}), + ?line badarg = ?MASK_ERROR(binary:part(Simple,{1,-8})), + ?line badarg = ?MASK_ERROR(binary:part(Simple,{8,-9})), + ?line badarg = ?MASK_ERROR(binary:part(Simple,{0,-1})), + ?line <<>> = binary:part(Simple,{8,0}), + ?line badarg = ?MASK_ERROR(binary:part(Simple,{9,0})), + ?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}), + ?line random_parts(5000), + ok. + + +random_parts(0) -> + ok; +random_parts(N) -> + Str = random_string({1,N}), + Parts0 = random_parts(10,N), + Parts1 = Parts0 ++ [ {X+Y,-Y} || {X,Y} <- Parts0 ], + [ begin + true = ?MASK_ERROR(binary:part(Str,Z)) =:= + ?MASK_ERROR(binref:part(Str,Z)), + true = ?MASK_ERROR(binary:part(Str,Z)) =:= + ?MASK_ERROR(erlang:binary_part(Str,Z)), + true = ?MASK_ERROR(binary:part(Str,Z)) =:= + ?MASK_ERROR(binary:part(make_unaligned(Str),Z)) + end || Z <- Parts1 ], + random_parts(N-1). + +random_parts(0,_) -> + []; +random_parts(X,N) -> + Pos = random:uniform(N), + Len = random: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) -> + ?line put(success_counter,0), + ?line random:seed({1271,769940,559934}), + ?line do_random_match_comp(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_match_comp2(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_match_comp3(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_match_comp4(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_matches_comp(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_matches_comp2(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_matches_comp3(5,{1,40},{30,1000}), + ?line erts_debug:set_internal_state(available_internal_state,true), + ?line io:format("oldlimit: ~p~n",[ erts_debug:set_internal_state(binary_loop_limit,100)]), + ?line do_random_match_comp(5000,{1,40},{30,1000}), + ?line do_random_matches_comp3(5,{1,40},{30,1000}), + ?line io:format("limit was: ~p~n",[ erts_debug:set_internal_state(binary_loop_limit,default)]), + ?line erts_debug:set_internal_state(available_internal_state,false), + ok. + +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) -> + ?line put(success_counter,0), + ?line random:seed({1271,769940,559934}), + ?line do_random_split_comp(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_replace_comp(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_split_comp2(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ?line do_random_replace_comp2(5000,{1,40},{30,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ok. +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}), + ?line do_random_first_comp(5000,{1,1000}), + ?line do_random_last_comp(5000,{1,1000}), + ?line do_random_at_comp(5000,{1,1000}), + io:format("Number of successes: ~p~n",[get(success_counter)]), + ok. + +do_random_first_comp(0,_) -> + ok; +do_random_first_comp(N,Range) -> + S = random_string(Range), + A = ?MASK_ERROR(binref:first(S)), + B = ?MASK_ERROR(binary:first(S)), + C = ?MASK_ERROR(binary:first(make_unaligned(S))), + case {(A =:= B), (B =:= C)} of + {true,true} -> + do_random_first_comp(N-1,Range); + _ -> + io:format("Failed to pick first of ~s~n", + [S]), + io:format("A:~p,~nB:~p,~n,C:~p.~n", + [A,B,C]), + exit(mismatch) + end. + +do_random_last_comp(0,_) -> + ok; +do_random_last_comp(N,Range) -> + S = random_string(Range), + A = ?MASK_ERROR(binref:last(S)), + B = ?MASK_ERROR(binary:last(S)), + C = ?MASK_ERROR(binary:last(make_unaligned(S))), + case {(A =:= B), (B =:= C)} of + {true,true} -> + do_random_last_comp(N-1,Range); + _ -> + io:format("Failed to pick last of ~s~n", + [S]), + io:format("A:~p,~nB:~p,~n,C:~p.~n", + [A,B,C]), + exit(mismatch) + end. +do_random_at_comp(0,_) -> + ok; +do_random_at_comp(N,{Min,Max}=Range) -> + S = random_string(Range), + XMax = Min + ((Max - Min) * 3) div 4, + Pos = random_length({Min,XMax}), %% some out of range + A = ?MASK_ERROR(binref:at(S,Pos)), + B = ?MASK_ERROR(binary:at(S,Pos)), + C = ?MASK_ERROR(binary:at(make_unaligned(S),Pos)), + if + A =/= badarg -> + put(success_counter,get(success_counter)+1); + true -> + ok + end, + case {(A =:= B), (B =:= C)} of + {true,true} -> + do_random_at_comp(N-1,Range); + _ -> + io:format("Failed to pick last of ~s~n", + [S]), + io:format("A:~p,~nB:~p,~n,C:~p.~n", + [A,B,C]), + exit(mismatch) + end. + +do_random_matches_comp(0,_,_) -> + ok; +do_random_matches_comp(N,NeedleRange,HaystackRange) -> + NumNeedles = element(2,HaystackRange) div element(2,NeedleRange), + Needles = [random_string(NeedleRange) || + _ <- lists:duplicate(NumNeedles,a)], + Haystack = random_string(HaystackRange), + true = do_matches_comp(Needles,Haystack), + do_random_matches_comp(N-1,NeedleRange,HaystackRange). + +do_random_matches_comp2(0,_,_) -> + ok; +do_random_matches_comp2(N,NeedleRange,HaystackRange) -> + NumNeedles = element(2,HaystackRange) div element(2,NeedleRange), + Haystack = random_string(HaystackRange), + Needles = [random_substring(NeedleRange,Haystack) || + _ <- lists:duplicate(NumNeedles,a)], + true = do_matches_comp(Needles,Haystack), + do_random_matches_comp2(N-1,NeedleRange,HaystackRange). + +do_random_matches_comp3(0,_,_) -> + ok; +do_random_matches_comp3(N,NeedleRange,HaystackRange) -> + NumNeedles = element(2,HaystackRange) div element(2,NeedleRange), + Haystack = random_string(HaystackRange), + Needles = [random_substring(NeedleRange,Haystack) || + _ <- lists:duplicate(NumNeedles,a)], + RefRes = binref:matches(Haystack,Needles), + true = do_matches_comp_loop(10000,Needles,Haystack, RefRes), + do_random_matches_comp3(N-1,NeedleRange,HaystackRange). + +do_matches_comp_loop(0,_,_,_) -> + true; +do_matches_comp_loop(N, Needles, Haystack0,RR) -> + DummySize=N*8, + Haystack1 = <<0:DummySize,Haystack0/binary>>, + RR1=[{X+N,Y} || {X,Y} <- RR], + true = do_matches_comp2(Needles,Haystack1,RR1), + Haystack2 = <<Haystack0/binary,Haystack1/binary>>, + RR2 = RR ++ [{X2+N+byte_size(Haystack0),Y2} || {X2,Y2} <- RR], + true = do_matches_comp2(Needles,Haystack2,RR2), + do_matches_comp_loop(N-1, Needles, Haystack0,RR). + + +do_matches_comp2(N,H,A) -> + C = ?MASK_ERROR(binary:matches(H,N)), + case (A =:= C) of + true -> + true; + _ -> + io:format("Failed to match ~p (needle) against ~s (haystack)~n", + [N,H]), + io:format("A:~p,~n,C:~p.~n", + [A,C]), + exit(mismatch) + end. +do_matches_comp(N,H) -> + A = ?MASK_ERROR(binref:matches(H,N)), + B = ?MASK_ERROR(binref:matches(H,binref:compile_pattern(N))), + C = ?MASK_ERROR(binary:matches(H,N)), + D = ?MASK_ERROR(binary:matches(make_unaligned(H), + binary:compile_pattern([make_unaligned2(X) || X <- N]))), + if + A =/= nomatch -> + put(success_counter,get(success_counter)+1); + true -> + ok + end, + case {(A =:= B), (B =:= C),(C =:= D)} of + {true,true,true} -> + true; + _ -> + io:format("Failed to match ~p (needle) against ~s (haystack)~n", + [N,H]), + io:format("A:~p,~nB:~p,~n,C:~p,~n,D:~p.~n", + [A,B,C,D]), + exit(mismatch) + end. + +do_random_match_comp(0,_,_) -> + ok; +do_random_match_comp(N,NeedleRange,HaystackRange) -> + Needle = random_string(NeedleRange), + Haystack = random_string(HaystackRange), + true = do_match_comp(Needle,Haystack), + do_random_match_comp(N-1,NeedleRange,HaystackRange). + +do_random_match_comp2(0,_,_) -> + ok; +do_random_match_comp2(N,NeedleRange,HaystackRange) -> + Haystack = random_string(HaystackRange), + Needle = random_substring(NeedleRange,Haystack), + true = do_match_comp(Needle,Haystack), + do_random_match_comp2(N-1,NeedleRange,HaystackRange). + +do_random_match_comp3(0,_,_) -> + ok; +do_random_match_comp3(N,NeedleRange,HaystackRange) -> + NumNeedles = element(2,HaystackRange) div element(2,NeedleRange), + Haystack = random_string(HaystackRange), + Needles = [random_substring(NeedleRange,Haystack) || + _ <- lists:duplicate(NumNeedles,a)], + true = do_match_comp3(Needles,Haystack), + do_random_match_comp3(N-1,NeedleRange,HaystackRange). + +do_random_match_comp4(0,_,_) -> + ok; +do_random_match_comp4(N,NeedleRange,HaystackRange) -> + NumNeedles = element(2,HaystackRange) div element(2,NeedleRange), + Haystack = random_string(HaystackRange), + Needles = [random_string(NeedleRange) || + _ <- lists:duplicate(NumNeedles,a)], + true = do_match_comp3(Needles,Haystack), + do_random_match_comp4(N-1,NeedleRange,HaystackRange). + +do_match_comp(N,H) -> + A = ?MASK_ERROR(binref:match(H,N)), + B = ?MASK_ERROR(binref:match(H,binref:compile_pattern([N]))), + C = ?MASK_ERROR(binary:match(make_unaligned(H),N)), + D = ?MASK_ERROR(binary:match(H,binary:compile_pattern([N]))), + E = ?MASK_ERROR(binary:match(H,binary:compile_pattern(make_unaligned(N)))), + if + A =/= nomatch -> + put(success_counter,get(success_counter)+1); + true -> + ok + end, + case {(A =:= B), (B =:= C),(C =:= D),(D =:= E)} of + {true,true,true,true} -> + true; + _ -> + io:format("Failed to match ~s (needle) against ~s (haystack)~n", + [N,H]), + io:format("A:~p,~nB:~p,~n,C:~p,~n,D:~p,E:~p.~n", + [A,B,C,D,E]), + exit(mismatch) + end. + +do_match_comp3(N,H) -> + A = ?MASK_ERROR(binref:match(H,N)), + B = ?MASK_ERROR(binref:match(H,binref:compile_pattern(N))), + C = ?MASK_ERROR(binary:match(H,N)), + D = ?MASK_ERROR(binary:match(H,binary:compile_pattern(N))), + if + A =/= nomatch -> + put(success_counter,get(success_counter)+1); + true -> + ok + end, + case {(A =:= B), (B =:= C),(C =:= D)} of + {true,true,true} -> + true; + _ -> + io:format("Failed to match ~s (needle) against ~s (haystack)~n", + [N,H]), + io:format("A:~p,~nB:~p,~n,C:~p,~n,D:~p.~n", + [A,B,C,D]), + exit(mismatch) + end. + +do_random_split_comp(0,_,_) -> + ok; +do_random_split_comp(N,NeedleRange,HaystackRange) -> + Haystack = random_string(HaystackRange), + Needle = random_substring(NeedleRange,Haystack), + true = do_split_comp(Needle,Haystack,[]), + true = do_split_comp(Needle,Haystack,[global]), + true = do_split_comp(Needle,Haystack,[global,trim]), + do_random_split_comp(N-1,NeedleRange,HaystackRange). +do_random_split_comp2(0,_,_) -> + ok; +do_random_split_comp2(N,NeedleRange,HaystackRange) -> + NumNeedles = element(2,HaystackRange) div element(2,NeedleRange), + Haystack = random_string(HaystackRange), + Needles = [random_substring(NeedleRange,Haystack) || + _ <- lists:duplicate(NumNeedles,a)], + true = do_split_comp(Needles,Haystack,[]), + true = do_split_comp(Needles,Haystack,[global]), + do_random_split_comp2(N-1,NeedleRange,HaystackRange). + +do_split_comp(N,H,Opts) -> + A = ?MASK_ERROR(binref:split(H,N,Opts)), + D = ?MASK_ERROR(binary:split(H,binary:compile_pattern(N),Opts)), + if + (A =/= [N]) and is_list(A) -> + put(success_counter,get(success_counter)+1); + true -> + ok + end, + case (A =:= D) of + true -> + true; + _ -> + io:format("Failed to split ~n~p ~n(haystack) with ~n~p ~n(needle) " + "~nand options ~p~n", + [H,N,Opts]), + io:format("A:~p,D:~p.~n", + [A,D]), + exit(mismatch) + end. + +do_random_replace_comp(0,_,_) -> + ok; +do_random_replace_comp(N,NeedleRange,HaystackRange) -> + Haystack = random_string(HaystackRange), + Needle = random_substring(NeedleRange,Haystack), + Repl = random_string(NeedleRange), + Insertat = random_length(NeedleRange), %Sometimes larger than Repl + true = do_replace_comp(Needle,Haystack,Repl,[]), + true = do_replace_comp(Needle,Haystack,Repl,[global]), + true = do_replace_comp(Needle,Haystack,Repl, + [global,{insert_replaced,Insertat}]), + do_random_replace_comp(N-1,NeedleRange,HaystackRange). +do_random_replace_comp2(0,_,_) -> + ok; +do_random_replace_comp2(N,NeedleRange,HaystackRange) -> + NumNeedles = element(2,HaystackRange) div element(2,NeedleRange), + Haystack = random_string(HaystackRange), + Needles = [random_substring(NeedleRange,Haystack) || + _ <- lists:duplicate(NumNeedles,a)], + Repl = random_string(NeedleRange), + Insertat = random_length(NeedleRange), %Sometimes larger than Repl + true = do_replace_comp(Needles,Haystack,Repl,[]), + true = do_replace_comp(Needles,Haystack,Repl,[global]), + true = do_replace_comp(Needles,Haystack,Repl, + [global,{insert_replaced,Insertat}]), + do_random_replace_comp2(N-1,NeedleRange,HaystackRange). + +do_replace_comp(N,H,R,Opts) -> + A = ?MASK_ERROR(binref:replace(H,N,R,Opts)), + D = ?MASK_ERROR(binary:replace(H,binary:compile_pattern(N),R,Opts)), + if + (A =/= N) and is_binary(A) -> + put(success_counter,get(success_counter)+1); + true -> + ok + end, + case (A =:= D) of + true -> + true; + _ -> + io:format("Failed to replace ~s (haystack) by ~s (needle) " + "inserting ~s (replacement) and options ~p~n", + [H,N,R,Opts]), + io:format("A:~p,D:~p.~n", + [A,D]), + exit(mismatch) + end. + +one_random_number(N) -> + M = ((N - 1) rem 10) + 1, + element(M,{$0,$1,$2,$3,$4,$5,$6,$7,$8,$9}). + +one_random(N) -> + M = ((N - 1) rem 68) + 1, + element(M,{$a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t, + $u,$v,$w,$x,$y,$z,$�,$�,$�,$A,$B,$C,$D,$E,$F,$G,$H, + $I,$J,$K,$L,$M,$N,$O,$P,$Q,$R,$S,$T,$U,$V,$W,$X,$Y,$Z,$�, + $�,$�,$0,$1,$2,$3,$4,$5,$6,$7,$8,$9}). + +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)]). + + +random_length({Min,Max}) -> + random: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)]). +random_substring({Min,Max},Hay) -> + X = random: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/binary,Res:Z/binary,_/binary>> = Hay, + Res. + +mask_error({'EXIT',{Err,_}}) -> + Err; +mask_error(Else) -> + Else. + +make_unaligned(Bin0) when is_binary(Bin0) -> + Bin1 = <<0:3,Bin0/binary,31:5>>, + Sz = byte_size(Bin0), + <<0:3,Bin:Sz/binary,31:5>> = id(Bin1), + Bin. +make_unaligned2(Bin0) when is_binary(Bin0) -> + Bin1 = <<31:5,Bin0/binary,0:3>>, + Sz = byte_size(Bin0), + <<31:5,Bin:Sz/binary,0:3>> = id(Bin1), + Bin. + +id(I) -> I. diff --git a/lib/stdlib/test/binref.erl b/lib/stdlib/test/binref.erl new file mode 100644 index 0000000000..6d96736ef3 --- /dev/null +++ b/lib/stdlib/test/binref.erl @@ -0,0 +1,588 @@ +-module(binref). + +-export([compile_pattern/1,match/2,match/3,matches/2,matches/3, + split/2,split/3,replace/3,replace/4,first/1,last/1,at/2, + part/2,part/3,copy/1,copy/2,encode_unsigned/1,encode_unsigned/2, + decode_unsigned/1,decode_unsigned/2,referenced_byte_size/1, + longest_common_prefix/1,longest_common_suffix/1,bin_to_list/1, + bin_to_list/2,bin_to_list/3,list_to_bin/1]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% compile_pattern, a dummy +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +compile_pattern(Pattern) when is_binary(Pattern) -> + {[Pattern]}; +compile_pattern(Pattern) -> + try + [ true = is_binary(P) || P <- Pattern ], + {Pattern} + catch + _:_ -> + erlang:error(badarg) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% match and matches +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +match(H,N) -> + match(H,N,[]). +match(Haystack,Needle,Options) when is_binary(Needle) -> + match(Haystack,[Needle],Options); +match(Haystack,{Needles},Options) -> + match(Haystack,Needles,Options); +match(Haystack,Needles,Options) -> + try + true = is_binary(Haystack) and is_list(Needles), % badarg, not function_clause + case get_opts_match(Options,nomatch) of + nomatch -> + mloop(Haystack,Needles); + {A,B} when B > 0 -> + <<_:A/binary,SubStack:B/binary,_/binary>> = Haystack, + mloop(SubStack,Needles,A,B+A); + {A,B} when B < 0 -> + Start = A + B, + Len = -B, + <<_:Start/binary,SubStack:Len/binary,_/binary>> = Haystack, + mloop(SubStack,Needles,Start,Len+Start); + _ -> + nomatch + end + catch + _:_ -> + erlang:error(badarg) + end. +matches(H,N) -> + matches(H,N,[]). +matches(Haystack,Needle,Options) when is_binary(Needle) -> + matches(Haystack,[Needle],Options); +matches(Haystack,{Needles},Options) -> + matches(Haystack,Needles,Options); +matches(Haystack,Needles,Options) -> + try + true = is_binary(Haystack) and is_list(Needles), % badarg, not function_clause + case get_opts_match(Options,nomatch) of + nomatch -> + msloop(Haystack,Needles); + {A,B} when B > 0 -> + <<_:A/binary,SubStack:B/binary,_/binary>> = Haystack, + msloop(SubStack,Needles,A,B+A); + {A,B} when B < 0 -> + Start = A + B, + Len = -B, + <<_:Start/binary,SubStack:Len/binary,_/binary>> = Haystack, + msloop(SubStack,Needles,Start,Len+Start); + _ -> + [] + end + catch + _:_ -> + erlang:error(badarg) + end. + +mloop(Haystack,Needles) -> + mloop(Haystack,Needles,0,byte_size(Haystack)). + +mloop(_Haystack,_Needles,N,M) when N >= M -> + nomatch; +mloop(Haystack,Needles,N,M) -> + case mloop2(Haystack,Needles,N,nomatch) of + nomatch -> + % Not found + <<_:8,NewStack/binary>> = Haystack, + mloop(NewStack,Needles,N+1,M); + {N,Len} -> + {N,Len} + end. + +msloop(Haystack,Needles) -> + msloop(Haystack,Needles,0,byte_size(Haystack)). + +msloop(_Haystack,_Needles,N,M) when N >= M -> + []; +msloop(Haystack,Needles,N,M) -> + case mloop2(Haystack,Needles,N,nomatch) of + nomatch -> + % Not found + <<_:8,NewStack/binary>> = Haystack, + msloop(NewStack,Needles,N+1,M); + {N,Len} -> + NewN = N+Len, + if + NewN >= M -> + [{N,Len}]; + true -> + <<_:Len/binary,NewStack/binary>> = Haystack, + [{N,Len} | msloop(NewStack,Needles,NewN,M)] + end + end. + +mloop2(_Haystack,[],_N,Res) -> + Res; +mloop2(Haystack,[Needle|Tail],N,Candidate) -> + NS = byte_size(Needle), + case Haystack of + <<Needle:NS/binary,_/binary>> -> + NewCandidate = case Candidate of + nomatch -> + {N,NS}; + {N,ONS} when ONS < NS -> + {N,NS}; + Better -> + Better + end, + mloop2(Haystack,Tail,N,NewCandidate); + _ -> + mloop2(Haystack,Tail,N,Candidate) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% split +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +split(H,N) -> + split(H,N,[]). +split(Haystack,{Needles},Options) -> + split(Haystack, Needles, Options); +split(Haystack,Needles0,Options) -> + try + Needles = if + is_list(Needles0) -> + Needles0; + is_binary(Needles0) -> + [Needles0]; + true -> + exit(badtype) + end, + {Part,Global,Trim} = get_opts_split(Options,{nomatch,false,false}), + {Start,End,NewStack} = + case Part of + nomatch -> + {0,byte_size(Haystack),Haystack}; + {A,B} when B >= 0 -> + <<_:A/binary,SubStack:B/binary,_/binary>> = Haystack, + {A,A+B,SubStack}; + {A,B} when B < 0 -> + S = A + B, + L = -B, + <<_:S/binary,SubStack:L/binary,_/binary>> = Haystack, + {S,S+L,SubStack} + end, + MList = if + Global -> + msloop(NewStack,Needles,Start,End); + true -> + case mloop(NewStack,Needles,Start,End) of + nomatch -> + []; + X -> + [X] + end + end, + do_split(Haystack,MList,0,Trim) + catch + _:_ -> + erlang:error(badarg) + end. + +do_split(H,[],N,true) when N >= byte_size(H) -> + []; +do_split(H,[],N,_) -> + [part(H,{N,byte_size(H)-N})]; +do_split(H,[{A,B}|T],N,Trim) -> + case part(H,{N,A-N}) of + <<>> -> + Rest = do_split(H,T,A+B,Trim), + case {Trim, Rest} of + {true,[]} -> + []; + _ -> + [<<>> | Rest] + end; + Oth -> + [Oth | do_split(H,T,A+B,Trim)] + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% replace +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +replace(H,N,R) -> + replace(H,N,R,[]). +replace(Haystack,{Needles},Replacement,Options) -> + replace(Haystack,Needles,Replacement,Options); + +replace(Haystack,Needles0,Replacement,Options) -> + try + Needles = if + is_list(Needles0) -> + Needles0; + is_binary(Needles0) -> + [Needles0]; + true -> + exit(badtype) + end, + true = is_binary(Replacement), % Make badarg instead of function clause + {Part,Global,Insert} = get_opts_replace(Options,{nomatch,false,[]}), + {Start,End,NewStack} = + case Part of + nomatch -> + {0,byte_size(Haystack),Haystack}; + {A,B} when B >= 0 -> + <<_:A/binary,SubStack:B/binary,_/binary>> = Haystack, + {A,A+B,SubStack}; + {A,B} when B < 0 -> + S = A + B, + L = -B, + <<_:S/binary,SubStack:L/binary,_/binary>> = Haystack, + {S,S+L,SubStack} + end, + MList = if + Global -> + msloop(NewStack,Needles,Start,End); + true -> + case mloop(NewStack,Needles,Start,End) of + nomatch -> + []; + X -> + [X] + end + end, + ReplList = case Insert of + [] -> + Replacement; + Y when is_integer(Y) -> + splitat(Replacement,0,[Y]); + Li when is_list(Li) -> + splitat(Replacement,0,lists:sort(Li)) + end, + erlang:iolist_to_binary(do_replace(Haystack,MList,ReplList,0)) + catch + _:_ -> + erlang:error(badarg) + end. + + +do_replace(H,[],_,N) -> + [part(H,{N,byte_size(H)-N})]; +do_replace(H,[{A,B}|T],Replacement,N) -> + [part(H,{N,A-N}), + if + is_list(Replacement) -> + do_insert(Replacement, part(H,{A,B})); + true -> + Replacement + end + | do_replace(H,T,Replacement,A+B)]. + +do_insert([X],_) -> + [X]; +do_insert([H|T],R) -> + [H,R|do_insert(T,R)]. + +splitat(H,N,[]) -> + [part(H,{N,byte_size(H)-N})]; +splitat(H,N,[I|T]) -> + [part(H,{N,I-N})|splitat(H,I,T)]. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% first, last and at +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +first(Subject) -> + try + <<A:8,_/binary>> = Subject, + A + catch + _:_ -> + erlang:error(badarg) + end. + +last(Subject) -> + try + N = byte_size(Subject) - 1, + <<_:N/binary,A:8>> = Subject, + A + catch + _:_ -> + erlang:error(badarg) + end. + +at(Subject,X) -> + try + <<_:X/binary,A:8,_/binary>> = Subject, + A + catch + _:_ -> + erlang:error(badarg) + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% bin_to_list +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +bin_to_list(Subject) -> + try + binary_to_list(Subject) + catch + _:_ -> + erlang:error(badarg) + end. + +bin_to_list(Subject,T) -> + try + {A0,B0} = T, + {A,B} = if + B0 < 0 -> + {A0+B0,-B0}; + true -> + {A0,B0} + end, + binary_to_list(Subject,A+1,A+B) + catch + _:_ -> + erlang:error(badarg) + end. + +bin_to_list(Subject,A,B) -> + try + bin_to_list(Subject,{A,B}) + catch + _:_ -> + erlang:error(badarg) + end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% list_to_bin +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +list_to_bin(List) -> + try + erlang:list_to_binary(List) + catch + _:_ -> + erlang:error(badarg) + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% longest_common_prefix +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +longest_common_prefix(LB) -> + try + true = is_list(LB) and (length(LB) > 0), % Make badarg instead of function clause + do_longest_common_prefix(LB,0) + catch + _:_ -> + erlang:error(badarg) + end. + +do_longest_common_prefix(LB,X) -> + case do_lcp(LB,X,no) of + true -> + do_longest_common_prefix(LB,X+1); + false -> + X + end. +do_lcp([],_,_) -> + true; +do_lcp([Bin|_],X,_) when byte_size(Bin) =< X -> + false; +do_lcp([Bin|T],X,no) -> + Ch = at(Bin,X), + do_lcp(T,X,Ch); +do_lcp([Bin|T],X,Ch) -> + Ch2 = at(Bin,X), + if + Ch =:= Ch2 -> + do_lcp(T,X,Ch); + true -> + false + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% longest_common_suffix +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +longest_common_suffix(LB) -> + try + true = is_list(LB) and (length(LB) > 0), % Make badarg instead of function clause + do_longest_common_suffix(LB,0) + catch + _:_ -> + erlang:error(badarg) + end. + +do_longest_common_suffix(LB,X) -> + case do_lcs(LB,X,no) of + true -> + do_longest_common_suffix(LB,X+1); + false -> + X + end. +do_lcs([],_,_) -> + true; +do_lcs([Bin|_],X,_) when byte_size(Bin) =< X -> + false; +do_lcs([Bin|T],X,no) -> + Ch = at(Bin,byte_size(Bin) - 1 - X), + do_lcs(T,X,Ch); +do_lcs([Bin|T],X,Ch) -> + Ch2 = at(Bin,byte_size(Bin) - 1 - X), + if + Ch =:= Ch2 -> + do_lcs(T,X,Ch); + true -> + false + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% part +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +part(Subject,Part) -> + try + do_part(Subject,Part) + catch + _:_ -> + erlang:error(badarg) + end. + +part(Subject,Pos,Len) -> + part(Subject,{Pos,Len}). + +do_part(Bin,{A,B}) when B >= 0 -> + <<_:A/binary,Sub:B/binary,_/binary>> = Bin, + Sub; +do_part(Bin,{A,B}) when B < 0 -> + S = A + B, + L = -B, + <<_:S/binary,Sub:L/binary,_/binary>> = Bin, + Sub. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% copy +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +copy(Subject) -> + copy(Subject,1). +copy(Subject,N) -> + try + true = is_integer(N) and (N >= 0) and is_binary(Subject), % Badarg, not function clause + erlang:list_to_binary(lists:duplicate(N,Subject)) + catch + _:_ -> + erlang:error(badarg) + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_unsigned +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +encode_unsigned(Unsigned) -> + encode_unsigned(Unsigned,big). +encode_unsigned(Unsigned,Endian) -> + try + true = is_integer(Unsigned) and (Unsigned >= 0), + if + Unsigned =:= 0 -> + <<0>>; + true -> + case Endian of + big -> + list_to_binary(do_encode(Unsigned,[])); + little -> + list_to_binary(do_encode_r(Unsigned)) + end + end + catch + _:_ -> + erlang:error(badarg) + end. + +do_encode(0,L) -> + L; +do_encode(N,L) -> + Byte = N band 255, + NewN = N bsr 8, + do_encode(NewN,[Byte|L]). + +do_encode_r(0) -> + []; +do_encode_r(N) -> + Byte = N band 255, + NewN = N bsr 8, + [Byte|do_encode_r(NewN)]. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_unsigned +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +decode_unsigned(Subject) -> + decode_unsigned(Subject,big). + +decode_unsigned(Subject,Endian) -> + try + true = is_binary(Subject), + case Endian of + big -> + do_decode(Subject,0); + little -> + do_decode_r(Subject,0) + end + catch + _:_ -> + erlang:error(badarg) + end. + +do_decode(<<>>,N) -> + N; +do_decode(<<X:8,Bin/binary>>,N) -> + do_decode(Bin,(N bsl 8) bor X). + +do_decode_r(<<>>,N) -> + N; +do_decode_r(Bin,N) -> + Sz = byte_size(Bin) - 1, + <<NewBin:Sz/binary,X>> = Bin, + do_decode_r(NewBin, (N bsl 8) bor X). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% referenced_byte_size cannot +%% be implemented in pure +%% erlang +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +referenced_byte_size(Bin) when is_binary(Bin) -> + erlang:error(not_implemented); +referenced_byte_size(_) -> + erlang:error(badarg). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Simple helper functions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Option "parsing" +get_opts_match([],Part) -> + Part; +get_opts_match([{scope,{A,B}} | T],_Part) -> + get_opts_match(T,{A,B}); +get_opts_match(_,_) -> + throw(badopt). + +get_opts_split([],{Part,Global,Trim}) -> + {Part,Global,Trim}; +get_opts_split([{scope,{A,B}} | T],{_Part,Global,Trim}) -> + get_opts_split(T,{{A,B},Global,Trim}); +get_opts_split([global | T],{Part,_Global,Trim}) -> + get_opts_split(T,{Part,true,Trim}); +get_opts_split([trim | T],{Part,Global,_Trim}) -> + get_opts_split(T,{Part,Global,true}); +get_opts_split(_,_) -> + throw(badopt). + +get_opts_replace([],{Part,Global,Insert}) -> + {Part,Global,Insert}; +get_opts_replace([{scope,{A,B}} | T],{_Part,Global,Insert}) -> + get_opts_replace(T,{{A,B},Global,Insert}); +get_opts_replace([global | T],{Part,_Global,Insert}) -> + get_opts_replace(T,{Part,true,Insert}); +get_opts_replace([{insert_replaced,N} | T],{Part,Global,_Insert}) -> + get_opts_replace(T,{Part,Global,N}); +get_opts_replace(_,_) -> + throw(badopt). diff --git a/lib/stdlib/test/dummy1_h.erl b/lib/stdlib/test/dummy1_h.erl index 4377d774a3..5b503d5984 100644 --- a/lib/stdlib/test/dummy1_h.erl +++ b/lib/stdlib/test/dummy1_h.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(dummy1_h). @@ -21,7 +21,7 @@ %% Test event handler for gen_event_SUITE.erl -export([init/1, handle_event/2, handle_call/2, handle_info/2, - terminate/2]). + terminate/2, format_status/2]). init(make_error) -> {error, my_error}; @@ -67,4 +67,5 @@ terminate(remove_handler, Parent) -> terminate(_Reason, _State) -> ok. - +format_status(_Opt, [_PDict, _State]) -> + "dummy1_h handler state". diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index 9a3ae0baf5..e31dfdd764 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -19,11 +19,12 @@ -module(epp_SUITE). -export([all/1]). --export([rec_1/1, predef_mac/1, +-export([rec_1/1, predef_mac/1, upcase_mac/1, upcase_mac_1/1, upcase_mac_2/1, variable/1, variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1, pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1, - otp_8130/1, overload_mac/1, otp_8388/1]). + otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8503/1, + otp_8562/1, otp_8665/1]). -export([epp_parse_erl_form/2]). @@ -38,7 +39,7 @@ -define(config(A,B),config(A,B)). %% -define(t, test_server). -define(t, io). -config(priv_dir, _) -> +config(priv_dir, _) -> filename:absname("./epp_SUITE_priv"); config(data_dir, _) -> filename:absname("./epp_SUITE_data"). @@ -63,7 +64,7 @@ all(doc) -> all(suite) -> [rec_1, upcase_mac, predef_mac, variable, otp_4870, otp_4871, otp_5362, pmod, not_circular, skip_header, otp_6277, otp_7702, otp_8130, - overload_mac, otp_8388]. + overload_mac, otp_8388, otp_8470, otp_8503, otp_8562, otp_8665]. rec_1(doc) -> ["Recursive macros hang or crash epp (OTP-1398)."]; @@ -191,7 +192,7 @@ variable_1(Config) when is_list(Config) -> %% variable_1.erl includes variable_1_include.hrl and %% variable_1_include_dir.hrl. ?line {ok, List} = epp:parse_file(File, [], []), - ?line {value, {attribute,_,a,{value1,value2}}} = + ?line {value, {attribute,_,a,{value1,value2}}} = lists:keysearch(a,3,List), ok. @@ -218,13 +219,13 @@ otp_4871(Config) when is_list(Config) -> %% Testing crash in erl_scan. Unfortunately there currently is %% no known way to crash erl_scan so it is emulated by killing the %% file io server. This assumes lots of things about how - %% the processes are started and how monitors are set up, + %% the processes are started and how monitors are set up, %% so there are some sanity checks before killing. ?line {ok,Epp} = epp:open(File, []), timer:sleep(1), ?line {current_function,{epp,_,_}} = process_info(Epp, current_function), ?line {monitored_by,[Io]} = process_info(Epp, monitored_by), - ?line {current_function,{file_io_server,_,_}} = + ?line {current_function,{file_io_server,_,_}} = process_info(Io, current_function), ?line exit(Io, emulate_crash), timer:sleep(1), @@ -301,7 +302,7 @@ otp_5362(Config) when is_list(Config) -> Back_hrl = [<<" -file(\"">>,File_Back,<<"\", 2). ">>], - + ?line ok = file:write_file(File_Back, Back), ?line ok = file:write_file(File_Back_hrl, list_to_binary(Back_hrl)), @@ -332,7 +333,7 @@ otp_5362(Config) when is_list(Config) -> ?line ok = file:write_file(File_Change, list_to_binary(Change)), - ?line {ok, change_5362, ChangeWarnings} = + ?line {ok, change_5362, ChangeWarnings} = compile:file(File_Change, Copts), ?line true = message_compare( [{File_Change,[{{1002,21},erl_lint,{unused_var,'B'}}]}, @@ -440,9 +441,9 @@ skip_header(Config) when is_list(Config) -> that should be skipped -module(epp_test_skip_header). -export([main/1]). - + main(_) -> ?MODULE. - + ">>), ?line {ok, Fd} = file:open(File, [read]), ?line io:get_line(Fd, ''), @@ -493,9 +494,9 @@ otp_7702(Config) when is_list(Config) -> t() -> ?RECEIVE(foo, bar).">>, ?line ok = file:write_file(File, Contents), - ?line {ok, file_7702, []} = + ?line {ok, file_7702, []} = compile:file(File, [debug_info,return,{outdir,Dir}]), - + BeamFile = filename:join(Dir, "file_7702.beam"), {ok, AC} = beam_lib:chunks(BeamFile, [abstract_code]), @@ -505,7 +506,7 @@ otp_7702(Config) when is_list(Config) -> L end, Forms2 = [erl_lint:modify_line(Form, Fun) || Form <- Forms], - ?line + ?line [{attribute,1,file,_}, _, _, @@ -616,9 +617,9 @@ otp_8130(Config) when is_list(Config) -> "t() -> 14 = (#file_info{size = 14})#file_info.size, ok.\n">>, ok}, - {otp_8130_7, + {otp_8130_7_new, <<"-record(b, {b}).\n" - "-define(A, {{a,#b.b.\n" + "-define(A, {{a,#b.b).\n" "t() -> {{a,2}} = ?A}}, ok.">>, ok}, @@ -636,7 +637,7 @@ otp_8130(Config) when is_list(Config) -> ], ?line [] = run(Config, Ts), - + Cs = [{otp_8130_c1, <<"-define(M1(A), if\n" "A =:= 1 -> B;\n" @@ -680,7 +681,7 @@ otp_8130(Config) when is_list(Config) -> <<"\n-include_lib(\"$apa/foo.hrl\").\n">>, {errors,[{{2,2},epp,{include,lib,"$apa/foo.hrl"}}],[]}}, - + {otp_8130_c9, <<"-define(S, ?S).\n" "t() -> ?S.\n">>, @@ -750,7 +751,14 @@ otp_8130(Config) when is_list(Config) -> {otp_8130_c24, <<"\n-include(\"no such file.erl\").\n">>, - {errors,[{{2,2},epp,{include,file,"no such file.erl"}}],[]}} + {errors,[{{2,2},epp,{include,file,"no such file.erl"}}],[]}}, + + {otp_8130_7, + <<"-record(b, {b}).\n" + "-define(A, {{a,#b.b.\n" + "t() -> {{a,2}} = ?A}}, ok.">>, + {errors,[{{2,20},epp,missing_parenthesis}, + {{3,19},epp,{undefined,'A',none}}],[]}} ], ?line [] = compile(Config, Cs), @@ -767,7 +775,7 @@ otp_8130(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "otp_8130.erl"), - ?line ok = file:write_file(File, + ?line ok = file:write_file(File, "-module(otp_8130).\n" "-define(a, 3.14).\n" "t() -> ?a.\n"), @@ -780,7 +788,7 @@ otp_8130(Config) when is_list(Config) -> ?line {eof,_} = epp:scan_erl_form(Epp), ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE', 'MACHINE','MODULE','MODULE_STRING',a] = macs(Epp), - ?line epp:close(Epp), + ?line epp:close(Epp), %% escript ModuleStr = "any_name", @@ -807,7 +815,7 @@ otp_8130(Config) when is_list(Config) -> PreDefMacros = [{a,1},a], ?line {error,{redefine,a}} = epp:open(File, [], PreDefMacros) end(), - + ?line {error,enoent} = epp:open("no such file", []), ?line {error,enoent} = epp:parse_file("no such file", [], []), @@ -933,7 +941,7 @@ ifdef(Config) -> <<"\n-if.\n" "-endif.\n">>, {errors,[{{2,2},epp,{'NYI','if'}}],[]}}, - + {define_c7, <<"-ifndef(a).\n" "-elif.\n" @@ -1047,13 +1055,13 @@ overload_mac(Config) when is_list(Config) -> "-undef(A).\n" "t1() -> ?A.\n", "t2() -> ?A(1).">>, - {errors,[{{4,9},epp,{undefined,'A', none}}, - {{5,9},epp,{undefined,'A', 1}}],[]}}, + {errors,[{{4,10},epp,{undefined,'A', none}}, + {{5,10},epp,{undefined,'A', 1}}],[]}}, %% cannot overload predefined macros {overload_mac_c2, <<"-define(MODULE(X), X).">>, - {errors,[{{1,9},epp,{redefine_predef,'MODULE'}}],[]}}, + {errors,[{{1,50},epp,{redefine_predef,'MODULE'}}],[]}}, %% cannot overload macros with same arity {overload_mac_c3, @@ -1120,25 +1128,87 @@ otp_8388(Config) when is_list(Config) -> {macro_1, <<"-define(m(A), A).\n" "t() -> ?m(,).\n">>, - {errors,[{{2,11},epp,{arg_error,m}}],[]}}, + {errors,[{{2,9},epp,{arg_error,m}}],[]}}, {macro_2, <<"-define(m(A), A).\n" "t() -> ?m(a,).\n">>, - {errors,[{{2,12},epp,{arg_error,m}}],[]}}, + {errors,[{{2,9},epp,{arg_error,m}}],[]}}, {macro_3, <<"-define(LINE, a).\n">>, - {errors,[{{1,9},epp,{redefine_predef,'LINE'}}],[]}}, + {errors,[{{1,50},epp,{redefine_predef,'LINE'}}],[]}}, {macro_4, <<"-define(A(B, C, D), {B,C,D}).\n" "t() -> ?A(a,,3).\n">>, - {errors,[{{2,8},epp,{mismatch,'A'}}],[]}}, + {errors,[{{2,9},epp,{mismatch,'A'}}],[]}}, {macro_5, <<"-define(Q, {?F0(), ?F1(,,4)}).\n">>, - {errors,[{{1,24},epp,{arg_error,'F1'}}],[]}} + {errors,[{{1,62},epp,{arg_error,'F1'}}],[]}}, + {macro_6, + <<"-define(FOO(X), ?BAR(X)).\n" + "-define(BAR(X), ?FOO(X)).\n" + "-undef(FOO).\n" + "test() -> ?BAR(1).\n">>, + {errors,[{{4,12},epp,{undefined,'FOO',1}}],[]}} ], ?line [] = compile(Config, Ts), ok. +otp_8470(doc) -> + ["OTP-8470. Bugfix (one request - two replies)."]; +otp_8470(suite) -> + []; +otp_8470(Config) when is_list(Config) -> + Dir = ?config(priv_dir, Config), + C = <<"-file(\"erl_parse.yrl\", 486).\n" + "-file(\"erl_parse.yrl\", 488).\n">>, + ?line File = filename:join(Dir, "otp_8470.erl"), + ?line ok = file:write_file(File, C), + ?line {ok, _List} = epp:parse_file(File, [], []), + file:delete(File), + ?line receive _ -> fail() after 0 -> ok end, + ok. + +otp_8503(doc) -> + ["OTP-8503. Record with no fields is considered typed."]; +otp_8503(suite) -> + []; +otp_8503(Config) when is_list(Config) -> + Dir = ?config(priv_dir, Config), + C = <<"-record(r, {}).">>, + ?line File = filename:join(Dir, "otp_8503.erl"), + ?line ok = file:write_file(File, C), + ?line {ok, List} = epp:parse_file(File, [], []), + ?line [_] = [F || {attribute,_,type,{{record,r},[],[]}}=F <- List], + file:delete(File), + ?line receive _ -> fail() after 0 -> ok end, + ok. + +otp_8562(doc) -> + ["OTP-8503. Record with no fields is considered typed."]; +otp_8562(suite) -> + []; +otp_8562(Config) when is_list(Config) -> + Cs = [{otp_8562, + <<"-define(P(), {a,b}.\n" + "-define(P3, .\n">>, + {errors,[{{1,60},epp,missing_parenthesis}, + {{2,13},epp,missing_parenthesis}], []}} + ], + ?line [] = compile(Config, Cs), + ok. + +otp_8665(doc) -> + ["OTP-8665. Bugfix premature end."]; +otp_8665(suite) -> + []; +otp_8665(Config) when is_list(Config) -> + Cs = [{otp_8562, + <<"-define(A, a)\n">>, + {errors,[{{1,54},epp,premature_end}],[]}} + ], + ?line [] = compile(Config, Cs), + ok. + check(Config, Tests) -> eval_tests(Config, fun check_test/2, Tests). @@ -1155,7 +1225,7 @@ eval_tests(Config, Fun, Tests) -> case message_compare(E, Return) of true -> BadL; - false -> + false -> ?t:format("~nTest ~p failed. Expected~n ~p~n" "but got~n ~p~n", [N, E, Return]), fail() @@ -1170,9 +1240,9 @@ check_test(Config, Test) -> ?line File = filename:join(PrivDir, Filename), ?line ok = file:write_file(File, Test), ?line case epp:parse_file(File, [PrivDir], []) of - {ok,Forms} -> + {ok,Forms} -> [E || E={error,_} <- Forms]; - {error,Error} -> + {error,Error} -> Error end. @@ -1187,7 +1257,7 @@ compile_test(Config, Test0) -> {ok, Ws} -> warnings(File, Ws); Else -> Else end. - + warnings(File, Ws) -> case lists:append([W || {F, W} <- Ws, F =:= File]) of [] -> []; @@ -1231,7 +1301,7 @@ message_compare(T, T) -> message_compare(T1, T2) -> ln(T1) =:= T2. -%% Replaces locations like {Line,Column} with Line. +%% Replaces locations like {Line,Column} with Line. ln({warnings,L}) -> {warnings,ln0(L)}; ln({errors,EL,WL}) -> diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 8581b496aa..d0c0d68b4a 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -1784,6 +1784,9 @@ otp_5362(Config) when is_list(Config) -> {15,erl_lint,{undefined_field,ok,nix}}, {16,erl_lint,{field_name_is_variable,ok,'Var'}}]}}, + %% Nowarn_bif_clash has changed behaviour as local functions + %% nowdays supersede auto-imported BIFs, why nowarn_bif_clash in itself generates an error + %% (OTP-8579) /PaN {otp_5362_4, <<"-compile(nowarn_deprecated_function). -compile(nowarn_bif_clash). @@ -1795,9 +1798,8 @@ otp_5362(Config) when is_list(Config) -> warn_deprecated_function, warn_bif_clash]}, {error, - [{5,erl_lint,{call_to_redefined_bif,{spawn,1}}}], - [{3,erl_lint,{redefine_bif,{spawn,1}}}, - {4,erl_lint,{deprecated,{erlang,hash,2},{erlang,phash2,2}, + [{5,erl_lint,{call_to_redefined_old_bif,{spawn,1}}}], + [{4,erl_lint,{deprecated,{erlang,hash,2},{erlang,phash2,2}, "in a future release"}}]}}, {otp_5362_5, @@ -1808,8 +1810,8 @@ otp_5362(Config) when is_list(Config) -> spawn(A). ">>, {[nowarn_unused_function]}, - {warnings, - [{3,erl_lint,{redefine_bif,{spawn,1}}}]}}, + {errors, + [{2,erl_lint,disallowed_nowarn_bif_clash}],[]}}, %% The special nowarn_X are not affected by general warn_X. {otp_5362_6, @@ -1822,8 +1824,8 @@ otp_5362(Config) when is_list(Config) -> {[nowarn_unused_function, warn_deprecated_function, warn_bif_clash]}, - {warnings, - [{3,erl_lint,{redefine_bif,{spawn,1}}}]}}, + {errors, + [{2,erl_lint,disallowed_nowarn_bif_clash}],[]}}, {otp_5362_7, <<"-export([spawn/1]). @@ -1838,7 +1840,9 @@ otp_5362(Config) when is_list(Config) -> spawn(A). ">>, {[nowarn_unused_function]}, - {error,[{4,erl_lint,{bad_nowarn_bif_clash,{spawn,2}}}], + {error,[{3,erl_lint,disallowed_nowarn_bif_clash}, + {4,erl_lint,disallowed_nowarn_bif_clash}, + {4,erl_lint,{bad_nowarn_bif_clash,{spawn,2}}}], [{5,erl_lint,{bad_nowarn_deprecated_function,{3,hash,-1}}}, {5,erl_lint,{bad_nowarn_deprecated_function,{erlang,hash,-1}}}, {5,erl_lint,{bad_nowarn_deprecated_function,{{a,b,c},hash,-1}}}]} @@ -1865,7 +1869,21 @@ otp_5362(Config) when is_list(Config) -> t() -> #a{}. ">>, {[]}, - []} + []}, + + {otp_5362_10, + <<"-compile({nowarn_deprecated_function,{erlang,hash,2}}). + -compile({nowarn_bif_clash,{spawn,1}}). + -import(x,[spawn/1]). + spin(A) -> + erlang:hash(A, 3000), + spawn(A). + ">>, + {[nowarn_unused_function, + warn_deprecated_function, + warn_bif_clash]}, + {errors, + [{2,erl_lint,disallowed_nowarn_bif_clash}],[]}} ], @@ -2234,7 +2252,7 @@ otp_5878(Config) when is_list(Config) -> {15,erl_lint,{undefined_field,r3,q}}, {17,erl_lint,{undefined_field,r,q}}, {21,erl_lint,illegal_guard_expr}, - {23,erl_lint,illegal_guard_expr}], + {23,erl_lint,{illegal_guard_local_call,{l,0}}}], []} = run_test2(Config, Ill1, [warn_unused_record]), @@ -2389,9 +2407,9 @@ bif_clash(Config) when is_list(Config) -> N. ">>, [], - {errors,[{2,erl_lint,{call_to_redefined_bif,{size,1}}}],[]}}, + {errors,[{2,erl_lint,{call_to_redefined_old_bif,{size,1}}}],[]}}, - %% Verify that (some) warnings can be turned off. + %% Verify that warnings can not be turned off in the old way. {clash2, <<"-export([t/1,size/1]). t(X) -> @@ -2400,17 +2418,198 @@ bif_clash(Config) when is_list(Config) -> size({N,_}) -> N. - %% My own abs/1 function works on lists too. - %% Unfortunately, it is not exported, so there will - %% be a warning that can't be turned off. + %% My own abs/1 function works on lists too. From R14 this really works. abs([H|T]) when $a =< H, H =< $z -> [H-($a-$A)|abs(T)]; abs([H|T]) -> [H|abs(T)]; abs([]) -> []; abs(X) -> erlang:abs(X). ">>, - {[nowarn_bif_clash]}, - {warnings,[{11,erl_lint,{redefine_bif,{abs,1}}}, - {11,erl_lint,{unused_function,{abs,1}}}]}}], + {[nowarn_unused_function,nowarn_bif_clash]}, + {errors,[{erl_lint,disallowed_nowarn_bif_clash}],[]}}, + %% As long as noone calls an overridden BIF, it's totally OK + {clash3, + <<"-export([size/1]). + size({N,_}) -> + N; + size(X) -> + erlang:size(X). + ">>, + [], + []}, + %% But this is totally wrong - meaning of the program changed in R14, so this is an error + {clash4, + <<"-export([size/1]). + size({N,_}) -> + N; + size(X) -> + size(X). + ">>, + [], + {errors,[{5,erl_lint,{call_to_redefined_old_bif,{size,1}}}],[]}}, + %% For a post R14 bif, its only a warning + {clash5, + <<"-export([binary_part/2]). + binary_part({B,_},{X,Y}) -> + binary_part(B,{X,Y}); + binary_part(B,{X,Y}) -> + binary:part(B,X,Y). + ">>, + [], + {warnings,[{3,erl_lint,{call_to_redefined_bif,{binary_part,2}}}]}}, + %% If you really mean to call yourself here, you can "unimport" size/1 + {clash6, + <<"-export([size/1]). + -compile({no_auto_import,[size/1]}). + size([]) -> + 0; + size({N,_}) -> + N; + size([_|T]) -> + 1+size(T). + ">>, + [], + []}, + %% Same for the post R14 autoimport warning + {clash7, + <<"-export([binary_part/2]). + -compile({no_auto_import,[binary_part/2]}). + binary_part({B,_},{X,Y}) -> + binary_part(B,{X,Y}); + binary_part(B,{X,Y}) -> + binary:part(B,X,Y). + ">>, + [], + []}, + %% but this doesn't mean the local function is allowed in a guard... + {clash8, + <<"-export([x/1]). + -compile({no_auto_import,[binary_part/2]}). + x(X) when binary_part(X,{1,2}) =:= <<1,2>> -> + hej. + binary_part({B,_},{X,Y}) -> + binary_part(B,{X,Y}); + binary_part(B,{X,Y}) -> + binary:part(B,X,Y). + ">>, + [], + {errors,[{3,erl_lint,{illegal_guard_local_call,{binary_part,2}}}],[]}}, + %% no_auto_import is not like nowarn_bif_clash, it actually removes the autoimport + {clash9, + <<"-export([x/1]). + -compile({no_auto_import,[binary_part/2]}). + x(X) -> + binary_part(X,{1,2}) =:= <<1,2>>. + ">>, + [], + {errors,[{4,erl_lint,{undefined_function,{binary_part,2}}}],[]}}, + %% but we could import it again... + {clash10, + <<"-export([x/1]). + -compile({no_auto_import,[binary_part/2]}). + -import(erlang,[binary_part/2]). + x(X) -> + binary_part(X,{1,2}) =:= <<1,2>>. + ">>, + [], + []}, + %% and actually use it in a guard... + {clash11, + <<"-export([x/1]). + -compile({no_auto_import,[binary_part/2]}). + -import(erlang,[binary_part/2]). + x(X) when binary_part(X,{0,1}) =:= <<0>> -> + binary_part(X,{1,2}) =:= <<1,2>>. + ">>, + [], + []}, + %% but for non-obvious historical reasons, imported functions cannot be used in + %% fun construction without the module name... + {clash12, + <<"-export([x/1]). + -compile({no_auto_import,[binary_part/2]}). + -import(erlang,[binary_part/2]). + x(X) when binary_part(X,{0,1}) =:= <<0>> -> + binary_part(X,{1,2}) =:= fun binary_part/2. + ">>, + [], + {errors,[{5,erl_lint,{undefined_function,{binary_part,2}}}],[]}}, + %% Not from erlang and not from anywhere else + {clash13, + <<"-export([x/1]). + -compile({no_auto_import,[binary_part/2]}). + -import(x,[binary_part/2]). + x(X) -> + binary_part(X,{1,2}) =:= fun binary_part/2. + ">>, + [], + {errors,[{5,erl_lint,{undefined_function,{binary_part,2}}}],[]}}, + %% ...while real auto-import is OK. + {clash14, + <<"-export([x/1]). + x(X) when binary_part(X,{0,1}) =:= <<0>> -> + binary_part(X,{1,2}) =:= fun binary_part/2. + ">>, + [], + []}, + %% Import directive clashing with old bif is an error, regardless of if it's called or not + {clash15, + <<"-export([x/1]). + -import(x,[abs/1]). + x(X) -> + binary_part(X,{1,2}). + ">>, + [], + {errors,[{2,erl_lint,{redefine_old_bif_import,{abs,1}}}],[]}}, + %% For a new BIF, it's only a warning + {clash16, + <<"-export([x/1]). + -import(x,[binary_part/3]). + x(X) -> + abs(X). + ">>, + [], + {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}}, + %% And, you cannot redefine already imported things that aren't auto-imported + {clash17, + <<"-export([x/1]). + -import(x,[binary_port/3]). + -import(y,[binary_port/3]). + x(X) -> + abs(X). + ">>, + [], + {errors,[{3,erl_lint,{redefine_import,{{binary_port,3},x}}}],[]}}, + %% Not with local functions either + {clash18, + <<"-export([x/1]). + -import(x,[binary_port/3]). + binary_port(A,B,C) -> + binary_part(A,B,C). + x(X) -> + abs(X). + ">>, + [], + {errors,[{3,erl_lint,{define_import,{binary_port,3}}}],[]}}, + %% Like clash8: Dont accept a guard if it's explicitly module-name called either + {clash19, + <<"-export([binary_port/3]). + -compile({no_auto_import,[binary_part/3]}). + -import(x,[binary_part/3]). + binary_port(A,B,C) when x:binary_part(A,B,C) -> + binary_part(A,B,C+1). + ">>, + [], + {errors,[{4,erl_lint,illegal_guard_expr}],[]}}, + %% Not with local functions either + {clash20, + <<"-export([binary_port/3]). + -import(x,[binary_part/3]). + binary_port(A,B,C) -> + binary_part(A,B,C). + ">>, + [warn_unused_import], + {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}} + ], ?line [] = run(Config, Ts), ok. diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index 0a119d1e38..c57541fba9 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %%%---------------------------------------------------------------- @@ -45,7 +45,8 @@ hook/1, neg_indent/1, tickets/1, - otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1]). + otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1, + otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1]). %% Internal export. -export([ehook/6]). @@ -149,15 +150,15 @@ recs(Config) when is_list(Config) -> (A#r1.a)#r.a > 3 -> 3 end(#r1{a = #r{a = 4}}), 7 = fun(A) when record(A#r3.a, r1) -> 7 end(#r3{}), - [#r1{a = 2,b = 1}] = + [#r1{a = 2,b = 1}] = fun() -> - [A || A <- [#r1{a = 1, b = 3}, - #r2{a = 2,b = 1}, + [A || A <- [#r1{a = 1, b = 3}, + #r2{a = 2,b = 1}, #r1{a = 2, b = 1}], - A#r1.a > + A#r1.a > A#r1.b] end(), - {[_],b} = + {[_],b} = fun(L) -> %% A is checked only once: R1 = [{A,B} || A <- L, A#r1.a, B <- L, A#r1.b], @@ -176,7 +177,7 @@ recs(Config) when is_list(Config) -> end(#r1{a = 2}), %% The test done twice (an effect of doing the test as soon as possible). - 3 = fun(A) when A#r1.a > 3, + 3 = fun(A) when A#r1.a > 3, record(A, r1) -> 3 end(#r1{a = 5}), @@ -250,18 +251,18 @@ recs(Config) when is_list(Config) -> ok end(), - both = fun(A) when A#r.a, A#r.b -> both + both = fun(A) when A#r.a, A#r.b -> both end(#r{a = true, b = true}), ok = fun() -> - F = fun(A, B) when ((A#r1.a) orelse (B#r2.a)) + F = fun(A, B) when ((A#r1.a) orelse (B#r2.a)) or (B#r2.b) or (A#r1.b) -> true; (_, _) -> false end, - true = F(#r1{a = false, b = false}, + true = F(#r1{a = false, b = false}, #r2{a = false, b = true}), - false = F(#r1{a = true, b = true}, + false = F(#r1{a = true, b = true}, #r1{a = false, b = true}), ok end(), @@ -272,7 +273,7 @@ recs(Config) when is_list(Config) -> <<"-record(r1, {a, b = foo:bar(kljlfjsdlf, kjlksdjf)}). -record(r2, {c = #r1{}, d = #r1{a = bar:foo(kljklsjdf)}}). - t() -> + t() -> R = #r2{}, R#r2{c = R, d = #r1{}}.">>} ], @@ -303,10 +304,10 @@ try_catch(Config) when is_list(Config) -> {try_6, <<"t() -> try 1=2 catch throw:{badmatch,2} -> 3 end.">>}, {try_7, - <<"t() -> try 1=2 of 3 -> 4 + <<"t() -> try 1=2 of 3 -> 4 catch error:{badmatch,2} -> 5 end.">>}, {try_8, - <<"t() -> try 1=2 + <<"t() -> try 1=2 catch error:{badmatch,2} -> 3 after put(try_catch, 4) end.">>}, {try_9, @@ -370,7 +371,7 @@ receive_after(Config) when is_list(Config) -> {X,Y}; Z -> Z - after + after foo:bar() -> {3,4} end.">>} @@ -428,7 +429,7 @@ head_tail(Config) when is_list(Config) -> {list_4, <<"t() -> [a].">>}, {list_5, - <<"t() -> + <<"t() -> [foo:bar(lkjljlskdfj, klsdajflds, sdafkljsdlfkjdas, kjlsdadjl), bar:foo(kljlkjsdf, lkjsdlfj, [kljsfj, sdfdsfsad])].">>} ], @@ -461,7 +462,7 @@ cond1(Config) when is_list(Config) -> " true ->\n" " {x,y}\n" "end" = CChars, -% ?line ok = pp_expr(<<"cond +% ?line ok = pp_expr(<<"cond % {foo,bar} -> % [a,b]; % true -> @@ -543,7 +544,7 @@ old_mnemosyne_syntax(Config) when is_list(Config) -> " X <- table(tab),\n" " X.foo = bar\n" " ]\n" - "end" = + "end" = lists:flatten(erl_pp:expr(Q)), R = {rule,12,sales,2, @@ -558,7 +559,7 @@ old_mnemosyne_syntax(Config) when is_list(Config) -> {atom,14,sales}}]}]}, ?line "sales(E, employee) :-\n" " E <- table(employee),\n" - " E.salary = sales.\n" = + " E.salary = sales.\n" = lists:flatten(erl_pp:form(R)), ok. @@ -659,7 +660,7 @@ hook(Config) when is_list(Config) -> ?line "INVALID-FORM:{foo,bar}:" = lists:flatten(erl_pp:expr({foo,bar})), - %% A list (as before R6), not a list of lists. + %% A list (as before R6), not a list of lists. G = [{op,1,'>',{atom,1,a},{foo,{atom,1,b}}}], % not a proper guard GChars = lists:flatten(erl_pp:guard(G, H)), G2 = [{op,1,'>',{atom,1,a}, @@ -676,23 +677,23 @@ hook(Config) when is_list(Config) -> %% Note: no leading spaces before "begin". Block = {block,0,[{match,0,{var,0,'A'},{integer,0,3}}, {atom,0,true}]}, - ?line "begin\n A =" ++ _ = + ?line "begin\n A =" ++ _ = lists:flatten(erl_pp:expr(Block, 17, none)), %% Special... - ?line true = + ?line true = "{some,value}" =:= lists:flatten(erl_pp:expr({value,0,{some,value}})), %% Silly... ?line true = - "if true -> 0 end" =:= + "if true -> 0 end" =:= flat_expr({'if',0,[{clause,0,[],[],[{atom,0,0}]}]}), %% More compatibility: before R6 OldIf = {'if',0,[{clause,0,[],[{atom,0,true}],[{atom,0,b}]}]}, NewIf = {'if',0,[{clause,0,[],[[{atom,0,true}]],[{atom,0,b}]}]}, OldIfChars = lists:flatten(erl_pp:expr(OldIf)), - NewIfChars = lists:flatten(erl_pp:expr(NewIf)), + NewIfChars = lists:flatten(erl_pp:expr(NewIf)), ?line true = OldIfChars =:= NewIfChars, ok. @@ -705,7 +706,7 @@ remove_indentation(S) -> ehook(HE, I, P, H, foo, bar) -> hook(HE, I, P, H). -hook({foo,E}, I, P, H) -> +hook({foo,E}, I, P, H) -> erl_pp:expr({call,0,{atom,0,foo},[E]}, I, P, H). neg_indent(suite) -> @@ -721,14 +722,14 @@ neg_indent(Config) when is_list(Config) -> end">>), ?line ok = pp_expr( <<"fun() -> - F = fun(A, B) when ((A#r1.a) orelse (B#r2.a)) + F = fun(A, B) when ((A#r1.a) orelse (B#r2.a)) or (B#r2.b) or (A#r1.b) -> true; (_, _) -> false end, - true = F(#r1{a = false, b = false}, + true = F(#r1{a = false, b = false}, #r2{a = false, b = true}), - false = F(#r1{a = true, b = true}, + false = F(#r1{a = true, b = true}, #r1{a = false, b = true}), ok end()">>), @@ -763,7 +764,8 @@ neg_indent(Config) when is_list(Config) -> ok. tickets(suite) -> - [otp_6321, otp_6911, otp_6914, otp_8150, otp_8238]. + [otp_6321, otp_6911, otp_6914, otp_8150, otp_8238, otp_8473, otp_8522, + otp_8567, otp_8664]. otp_6321(doc) -> "OTP_6321. Bug fix of exprs()."; @@ -812,7 +814,7 @@ otp_8150(doc) -> "OTP_8150. Types."; otp_8150(suite) -> []; otp_8150(Config) when is_list(Config) -> - ?line _ = [{N,ok} = {N,pp_forms(B)} || + ?line _ = [{N,ok} = {N,pp_forms(B)} || {N,B} <- type_examples() ], ok. @@ -846,7 +848,7 @@ type_examples() -> {ex4,<<"-type t1() :: atom(). ">>}, {ex5,<<"-type t2() :: [t1()]. ">>}, {ex6,<<"-type t3(Atom) :: integer(Atom). ">>}, - {ex7,<<"-type t4() :: t3(foobar). ">>}, + {ex7,<<"-type '\\'t::4'() :: t3('\\'foobar'). ">>}, {ex8,<<"-type t5() :: {t1(), t3(foo)}. ">>}, {ex9,<<"-type t6() :: 1 | 2 | 3 | 'foo' | 'bar'. ">>}, {ex10,<<"-type t7() :: []. ">>}, @@ -882,16 +884,16 @@ type_examples() -> "1|2|3|4|a|b|c|d| " "nonempty_maybe_improper_list(integer, any())]}. ">>}, {ex30,<<"-type t99() ::" - "{t2(),t4(),t5(),t6(),t7(),t8(),t10(),t14()," + "{t2(),'\\'t::4'(),t5(),t6(),t7(),t8(),t10(),t14()," "t15(),t20(),t21(), t22(),t25()}. ">>}, {ex31,<<"-spec t1(FooBar :: t99()) -> t99();" "(t2()) -> t2();" - "(t4()) -> t4() when is_subtype(t4(), t24);" + "('\\'t::4'()) -> '\\'t::4'() when is_subtype('\\'t::4'(), t24);" "(t23()) -> t23() when is_subtype(t23(), atom())," " is_subtype(t23(), t14());" "(t24()) -> t24() when is_subtype(t24(), atom())," " is_subtype(t24(), t14())," - " is_subtype(t24(), t4()).">>}, + " is_subtype(t24(), '\\'t::4'()).">>}, {ex32,<<"-spec mod:t2() -> any(). ">>}, {ex33,<<"-opaque attributes_data() :: " "[{'column', column()} | {'line', info_line()} |" @@ -911,12 +913,126 @@ type_examples() -> "f19 = 3 :: integer()|undefined," "f5 = 3 :: undefined|integer()}). ">>}]. +otp_8473(doc) -> + "OTP_8473. Bugfix abstract type 'fun'."; +otp_8473(suite) -> []; +otp_8473(Config) when is_list(Config) -> + Ex = [{ex1,<<"-type 'fun'(A) :: A.\n" + "-type funkar() :: 'fun'(fun((integer()) -> atom())).\n">>}], + ?line _ = [{N,ok} = {N,pp_forms(B)} || + {N,B} <- Ex], + ok. + +otp_8522(doc) -> + "OTP_8522. Avoid duplicated 'undefined' in record field types."; +otp_8522(suite) -> []; +otp_8522(Config) when is_list(Config) -> + FileName = filename('otp_8522.erl', Config), + C = <<"-module(otp_8522).\n" + "-record(r, {f1 :: undefined,\n" + " f2 :: A :: undefined,\n" + " f3 :: (undefined),\n" + " f4 :: x | y | undefined | z,\n" + " f5 :: a}).\n">>, + ?line ok = file:write_file(FileName, C), + ?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), + ok. + +count_atom(A, A) -> + 1; +count_atom(T, A) when is_tuple(T) -> + count_atom(tuple_to_list(T), A); +count_atom(L, A) when is_list(L) -> + lists:sum([count_atom(T, A) || T <- L]); +count_atom(_, _) -> + 0. + +otp_8567(doc) -> + "OTP_8567. Avoid duplicated 'undefined' in record field types."; +otp_8567(suite) -> []; +otp_8567(Config) when is_list(Config) -> + FileName = filename('otp_8567.erl', Config), + C = <<"-module otp_8567.\n" + "-compile export_all.\n" + "-spec(a).\n" + "-record r, {a}.\n" + "-record s, {a :: integer()}.\n" + "-type t() :: {#r{},#s{}}.\n">>, + ?line ok = file:write_file(FileName, C), + ?line {error,[{_,[{3,erl_parse,["syntax error before: ","')'"]}]}],_} = + compile:file(FileName, [return]), + + F = <<"-module(otp_8567).\n" + "-compile(export_all).\n" + "-record(t, {a}).\n" + "-record(u, {a :: integer()}).\n" + "-opaque ot() :: {#t{}, #u{}}.\n" + "-opaque(ot1() :: atom()).\n" + "-type a() :: integer().\n" + "-spec t() -> a().\n" + "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">>, + ?line ok = pp_forms(F), + + ok. + +otp_8664(doc) -> + "OTP_8664. Types with integer expressions."; +otp_8664(suite) -> []; +otp_8664(Config) when is_list(Config) -> + FileName = filename('otp_8664.erl', Config), + C1 = <<"-module(otp_8664).\n" + "-export([t/0]).\n" + "-define(A, -3).\n" + "-define(B, (?A*(-1 band (((2)))))).\n" + "-type t1() :: ?B | ?A.\n" + "-type t2() :: ?B-1 .. -?B.\n" + "-type t3() :: 9 band (8 - 3) | 1+2 | 5 band 3.\n" + "-type b1() :: <<_:_*(3-(-1))>>\n" + " | <<_:(-(?B))>>\n" + " | <<_:4>>.\n" + "-type u() :: 1 .. 2 | 3.. 4 | (8-3) ..6 | 5+0..6.\n" + "-type t() :: t1() | t2() | t3() | b1() | u().\n" + "-spec t() -> t().\n" + "t() -> 3.\n">>, + ?line ok = file:write_file(FileName, C1), + ?line {ok, _, []} = compile:file(FileName, [return]), + + C2 = <<"-module(otp_8664).\n" + "-export([t/0]).\n" + "-spec t() -> 9 and 4.\n" + "t() -> 0.\n">>, + ?line ok = file:write_file(FileName, C2), + ?line {error,[{_,[{3,erl_lint,{type_syntax,integer}}]}],_} = + compile:file(FileName, [return]), + + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% compile(Config, Tests) -> F = fun({N,P}, BadL) -> case catch compile_file(Config, P) of - ok -> + ok -> case pp_forms(P) of ok -> BadL; @@ -924,8 +1040,8 @@ compile(Config, Tests) -> ?t:format("~nTest ~p failed.~n", [N]), fail() end; - Bad -> - ?t:format("~nTest ~p failed. got~n ~p~n", + Bad -> + ?t:format("~nTest ~p failed. got~n ~p~n", [N, Bad]), fail() end @@ -955,7 +1071,7 @@ compile_file(Config, Test0) -> Error -> Error end. - + compile_file(Config, Test0, Opts0) -> FileName = filename('erl_pp_test.erl', Config), Test = list_to_binary(["-module(erl_pp_test). " @@ -964,7 +1080,7 @@ compile_file(Config, Test0, Opts0) -> Opts = [export_all,return,nowarn_unused_record,{outdir,?privdir} | Opts0], ok = file:write_file(FileName, Test), case compile:file(FileName, Opts) of - {ok, _M, _Ws} -> + {ok, _M, _Ws} -> {ok, filename:rootname(FileName)}; Error -> Error end. @@ -991,7 +1107,7 @@ pp_forms(Bin, Hook) -> end. parse_and_pp_forms(String, Hook) -> - lists:append(lists:map(fun(AF) -> erl_pp:form(AF, Hook) + lists:append(lists:map(fun(AF) -> erl_pp:form(AF, Hook) end, parse_forms(String))). parse_forms(Chars) -> @@ -999,13 +1115,13 @@ parse_forms(Chars) -> parse_forms2(String, [], 1, []). parse_forms2([], _Cont, _Line, Forms) -> - lists:reverse(Forms); + lists:reverse(Forms); parse_forms2(String, Cont0, Line, Forms) -> case erl_scan:tokens(Cont0, String, Line) of {done, {ok, Tokens, EndLine}, Chars} -> {ok, Form} = erl_parse:parse_form(Tokens), parse_forms2(Chars, [], EndLine, [Form | Forms]); - {more, Cont} when element(3, Cont) =:= [] -> + {more, Cont} when element(3, Cont) =:= [] -> %% extra spaces after forms... parse_forms2([], Cont, Line, Forms); {more, Cont} -> @@ -1023,10 +1139,10 @@ pp_expr(Bin, Hook) -> PP2 = (catch parse_and_pp_expr(PPneg, 0, Hook)), if PP1 =:= PP2 -> % same line numbers - case + case (test_max_line(PP1) =:= ok) and (test_new_line(PPneg) =:= ok) of - true -> + true -> ok; false -> not_ok @@ -1059,7 +1175,7 @@ test_max_line(String) -> end. max_line(String) -> - lists:max([0 | [length(Sub) || + lists:max([0 | [length(Sub) || Sub <- string:tokens(String, "\n"), string:substr(Sub, 1, 5) =/= "-file"]]). diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl index 32a06d15c7..32eb97bc92 100644 --- a/lib/stdlib/test/erl_scan_SUITE.erl +++ b/lib/stdlib/test/erl_scan_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% -module(erl_scan_SUITE). @@ -34,7 +34,7 @@ -define(line, put(line, ?LINE), ). -define(config(A,B),config(A,B)). -define(t, test_server). -%% config(priv_dir, _) -> +%% config(priv_dir, _) -> %% "."; %% config(data_dir, _) -> %% ".". @@ -45,7 +45,7 @@ init_per_testcase(_Case, Config) when is_list(Config) -> ?line Dog=test_server:timetrap(test_server:seconds(1200)), [{watchdog, Dog}|Config]. - + fin_per_testcase(_Case, Config) -> Dog=?config(watchdog, Config), test_server:timetrap_cancel(Dog), @@ -97,7 +97,7 @@ assert_type(N, integer) when is_integer(N) -> ok; assert_type(N, atom) when is_atom(N) -> ok. - + check(String) -> Error = erl_scan:string(String), check_error(Error, erl_scan). @@ -146,7 +146,7 @@ iso88591(Config) when is_list(Config) -> ok -> ok %Aok end. -otp_7810(doc) -> +otp_7810(doc) -> ["OTP-7810. White spaces, comments, and more.."]; otp_7810(suite) -> []; @@ -185,7 +185,7 @@ reserved_words() -> 'andalso', 'orelse', 'end', 'fun', 'if', 'let', 'of', 'query', 'receive', 'when', 'bnot', 'not', 'div', 'rem', 'band', 'and', 'bor', 'bxor', 'bsl', 'bsr', - 'or', 'xor', 'spec'] , % 'spec' shouldn't be there... + 'or', 'xor'], [begin ?line {RW, true} = {RW, erl_scan:reserved_word(RW)}, S = atom_to_list(RW), @@ -203,7 +203,7 @@ atoms() -> ?line test_string("a@2", [{atom,1,a@2}]), ?line test_string([39,65,200,39], [{atom,1,'A�'}]), ?line test_string("�rlig �sten", [{atom,1,�rlig},{atom,1,�sten}]), - ?line {ok,[{atom,_,'$a'}],{1,6}} = + ?line {ok,[{atom,_,'$a'}],{1,6}} = erl_scan:string("'$\\a'", {1,1}), ?line test("'$\\a'"), ok. @@ -221,8 +221,8 @@ punctuations() -> Three = ["/=:=", "<=:=", "==:=", ">=:="], % three tokens... No = Three ++ L, SL0 = [{S1++S2,{-length(S1),S1,S2}} || - S1 <- L, - S2 <- L, + S1 <- L, + S2 <- L, not lists:member(S1++S2, No)], SL = family_list(SL0), %% Two tokens. When there are several answers, the one with @@ -244,21 +244,24 @@ punctuations() -> {'\\',1},{'^',1},{'`',1},{'~',1}], ?line test_string("#&*+/:<>?@\\^`~", PTs2), + ?line test_string(".. ", [{'..',1}]), + ?line test("1 .. 2"), + ?line test_string("...", [{'...',1}]), ok. comments() -> ?line test("a %%\n b"), ?line {ok,[],1} = erl_scan:string("%"), ?line test("a %%\n b"), - ?line {ok,[{atom,_,a},{atom,_,b}],{2,3}} = + ?line {ok,[{atom,_,a},{atom,_,b}],{2,3}} = erl_scan:string("a %%\n b",{1,1}), - ?line {ok,[{atom,_,a},{comment,_,"%%"},{atom,_,b}],{2,3}} = + ?line {ok,[{atom,_,a},{comment,_,"%%"},{atom,_,b}],{2,3}} = erl_scan:string("a %%\n b",{1,1}, [return_comments]), ?line {ok,[{atom,_,a}, {white_space,_," "}, {white_space,_,"\n "}, {atom,_,b}], - {2,3}} = + {2,3}} = erl_scan:string("a %%\n b",{1,1},[return_white_spaces]), ?line {ok,[{atom,_,a}, {white_space,_," "}, @@ -275,14 +278,14 @@ errors() -> ?line {error,{1,erl_scan,char},1} = erl_scan:string("$"), ?line test_string([34,65,200,34], [{string,1,"A�"}]), ?line test_string("\\", [{'\\',1}]), - ?line {'EXIT',_} = + ?line {'EXIT',_} = (catch {foo, erl_scan:string('$\\a', {1,1})}), % type error - ?line {'EXIT',_} = + ?line {'EXIT',_} = (catch {foo, erl_scan:tokens([], '$\\a', {1,1})}), % type error ?line "{a,tuple}" = erl_scan:format_error({a,tuple}), ok. - + integers() -> [begin I = list_to_integer(S), @@ -299,14 +302,14 @@ base_integers() -> ?line test_string(BS++"#"++S, Ts) end || {BS,S} <- [{"2","11"}, {"5","23234"}, {"12","05a"}, {"16","abcdef"}, {"16","ABCDEF"}] ], - + ?line {error,{1,erl_scan,{base,1}},1} = erl_scan:string("1#000"), - + ?line test_string("12#bc", [{integer,1,11},{atom,1,c}]), - + [begin Str = BS ++ "#" ++ S, - ?line {error,{1,erl_scan,{illegal,integer}},1} = + ?line {error,{1,erl_scan,{illegal,integer}},1} = erl_scan:string(Str) end || {BS,S} <- [{"3","3"},{"15","f"}, {"12","c"}] ], @@ -323,8 +326,8 @@ floats() -> end || FS <- ["1.0","001.17","3.31200","1.0e0","1.0E17", "34.21E-18", "17.0E+14"]], ?line test_string("1.e2", [{integer,1,1},{'.',1},{atom,1,e2}]), - - ?line {error,{1,erl_scan,{illegal,float}},1} = + + ?line {error,{1,erl_scan,{illegal,float}},1} = erl_scan:string("1.0e400"), [begin ?line {error,{1,erl_scan,{illegal,float}},1} = erl_scan:string(S) @@ -345,16 +348,16 @@ dots() -> {".a", {ok,[{'.',1},{atom,1,a}],1}} ], ?line [R = erl_scan:string(S) || {S, R} <- Dot], - + ?line {ok,[{dot,_}=T1],{1,2}} = erl_scan:string(".", {1,1}, text), - ?line [{column,1},{length,1},{line,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,"."}] = + ?line [{column,1},{length,1},{line,1},{text,"."}] = erl_scan:token_info(T2, [column, length, line, text]), ?line {ok,[{dot,_}=T3],{1,6}} = erl_scan:string(".% �h", {1,1}, text), - ?line [{column,1},{length,1},{line,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}), @@ -376,10 +379,10 @@ dots() -> ?line {done,{ok,[{comment,_,"%. "}, {white_space,_,"\n"}, {dot,_}], - {2,3}}, ""} = + {2,3}}, ""} = erl_scan:tokens(C, "\n. ", {1,1}, return), % any loc, any options - ?line [test_string(S, R) || + ?line [test_string(S, R) || {S, R} <- [{".$\n", [{'.',1},{char,1,$\n}]}, {"$\\\n", [{char,1,$\n}]}, {"'\\\n'", [{atom,1,'\n'}]}, @@ -392,7 +395,7 @@ chars() -> Ts = [{char,1,C}], ?line test_string(L, Ts) end || C <- lists:seq(0, 255)], - + %% Leading zeroes... [begin L = lists:flatten(io_lib:format("$\\~3.8.0b", [C])), @@ -406,13 +409,13 @@ chars() -> Ts = [{char,1,C band 2#11111}], ?line test_string(L, Ts) end || C <- lists:seq(0, 255)], - + [begin L = "$\\" ++ [C], Ts = [{char,1,V}], ?line test_string(L, Ts) - end || {C,V} <- [{$n,$\n}, {$r,$\r}, {$t,$\t}, {$v,$\v}, - {$b,$\b}, {$f,$\f}, {$e,$\e}, {$s,$\s}, + end || {C,V} <- [{$n,$\n}, {$r,$\r}, {$t,$\t}, {$v,$\v}, + {$b,$\b}, {$f,$\f}, {$e,$\e}, {$s,$\s}, {$d,$\d}]], EC = [$\n,$\r,$\t,$\v,$\b,$\f,$\e,$\s,$\d], @@ -445,7 +448,7 @@ chars() -> end || C <- lists:seq(0, 255) -- (No ++ [$\\])], ?line test_string("$\n", [{char,1,$\n}]), - ?line {error,{{1,1},erl_scan,char},{1,4}} = + ?line {error,{{1,1},erl_scan,char},{1,4}} = erl_scan:string("$\\^",{1,1}), ?line test_string("$\\\n", [{char,1,$\n}]), %% Robert's scanner returns line 1: @@ -453,7 +456,7 @@ chars() -> ?line test_string("$\n\n", [{char,1,$\n}]), ?line test("$\n\n"), ok. - + variables() -> ?line test_string(" \237_Aou�eiy��", [{var,1,'_Aou�eiy��'}]), @@ -469,8 +472,8 @@ eof() -> ?line {done,{eof,2},eof} = erl_scan:tokens(C1, eof, 1), {more, C2} = erl_scan:tokens([], "abra", 1), %% An error before R13A. - %% ?line {done,Err={error,{1,erl_scan,scan},1},eof} = - ?line {done,{ok,[{atom,1,abra}],1},eof} = + %% ?line {done,Err={error,{1,erl_scan,scan},1},eof} = + ?line {done,{ok,[{atom,1,abra}],1},eof} = erl_scan:tokens(C2, eof, 1), %% With column. @@ -478,7 +481,7 @@ eof() -> ?line {done,{eof,{2,1}},eof} = erl_scan:tokens(C3, eof, 1), {more, C4} = erl_scan:tokens([], "abra", {1,1}), %% An error before R13A. - %% ?line {done,{error,{{1,1},erl_scan,scan},{1,5}},eof} = + %% ?line {done,{error,{{1,1},erl_scan,scan},{1,5}},eof} = ?line {done,{ok,[{atom,_,abra}],{1,5}},eof} = erl_scan:tokens(C4, eof, 1), @@ -486,7 +489,7 @@ eof() -> %% the R12B scanner returns eof as LeftoverChars: (eof is correct) ?line {more, C5} = erl_scan:tokens([], "a", 1), %% An error before R13A. - %% ?line {done,{error,{1,erl_scan,scan},1},eof} = + %% ?line {done,{error,{1,erl_scan,scan},1},eof} = ?line {done,{ok,[{atom,1,a}],1},eof} = erl_scan:tokens(C5,eof,1), @@ -528,7 +531,7 @@ illegal() -> erl_scan:tokens([], "foo "++Atom++". ", {1,1}), ?line {error,{{1,1},erl_scan,{illegal,atom}},{1,1003}} = erl_scan:string(QAtom, {1,1}), - ?line {done,{error,{{1,5},erl_scan,{illegal,atom}},{1,1007}},". "} = + ?line {done,{error,{{1,5},erl_scan,{illegal,atom}},{1,1007}},". "} = erl_scan:tokens([], "foo "++QAtom++". ", {1,1}), ?line {error,{{1,1},erl_scan,{illegal,var}},{1,1001}} = erl_scan:string(Var, {1,1}), @@ -553,7 +556,7 @@ crashes() -> ?line {'EXIT',_} = (catch {foo, erl_scan:string("\"\\v"++[-1,$"])}), %$" ?line {'EXIT',_} = (catch {foo, erl_scan:string([$",-1,$"])}), ?line {'EXIT',_} = (catch {foo, erl_scan:string("% foo"++[-1])}), - ?line {'EXIT',_} = + ?line {'EXIT',_} = (catch {foo, erl_scan:string("% foo"++[-1],{1,1})}), ?line {'EXIT',_} = (catch {foo, erl_scan:string([a])}), % type error @@ -564,7 +567,7 @@ crashes() -> ?line {'EXIT',_} = (catch {foo, erl_scan:string("\"\\v"++[a,$"])}), %$" ?line {'EXIT',_} = (catch {foo, erl_scan:string([$",a,$"])}), ?line {'EXIT',_} = (catch {foo, erl_scan:string("% foo"++[a])}), - ?line {'EXIT',_} = + ?line {'EXIT',_} = (catch {foo, erl_scan:string("% foo"++[a],{1,1})}), ?line {'EXIT',_} = (catch {foo, erl_scan:string([3.0])}), % type error @@ -573,26 +576,26 @@ crashes() -> options() -> %% line and column are not options, but tested here - ?line {ok,[{atom,1,foo},{white_space,1," "},{comment,1,"% bar"}], 1} = + ?line {ok,[{atom,1,foo},{white_space,1," "},{comment,1,"% bar"}], 1} = erl_scan:string("foo % bar", 1, return), - ?line {ok,[{atom,1,foo},{white_space,1," "}],1} = + ?line {ok,[{atom,1,foo},{white_space,1," "}],1} = erl_scan:string("foo % bar", 1, return_white_spaces), - ?line {ok,[{atom,1,foo},{comment,1,"% bar"}],1} = + ?line {ok,[{atom,1,foo},{comment,1,"% bar"}],1} = erl_scan:string("foo % bar", 1, return_comments), - ?line {ok,[{atom,17,foo}],17} = + ?line {ok,[{atom,17,foo}],17} = erl_scan:string("foo % bar", 17), - ?line {'EXIT',{function_clause,_}} = - (catch {foo, + ?line {'EXIT',{function_clause,_}} = + (catch {foo, erl_scan:string("foo % bar", {a,1}, [])}), % type error - ?line {ok,[{atom,_,foo}],{17,18}} = + ?line {ok,[{atom,_,foo}],{17,18}} = erl_scan:string("foo % bar", {17,9}, []), - ?line {'EXIT',{function_clause,_}} = + ?line {'EXIT',{function_clause,_}} = (catch {foo, erl_scan:string("foo % bar", {1,0}, [])}), % type error - ?line {ok,[{foo,1}],1} = + ?line {ok,[{foo,1}],1} = erl_scan:string("foo % bar",1, [{reserved_word_fun, fun(W) -> W =:= foo end}]), - ?line {'EXIT',{badarg,_}} = + ?line {'EXIT',{badarg,_}} = (catch {foo, erl_scan:string("foo % bar",1, % type error [{reserved_word_fun, @@ -618,14 +621,14 @@ more_options() -> token_info() -> ?line {ok,[T1],_} = erl_scan:string("foo", {1,18}, [text]), - {'EXIT',{badarg,_}} = + {'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"}] = + {symbol,foo},{text,"foo"}] = erl_scan:token_info(T1), ?line [{length,3},{column,18}] = erl_scan:token_info(T1, [length, column]), @@ -648,9 +651,9 @@ token_info() -> ?line {category,'='} = erl_scan:token_info(T3, category), ?line [{symbol,'='}] = erl_scan:token_info(T3, [symbol]), ok. - + attributes_info() -> - ?line {'EXIT',_} = + ?line {'EXIT',_} = (catch {foo,erl_scan:attributes_info(foo)}), % type error ?line [{line,18}] = erl_scan:attributes_info(18), ?line {location,19} = erl_scan:attributes_info(19, location), @@ -717,9 +720,9 @@ set_attribute() -> ?line [{line,{17,11}},{text,"foo"}] = erl_scan:attributes_info(A7, [line,column,text]), - ?line {'EXIT',_} = + ?line {'EXIT',_} = (catch {foo, erl_scan:set_attribute(line, [], F2)}), % type error - ?line {'EXIT',{badarg,_}} = + ?line {'EXIT',{badarg,_}} = (catch {foo, erl_scan:set_attribute(column, [], F2)}), % type error ok. @@ -790,14 +793,14 @@ unicode() -> ?line {ok,[{char,1,83},{integer,1,45}],1} = erl_scan:string("$\\12345"), % not unicode - ?line {error,{1,erl_scan,{illegal,character}},1} = + ?line {error,{1,erl_scan,{illegal,character}},1} = erl_scan:string([1089]), - ?line {error,{{1,1},erl_scan,{illegal,character}},{1,2}} = + ?line {error,{{1,1},erl_scan,{illegal,character}},{1,2}} = erl_scan:string([1089], {1,1}), ?line {error,{1,erl_scan,{illegal,character}},1} = - %% ?line {error,{1,erl_scan,{illegal,atom}},1} = + %% ?line {error,{1,erl_scan,{illegal,atom}},1} = erl_scan:string("'a"++[1089]++"b'"), - ?line {error,{{1,3},erl_scan,{illegal,character}},{1,4}} = + ?line {error,{{1,3},erl_scan,{illegal,character}},{1,4}} = erl_scan:string("'a"++[1089]++"b'", {1,1}), ?line test("\"a"++[1089]++"b\""), ?line {ok,[{char,1,1}],1} = erl_scan:string([$$,$\\,$^,1089]), @@ -822,7 +825,7 @@ unicode() -> ?line {ok,[{integer,1,16#aaa}],1} = erl_scan:string(Qs), ?line {ok,[Q2],{1,9}} = erl_scan:string("$\\x{aaa}", {1,1}, text), ?line [{category,integer},{column,1},{length,8}, - {line,1},{symbol,16#aaa},{text,Qs}] = + {line,1},{symbol,16#aaa},{text,Qs}] = erl_scan:token_info(Q2), U1 = "\"\\x{aaa}\"", @@ -830,11 +833,11 @@ unicode() -> ?line [{category,'['},{column,1},{length,1},{line,1}, {symbol,'['},{text,"\""}] = erl_scan:token_info(T1, Tags), ?line [{category,integer},{column,2},{length,7}, - {line,1},{symbol,16#aaa},{text,"\\x{aaa}"}] = + {line,1},{symbol,16#aaa},{text,"\\x{aaa}"}] = erl_scan:token_info(T2, Tags), ?line [{category,']'},{column,9},{length,1},{line,1}, {symbol,']'},{text,"\""}] = erl_scan:token_info(T3, Tags), - ?line {ok,[{'[',1},{integer,1,16#aaa},{']',1}],1} = + ?line {ok,[{'[',1},{integer,1,16#aaa},{']',1}],1} = erl_scan:string(U1, 1), U2 = "\"\\x41\\x{fff}\\x42\"", @@ -844,7 +847,7 @@ unicode() -> U3 = "\"a\n\\x{fff}\n\"", ?line {ok,[{'[',1},{char,1,$a},{',',1},{char,1,$\n}, {',',2},{integer,2,16#fff},{',',2},{char,2,$\n}, - {']',3}],3} = + {']',3}],3} = erl_scan:string(U3, 1), U4 = "\"\\^\n\\x{aaa}\\^\n\"", @@ -867,10 +870,10 @@ unicode() -> {char,_,$d},{']',_}],{1,8}} = erl_scan:string(Str1, {1,1}), ?line test(Str1), Comment = "%% "++[1089], - ?line {ok,[{comment,1,[$%,$%,$\s,1089]}],1} = + ?line {ok,[{comment,1,[$%,$%,$\s,1089]}],1} = erl_scan:string(Comment, 1, return), - ?line {ok,[{comment,_,[$%,$%,$\s,1089]}],{1,5}} = - erl_scan:string(Comment, {1,1}, return), + ?line {ok,[{comment,_,[$%,$%,$\s,1089]}],{1,5}} = + erl_scan:string(Comment, {1,1}, return), ok. more_chars() -> @@ -885,7 +888,7 @@ more_chars() -> erl_scan:tokens(C1, eof, 1), ?line {ok,[{char,1,123},{atom,1,a},{'}',1}],1} = erl_scan:string("$\\{a}"), - + ?line {error,{{1,1},erl_scan,char},{1,4}} = erl_scan:string("$\\x", {1,1}), ?line {error,{{1,1},erl_scan,char},{1,5}} = @@ -893,12 +896,12 @@ more_chars() -> ?line {more, C3} = erl_scan:tokens([], "$\\x", {1,1}), ?line {done,{error,{{1,1},erl_scan,char},{1,4}},eof} = erl_scan:tokens(C3, eof, 1), - ?line {error,{{1,1},erl_scan,char},{1,5}} = + ?line {error,{{1,1},erl_scan,char},{1,5}} = erl_scan:string("$\\x{",{1,1}), ?line {more, C2} = erl_scan:tokens([], "$\\x{", {1,1}), - ?line {done,{error,{{1,1},erl_scan,char},{1,5}},eof} = + ?line {done,{error,{{1,1},erl_scan,char},{1,5}},eof} = erl_scan:tokens(C2, eof, 1), - ?line {error,{1,erl_scan,{illegal,character}},1} = + ?line {error,{1,erl_scan,{illegal,character}},1} = erl_scan:string("$\\x{g}"), ?line {error,{{1,1},erl_scan,{illegal,character}},{1,5}} = erl_scan:string("$\\x{g}", {1,1}), @@ -924,12 +927,12 @@ more_chars() -> ?line test("$\\x{10FFFF}"), ?line test("$\\x{10ffff}"), ?line test("\"$\n \\{1}\""), - ?line {error,{1,erl_scan,{illegal,character}},1} = + ?line {error,{1,erl_scan,{illegal,character}},1} = erl_scan:string("$\\x{110000}"), - ?line {error,{{1,1},erl_scan,{illegal,character}},{1,12}} = + ?line {error,{{1,1},erl_scan,{illegal,character}},{1,12}} = erl_scan:string("$\\x{110000}", {1,1}), - ?line {error,{{1,1},erl_scan,{illegal,character}},{1,4}} = + ?line {error,{{1,1},erl_scan,{illegal,character}},{1,4}} = erl_scan:string("$\\xfg", {1,1}), ?line test("$\\xffg"), @@ -953,11 +956,11 @@ test(String) -> {Wtokens, Wend}, {Ctokens, Cend}, {CWtokens, CWend}, - {CWtokens2, _}] = + {CWtokens2, _}] = [scan_string_with_column(String, X) || - X <- [[], - [return_white_spaces], - [return_comments], + X <- [[], + [return_white_spaces], + [return_comments], [return], [return]]], % for white space compaction test @@ -969,7 +972,7 @@ test(String) -> {none,Tokens} = {none, filter_tokens(CWtokens, [white_space,comment])}, {comments,Ctokens} = {comments,filter_tokens(CWtokens, [white_space])}, - {white_spaces,Wtokens} = + {white_spaces,Wtokens} = {white_spaces,filter_tokens(CWtokens, [comment])}, %% Use token attributes to extract parts from the original string, @@ -991,9 +994,9 @@ test(String) -> %% Line attribute only: [Simple,Wsimple,Csimple,WCsimple] = Simples = [element(2, erl_scan:string(String, 1, Opts)) || - Opts <- [[], - [return_white_spaces], - [return_comments], + Opts <- [[], + [return_white_spaces], + [return_comments], [return]]], {consistent,true} = {consistent,consistent_attributes(Simples)}, {simple_wc,WCsimple} = {simple_wc,simplify(CWtokens)}, @@ -1004,19 +1007,19 @@ test(String) -> %% Line attribute only, with text: [SimpleTxt,WsimpleTxt,CsimpleTxt,WCsimpleTxt] = SimplesTxt = [element(2, erl_scan:string(String, 1, [text|Opts])) || - Opts <- [[], - [return_white_spaces], - [return_comments], + Opts <- [[], + [return_white_spaces], + [return_comments], [return]]], TextTxt = get_text(WCsimpleTxt), {text_txt,TextTxt,String} = {text_txt,String,TextTxt}, - {consistent_txt,true} = + {consistent_txt,true} = {consistent_txt,consistent_attributes(SimplesTxt)}, - {simple_txt,SimpleTxt} = + {simple_txt,SimpleTxt} = {simple_txt,filter_tokens(WCsimpleTxt, [white_space,comment])}, - {simple_c_txt,CsimpleTxt} = + {simple_c_txt,CsimpleTxt} = {simple_c_txt,filter_tokens(WCsimpleTxt, [white_space])}, - {simple_w_txt,WsimpleTxt} = + {simple_w_txt,WsimpleTxt} = {simple_w_txt,filter_tokens(WCsimpleTxt, [comment])}, ok. @@ -1024,18 +1027,18 @@ test(String) -> test_white_space_compaction(Tokens, Tokens2) when Tokens =:= Tokens2 -> [WS, WS2] = [select_tokens(Ts, [white_space]) || Ts <- [Tokens, Tokens2]], test_wsc(WS, WS2). - + test_wsc([], []) -> ok; test_wsc([Token|Tokens], [Token2|Tokens2]) -> - [Text, Text2] = [Text || - {text, Text} <- + [Text, Text2] = [Text || + {text, Text} <- [erl_scan:token_info(T, text) || T <- [Token, Token2]]], Sz = erts_debug:size(Text), Sz2 = erts_debug:size({Text, Text2}), IsCompacted = Sz2 < 2*Sz+erts_debug:size({a,a}), - ToBeCompacted = is_compacted(Text), + ToBeCompacted = is_compacted(Text), if IsCompacted =:= ToBeCompacted -> test_wsc(Tokens, Tokens2); @@ -1050,14 +1053,14 @@ is_compacted("\n\r") -> is_compacted("\n\f") -> true; is_compacted([$\n|String]) -> - all_spaces(String) + all_spaces(String) orelse all_tabs(String); is_compacted(String) -> all_spaces(String) orelse all_tabs(String). - + all_spaces(L) -> all_same(L, $\s). @@ -1078,7 +1081,7 @@ newlines_first([Token|Tokens]) -> _ -> Nnls =:= 0 end, - if + if OK -> newlines_first(Tokens); true -> OK end. @@ -1097,7 +1100,7 @@ simplify([]) -> get_text(Tokens) -> lists:flatten( - [T || + [T || Token <- Tokens, ({text,T} = erl_scan:token_info(Token, text)) =/= []]). @@ -1108,7 +1111,7 @@ test_decorated_tokens(String, Tokens) -> token_attrs(Tokens) -> [{L,C,Len,T} || Token <- Tokens, - ([{line,L},{column,C},{length,Len},{text,T}] = + ([{line,L},{column,C},{length,Len},{text,T}] = erl_scan:token_info(Token, [line,column,length,text])) =/= []]. test_strings([], _S, Line, Column) -> @@ -1150,7 +1153,7 @@ scan_string_with_column(String, Options0) -> {ok, Ts1, End1} = erl_scan:string(String, StartLoc, Options), TString = String ++ ". ", {ok,Ts2,End2} = scan_tokens(TString, Options, [], StartLoc), - {ok, Ts3, End3} = + {ok, Ts3, End3} = scan_tokens_1({more, []}, TString, Options, [], StartLoc), {end_2,End2,End3} = {end_2,End3,End2}, {EndLine1,EndColumn1} = End1, @@ -1190,8 +1193,8 @@ 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,_} <- + erl_scan:attributes_info(element(2, T))] || T <- Ts], case lists:usort(TagsL) of [_] -> diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl index 70aae54d62..77fd190e45 100644 --- a/lib/stdlib/test/escript_SUITE.erl +++ b/lib/stdlib/test/escript_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% -module(escript_SUITE). @@ -22,16 +22,20 @@ init_per_testcase/2, fin_per_testcase/2, basic/1, - errors/1, + errors/1, strange_name/1, emulator_flags/1, module_script/1, beam_script/1, archive_script/1, - epp/1 + epp/1, + create_and_extract/1, + foldl/1, + verify_sections/3 ]). -include("test_server.hrl"). +-include_lib("kernel/include/file.hrl"). all(suite) -> [ @@ -42,7 +46,9 @@ all(suite) -> module_script, beam_script, archive_script, - epp + epp, + create_and_extract, + foldl ]. init_per_testcase(_Case, Config) -> @@ -68,11 +74,11 @@ basic(Config) when is_list(Config) -> ?line run(Dir, "factorial_warning 20", [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\n" "factorial 20 = 2432902008176640000\nExitCode:0">>]), - ?line run(Dir, "-s", "factorial_warning", + ?line run_with_opts(Dir, "-s", "factorial_warning", [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]), - ?line run(Dir, "-s -i", "factorial_warning", + ?line run_with_opts(Dir, "-s -i", "factorial_warning", [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]), - ?line run(Dir, "-c -s", "factorial_warning", + ?line run_with_opts(Dir, "-c -s", "factorial_warning", [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]), ?line run(Dir, "filesize "++filename:join(?config(data_dir, Config),"filesize"), [data_dir,<<"filesize:11: Warning: function id/1 is unused\n324\nExitCode:0">>]), @@ -100,7 +106,7 @@ errors(Config) when is_list(Config) -> [data_dir,<<"lint_error:6: function main/1 already defined\n">>, data_dir,"lint_error:8: variable 'ExitCode' is unbound\n", <<"escript: There were compilation errors.\nExitCode:127">>]), - ?line run(Dir, "-s", "lint_error", + ?line run_with_opts(Dir, "-s", "lint_error", [data_dir,<<"lint_error:6: function main/1 already defined\n">>, data_dir,"lint_error:8: variable 'ExitCode' is unbound\n", <<"escript: There were compilation errors.\nExitCode:127">>]), @@ -140,31 +146,31 @@ module_script(Config) when is_list(Config) -> OrigFile = filename:join([Data,"emulator_flags"]), {ok, OrigBin} = file:read_file(OrigFile), ?line [Shebang, Mode, Flags | Source] = string:tokens(binary_to_list(OrigBin), "\n"), - ?line {ok, OrigFI} = file:read_file_info(OrigFile), + ?line {ok, OrigFI} = file:read_file_info(OrigFile), %% Write source file Priv = ?config(priv_dir, Config), Dir = filename:absname(Priv), % Get rid of trailing slash. Base = "module_script", ErlFile = filename:join([Priv, Base ++ ".erl"]), - ErlCode = ["-module(", Base, ").\n", + ErlCode = ["\n-module(", Base, ").\n", "-export([main/1]).\n\n", string:join(Source, "\n"), "\n"], ?line ok = file:write_file(ErlFile, ErlCode), - + %%%%%%% %% Create and run scripts without emulator flags %% With shebang NoArgsBase = Base ++ "_no_args_with_shebang", NoArgsFile = filename:join([Priv, NoArgsBase]), - ?line ok = file:write_file(NoArgsFile, + ?line ok = file:write_file(NoArgsFile, [Shebang, "\n", ErlCode]), ?line ok = file:write_file_info(NoArgsFile, OrigFI), - - ?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3", + + ?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -172,7 +178,7 @@ module_script(Config) when is_list(Config) -> "unknown:[]\n" "ExitCode:0">>]), - ?line run(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3", + ?line run_with_opts(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -183,33 +189,33 @@ module_script(Config) when is_list(Config) -> %% Without shebang NoArgsBase2 = Base ++ "_no_args_without_shebang", NoArgsFile2 = filename:join([Priv, NoArgsBase2]), - ?line ok = file:write_file(NoArgsFile2, + ?line ok = file:write_file(NoArgsFile2, ["Something else than shebang!!!", "\n", ErlCode]), ?line ok = file:write_file_info(NoArgsFile2, OrigFI), - - ?line run(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3", + + ?line run_with_opts(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" "ERL_FLAGS=false\n" "unknown:[]\n" "ExitCode:0">>]), - + %% Plain module without header NoArgsBase3 = Base ++ "_no_args_without_header", NoArgsFile3 = filename:join([Priv, NoArgsBase3]), ?line ok = file:write_file(NoArgsFile3, [ErlCode]), ?line ok = file:write_file_info(NoArgsFile3, OrigFI), - - ?line run(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3", + + ?line run_with_opts(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" "ERL_FLAGS=false\n" "unknown:[]\n" "ExitCode:0">>]), - + %%%%%%% %% Create and run scripts with emulator flags @@ -217,12 +223,12 @@ module_script(Config) when is_list(Config) -> ArgsBase = Base ++ "_args_with_shebang", ArgsFile = filename:join([Priv, ArgsBase]), ?line ok = file:write_file(ArgsFile, - [Shebang, "\n", + [Shebang, "\n", Mode, "\n", Flags, "\n", ErlCode]), - ?line ok = file:write_file_info(ArgsFile, OrigFI), - + ?line ok = file:write_file_info(ArgsFile, OrigFI), + ?line run(Dir, ArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[{nostick,[]}]\n" @@ -242,32 +248,32 @@ beam_script(Config) when is_list(Config) -> OrigFile = filename:join([Data,"emulator_flags"]), {ok, OrigBin} = file:read_file(OrigFile), ?line [Shebang, Mode, Flags | Source] = string:tokens(binary_to_list(OrigBin), "\n"), - ?line {ok, OrigFI} = file:read_file_info(OrigFile), + ?line {ok, OrigFI} = file:read_file_info(OrigFile), %% Write source file Priv = ?config(priv_dir, Config), Dir = filename:absname(Priv), % Get rid of trailing slash. Base = "beam_script", ErlFile = filename:join([Priv, Base ++ ".erl"]), - ?line ok = file:write_file(ErlFile, - ["-module(", Base, ").\n", + ?line ok = file:write_file(ErlFile, + ["\n-module(", Base, ").\n", "-export([main/1]).\n\n", string:join(Source, "\n"), "\n"]), %% Compile the code ?line {ok, _Mod, BeamCode} = compile:file(ErlFile, [binary]), - + %%%%%%% %% Create and run scripts without emulator flags %% With shebang NoArgsBase = Base ++ "_no_args_with_shebang", NoArgsFile = filename:join([Priv, NoArgsBase]), - ?line ok = file:write_file(NoArgsFile, + ?line ok = file:write_file(NoArgsFile, [Shebang, "\n", BeamCode]), - ?line ok = file:write_file_info(NoArgsFile, OrigFI), + ?line ok = file:write_file_info(NoArgsFile, OrigFI), ?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" @@ -277,7 +283,7 @@ beam_script(Config) when is_list(Config) -> "unknown:[]\n" "ExitCode:0">>]), - ?line run(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3", + ?line run_with_opts(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -288,12 +294,12 @@ beam_script(Config) when is_list(Config) -> %% Without shebang NoArgsBase2 = Base ++ "_no_args_without_shebang", NoArgsFile2 = filename:join([Priv, NoArgsBase2]), - ?line ok = file:write_file(NoArgsFile2, + ?line ok = file:write_file(NoArgsFile2, ["Something else than shebang!!!", "\n", BeamCode]), - ?line ok = file:write_file_info(NoArgsFile2, OrigFI), + ?line ok = file:write_file_info(NoArgsFile2, OrigFI), - ?line run(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3", + ?line run_with_opts(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -305,9 +311,9 @@ beam_script(Config) when is_list(Config) -> NoArgsBase3 = Base ++ "_no_args_without_header", NoArgsFile3 = filename:join([Priv, NoArgsBase3]), ?line ok = file:write_file(NoArgsFile3, [BeamCode]), - ?line ok = file:write_file_info(NoArgsFile3, OrigFI), + ?line ok = file:write_file_info(NoArgsFile3, OrigFI), - ?line run(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3", + ?line run_with_opts(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -322,12 +328,12 @@ beam_script(Config) when is_list(Config) -> ArgsBase = Base ++ "_args", ArgsFile = filename:join([Priv, ArgsBase]), ?line ok = file:write_file(ArgsFile, - [Shebang, "\n", + [Shebang, "\n", Mode, "\n", Flags, "\n", BeamCode]), - ?line ok = file:write_file_info(ArgsFile, OrigFI), - + ?line ok = file:write_file_info(ArgsFile, OrigFI), + ?line run(Dir, ArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[{nostick,[]}]\n" @@ -356,13 +362,13 @@ archive_script(Config) when is_list(Config) -> ?line ok = compile_app(TopDir, "archive_script_dict"), ?line ok = compile_app(TopDir, "archive_script_dummy"), ?line {ok, MainFiles} = file:list_dir(TopDir), - ?line ok = compile_files(MainFiles, TopDir, TopDir), - + ?line ok = compile_files(MainFiles, TopDir, TopDir), + %% Create the archive {ok, TopFiles} = file:list_dir(TopDir), ?line {ok, {_, ArchiveBin}} = zip:create(Archive, TopFiles, [memory, {compress, []}, {cwd, TopDir}]), - + %% Read the source script OrigFile = filename:join([DataDir, "emulator_flags"]), {ok, OrigBin} = file:read_file(OrigFile), @@ -371,73 +377,73 @@ archive_script(Config) when is_list(Config) -> Flags = "%%! -archive_script_dict foo bar" " -archive_script_dict foo" " -archive_script_dummy bar", - ?line {ok, OrigFI} = file:read_file_info(OrigFile), - + ?line {ok, OrigFI} = file:read_file_info(OrigFile), + %%%%%%% %% Create and run scripts without emulator flags - MainBase = "archive_script_main", - MainScript = filename:join([PrivDir, MainBase]), + MainBase = "archive_script_main", + MainScript = filename:join([PrivDir, MainBase]), %% With shebang - ?line ok = file:write_file(MainScript, + ?line ok = file:write_file(MainScript, [Shebang, "\n", Flags, "\n", ArchiveBin]), - ?line ok = file:write_file_info(MainScript, OrigFI), - + ?line ok = file:write_file_info(MainScript, OrigFI), + ?line run(PrivDir, MainBase ++ " -arg1 arg2 arg3", - [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" + [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n" "dummy:[{archive_script_dummy,[\"bar\"]}]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), - ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", - [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" + ?line run_with_opts(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", + [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n" "dummy:[{archive_script_dummy,[\"bar\"]}]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), - + ?line ok = file:rename(MainScript, MainScript ++ "_with_shebang"), %% Without shebang (no flags) - ?line ok = file:write_file(MainScript, + ?line ok = file:write_file(MainScript, ["Something else than shebang!!!", "\n", ArchiveBin]), - ?line ok = file:write_file_info(MainScript, OrigFI), - - ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", - [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" + ?line ok = file:write_file_info(MainScript, OrigFI), + + ?line run_with_opts(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", + [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "dict:[]\n" "dummy:[]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), ?line ok = file:rename(MainScript, MainScript ++ "_without_shebang"), - + %% Plain archive without header (no flags) - + ?line ok = file:write_file(MainScript, [ArchiveBin]), - ?line ok = file:write_file_info(MainScript, OrigFI), - - ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", - [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" + ?line ok = file:write_file_info(MainScript, OrigFI), + + ?line run_with_opts(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", + [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "dict:[]\n" "dummy:[]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), ?line ok = file:rename(MainScript, MainScript ++ "_without_header"), - + %%%%%%% %% Create and run scripts with emulator flags AltBase = "archive_script_alternate_main", AltScript = filename:join([PrivDir, AltBase]), - ?line ok = file:write_file(AltScript, + ?line ok = file:write_file(AltScript, [Shebang, "\n", Mode, "\n", Flags, " -escript main archive_script_main2\n", ArchiveBin]), - ?line ok = file:write_file_info(AltScript, OrigFI), + ?line ok = file:write_file_info(AltScript, OrigFI), ?line run(PrivDir, AltBase ++ " -arg1 arg2 arg3", [<<"main2:[\"-arg1\",\"arg2\",\"arg3\"]\n" @@ -445,7 +451,7 @@ archive_script(Config) when is_list(Config) -> "dummy:[{archive_script_dummy,[\"bar\"]}]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), - + ok. compile_app(TopDir, AppName) -> @@ -482,6 +488,254 @@ epp(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +create_and_extract(Config) when is_list(Config) -> + {NewFile, FileInfo, + EmuArg, Source, + _ErlBase, ErlCode, + _BeamBase, BeamCode, + ArchiveBin} = + prepare_creation("create_and_extract", Config), + + Bodies = + [[{source, ErlCode}], + [{beam, BeamCode}], + [{archive, ArchiveBin}]], + + %% Verify all combinations of scripts with shebangs + [verify_sections(NewFile, FileInfo, S ++ C ++ E ++ B) || + S <- [[{shebang, default}], + [{shebang, "/usr/bin/env escript"}]], + C <- [[], + [{comment, undefined}], + [{comment, default}], + [{comment, "This is a nonsense comment"}]], + E <- [[], + [{emu_args, undefined}], + [{emu_args, EmuArg}]], + B <- [[{source, Source}] | Bodies]], + + %% Verify all combinations of scripts without shebangs + [verify_sections(NewFile, FileInfo, S ++ C ++ E ++ B) || + S <- [[], [{shebang, undefined}]], + C <- [[], [{comment, undefined}]], + E <- [[], [{emu_args, undefined}]], + B <- Bodies], + + %% Verify the compile_source option + file:delete(NewFile), + ?line ok = escript:create(NewFile, [{source, Source}]), + ?line {ok, [_, _, _, {source, Source}]} = escript:extract(NewFile, []), + ?line {ok, [_, _, _, {source, BeamCode2}]} = + escript:extract(NewFile, [compile_source]), + verify_sections(NewFile, FileInfo, + [{shebang, default}, + {comment, default}, + {beam, BeamCode2}]), + + file:delete(NewFile), + ok. + +prepare_creation(Base, Config) -> + %% Read the source + PrivDir = ?config(priv_dir, Config), + DataDir = ?config(data_dir, Config), + OrigFile = filename:join([DataDir,"emulator_flags"]), + ?line {ok, FileInfo} = file:read_file_info(OrigFile), + NewFile = filename:join([PrivDir, Base]), + ?line {ok, [{shebang, default}, + {comment, _}, + {emu_args, EmuArg}, + {source, Source}]} = + escript:extract(OrigFile, []), + + %% Compile the code + ErlFile = NewFile ++ ".erl", + ErlCode = list_to_binary(["\n-module(", Base, ").\n", + "-export([main/1]).\n\n", + Source, "\n\n"]), + ?line ok = file:write_file(ErlFile, ErlCode), + + %% Compile the code + ?line {ok, _Mod, BeamCode} = + compile:file(ErlFile, [binary, debug_info]), + + %% Create an archive + ?line {ok, {_, ArchiveBin}} = + zip:create("dummy_archive_name", + [{Base ++ ".erl", ErlCode}, + {Base ++ ".beam", BeamCode}], + [{compress, []}, memory]), + {NewFile, FileInfo, + EmuArg, Source, + Base ++ ".erl", ErlCode, + Base ++ ".beam", BeamCode, + ArchiveBin}. + +verify_sections(File, FileInfo, Sections) -> + io:format("~p:verify_sections(\n\t~p,\n\t~p,\n\t~p).\n", + [?MODULE, File, FileInfo, Sections]), + + %% Create + file:delete(File), + ?line ok = escript:create(File, Sections), + ?line ok = file:write_file_info(File, FileInfo), + + %% Run + Dir = filename:absname(filename:dirname(File)), + Base = filename:basename(File), + + HasArg = fun(Tag) -> + case lists:keysearch(Tag, 1, Sections) of + false -> false; + {value, {_, undefined}} -> false; + {value, _} -> true + end + end, + ExpectedMain = <<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n">>, + ExpectedOutput = + case HasArg(emu_args) of + true -> + <<"nostick:[{nostick,[]}]\n" + "mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n" + "ERL_FLAGS=false\n" + "unknown:[]\n" + "ExitCode:0">>; + false -> + <<"nostick:[]\nmnesia:[]\nERL_FLAGS=false\nunknown:[]\nExitCode:0">> + end, + + InputArgs = Base ++ " -arg1 arg2 arg3", + Expected = <<ExpectedMain/binary, ExpectedOutput/binary>>, + case HasArg(shebang) of + true -> + ?line run(Dir, InputArgs, [Expected]); + false -> + ?line run_with_opts(Dir, [], InputArgs, [Expected]) + end, + + %% Verify + ?line {ok, Bin} = escript:create(binary, Sections), + ?line {ok, Read} = file:read_file(File), + ?line Bin = Read, % Assert + + Normalized = normalize_sections(Sections), + ?line {ok, Extracted} = escript:extract(File, []), + io:format("Normalized; ~p\n", [Normalized]), + io:format("Extracted ; ~p\n", [Extracted]), + ?line Normalized = Extracted, % Assert + ok. + +normalize_sections(Sections) -> + AtomToTuple = + fun(Val) -> + if + is_atom(Val) -> {Val, default}; + true -> Val + end + end, + case lists:map(AtomToTuple, [{K, V} || {K, V} <- Sections, V =/= undefined]) of + [{shebang, Shebang} | Rest] -> + [{shebang, Shebang} | + case Rest of + [{comment, Comment} | Rest2] -> + [{comment, Comment} | + case Rest2 of + [{emu_args, EmuArgs}, Body] -> + [{emu_args, EmuArgs}, Body]; + [Body] -> + [{emu_args, undefined}, Body] + end + ]; + [{emu_args, EmuArgs}, Body] -> + [{comment, undefined}, {emu_args, EmuArgs}, Body]; + [Body] -> + [{comment, undefined}, {emu_args, undefined}, Body] + end + ]; + [Body] -> + [{shebang, undefined}, {comment, undefined}, {emu_args, undefined}, Body] + end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +foldl(Config) when is_list(Config) -> + {NewFile, _FileInfo, + _EmuArg, _Source, + ErlBase, ErlCode, + BeamBase, _BeamCode, + ArchiveBin} = + prepare_creation("foldl", Config), + + Collect = fun(Name, GetInfo, GetBin, Acc) -> + [{Name, GetInfo(), GetBin()} | Acc] + end, + + %% Get line numbers and the file attribute right + SourceFile = NewFile ++ ".erl", + <<_:1/binary, ErlCode2/binary>> = ErlCode, + ?line ok = file:write_file(SourceFile, ErlCode2), + ?line {ok, _Mod, BeamCode} = + compile:file(SourceFile, [binary, debug_info]), + + %% Verify source script + ?line ok = escript:create(SourceFile, [{source, ErlCode}]), + ?line {ok, [{".", _, BeamCode2}]} + = escript_foldl(Collect, [], SourceFile), + + ?line {ok, Abstr} = beam_lib:chunks(BeamCode, [abstract_code]), + ?line {ok, Abstr2} = beam_lib:chunks(BeamCode2, [abstract_code]), + %% io:format("abstr1=~p\n", [Abstr]), + %% io:format("abstr2=~p\n", [Abstr2]), + ?line Abstr = Abstr2, % Assert + + %% Verify beam script + ?line ok = escript:create(NewFile, [{beam, BeamCode}]), + ?line {ok, [{".", _, BeamCode}]} + = escript_foldl(Collect, [], NewFile), + + %% Verify archive scripts + ?line ok = escript:create(NewFile, [{archive, ArchiveBin}]), + ?line {ok, [{BeamBase, #file_info{}, _}, + {ErlBase, #file_info{}, _}]} + = escript_foldl(Collect, [], NewFile), + + ArchiveFiles = [{ErlBase, ErlCode}, {BeamBase, BeamCode}], + ?line ok = escript:create(NewFile, [{archive, ArchiveFiles, []}]), + ?line {ok, [{BeamBase, _, _}, + {ErlBase, _, _}]} + = escript_foldl(Collect, [], NewFile), + + ok. + +escript_foldl(Fun, Acc, File) -> + code:ensure_loaded(zip), + case erlang:function_exported(zip, foldl, 3) of + true -> + emulate_escript_foldl(Fun, Acc, File); + false -> + escript:foldl(Fun, Acc, File) + end. + +emulate_escript_foldl(Fun, Acc, File) -> + case escript:extract(File, [compile_source]) of + {ok, [_Shebang, _Comment, _EmuArgs, Body]} -> + case Body of + {source, BeamCode} -> + GetInfo = fun() -> file:read_file_info(File) end, + GetBin = fun() -> BeamCode end, + {ok, Fun(".", GetInfo, GetBin, Acc)}; + {beam, BeamCode} -> + GetInfo = fun() -> file:read_file_info(File) end, + GetBin = fun() -> BeamCode end, + {ok, Fun(".", GetInfo, GetBin, Acc)}; + {archive, ArchiveBin} -> + zip:foldl(Fun, Acc, {File, ArchiveBin}) + end; + {error, Reason} -> + {error, Reason} + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + run(Dir, Cmd0, Expected0) -> Expected = iolist_to_binary(expected_output(Expected0, Dir)), Cmd = case os:type() of @@ -490,7 +744,7 @@ run(Dir, Cmd0, Expected0) -> end, do_run(Dir, Cmd, Expected). -run(Dir, Opts, Cmd0, Expected) -> +run_with_opts(Dir, Opts, Cmd0, Expected) -> Cmd = case os:type() of {win32,_} -> "escript " ++ Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0; _ -> "escript " ++ Opts ++ " " ++ Dir ++ "/" ++ Cmd0 @@ -533,8 +787,8 @@ expected_output([data_dir|T], Data) -> [filename:nativename(Data)++Slash|expected_output(T, Data)]; expected_output([H|T], Data) -> [H|expected_output(T, Data)]; -expected_output([], _) -> +expected_output([], _) -> []; -expected_output(Bin, _) when is_binary(Bin) -> +expected_output(Bin, _) when is_binary(Bin) -> Bin. diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 13c87ca005..5d7e558601 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -33,7 +33,7 @@ -export([misc/1, dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]). -export([files/1, tab2file/1, tab2file2/1, tab2file3/1, tabfile_ext1/1, tabfile_ext2/1, tabfile_ext3/1, tabfile_ext4/1]). --export([heavy/1, heavy_lookup/1, heavy_lookup_element/1]). +-export([heavy/1, heavy_lookup/1, heavy_lookup_element/1, heavy_concurrent/1]). -export([lookup_element/1, lookup_element_mult/1]). -export([fold/1]). -export([foldl_ordered/1, foldr_ordered/1, foldl/1, foldr/1, fold_empty/1]). @@ -63,7 +63,8 @@ meta_lookup_unnamed_read/1, meta_lookup_unnamed_write/1, meta_lookup_named_read/1, meta_lookup_named_write/1, meta_newdel_unnamed/1, meta_newdel_named/1]). --export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1, otp_8166/1]). +-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1, + otp_8166/1, otp_8732/1]). -export([exit_large_table_owner/1, exit_many_large_table_owner/1, exit_many_tables_owner/1, @@ -89,7 +90,8 @@ match_delete_do/1, match_delete3_do/1, firstnext_do/1, slot_do/1, match1_do/1, match2_do/1, match_object_do/1, match_object2_do/1, misc1_do/1, safe_fixtable_do/1, info_do/1, dups_do/1, heavy_lookup_do/1, - heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1 + heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1, + do_heavy_concurrent/1 ]). -include("test_server.hrl"). @@ -129,7 +131,7 @@ all(suite) -> t_select_delete, t_ets_dets, memory, t_bucket_disappears, select_fail,t_insert_new, t_repair_continuation, otp_5340, otp_6338, - otp_6842_select_1000, otp_7665, + otp_6842_select_1000, otp_7665, otp_8732, meta_wb, grow_shrink, grow_pseudo_deleted, shrink_pseudo_deleted, meta_smp, @@ -391,7 +393,7 @@ memory(Config) when is_list(Config) -> ?line erts_debug:set_internal_state(available_internal_state, true), ?line ok = chk_normal_tab_struct_size(), ?line L = [T1,T2,T3,T4] = fill_sets_int(1000), - ?line XRes1 = adjust_xmem(L, {16862,16072,16072,16078}), + ?line XRes1 = adjust_xmem(L, {14862,14072,14072,14078}), ?line Res1 = {?S(T1),?S(T2),?S(T3),?S(T4)}, ?line lists:foreach(fun(T) -> Before = ets:info(T,size), @@ -402,7 +404,7 @@ memory(Config) when is_list(Config) -> [Key, ets:info(T,type), Before, ets:info(T,size), Objs]) end, L), - ?line XRes2 = adjust_xmem(L, {16849,16060,16048,16054}), + ?line XRes2 = adjust_xmem(L, {14851,14062,14052,14058}), ?line Res2 = {?S(T1),?S(T2),?S(T3),?S(T4)}, ?line lists:foreach(fun(T) -> Before = ets:info(T,size), @@ -413,7 +415,7 @@ memory(Config) when is_list(Config) -> [Key, ets:info(T,type), Before, ets:info(T,size), Objs]) end, L), - ?line XRes3 = adjust_xmem(L, {16836,16048,16024,16030}), + ?line XRes3 = adjust_xmem(L, {14840,14052,14032,14038}), ?line Res3 = {?S(T1),?S(T2),?S(T3),?S(T4)}, ?line lists:foreach(fun(T) -> ?line ets:delete_all_objects(T) @@ -3877,7 +3879,7 @@ make_sub_binary(List, Num) when is_list(List) -> {_,B} = split_binary(Bin, N+1), B. -heavy(suite) -> [heavy_lookup, heavy_lookup_element]. +heavy(suite) -> [heavy_lookup, heavy_lookup_element, heavy_concurrent]. %% Lookup stuff like crazy... heavy_lookup(doc) -> ["Performs multiple lookups for every key ", @@ -3940,6 +3942,44 @@ do_lookup_element(Tab, N, M) -> end. +heavy_concurrent(Config) -> + repeat_for_opts(do_heavy_concurrent). + +do_heavy_concurrent(Opts) -> + ?line Size = 20000, + ?line EtsMem = etsmem(), + ?line Tab = ets:new(blupp, [set, public, {keypos, 2} | Opts]), + ?line ok = fill_tab2(Tab, 0, Size), + ?line Procs = lists:map( + fun (N) -> + spawn_link( + fun () -> + do_heavy_concurrent_proc(Tab, Size, N) + end) + end, + lists:seq(1, 500)), + ?line lists:foreach(fun (P) -> + M = erlang:monitor(process, P), + receive + {'DOWN', Mon, process, P, _} -> + ok + end + end, + Procs), + ?line true = ets:delete(Tab), + ?line verify_etsmem(EtsMem). + +do_heavy_concurrent_proc(_Tab, 0, _Offs) -> + done; +do_heavy_concurrent_proc(Tab, N, Offs) when (N+Offs) rem 100 == 0 -> + Data = {"here", are, "S O M E ", data, "toooooooooooooooooo", insert, + make_ref(), make_ref(), make_ref()}, + true=ets:insert(Tab, {{self(),Data}, N}), + do_heavy_concurrent_proc(Tab, N-1, Offs); +do_heavy_concurrent_proc(Tab, N, Offs) -> + _ = ets:lookup(Tab, N), + do_heavy_concurrent_proc(Tab, N-1, Offs). + fold(suite) -> [foldl_ordered, foldr_ordered, foldl, foldr, fold_empty]. @@ -5010,8 +5050,14 @@ verify_table_load(T) -> end. - - +otp_8732(doc) -> ["ets:select on a tree with NIL key object"]; +otp_8732(Config) when is_list(Config) -> + Tab = ets:new(noname,[ordered_set]), + filltabstr(Tab,999), + ets:insert(Tab,{[],"nasty NIL object"}), + ?line [] = ets:match(Tab,{'_',nomatch}), %% Will hang if bug not fixed + ok. + smp_select_delete(suite) -> []; smp_select_delete(doc) -> @@ -5336,7 +5382,7 @@ only_if_smp(Schedulers, Func) -> %% Repeat test function with different combination of table options %% repeat_for_opts(F) -> - repeat_for_opts(F, [write_concurrency]). + repeat_for_opts(F, [write_concurrency, read_concurrency]). repeat_for_opts(F, OptGenList) when is_atom(F) -> repeat_for_opts(fun(Opts) -> ?MODULE:F(Opts) end, OptGenList); @@ -5356,6 +5402,7 @@ repeat_for_opts(F, [Atom | Tail], AccList) when is_atom(Atom) -> repeat_for_opts(F, [repeat_for_opts_atom2list(Atom) | Tail ], AccList). repeat_for_opts_atom2list(all_types) -> [set,ordered_set,bag,duplicate_bag]; -repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}]. +repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}]; +repeat_for_opts_atom2list(read_concurrency) -> [{read_concurrency,false},{read_concurrency,true}]. diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl index 8cbffaca56..4f7de451e3 100644 --- a/lib/stdlib/test/gen_event_SUITE.erl +++ b/lib/stdlib/test/gen_event_SUITE.erl @@ -23,9 +23,11 @@ -export([all/1]). -export([start/1, test_all/1, add_handler/1, add_sup_handler/1, delete_handler/1, swap_handler/1, swap_sup_handler/1, - notify/1, sync_notify/1, call/1, info/1, hibernate/1]). + notify/1, sync_notify/1, call/1, info/1, hibernate/1, + call_format_status/1, error_format_status/1]). -all(suite) -> {req, [stdlib], [start, test_all, hibernate]}. +all(suite) -> {req, [stdlib], [start, test_all, hibernate, + call_format_status, error_format_status]}. %% -------------------------------------- %% Start an event manager. @@ -844,3 +846,56 @@ info(Config) when is_list(Config) -> ?line ok = gen_event:stop(my_dummy_handler), ok. + +call_format_status(suite) -> + []; +call_format_status(doc) -> + ["Test that sys:get_status/1,2 calls format_status/2"]; +call_format_status(Config) when is_list(Config) -> + ?line {ok, Pid} = gen_event:start({local, my_dummy_handler}), + %% State here intentionally differs from what we expect from format_status + State = self(), + FmtState = "dummy1_h handler state", + ?line ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State]), + ?line Status1 = sys:get_status(Pid), + ?line Status2 = sys:get_status(Pid, 5000), + ?line ok = gen_event:stop(Pid), + ?line {status, Pid, _, [_, _, Pid, [], Data1]} = Status1, + ?line HandlerInfo1 = proplists:get_value(items, Data1), + ?line {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo1, + ?line {status, Pid, _, [_, _, Pid, [], Data2]} = Status2, + ?line HandlerInfo2 = proplists:get_value(items, Data2), + ?line {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo2, + ok. + +error_format_status(suite) -> + []; +error_format_status(doc) -> + ["Test that a handler error calls format_status/2"]; +error_format_status(Config) when is_list(Config) -> + ?line error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + State = self(), + ?line {ok, Pid} = gen_event:start({local, my_dummy_handler}), + ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy1_h, [State]), + ?line ok = gen_event:notify(my_dummy_handler, do_crash), + ?line receive + {gen_event_EXIT,dummy1_h,{'EXIT',_}} -> ok + after 5000 -> + ?t:fail(exit_gen_event) + end, + FmtState = "dummy1_h handler state", + receive + {error,_GroupLeader, {Pid, + "** gen_event handler"++_, + [dummy1_h,my_dummy_handler,do_crash, + FmtState, _]}} -> + ok; + Other -> + ?line io:format("Unexpected: ~p", [Other]), + ?line ?t:fail() + end, + ?t:messages_get(), + ?line ok = gen_event:stop(Pid), + process_flag(trap_exit, OldFl), + ok. diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl index 23c1d9a193..dd120f8c05 100644 --- a/lib/stdlib/test/gen_fsm_SUITE.erl +++ b/lib/stdlib/test/gen_fsm_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(gen_fsm_SUITE). @@ -30,7 +30,7 @@ -export([shutdown/1]). --export([sys/1, sys1/1, call_format_status/1]). +-export([sys/1, sys1/1, call_format_status/1, error_format_status/1]). -export([hibernate/1,hiber_idle/3,hiber_wakeup/3,hiber_idle/2,hiber_wakeup/2]). @@ -305,7 +305,7 @@ shutdown(Config) when is_list(Config) -> ok. -sys(suite) -> [sys1, call_format_status]. +sys(suite) -> [sys1, call_format_status, error_format_status]. sys1(Config) when is_list(Config) -> ?line {ok, Pid} = @@ -320,10 +320,53 @@ sys1(Config) when is_list(Config) -> call_format_status(Config) when is_list(Config) -> ?line {ok, Pid} = gen_fsm:start(gen_fsm_SUITE, [], []), ?line Status = sys:get_status(Pid), - ?line {status, Pid, _Mod, [_PDict, running, _Parent, _, Data]} = Status, + ?line {status, Pid, _Mod, [_PDict, running, _, _, Data]} = Status, ?line [format_status_called | _] = lists:reverse(Data), - ?line stop_it(Pid). + ?line stop_it(Pid), + + %% check that format_status can handle a name being an atom (pid is + %% already checked by the previous test) + ?line {ok, Pid2} = gen_fsm:start({local, gfsm}, gen_fsm_SUITE, [], []), + ?line Status2 = sys:get_status(gfsm), + ?line {status, Pid2, _Mod, [_PDict2, running, _, _, Data2]} = Status2, + ?line [format_status_called | _] = lists:reverse(Data2), + ?line stop_it(Pid2), + %% check that format_status can handle a name being a term other than a + %% pid or atom + GlobalName1 = {global, "CallFormatStatus"}, + ?line {ok, Pid3} = gen_fsm:start(GlobalName1, gen_fsm_SUITE, [], []), + ?line Status3 = sys:get_status(GlobalName1), + ?line {status, Pid3, _Mod, [_PDict3, running, _, _, Data3]} = Status3, + ?line [format_status_called | _] = lists:reverse(Data3), + ?line stop_it(Pid3), + GlobalName2 = {global, {name, "term"}}, + ?line {ok, Pid4} = gen_fsm:start(GlobalName2, gen_fsm_SUITE, [], []), + ?line Status4 = sys:get_status(GlobalName2), + ?line {status, Pid4, _Mod, [_PDict4, running, _, _, Data4]} = Status4, + ?line [format_status_called | _] = lists:reverse(Data4), + ?line stop_it(Pid4). + +error_format_status(Config) when is_list(Config) -> + ?line error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + StateData = "called format_status", + ?line {ok, Pid} = gen_fsm:start(gen_fsm_SUITE, {state_data, StateData}, []), + %% bad return value in the gen_fsm loop + ?line {'EXIT',{{bad_return_value, badreturn},_}} = + (catch gen_fsm:sync_send_event(Pid, badreturn)), + receive + {error,_GroupLeader,{Pid, + "** State machine"++_, + [Pid,{_,_,badreturn},idle,StateData,_]}} -> + ok; + Other -> + ?line io:format("Unexpected: ~p", [Other]), + ?line ?t:fail() + end, + ?t:messages_get(), + process_flag(trap_exit, OldFl), + ok. %% Hibernation hibernate(suite) -> []; @@ -704,6 +747,8 @@ init(hiber) -> {ok, hiber_idle, []}; init(hiber_now) -> {ok, hiber_idle, [], hibernate}; +init({state_data, StateData}) -> + {ok, idle, StateData}; init(_) -> {ok, idle, state_data}. @@ -844,5 +889,7 @@ handle_sync_event(stop_shutdown_reason, _From, _State, Data) -> handle_sync_event({get, _Pid}, _From, State, Data) -> {reply, {state, State, Data}, State, Data}. -format_status(_Opt, [_Pdict, _StateData]) -> +format_status(terminate, [_Pdict, StateData]) -> + StateData; +format_status(normal, [_Pdict, _StateData]) -> [format_status_called]. diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index 6efdce78a1..99388ba2e3 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(gen_server_SUITE). @@ -30,7 +30,8 @@ call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1, spec_init_local_registered_parent/1, spec_init_global_registered_parent/1, - otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1 + otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1, + error_format_status/1, call_with_huge_message_queue/1 ]). % spawn export @@ -51,7 +52,9 @@ all(suite) -> call_remote_n2, call_remote_n3, spec_init, spec_init_local_registered_parent, spec_init_global_registered_parent, - otp_5854, hibernate, otp_7669, call_format_status]. + otp_5854, hibernate, otp_7669, + call_format_status, error_format_status, + call_with_huge_message_queue]. -define(default_timeout, ?t:minutes(1)). @@ -895,15 +898,105 @@ call_format_status(doc) -> ["Test that sys:get_status/1,2 calls format_status/2"]; call_format_status(Config) when is_list(Config) -> ?line {ok, Pid} = gen_server:start_link({local, call_format_status}, - gen_server_SUITE, [], []), + ?MODULE, [], []), ?line Status1 = sys:get_status(call_format_status), ?line {status, Pid, _Mod, [_PDict, running, _Parent, _, Data1]} = Status1, ?line [format_status_called | _] = lists:reverse(Data1), ?line Status2 = sys:get_status(call_format_status, 5000), ?line {status, Pid, _Mod, [_PDict, running, _Parent, _, Data2]} = Status2, ?line [format_status_called | _] = lists:reverse(Data2), + + %% check that format_status can handle a name being a pid (atom is + %% already checked by the previous test) + ?line {ok, Pid3} = gen_server:start_link(gen_server_SUITE, [], []), + ?line Status3 = sys:get_status(Pid3), + ?line {status, Pid3, _Mod, [_PDict3, running, _Parent, _, Data3]} = Status3, + ?line [format_status_called | _] = lists:reverse(Data3), + + %% check that format_status can handle a name being a term other than a + %% pid or atom + GlobalName1 = {global, "CallFormatStatus"}, + ?line {ok, Pid4} = gen_server:start_link(GlobalName1, + gen_server_SUITE, [], []), + ?line Status4 = sys:get_status(Pid4), + ?line {status, Pid4, _Mod, [_PDict4, running, _Parent, _, Data4]} = Status4, + ?line [format_status_called | _] = lists:reverse(Data4), + GlobalName2 = {global, {name, "term"}}, + ?line {ok, Pid5} = gen_server:start_link(GlobalName2, + gen_server_SUITE, [], []), + ?line Status5 = sys:get_status(GlobalName2), + ?line {status, Pid5, _Mod, [_PDict5, running, _Parent, _, Data5]} = Status5, + ?line [format_status_called | _] = lists:reverse(Data5), + ok. + +%% Verify that error termination correctly calls our format_status/2 fun +%% +error_format_status(suite) -> + []; +error_format_status(doc) -> + ["Test that an error termination calls format_status/2"]; +error_format_status(Config) when is_list(Config) -> + ?line error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + State = "called format_status", + ?line {ok, Pid} = gen_server:start_link(?MODULE, {state, State}, []), + ?line {'EXIT',{crashed,_}} = (catch gen_server:call(Pid, crash)), + receive + {'EXIT', Pid, crashed} -> + ok + end, + receive + {error,_GroupLeader,{Pid, + "** Generic server"++_, + [Pid,crash,State,crashed]}} -> + ok; + Other -> + ?line io:format("Unexpected: ~p", [Other]), + ?line ?t:fail() + end, + ?t:messages_get(), + process_flag(trap_exit, OldFl), + ok. + +%% Test that the time for a huge message queue is not +%% significantly slower than with an empty message queue. +call_with_huge_message_queue(Config) when is_list(Config) -> + ?line Pid = spawn_link(fun echo_loop/0), + + ?line {Time,ok} = tc(fun() -> calls(10, Pid) end), + + ?line [self() ! {msg,N} || N <- lists:seq(1, 500000)], + erlang:garbage_collect(), + ?line {NewTime,ok} = tc(fun() -> calls(10, Pid) end), + io:format("Time for empty message queue: ~p", [Time]), + io:format("Time for huge message queue: ~p", [NewTime]), + + case (NewTime+1) / (Time+1) of + Q when Q < 10 -> + ok; + Q -> + io:format("Q = ~p", [Q]), + ?line ?t:fail() + end, ok. +calls(0, _) -> ok; +calls(N, Pid) -> + {ultimate_answer,42} = call(Pid, {ultimate_answer,42}), + calls(N-1, Pid). + +call(Pid, Msg) -> + gen_server:call(Pid, Msg, infinity). + +tc(Fun) -> + timer:tc(erlang, apply, [Fun,[]]). + +echo_loop() -> + receive + {'$gen_call',{Pid,Ref},Msg} -> + Pid ! {Ref,Msg}, + echo_loop() + end. %%-------------------------------------------------------------- %% Help functions to spec_init_* @@ -1064,5 +1157,7 @@ terminate({From, stopped_info}, _State) -> terminate(_Reason, _State) -> ok. -format_status(_Opt, [_PDict, _State]) -> - [format_status_called]. +format_status(terminate, [_PDict, State]) -> + State; +format_status(normal, [_PDict, _State]) -> + format_status_called. diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl index 93159fbd5b..d9672a8c7b 100644 --- a/lib/stdlib/test/io_proto_SUITE.erl +++ b/lib/stdlib/test/io_proto_SUITE.erl @@ -17,6 +17,7 @@ %% %CopyrightEnd% %% -module(io_proto_SUITE). +-compile(r12). -export([all/1]). diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index ff11ebc6bf..e21de8770a 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -1,25 +1,26 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %%%---------------------------------------------------------------- %%% Purpose:Test Suite for the 'qlc' module. %%%----------------------------------------------------------------- -module(qlc_SUITE). +-compile(r12). -define(QLC, qlc). -define(QLCs, "qlc"). @@ -3183,7 +3184,9 @@ lookup2(Config) when is_list(Config) -> [] = qlc:e(Q), false = lookup_keys(Q) end, [{1,b},{2,3}])">>, - {warnings,[{{3,48},qlc,nomatch_filter}]}}, + {warnings,[{2,sys_core_fold,nomatch_guard}, + {3,qlc,nomatch_filter}, + {3,sys_core_fold,{eval_failure,badarg}}]}}, <<"etsc(fun(E) -> Q = qlc:q([X || {X} <- ets:table(E), element(1,{X}) =:= 1]), diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl index 02683f9f1a..46a84d4e24 100644 --- a/lib/stdlib/test/re_SUITE.erl +++ b/lib/stdlib/test/re_SUITE.erl @@ -18,12 +18,12 @@ %% -module(re_SUITE). --export([all/1, pcre/1,compile_options/1,run_options/1,combined_options/1,replace_autogen/1,global_capture/1,replace_input_types/1,replace_return/1,split_autogen/1,split_options/1,split_specials/1,error_handling/1,pcre_cve_2008_2371/1]). +-export([all/1, pcre/1,compile_options/1,run_options/1,combined_options/1,replace_autogen/1,global_capture/1,replace_input_types/1,replace_return/1,split_autogen/1,split_options/1,split_specials/1,error_handling/1,pcre_cve_2008_2371/1,pcre_compile_workspace_overflow/1,re_infinite_loop/1]). -include("test_server.hrl"). -include_lib("kernel/include/file.hrl"). -all(suite) -> [pcre,compile_options,run_options,combined_options,replace_autogen,global_capture,replace_input_types,replace_return,split_autogen,split_options,split_specials,error_handling,pcre_cve_2008_2371]. +all(suite) -> [pcre,compile_options,run_options,combined_options,replace_autogen,global_capture,replace_input_types,replace_return,split_autogen,split_options,split_specials,error_handling,pcre_cve_2008_2371,pcre_compile_workspace_overflow,re_infinite_loop]. pcre(doc) -> ["Run all applicable tests from the PCRE testsuites."]; @@ -544,3 +544,25 @@ pcre_cve_2008_2371(Config) when is_list(Config) -> %% Make sure it doesn't crash the emulator. re:compile(<<"(?i)[\xc3\xa9\xc3\xbd]|[\xc3\xa9\xc3\xbdA]">>, [unicode]), ok. + +pcre_compile_workspace_overflow(doc) -> + "Patch from http://vcs.pcre.org/viewvc/code/trunk/pcre_compile.c?r1=504&r2=505&view=patch"; +pcre_compile_workspace_overflow(Config) when is_list(Config) -> + N = 819, + ?line {error,{"internal error: overran compiling workspace",799}} = + re:compile([lists:duplicate(N, $(), lists:duplicate(N, $))]), + ok. +re_infinite_loop(doc) -> + "Make sure matches that really loop infinitely actually fail"; +re_infinite_loop(Config) when is_list(Config) -> + Dog = ?t:timetrap(?t:minutes(1)), + ?line Str = + "http:/www.flickr.com/slideShow/index.gne?group_id=&user_id=69845378@N0", + ?line EMail_regex = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+" + ++ "(\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*" + ++ "@.*([a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+" + ++ "([a-zA-Z]{2}|com|org|net|gov|mil" + ++ "|biz|info|mobi|name|aero|jobs|museum)", + ?line nomatch = re:run(Str, EMail_regex), + ?t:timetrap_cancel(Dog), + ok. diff --git a/lib/stdlib/test/timer_simple_SUITE.erl b/lib/stdlib/test/timer_simple_SUITE.erl index 021a22c61b..6aa2b7b945 100644 --- a/lib/stdlib/test/timer_simple_SUITE.erl +++ b/lib/stdlib/test/timer_simple_SUITE.erl @@ -224,11 +224,19 @@ cancel2(Config) when is_list(Config) -> tc(doc) -> "Test sleep/1 and tc/3."; tc(suite) -> []; tc(Config) when is_list(Config) -> - % This should both sleep and tc - ?line {Res, ok} = timer:tc(timer, sleep, [500]), - ?line ok = if - Res < 500*1000 -> {too_early, Res}; % Too early - Res > 800*1000 -> {too_late, Res}; % Too much time + % This should both sleep and tc/3 + ?line {Res1, ok} = timer:tc(timer, sleep, [500]), + ?line ok = if + Res1 < 500*1000 -> {too_early, Res1}; % Too early + Res1 > 800*1000 -> {too_late, Res1}; % Too much time + true -> ok + end, + + % This should both sleep and tc/2 + ?line {Res2, ok} = timer:tc(fun(T) -> timer:sleep(T) end, [500]), + ?line ok = if + Res2 < 500*1000 -> {too_early, Res2}; % Too early + Res2 > 800*1000 -> {too_late, Res2}; % Too much time true -> ok end, diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl index 12ca655000..48b14396c1 100644 --- a/lib/stdlib/test/zip_SUITE.erl +++ b/lib/stdlib/test/zip_SUITE.erl @@ -18,12 +18,13 @@ %% -module(zip_SUITE). --export([all/1, borderline/1, atomic/1, +-export([all/1, borderline/1, atomic/1, bad_zip/1, unzip_from_binary/1, unzip_to_binary/1, zip_to_binary/1, unzip_options/1, zip_options/1, list_dir_options/1, aliases/1, openzip_api/1, zip_api/1, unzip_jar/1, - compress_control/1]). + compress_control/1, + foldl/1]). -include("test_server.hrl"). -include("test_server_line.hrl"). @@ -35,7 +36,8 @@ all(suite) -> [borderline, atomic, bad_zip, zip_to_binary, unzip_options, zip_options, list_dir_options, aliases, openzip_api, zip_api, unzip_jar, - compress_control]. + compress_control, + foldl]. borderline(doc) -> ["Test creating, listing and extracting one file from an archive " @@ -110,17 +112,17 @@ get_data(Port, Expect) -> {Port, {data, Bytes}} -> get_data(Port, match_output(Bytes, Expect, Port)); {Port, eof} -> - Port ! {self(), close}, + Port ! {self(), close}, receive {Port, closed} -> true - end, + end, receive - {'EXIT', Port, _} -> + {'EXIT', Port, _} -> ok after 1 -> % force context switch ok - end, + end, match_output(eof, Expect, Port) end. @@ -290,7 +292,7 @@ unzip_options(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), Long = filename:join(DataDir, "abc.zip"), - + %% create a temp directory Subdir = filename:join(PrivDir, "t"), ok = file:make_dir(Subdir), @@ -303,7 +305,7 @@ unzip_options(Config) when is_list(Config) -> %% Verify. ?line true = (length(FList) =:= length(RetList)), - ?line lists:foreach(fun(F)-> {ok,B} = file:read_file(filename:join(DataDir, F)), + ?line lists:foreach(fun(F)-> {ok,B} = file:read_file(filename:join(DataDir, F)), {ok,B} = file:read_file(filename:join(Subdir, F)) end, FList), ?line lists:foreach(fun(F)-> ok = file:delete(F) end, @@ -321,7 +323,7 @@ unzip_jar(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), JarFile = filename:join(DataDir, "test.jar"), - + %% create a temp directory Subdir = filename:join(PrivDir, "jartest"), ok = file:make_dir(Subdir), @@ -479,7 +481,7 @@ unzip_to_binary(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), - delete_all_in(PrivDir), + delete_all_in(PrivDir), file:set_cwd(PrivDir), Long = filename:join(DataDir, "abc.zip"), @@ -595,17 +597,17 @@ do_delete_files([],Cnt) -> Cnt; do_delete_files([Item|Rest], Cnt) -> case file:delete(Item) of - ok -> + ok -> DelCnt = 1; {error,eperm} -> file:change_mode(Item, 8#777), DelCnt = delete_files(filelib:wildcard(filename:join(Item, "*"))), - file:del_dir(Item); + file:del_dir(Item); {error,eacces} -> %% We'll see about that! file:change_mode(Item, 8#777), case file:delete(Item) of - ok -> + ok -> DelCnt = 1; {error,_} -> erlang:yield(), @@ -643,22 +645,22 @@ compress_control(Config) when is_list(Config) -> ], test_compress_control(Dir, - Files, + Files, [{compress, []}], []), test_compress_control(Dir, - Files, + Files, [{uncompress, all}], []), test_compress_control(Dir, - Files, + Files, [{uncompress, []}], [".txt", ".exe", ".zip", ".lzh", ".arj"]), test_compress_control(Dir, - Files, + Files, [], [".txt", ".exe"]), @@ -686,7 +688,7 @@ test_compress_control(Dir, Files, ZipOptions, Expected) -> create_files(Files), {ok, Zip} = zip:create(Zip, [Dir], ZipOptions), - + {ok, OpenZip} = zip:openzip_open(Zip, [memory]), {ok,[#zip_comment{comment = ""} | ZipList]} = zip:openzip_list_dir(OpenZip), io:format("compress_control: -> ~p -> ~p\n -> ~pn", [Expected, ZipOptions, ZipList]), @@ -698,19 +700,19 @@ test_compress_control(Dir, Files, ZipOptions, Expected) -> delete_files(lists:reverse(Names)), % Remove plain files before directories ok. - + verify_compression([{Name, Kind, _Filler} | Files], ZipList, OpenZip, ZipOptions, Expected) -> {Name2, BinSz} = case Kind of - dir -> + dir -> {Name ++ "/", 0}; - _ -> + _ -> {ok, {Name, Bin}} = zip:openzip_get(Name, OpenZip), {Name, size(Bin)} end, {Name2, {value, ZipFile}} = {Name2, lists:keysearch(Name2, #zip_file.name, ZipList)}, #zip_file{info = #file_info{size = InfoSz, type = InfoType}, comp_size = InfoCompSz} = ZipFile, - + Ext = filename:extension(Name), IsComp = is_compressed(Ext, Kind, ZipOptions), ExpComp = lists:member(Ext, Expected), @@ -757,3 +759,33 @@ extensions([H | T], Old) -> extensions([], Old) -> Old. +foldl(Config) -> + PrivDir = ?config(priv_dir, Config), + File = filename:join([PrivDir, "foldl.zip"]), + + FooBin = <<"FOO">>, + BarBin = <<"BAR">>, + Files = [{"foo", FooBin}, {"bar", BarBin}], + ?line {ok, {File, Bin}} = zip:create(File, Files, [memory]), + ZipFun = fun(N, I, B, Acc) -> [{N, B(), I()} | Acc] end, + ?line {ok, FileSpec} = zip:foldl(ZipFun, [], {File, Bin}), + ?line [{"bar", BarBin, #file_info{}}, {"foo", FooBin, #file_info{}}] = FileSpec, + ?line {ok, {File, Bin}} = zip:create(File, lists:reverse(FileSpec), [memory]), + ?line {foo_bin, FooBin} = + try + zip:foldl(fun("foo", _, B, _) -> throw(B()); (_, _, _, Acc) -> Acc end, [], {File, Bin}) + catch + throw:FooBin -> + {foo_bin, FooBin} + end, + ?line ok = file:write_file(File, Bin), + ?line {ok, FileSpec} = zip:foldl(ZipFun, [], File), + + ?line {error, einval} = zip:foldl(fun() -> ok end, [], File), + ?line {error, einval} = zip:foldl(ZipFun, [], 42), + ?line {error, einval} = zip:foldl(ZipFun, [], {File, 42}), + + ?line ok = file:delete(File), + ?line {error, enoent} = zip:foldl(ZipFun, [], File), + + ok. |