1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2001-2011. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: -module(lc_SUITE).
   21: 
   22: %% Copied from lc_SUITE in the compiler application.
   23: 
   24: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
   25: 	 init_per_testcase/2,end_per_testcase/2,
   26: 	 init_per_suite/1,end_per_suite/1,
   27: 	 basic/1,deeply_nested/1,no_generator/1,
   28: 	 empty_generator/1]).
   29: 
   30: -include_lib("test_server/include/test_server.hrl").
   31: 
   32: suite() -> [{ct_hooks,[ts_install_cth]}].
   33: 
   34: all() -> 
   35:     [basic, deeply_nested, no_generator, empty_generator].
   36: 
   37: groups() -> 
   38:     [].
   39: 
   40: init_per_group(_GroupName, Config) ->
   41:     Config.
   42: 
   43: end_per_group(_GroupName, Config) ->
   44:     Config.
   45: 
   46: init_per_testcase(_Case, Config) ->
   47:     test_lib:interpret(?MODULE),
   48:     Dog = test_server:timetrap(?t:minutes(1)),
   49:     [{watchdog,Dog}|Config].
   50: 
   51: end_per_testcase(_Case, Config) ->
   52:     Dog = ?config(watchdog, Config),
   53:     ?t:timetrap_cancel(Dog),
   54:     ok.
   55: 
   56: init_per_suite(Config) when is_list(Config) ->
   57:     ?line test_lib:interpret(?MODULE),
   58:     ?line true = lists:member(?MODULE, int:interpreted()),
   59:     Config.
   60: 
   61: end_per_suite(Config) when is_list(Config) ->
   62:     ok.
   63: 
   64: basic(Config) when is_list(Config) ->
   65:     ?line L0 = lists:seq(1, 10),
   66:     ?line L1 = my_map(fun(X) -> {x,X} end, L0),
   67:     ?line L1 = [{x,X} || X <- L0],
   68:     ?line L0 = my_map(fun({x,X}) -> X end, L1),
   69:     ?line [1,2,3,4,5] = [X || X <- L0, X < 6],
   70:     ?line [4,5,6] = [X || X <- L0, X > 3, X < 7],
   71:     ?line [] = [X || X <- L0, X > 32, X < 7],
   72:     ?line [1,3,5,7,9] = [X || X <- L0, odd(X)],
   73:     ?line [2,4,6,8,10] = [X || X <- L0, not odd(X)],
   74:     ?line [1,3,5,9] = [X || X <- L0, odd(X), X =/= 7],
   75:     ?line [2,4,8,10] = [X || X <- L0, not odd(X), X =/= 6],
   76: 
   77:     %% Append is specially handled.
   78:     ?line [1,3,5,9,2,4,8,10] = [X || X <- L0, odd(X), X =/= 7] ++
   79: 	[X || X <- L0, not odd(X), X =/= 6],
   80: 
   81:     %% Guards BIFs are evaluated in guard context. Weird, but true.
   82:     ?line [{a,b,true},{x,y,true,true}] = [X || X <- tuple_list(), element(3, X)],
   83: 
   84:     %% Filter expressions with andalso/orelse.
   85:     ?line "abc123" = alphanum("?abc123.;"),
   86: 
   87:     %% Error cases.
   88:     ?line [] = [{xx,X} || X <- L0, element(2, X) == no_no_no],
   89:     ?line {'EXIT',_} = (catch [X || X <- L1, list_to_atom(X) == dum]),
   90:     ?line [] = [X || X <- L1, X+1 < 2],
   91:     ?line {'EXIT',_} = (catch [X || X <- L1, odd(X)]),
   92: 
   93:     %% A bad generator has a different exception compared to BEAM.
   94:     ?line {'EXIT',{{bad_generator,x},_}} = (catch [E || E <- id(x)]),
   95:     ok.
   96: 
   97: tuple_list() ->
   98:     [{a,b,true},[a,b,c],glurf,{a,b,false,xx},{a,b},{x,y,true,true},{a,b,d,ddd}].
   99: 
  100: my_map(F, L) ->
  101:     [F(X) || X <- L].
  102: 
  103: odd(X) ->
  104:     X rem 2 == 1.
  105: 
  106: alphanum(Str) ->
  107:     [C || C <- Str, ((C >= $0) andalso (C =< $9))
  108: 	      orelse ((C >= $a) andalso (C =< $z))
  109: 	      orelse ((C >= $A) andalso (C =< $Z))].
  110: 
  111: deeply_nested(Config) when is_list(Config) ->
  112:     [[99,98,97,96,42,17,1764,12,11,10,9,8,7,6,5,4,3,7,2,1]] =  deeply_nested_1(),
  113:     ok.
  114: 
  115: deeply_nested_1() ->
  116:     %% This used to compile really, really SLOW before R11B-1...
  117:     [[X1,X2,X3,X4,X5,X6,X7(),X8,X9,X10,X11,X12,X13,X14,X15,X16,X17,X18(),X19,X20] ||
  118:         X1 <- [99],X2 <- [98],X3 <- [97],X4 <- [96],X5 <- [42],X6 <- [17],
  119: 	X7 <- [fun() -> X5*X5 end],X8 <- [12],X9 <- [11],X10 <- [10],
  120:         X11 <- [9],X12 <- [8],X13 <- [7],X14 <- [6],X15 <- [5],
  121: 	X16 <- [4],X17 <- [3],X18 <- [fun() -> X16+X17 end],X19 <- [2],X20 <- [1]].
  122: 
  123: no_generator(Config) when is_list(Config) ->
  124:     ?line Seq = lists:seq(-10, 17),
  125:     ?line [no_gen_verify(no_gen(A, B), A, B) || A <- Seq, B <- Seq],
  126: 
  127:     %% Literal expression, for coverage.
  128:     ?line [a] = [a || true],
  129:     ?line [a,b,c] = [a || true] ++ [b,c],
  130:     ok.
  131: 
  132: no_gen(A, B) ->
  133:     [{A,B} || A+B =:= 0] ++
  134: 	[{A,B} || A*B =:= 0] ++
  135: 	[{A,B} || A rem B =:= 3] ++
  136: 	[{A,B} || A =:= B] ++
  137: 	[{one_more,A,B} || no_gen_one_more(A, B)] ++
  138: 	[A || A =:= 1] ++
  139: 	[A || A =:= 2] ++
  140: 	[A || A =:= 3] ++
  141: 	[A || A =:= 4] ++
  142: 	[A || A =:= 5] ++
  143: 	[A || A =:= 6] ++
  144: 	[A || A =:= 7] ++
  145: 	[A || A =:= 8] ++
  146: 	[A || A =:= 9] ++
  147: 	[B || B =:= 1] ++
  148: 	[B || B =:= 2] ++
  149: 	[B || B =:= 3] ++
  150: 	[B || B =:= 4] ++
  151: 	[B || B =:= 5] ++
  152: 	[B || B =:= 6] ++
  153: 	[B || B =:= 7] ++
  154: 	[B || B =:= 8] ++
  155: 	[B || B =:= 9].
  156: 
  157: no_gen_verify(Res, A, B) ->
  158:     Pair = {A,B},
  159:     ShouldBe = no_gen_eval(fun() -> A+B =:= 0 end, Pair) ++
  160: 	no_gen_eval(fun() -> A*B =:= 0 end, Pair) ++
  161: 	no_gen_eval(fun() -> B =/= 0 andalso A rem B =:= 3 end, Pair) ++
  162: 	no_gen_eval(fun() -> A =:= B end, Pair) ++
  163: 	no_gen_eval(fun() -> A + 1 =:= B end, {one_more,A,B}) ++
  164: 	no_gen_eval(fun() -> 1 =< A andalso A =< 9 end, A) ++
  165: 	no_gen_eval(fun() -> 1 =< B andalso B =< 9 end, B),
  166:     case Res of
  167: 	ShouldBe -> ok;
  168: 	_ ->
  169: 	    io:format("A = ~p; B = ~p; Expected = ~p, actual = ~p", [A,B,ShouldBe,Res]),
  170: 	    ?t:fail()
  171:     end.
  172: 
  173: no_gen_eval(Fun, Res) ->
  174:     case Fun() of
  175: 	true -> [Res];
  176: 	false -> []
  177:     end.
  178: 
  179: no_gen_one_more(A, B) -> A + 1 =:= B.
  180: 
  181: empty_generator(Config) when is_list(Config) ->
  182:     ?line [] = [X || {X} <- [], (false or (X/0 > 3))],
  183:     ok.
  184: 
  185: id(I) -> I.