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).