1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 1999-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: -module(queue_SUITE).
   20: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   21: 	 init_per_group/2,end_per_group/2]).
   22: 
   23: -export([do/1, to_list/1, io_test/1, op_test/1, error/1, oops/1]).
   24: 
   25: -export([init_per_testcase/2, end_per_testcase/2]).
   26: 
   27: -include_lib("test_server/include/test_server.hrl").
   28: 
   29: % Default timetrap timeout (set in init_per_testcase).
   30: -define(default_timeout, ?t:minutes(1)).
   31: 
   32: init_per_testcase(_Case, Config) ->
   33:     ?line Dog = ?t:timetrap(?default_timeout),
   34:     [{watchdog, Dog} | Config].
   35: end_per_testcase(_Case, Config) ->
   36:     Dog = ?config(watchdog, Config),
   37:     test_server:timetrap_cancel(Dog),
   38:     ok.
   39: 
   40: suite() -> [{ct_hooks,[ts_install_cth]}].
   41: 
   42: all() -> 
   43:     [do, to_list, io_test, op_test, error, oops].
   44: 
   45: groups() -> 
   46:     [].
   47: 
   48: init_per_suite(Config) ->
   49:     Config.
   50: 
   51: end_per_suite(_Config) ->
   52:     ok.
   53: 
   54: init_per_group(_GroupName, Config) ->
   55:     Config.
   56: 
   57: end_per_group(_GroupName, Config) ->
   58:     Config.
   59: 
   60: 
   61: do(doc) ->
   62:     [""];
   63: do(suite) ->
   64:     [];
   65: do(Config) when is_list(Config) ->
   66:     ?line L = [{in, 1},
   67: 	       {in, 2},
   68: 	       {out, {value, 1}},
   69: 	       {in, 3},
   70: 	       {out, {value, 2}},
   71: 	       {out, {value, 3}},
   72: 	       {out, empty}
   73: 	      ],
   74:     
   75:     ?line E = queue:new(),
   76:     ?line [] = queue:to_list(E),
   77:     ?line Q = do_queue(E, L),
   78:     ?line true = queue:is_empty(Q),
   79:     ?line 0 = queue:len(Q),
   80:     ok.
   81: 
   82: to_list(doc) ->
   83:     ["OTP-2701"];
   84: to_list(suite) ->
   85:     [];
   86: to_list(Config) when is_list(Config) ->
   87:     ?line E = queue:new(),
   88:     ?line Q = do_queue(E, [{in, 1},
   89: 			   {in, 2},
   90: 			   {in, 3},
   91: 			   {out, {value, 1}},
   92: 			   {in, 4},
   93: 			   {in, 5}]),
   94:     ?line true = queue:is_queue(Q),
   95:     ?line 4 = queue:len(Q),
   96:     ?line case queue:to_list(Q) of
   97: 	      [2,3,4,5] ->
   98: 		  ok;
   99: 	      Other1 ->
  100: 		  test_server:fail(Other1)
  101: 	  end,
  102:     ok.
  103: 
  104: do_queue(Q, []) ->
  105:     Q;
  106: do_queue(Q, [E | Rest]) ->
  107:     do_queue(do_queue_1(E, Q), Rest).
  108: 
  109: do_queue_1({in, E}, Q) ->
  110:     queue:in(E, Q);
  111: do_queue_1({out, E}, Q) ->
  112:     case queue:out(Q) of
  113: 	{E, Q1} ->
  114: 	    Q1;
  115: 	Other ->
  116: 	    test_server:fail({"out failed", E, Q, Other})
  117:     end.
  118: 
  119: 
  120: io_test(doc) ->
  121:     "Test input and output";
  122: io_test(suite) ->
  123:     [];
  124: io_test(Config) when is_list(Config) ->
  125:     E = queue:new(),
  126:     do_io_test(E),
  127:     ok.
  128: 
  129: do_io_test(E) ->
  130:     ?line [4,3,5] = 
  131: 	io([snoc,snoc,head,head,head,cons,cons,snoc], E, 1),
  132:     ?line [5,3,4] = 
  133: 	io([cons,cons,daeh,daeh,daeh,snoc,snoc,cons], E, 1),
  134:     ?line [4,3,5] = 
  135: 	io([in,in,out,out,out,in_r,in_r,in], E, 1),
  136:     ?line [5,3,4] = 
  137: 	io([in_r,in_r,out_r,out_r,out_r,in,in,in_r], E, 1),
  138:     %%
  139:     ?line [] = 
  140: 	io([snoc,snoc,head,snoc,snoc,head,head,snoc,head,head], E, 1),
  141:     ?line [] = 
  142: 	io([cons,cons,daeh,cons,cons,daeh,daeh,cons,daeh,daeh], E, 1),
  143:     ?line [] = 
  144: 	io([in,in,out,in,in,out,out,in,out,out], E, 1),
  145:     ?line [] = 
  146: 	io([in_r,in_r,out_r,in_r,in_r,out_r,out_r,in_r,out_r,out_r], 
  147: 	   E, 1),
  148:     %%
  149:     ?line [5,6] = 
  150: 	io([snoc,snoc,snoc,head,head,snoc,snoc,snoc,head,head], E, 1),
  151:     ?line [6,5] = 
  152: 	io([cons,cons,cons,daeh,daeh,cons,cons,cons,daeh,daeh], E, 1),
  153:     ?line [5,6] = 
  154: 	io([in,in,in,out,out,in,in,in,out,out], E, 1),
  155:     ?line [6,5] = 
  156: 	io([in_r,in_r,in_r,out_r,out_r,in_r,in_r,in_r,out_r,out_r], 
  157: 	   E, 1),
  158:     %%
  159:     ?line [5] = 
  160: 	io([snoc,head,head,snoc,head,snoc,head,snoc,head,snoc], E, 1),
  161:     ?line [5] = 
  162: 	io([cons,daeh,daeh,cons,daeh,cons,daeh,cons,daeh,cons], E, 1),
  163:     ?line [5] = 
  164: 	io([in,out,out,in,out,in,out,in,out,in], E, 1),
  165:     ?line [5] = 
  166: 	io([in_r,out_r,out_r,in_r,out_r,in_r,out_r,in_r,out_r,in_r], 
  167: 	   E, 1),
  168:     %%
  169:     ?line [] =
  170: 	io([snoc,head,snoc,snoc,head,head,snoc,snoc,snoc,head,head,head], 
  171: 	   E, 1),
  172:     ?line [] =
  173: 	io([cons,daeh,cons,cons,daeh,daeh,cons,cons,cons,daeh,daeh,daeh],
  174: 	  E, 1),
  175:     ?line [] =
  176: 	io([in,out,in,in,out,out,in,in,in,out,out,out], 
  177: 	   E, 1),
  178:     ?line [] =
  179: 	io([in_r,out_r,in_r,in_r,out_r,out_r,in_r,in_r,in_r,out_r,out_r,out_r],
  180: 	  E, 1),
  181:     %%
  182:     ?line [3] =	io([cons,cons,cons,snoc,daeh,daeh,daeh], E, 1),
  183:     ?line [3] =	io([snoc,snoc,snoc,cons,head,head,head], E, 1),
  184:     ?line [3] =	io([in,in,in,in_r,out,out,out], E, 1),
  185:     ?line [3] =	io([in_r,in_r,in_r,in,out_r,out_r,out_r], E, 1),
  186:     %%
  187:     ?line Q2 = queue:join(queue:cons(1, E),queue:cons(2, E)),
  188:     ?line Q1 = queue:reverse(Q2),
  189:     ?line [1] = io([head],  Q1, 3),
  190:     ?line [1] = io([out],   Q1, 3),
  191:     ?line [1] = io([daeh],  Q2, 3),
  192:     ?line [1] = io([out_r], Q2, 3),
  193: %    ?line [2] =	io([cons,cons,snoc,daeh,daeh], [], 1),
  194: %    ?line [2] =	io([snoc,snoc,cons,head,head], [], 1),
  195: %    ?line [2] =	io([in,in,in_r,out,out], [], 1),
  196: %    ?line [2] =	io([in_r,in_r,in,out_r,out_r], [], 1),
  197:     %%
  198:     ?line [2] =
  199: 	io([in,peek,peek_r,drop,in_r,peek,peek_r,in,peek,peek_r,drop_r], E, 1),
  200:     %% Malformed queues UGLY-GUTS-ALL-OVER-THE-PLACE
  201:     ?line [2,1] = io([peek], {[1,2],[]}, 1),
  202:     ?line [1,2] = io([peek_r], {[],[1,2]}, 1),
  203:     %%
  204:     ok.
  205: 
  206: %% Perform a list of operations to a queue.
  207: %% Keep a reference queue on the side; just a list.
  208: %% Compare the read values between the queues.
  209: %% Return the resulting queue as a list.
  210: %% Inserted values are increments of the previously inserted.
  211: io(Ops, Q, X) ->
  212:     io(Ops, Q, queue:to_list(Q), X).
  213: 
  214: io([head | Tail], Q, [], X) ->
  215:     true = queue:is_empty(Q),
  216:     {'EXIT',{empty,_}} = (catch {ok,queue:head(Q)}),
  217:     {'EXIT',{empty,_}} = (catch {ok,queue:tail(Q)}),
  218:     io(Tail, Q, [], X);
  219: io([head | Tail], Q, [H | T], X) ->
  220:     H = queue:head(Q),
  221:     false = queue:is_empty(Q),
  222:     io(Tail, queue:tail(Q), T, X);
  223: io([daeh | Tail], Q, [], X) ->
  224:     true = queue:is_empty(Q),
  225:     {'EXIT',{empty,_}} = (catch {ok,queue:daeh(Q)}),
  226:     {'EXIT',{empty,_}} = (catch {ok,queue:liat(Q)}),
  227:     {'EXIT',{empty,_}} = (catch {ok,queue:lait(Q)}),
  228:     io(Tail, Q, [], X);
  229: io([daeh | Tail], Q, QQ, X) ->
  230:     H = queue:daeh(Q),
  231:     false = queue:is_empty(Q),
  232:     [H | T] = lists:reverse(QQ),
  233:     io(Tail, queue:liat(Q), lists:reverse(T), X);
  234: io([out | Tail], Q, [], X) ->
  235:     {empty, Q1} = queue:out(Q),
  236:     io(Tail, Q1, [], X);
  237: io([out | Tail], Q, [H | T], X) ->
  238:     {{value,H}, Q1} = queue:out(Q),
  239:     io(Tail, Q1, T, X);
  240: io([out_r | Tail], Q, [], X) ->
  241:     {empty, Q1} = queue:out_r(Q),
  242:     io(Tail, Q1, [], X);
  243: io([out_r | Tail], Q, QQ, X) ->
  244:     {{value,H}, Q1} = queue:out_r(Q),
  245:     [H | T] = lists:reverse(QQ),
  246:     io(Tail, Q1, lists:reverse(T), X);
  247: io([cons | Tail], Q, QQ, X) ->
  248:     io(Tail, queue:cons(X,Q), [X|QQ], X+1);
  249: io([snoc | Tail], Q, QQ, X) ->
  250:     io(Tail, queue:snoc(Q,X), QQ++[X], X+1);
  251: io([in_r | Tail], Q, QQ, X) ->
  252:     io(Tail, queue:in_r(X,Q), [X|QQ], X+1);
  253: io([in | Tail], Q, QQ, X) ->
  254:     io(Tail, queue:in(X,Q), QQ++[X], X+1);
  255: io([peek | Tail], Q, [], X) ->
  256:     empty = queue:peek(Q),
  257:     io(Tail, Q, [], X);
  258: io([peek | Tail], Q, [H|_]=Q0, X) ->
  259:     {value,H} = queue:peek(Q),
  260:     io(Tail, Q, Q0, X);
  261: io([peek_r | Tail], Q, [], X) ->
  262:     empty = queue:peek_r(Q),
  263:     io(Tail, Q, [], X);
  264: io([peek_r | Tail], Q, Q0, X) ->
  265:     E = lists:last(Q0),
  266:     {value,E} = queue:peek_r(Q),
  267:     io(Tail, Q, Q0, X);
  268: io([drop | Tail], Q, [], X) ->
  269:     try queue:drop(Q) of
  270: 	V ->
  271: 	    test_server:fail({?MODULE,?LINE,V})
  272:     catch
  273: 	error:empty ->
  274: 	    io(Tail, Q, [], X)
  275:     end;
  276: io([drop | Tail], Q, [_ | T], X) ->
  277:     Q1 = queue:drop(Q),
  278:     io(Tail, Q1, T, X);
  279: io([drop_r | Tail], Q, [], X) ->
  280:     try queue:drop_r(Q) of
  281: 	V ->
  282: 	    test_server:fail({?MODULE,?LINE,V})
  283:     catch
  284: 	error:empty ->
  285: 	    io(Tail, Q, [], X)
  286:     end;
  287: io([drop_r | Tail], Q, L, X) ->
  288:     io:format("~p~n", [{drop_r,Tail,Q,L,X}]),
  289:     Q1 = queue:drop_r(Q),
  290:     [_ | T] = lists:reverse(L),
  291:     io:format("~p~n", [{drop_r,Q1,T}]),
  292:     io(Tail, Q1, lists:reverse(T), X);
  293: io([], Q, QQ, _X) ->
  294:     QQ = queue:to_list(Q),
  295:     Length = length(QQ),
  296:     Length = queue:len(Q),
  297:     QQ.
  298: 
  299: 
  300: op_test(doc) ->
  301:     "Test operations on whole queues";
  302: op_test(suite) ->
  303:     [];
  304: op_test(Config) when is_list(Config) ->
  305:     do_op_test(fun id/1),
  306:     ok.
  307: 
  308: do_op_test(F) ->
  309:     ?line Len = 50,
  310:     ?line Len2 = 2*Len,
  311:     ?line L1 = lists:seq(1, Len),
  312:     ?line L1r = lists:reverse(L1),
  313:     ?line L2 = lists:seq(Len+1, Len2),
  314:     ?line L2r = lists:reverse(L2),
  315:     ?line L3 = L1++L2,
  316:     ?line L3r = L2r++L1r,
  317:     ?line Q0 = F(queue:new()),
  318:     ?line [] = queue:to_list(Q0),
  319:     ?line Q0 = F(queue:from_list([])),
  320:     ?line Q1 = F(queue:from_list(L1)),
  321:     ?line Q2 = F(queue:from_list(L2)),
  322:     ?line Q3 = F(queue:from_list(L3)),
  323:     ?line Len = queue:len(Q1),
  324:     ?line Len = queue:len(Q2),
  325:     ?line Len2 = queue:len(Q3),
  326:     ?line L1 = queue:to_list(Q1),
  327:     ?line L2 = queue:to_list(Q2),
  328:     ?line L3 = queue:to_list(Q3),
  329:     ?line Q3b = queue:join(Q0, queue:join(queue:join(Q1, Q2), Q0)),
  330:     ?line L3 = queue:to_list(Q3b),
  331:     ?line {Q0, Q3New1} = queue:split(0, Q3),
  332:     ?line L3 = queue:to_list(Q3New1),
  333:     ?line {Q3New2, Q0} = queue:split(Len2, Q3),
  334:     ?line L3 = queue:to_list(Q3New2),
  335:     ?line {Q1a, Q2a} = queue:split(Len, Q3),
  336:     ?line L1 = queue:to_list(Q1a),
  337:     ?line L2 = queue:to_list(Q2a),
  338:     ?line {Q3c, Q3d} = queue:split(2, Q3),
  339:     ?line L3 = queue:to_list(Q3c) ++ queue:to_list(Q3d),
  340:     ?line {Q1b, Q2b} = queue:split(Len, Q3b),
  341:     ?line L1 = queue:to_list(Q1b),
  342:     ?line L2 = queue:to_list(Q2b),
  343:     ?line Len = queue:len(Q1b),
  344:     ?line Len = queue:len(Q2b),
  345:     ?line Len2 = queue:len(Q3b),
  346:     ?line Q1r = queue:reverse(Q1),
  347:     ?line Q2r = queue:reverse(Q2),
  348:     ?line Q1ar = queue:reverse(Q1a),
  349:     ?line Q2ar = queue:reverse(Q2a),
  350:     ?line Q1br = queue:reverse(Q1b),
  351:     ?line Q2br = queue:reverse(Q2b),
  352:     ?line Q3br = queue:reverse(Q3b),
  353:     ?line L1r = queue:to_list(Q1r),
  354:     ?line L1r = queue:to_list(Q1ar),
  355:     ?line L1r = queue:to_list(Q1br),
  356:     ?line L2r = queue:to_list(Q2r),
  357:     ?line L2r = queue:to_list(Q2ar),
  358:     ?line L2r = queue:to_list(Q2br),
  359:     ?line L3r = queue:to_list(Q3br),
  360:     ?line Len = queue:len(Q1br),
  361:     ?line Len = queue:len(Q2br),
  362:     ?line Len2 = queue:len(Q3br),
  363:     ?line false = queue:member([], Q0),
  364:     ?line false = queue:member(0, Q0),
  365:     ?line false = queue:member(0, Q1),
  366:     ?line false = queue:member([], Q1),
  367:     ?line true = queue:member(1, Q1),
  368:     ?line false = queue:member(1.0, Q1),
  369:     ?line true = queue:member(Len, Q1),
  370:     %%
  371:     %% Additional coverage.
  372:     ?line {MyL1r,MyL2r} = lists:split(Len-2, L1r),
  373:     ?line MyQ0r = queue:reverse(F(queue:from_list(L1))),
  374:     ?line {MyQ1r,MyQ2r} = queue:split(Len-2, MyQ0r),
  375:     ?line MyL1r = queue:to_list(MyQ1r),
  376:     ?line MyL2r = queue:to_list(MyQ2r),
  377:     ?line MyQ3r = queue:filter(
  378: 		   fun (X) when X rem 4 >= 2 -> false;
  379: 		       (X) when X rem 8 == 0 -> [float(X),{X}];
  380: 		       (X) when X rem 2 >= 1 -> [{X}];
  381: 		       (_)                   -> true
  382: 		   end, MyQ1r),
  383:     ?line MyL3r = lists:flatten(
  384: 		    [if X rem 8 == 0 -> [float(X),{X}];
  385: 			X rem 2 >= 1 -> {X};
  386: 			true         -> X
  387: 		     end || X <- MyL1r,
  388: 			    X rem 4 < 2]),
  389:     ?line MyL3r = queue:to_list(MyQ3r),
  390:     ?line MyQ4 = F(queue:from_list([11,22,33,44])),
  391:     ?line [11,22] = queue:to_list(queue:filter(fun(X) when X < 27 -> true;
  392: 						  (_) -> [] end, MyQ4)),
  393:     ?line [33,44] = queue:to_list(queue:filter(fun(X) when X < 27 -> false;
  394: 						  (X) -> [X] end, MyQ4)),
  395:     %%
  396:     ok.
  397: 
  398: error(doc) ->
  399:     "Test queue errors";
  400: error(suite) ->
  401:     [];
  402: error(Config) when is_list(Config) ->
  403:     do_error(fun id/1, illegal_queue),
  404:     do_error(fun id/1, {[],illegal_queue}),
  405:     do_error(fun id/1, {illegal_queue,[17]}),
  406:     ok.
  407: 
  408: trycatch(F, Args) ->
  409:     trycatch(queue, F, Args).
  410: 
  411: trycatch(M, F, Args) ->
  412:     try apply(M, F, Args) of
  413: 	V -> {value,V}
  414:     catch
  415: 	C:R -> {C,R}
  416:     end.
  417: 
  418: do_error(F, IQ) ->
  419:     ?line io:format("Illegal Queue: ~p~n", [IQ]),
  420:     %%
  421:     ?line {error,badarg} = trycatch(in, [1, IQ]),
  422:     ?line {error,badarg} = trycatch(out, [IQ]),
  423:     ?line {error,badarg} = trycatch(in_r ,[1, IQ]),
  424:     ?line {error,badarg} = trycatch(out_r ,[IQ]),
  425:     ?line {error,badarg} = trycatch(to_list ,[IQ]),
  426:     %%
  427:     ?line {error,badarg} = trycatch(from_list, [no_list]),
  428:     ?line {error,badarg} = trycatch(is_empty, [IQ]),
  429:     ?line {error,badarg} = trycatch(len, [IQ]),
  430:     %%
  431:     ?line {error,badarg} = trycatch(cons, [1, IQ]),
  432:     ?line {error,badarg} = trycatch(head, [IQ]),
  433:     ?line {error,badarg} = trycatch(tail, [IQ]),
  434:     %%
  435:     ?line {error,badarg} = trycatch(snoc, [IQ, 1]),
  436:     ?line {error,badarg} = trycatch(last, [IQ]),
  437:     ?line {error,badarg} = trycatch(daeh, [IQ]),
  438:     ?line {error,badarg} = trycatch(liat, [IQ]),
  439:     ?line {error,badarg} = trycatch(lait, [IQ]),
  440:     ?line {error,badarg} = trycatch(init, [IQ]),
  441:     %%
  442:     ?line {error,badarg} = trycatch(reverse, [IQ]),
  443:     ?line {error,badarg} = trycatch(join, [F(queue:new()), IQ]),
  444:     ?line {error,badarg} = trycatch(join, [IQ, F(queue:new())]),
  445:     ?line {error,badarg} = trycatch(split, [17, IQ]),
  446:     ?line {error,badarg} = trycatch(head, [IQ]),
  447:     %%
  448:     ?line Q0 = F(queue:new()),
  449:     ?line {error,badarg} = trycatch(split, [1, Q0]),
  450:     ?line {error,badarg} = trycatch(split, [2, queue:snoc(Q0, 1)]),
  451:     %%
  452:     ?line {value,false}  = trycatch(is_queue, [IQ]),
  453:     ?line {error,badarg} = trycatch(get, [IQ]),
  454:     ?line {error,badarg} = trycatch(peek, [IQ]),
  455:     ?line {error,badarg} = trycatch(peek_r, [IQ]),
  456:     ?line {error,badarg} = trycatch(filter, [fun id/1, IQ]),
  457:     ?line {error,badarg} = trycatch(filter, [no_fun, Q0]),
  458:     %%
  459:     ?line {error,badarg} = trycatch(member, [1, IQ]),
  460:     ok.
  461: 
  462: id(X) ->
  463:     X.
  464: 
  465: oops(doc) ->
  466:     "Test queue errors";
  467: oops(suite) ->
  468:     [];
  469: oops(Config) when is_list(Config) ->
  470:     ?line N = 3142,
  471:     ?line Optab = optab(),
  472:     ?line Seed0 = random:seed0(),
  473:     ?line {Is,Seed} = random_list(N, tuple_size(Optab), Seed0, []),
  474:     ?line io:format("~p ", [Is]),
  475:     ?line QA = queue:new(),
  476:     ?line QB = {[]},
  477:     ?line emul([QA], [QB], Seed, [element(I, Optab) || I <- Is]).
  478: 
  479: optab() ->
  480:     {{new,[],        q,     fun ()     -> {[]} end},
  481:      {is_queue,[q],  v,     fun (_)    -> true end},
  482:      {is_empty,[q],  v,     fun (Q) -> 
  483: 				    case Q of 
  484: 					{[]} -> true;
  485: 					_    -> false
  486: 				    end end},
  487:      {len,[q],       v,     fun ({L})   -> length(L) end},
  488:      {to_list,[q],   v,     fun ({L})   -> L end},
  489:      {from_list,[l], q,     fun (L)     -> {L} end},
  490:      {in,[t,q],      q,     fun (X,{L}) -> {L++[X]} end},
  491:      {in_r,[t,q],    q,     fun (X,{L}) -> {[X|L]} end},
  492:      {out,[q],       {v,q}, fun ({L}=Q) ->
  493: 				    case L of
  494: 					[]    -> {empty,Q};
  495: 					[X|T] -> {{value,X},{T}}
  496: 				    end
  497: 			    end},
  498:      {out_r,[q],     {v,q}, fun ({L}=Q) ->
  499: 				    case L of
  500: 					[]    -> {empty,Q};
  501: 					_ -> 
  502: 					    [X|R] = lists:reverse(L),
  503: 					    T = lists:reverse(R),
  504: 					    {{value,X},{T}}
  505: 				    end
  506: 			    end},
  507:      {get,[q],       v,     fun ({[]})    -> erlang:error(empty);
  508: 				({[H|_]}) -> H
  509: 			    end},
  510:      {get_r,[q],     v,     fun ({[]})    -> erlang:error(empty);
  511: 				({L})     -> lists:last(L)
  512: 			    end},
  513:      {peek,[q],      v,     fun ({[]})    -> empty;
  514: 				({[H|_]}) -> {value,H}
  515: 			    end},
  516:      {peek_r,[q],    v,     fun ({[]})    -> empty;
  517: 				({L})     -> {value,lists:last(L)}
  518: 			    end},
  519:      {drop,[q],      q,     fun ({[]})    -> erlang:error(empty);
  520: 				({[_|T]}) -> {T}
  521: 			    end},
  522:      {drop_r,[q],    q,     fun ({[]})    -> erlang:error(empty);
  523: 				({L})     -> [_|R] = lists:reverse(L),
  524: 					     {lists:reverse(R)}
  525: 			    end},
  526:      {reverse,[q],   q,     fun ({L})     -> {lists:reverse(L)} end},
  527:      {join,[q,q],    q,     fun ({L1}, {L2}) -> {L1++L2} end},
  528:      {split,[n,q],   {q,q}, fun (N, {L})  -> {L1,L2} = lists:split(N, L),
  529: 					     {{L1},{L2}} end},
  530:      {member,[t,q],  v,     fun (X, {L})  -> lists:member(X, L) end}
  531:     }.
  532: 
  533: emul(_, _, _, []) ->
  534:     ok;
  535: emul(QsA0, QsB0, Seed0, [{Op,Ts,S,Fun}|Ops]) ->
  536:     {AsA,Seed} = args(Ts, QsA0, Seed0, []),
  537:     {AsB,Seed} = args(Ts, QsB0, Seed0, []),
  538:     io:format("~n% ~w % ~p ", [Op,AsA]),
  539:     io:format("% ~p :", [AsB]),
  540:     XX = call({queue,Op}, AsA),
  541:     YY = call(Fun, AsB),
  542:     case {XX,YY} of
  543: 	{{value,X},{value,Y}} ->
  544: 	    {[Qa|_]=QsA,[{Lb}|_]=QsB} = chk(QsA0, QsB0, S, X, Y),
  545: 	    case queue:to_list(Qa) of
  546: 		Lb ->
  547: 		    io:format("|~p| ", [Lb]),
  548: 		    emul(QsA, QsB, Seed, Ops);
  549: 		La ->
  550: 		    throw({to_list,[XX,YY,Op,AsA,AsB,La,Lb]})
  551: 	    end;
  552: 	{Exception,Exception} ->
  553: 	    io:format("!~p! ", [Exception]),
  554: 	    emul(QsA0, QsB0, Seed, Ops);
  555: 	_ ->
  556: 	    throw({diff,[XX,YY,Op,AsA,AsB]})
  557:     end.
  558: 
  559: args([], _, Seed, R) ->
  560:     {lists:reverse(R),Seed};
  561: args([q|Ts], [Q|Qs]=Qss, Seed, R) ->
  562:     args(Ts, if Qs =:= [] -> Qss; true -> Qs end, Seed, [Q|R]);
  563: args([l|Ts], Qs, Seed0, R) ->
  564:     {N,Seed1} = random:uniform_s(17, Seed0),
  565:     {L,Seed} = random_list(N, 4711, Seed1, []),
  566:     args(Ts, Qs, Seed, [L|R]);
  567: args([t|Ts], Qs, Seed0, R) ->
  568:     {T,Seed} = random:uniform_s(4711, Seed0),
  569:     args(Ts, Qs, Seed, [T|R]);
  570: args([n|Ts], Qs, Seed0, R) ->
  571:     {N,Seed} = random:uniform_s(17, Seed0),
  572:     args(Ts, Qs, Seed, [N|R]).
  573: 
  574: random_list(0, _, Seed, R) ->
  575:     {R,Seed};
  576: random_list(N, M, Seed0, R) ->
  577:     {X,Seed} = random:uniform_s(M, Seed0),
  578:     random_list(N-1, M, Seed, [X|R]).
  579: 
  580: call(Func, As) ->
  581:     try case Func of
  582: 	    {M,F} -> apply(M, F, As);
  583: 	    _     -> apply(Func, As)
  584: 	end of
  585: 	V ->
  586: 	    {value,V}
  587:     catch
  588: 	Class:Reason ->
  589: 	    {Class,Reason}
  590:     end.
  591: 
  592: chk(QsA, QsB, v, X, X) ->
  593:     io:format("<~p> ", [X]),
  594:     {QsA,QsB};
  595: chk(_, _, v, X, Y) ->
  596:     throw({diff,v,[X,Y]});
  597: chk(QsA, QsB, q, Qa, {Lb}=Qb) ->
  598:     case queue:to_list(Qa) of
  599: 	Lb -> 
  600: 	    io:format("|~p| ", [Lb]),
  601: 	    {[Qa|QsA],[Qb|QsB]};
  602: 	La ->
  603: 	    throw({diff,q,[Qa,La,Lb]})
  604:     end;
  605: chk(QsA, QsB, T, X, Y)
  606:   when tuple_size(T) =:= tuple_size(X), tuple_size(T) =:= tuple_size(Y) ->
  607:     io:format("{"),
  608:     try
  609: 	chk_tuple(QsA, QsB, T, X, Y, 1)
  610:     after
  611: 	io:format("}")
  612:     end;
  613: chk(_, _, T, X, Y)
  614:   when is_tuple(T), is_tuple(X), is_tuple(Y) ->
  615:     throw({diff,T,[X,Y]}).
  616: 
  617: chk_tuple(QsA, QsB, T, _, _, N) when N > tuple_size(T) ->
  618:     {QsA,QsB};
  619: chk_tuple(QsA0, QsB0, T, X, Y, N) ->
  620:     {QsA,QsB} = chk(QsA0, QsB0, element(N, T), element(N, X), element(N, Y)),
  621:     chk_tuple(QsA, QsB, T, X, Y, N+1).