aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/test/erl_pp_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/test/erl_pp_SUITE.erl')
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl216
1 files changed, 166 insertions, 50 deletions
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"]]).