1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2001-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(lc_SUITE). 21 22-export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1, 23 init_per_group/2,end_per_group/2, 24 init_per_testcase/2,end_per_testcase/2, 25 basic/1,deeply_nested/1,no_generator/1, 26 empty_generator/1,no_export/1,shadow/1, 27 effect/1]). 28 29-include_lib("common_test/include/ct.hrl"). 30 31suite() -> 32 [{ct_hooks,[ts_install_cth]}, 33 {timetrap,{minutes,1}}]. 34 35all() -> 36 [{group,p}]. 37 38groups() -> 39 [{p,test_lib:parallel(), 40 [basic, 41 deeply_nested, 42 no_generator, 43 empty_generator, 44 no_export, 45 shadow, 46 effect 47 ]}]. 48 49init_per_suite(Config) -> 50 test_lib:recompile(?MODULE), 51 Config. 52 53end_per_suite(_Config) -> 54 ok. 55 56init_per_group(_GroupName, Config) -> 57 Config. 58 59end_per_group(_GroupName, Config) -> 60 Config. 61 62 63init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> 64 Config. 65 66end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> 67 ok. 68 69basic(Config) when is_list(Config) -> 70 L0 = lists:seq(1, 10), 71 L1 = my_map(fun(X) -> {x,X} end, L0), 72 L1 = [{x,X} || X <- L0], 73 L0 = my_map(fun({x,X}) -> X end, L1), 74 [1,2,3,4,5] = [X || X <- L0, X < 6], 75 [4,5,6] = [X || X <- L0, X > 3, X < 7], 76 [] = [X || X <- L0, X > 32, X < 7], 77 [1,3,5,7,9] = [X || X <- L0, odd(X)], 78 [2,4,6,8,10] = [X || X <- L0, not odd(X)], 79 [1,3,5,9] = [X || X <- L0, odd(X), X =/= 7], 80 [2,4,8,10] = [X || X <- L0, not odd(X), X =/= 6], 81 82 %% Append is specially handled. 83 [1,3,5,9,2,4,8,10] = [X || X <- L0, odd(X), X =/= 7] ++ 84 [X || X <- L0, not odd(X), X =/= 6], 85 86 %% Guards BIFs are evaluated in guard context. Weird, but true. 87 [{a,b,true},{x,y,true,true}] = [X || X <- tuple_list(), element(3, X)], 88 89 %% Filter expressions with andalso/orelse. 90 "abc123" = alphanum("?abc123.;"), 91 92 %% Aliased patterns. 93 [] = [t || {C=D}={_,_} <- []], 94 [] = [X || {X,{Y}={X,X}} <- []], 95 [t] = [t || "a"++"b" = "ab" <- ["ab"]], 96 97 %% Strange filter block. 98 [] = [{X,Y} || {X} <- [], begin Y = X, Y =:= X end], 99 [{a,a}] = [{X,Y} || {X} <- [{a}], begin Y = X, Y =:= X end], 100 101 %% Not matching. 102 [] = [3 || {3=4} <- []], 103 104 %% Error cases. 105 [] = [{xx,X} || X <- L0, element(2, X) == no_no_no], 106 {'EXIT',_} = (catch [X || X <- L1, list_to_atom(X) == dum]), 107 [] = [X || X <- L1, X+1 < 2], 108 {'EXIT',_} = (catch [X || X <- L1, odd(X)]), 109 fc([x], catch [E || E <- id(x)]), 110 111 %% Make sure that line numbers point out the generator. 112 case ?MODULE of 113 lc_inline_SUITE -> 114 ok; 115 _ -> 116 {'EXIT',{function_clause, 117 [{?MODULE,_,_, 118 [{file,"bad_lc.erl"},{line,4}]}|_]}} = 119 (catch bad_generator(a)), 120 {'EXIT',{function_clause, 121 [{?MODULE,_,_, 122 [{file,"bad_lc.erl"},{line,4}]}|_]}} = 123 (catch bad_generator([a|b])), 124 {'EXIT',{badarg, 125 [{erlang,length,_,_}, 126 {?MODULE,bad_generator_bc,1, 127 [{file,"bad_lc.erl"},{line,7}]}|_]}} = 128 (catch bad_generator_bc(a)), 129 {'EXIT',{badarg, 130 [{erlang,length,_,_}, 131 {?MODULE,bad_generator_bc,1, 132 [{file,"bad_lc.erl"},{line,7}]}|_]}} = 133 (catch bad_generator_bc([a|b])) 134 end, 135 ok. 136 137tuple_list() -> 138 [{a,b,true},[a,b,c],glurf,{a,b,false,xx},{a,b},{x,y,true,true},{a,b,d,ddd}]. 139 140my_map(F, L) -> 141 [F(X) || X <- L]. 142 143odd(X) -> 144 X rem 2 == 1. 145 146alphanum(Str) -> 147 [C || C <- Str, ((C >= $0) andalso (C =< $9)) 148 orelse ((C >= $a) andalso (C =< $z)) 149 orelse ((C >= $A) andalso (C =< $Z))]. 150 151deeply_nested(Config) when is_list(Config) -> 152 [[99,98,97,96,42,17,1764,12,11,10,9,8,7,6,5,4,3,7,2,1]] = deeply_nested_1(), 153 ok. 154 155deeply_nested_1() -> 156 %% This used to compile really, really SLOW before R11B-1... 157 [[X1,X2,X3,X4,X5,X6,X7(),X8,X9,X10,X11,X12,X13,X14,X15,X16,X17,X18(),X19,X20] || 158 X1 <- [99],X2 <- [98],X3 <- [97],X4 <- [96],X5 <- [42],X6 <- [17], 159 X7 <- [fun() -> X5*X5 end],X8 <- [12],X9 <- [11],X10 <- [10], 160 X11 <- [9],X12 <- [8],X13 <- [7],X14 <- [6],X15 <- [5], 161 X16 <- [4],X17 <- [3],X18 <- [fun() -> X16+X17 end],X19 <- [2],X20 <- [1]]. 162 163no_generator(Config) when is_list(Config) -> 164 Seq = lists:seq(-10, 17), 165 [no_gen_verify(no_gen(A, B), A, B) || A <- Seq, B <- Seq], 166 167 %% Literal expression, for coverage. 168 [a] = [a || true], 169 [a,b,c] = [a || true] ++ [b,c], 170 ok. 171 172no_gen(A, B) -> 173 [{A,B} || A+B =:= 0] ++ 174 [{A,B} || A*B =:= 0] ++ 175 [{A,B} || A rem B =:= 3] ++ 176 [{A,B} || A =:= B] ++ 177 [{one_more,A,B} || no_gen_one_more(A, B)] ++ 178 [A || A =:= 1] ++ 179 [A || A =:= 2] ++ 180 [A || A =:= 3] ++ 181 [A || A =:= 4] ++ 182 [A || A =:= 5] ++ 183 [A || A =:= 6] ++ 184 [A || A =:= 7] ++ 185 [A || A =:= 8] ++ 186 [A || A =:= 9] ++ 187 [B || B =:= 1] ++ 188 [B || B =:= 2] ++ 189 [B || B =:= 3] ++ 190 [B || B =:= 4] ++ 191 [B || B =:= 5] ++ 192 [B || B =:= 6] ++ 193 [B || B =:= 7] ++ 194 [B || B =:= 8] ++ 195 [B || B =:= 9]. 196 197no_gen_verify(Res, A, B) -> 198 Pair = {A,B}, 199 ShouldBe = no_gen_eval(fun() -> A+B =:= 0 end, Pair) ++ 200 no_gen_eval(fun() -> A*B =:= 0 end, Pair) ++ 201 no_gen_eval(fun() -> B =/= 0 andalso A rem B =:= 3 end, Pair) ++ 202 no_gen_eval(fun() -> A =:= B end, Pair) ++ 203 no_gen_eval(fun() -> A + 1 =:= B end, {one_more,A,B}) ++ 204 no_gen_eval(fun() -> 1 =< A andalso A =< 9 end, A) ++ 205 no_gen_eval(fun() -> 1 =< B andalso B =< 9 end, B), 206 case Res of 207 ShouldBe -> ok; 208 _ -> 209 io:format("A = ~p; B = ~p; Expected = ~p, actual = ~p", [A,B,ShouldBe,Res]), 210 ct:fail(failed) 211 end. 212 213no_gen_eval(Fun, Res) -> 214 case Fun() of 215 true -> [Res]; 216 false -> [] 217 end. 218 219no_gen_one_more(A, B) -> A + 1 =:= B. 220 221empty_generator(Config) when is_list(Config) -> 222 [] = [X || {X} <- [], (false or (X/0 > 3))], 223 ok. 224 225no_export(Config) when is_list(Config) -> 226 [] = [ _X = a || false ] ++ [ _X = a || false ], 227 ok. 228 229%% Test that variables in list comprehensions are 230%% correctly shadowed. 231 232shadow(Config) when is_list(Config) -> 233 Shadowed = nomatch, 234 _ = id(Shadowed), %Eliminate warning. 235 L = [{Shadowed,Shadowed+1} || Shadowed <- lists:seq(7, 9)], 236 [{7,8},{8,9},{9,10}] = id(L), 237 [8,9] = id([Shadowed || {_,Shadowed} <- id(L), 238 Shadowed < 10]), 239 ok. 240 241effect(Config) when is_list(Config) -> 242 ct:timetrap({minutes,10}), 243 [{42,{a,b,c}}] = 244 do_effect(fun(F, L) -> 245 [F({V1,V2}) || 246 #{<<1:500>>:=V1,<<2:301>>:=V2} <- L], 247 ok 248 end, id([#{},x,#{<<1:500>>=>42,<<2:301>>=>{a,b,c}}])), 249 250 %% Will trigger the time-trap timeout if not tail-recursive. 251 case ?MODULE of 252 lc_SUITE -> 253 _ = [{'EXIT',{badarg,_}} = 254 (catch binary_to_atom(<<C/utf8>>, utf8)) || 255 C <- lists:seq(16#FF10000, 16#FFFFFFF)]; 256 _ -> 257 ok 258 end, 259 260 ok. 261 262do_effect(Lc, L) -> 263 put(?MODULE, []), 264 F = fun(V) -> put(?MODULE, [V|get(?MODULE)]) end, 265 ok = Lc(F, L), 266 lists:reverse(erase(?MODULE)). 267 268id(I) -> I. 269 270fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Args,_}|_]}}) -> ok; 271fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Arity,_}|_]}}) 272 when length(Args) =:= Arity -> 273 true = test_server:is_native(?MODULE); 274fc(Args, {'EXIT',{{case_clause,ActualArgs},_}}) 275 when ?MODULE =:= lc_inline_SUITE -> 276 Args = tuple_to_list(ActualArgs). 277 278-file("bad_lc.erl", 1). 279bad_generator(List) -> %Line 2 280 [I || %Line 3 281 I <- List]. %Line 4 282bad_generator_bc(List) -> %Line 5 283 << <<I:4>> || %Line 6 284 I <- List>>. %Line 7 285