1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1997-2013. 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: %%% Purpose: Test suite for the 'lists' module.
   21: %%%-----------------------------------------------------------------
   22: 
   23: -module(lists_SUITE).
   24: -include_lib("test_server/include/test_server.hrl").
   25: 
   26: 
   27: % Default timetrap timeout (set in init_per_testcase).
   28: % This should be set relatively high (10-15 times the expected
   29: % max testcasetime).
   30: -define(default_timeout, ?t:minutes(4)).
   31: 
   32: % Test server specific exports
   33: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   34: 	 init_per_group/2,end_per_group/2]).
   35: -export([init_per_testcase/2, end_per_testcase/2]).
   36: 
   37: % Test cases must be exported.
   38: -export([member/1, reverse/1,
   39: 	 keymember/1, keysearch_keyfind/1,
   40:          keystore/1, keytake/1,
   41: 	 append_1/1, append_2/1,
   42: 	 seq_loop/1, seq_2/1, seq_3/1, seq_2_e/1, seq_3_e/1,
   43: 	
   44: 	 sublist_2/1, sublist_3/1, sublist_2_e/1, sublist_3_e/1,
   45: 	 flatten_1/1, flatten_2/1, flatten_1_e/1, flatten_2_e/1,
   46: 	 dropwhile/1,
   47: 	 sort_1/1, sort_stable/1, merge/1, rmerge/1, sort_rand/1,
   48: 	 usort_1/1, usort_stable/1, umerge/1, rumerge/1,usort_rand/1,
   49: 	 keymerge/1, rkeymerge/1,
   50: 	 keysort_1/1, keysort_i/1, keysort_stable/1,
   51: 	 keysort_rand/1, keysort_error/1,
   52: 	 ukeymerge/1, rukeymerge/1,
   53: 	 ukeysort_1/1, ukeysort_i/1, ukeysort_stable/1,
   54: 	 ukeysort_rand/1, ukeysort_error/1,
   55: 	 funmerge/1, rfunmerge/1,
   56: 	 funsort_1/1, funsort_stable/1, funsort_rand/1,
   57: 	 funsort_error/1,
   58: 	 ufunmerge/1, rufunmerge/1,
   59: 	 ufunsort_1/1, ufunsort_stable/1, ufunsort_rand/1,
   60: 	 ufunsort_error/1,
   61: 	 zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1,
   62: 	 filter_partition/1, 
   63: 	 otp_5939/1, otp_6023/1, otp_6606/1, otp_7230/1,
   64: 	 suffix/1, subtract/1]).
   65: 
   66: %% Sort randomized lists until stopped.
   67: %%
   68: %% If you update some of the sort or merge functions, you should
   69: %% definitely let sort_loop work for a couple of hours or days. Try
   70: %% both sort_loop/0 and sort_loop/1 with a small argument (30-50 say).
   71: 
   72: -export([sort_loop/0, sort_loop/1, sloop/1]).
   73: 
   74: %% Internal export.
   75: -export([make_fun/1]).
   76: 
   77: %%
   78: %% all/1
   79: %%
   80: suite() -> [{ct_hooks,[ts_install_cth]}].
   81: 
   82: all() -> 
   83:     [{group, append}, reverse, member, keymember,
   84:      keysearch_keyfind, keystore, keytake, dropwhile, {group,sort},
   85:      {group, usort}, {group, keysort}, {group, ukeysort},
   86:      {group, funsort}, {group, ufunsort}, {group, sublist},
   87:      {group, flatten}, {group, seq}, zip_unzip, zip_unzip3,
   88:      zipwith, zipwith3, filter_partition, {group, tickets},
   89:      suffix, subtract].
   90: 
   91: groups() -> 
   92:     [{append, [], [append_1, append_2]},
   93:      {usort, [],
   94:       [umerge, rumerge, usort_1, usort_rand, usort_stable]},
   95:      {keysort, [],
   96:       [keymerge, rkeymerge, keysort_1, keysort_rand,
   97:        keysort_i, keysort_stable, keysort_error]},
   98:      {sort,[],[merge, rmerge, sort_1, sort_rand]},
   99:      {ukeysort, [],
  100:       [ukeymerge, rukeymerge, ukeysort_1, ukeysort_rand,
  101:        ukeysort_i, ukeysort_stable, ukeysort_error]},
  102:      {funsort, [],
  103:       [funmerge, rfunmerge, funsort_1, funsort_stable,
  104:        funsort_error, funsort_rand]},
  105:      {ufunsort, [],
  106:       [ufunmerge, rufunmerge, ufunsort_1, ufunsort_stable,
  107:        ufunsort_error, ufunsort_rand]},
  108:      {seq, [], [seq_loop, seq_2, seq_3, seq_2_e, seq_3_e]},
  109:      {sublist, [],
  110:       [sublist_2, sublist_3, sublist_2_e, sublist_3_e]},
  111:      {flatten, [],
  112:       [flatten_1, flatten_2, flatten_1_e, flatten_2_e]},
  113:      {tickets, [], [otp_5939, otp_6023, otp_6606, otp_7230]}].
  114: 
  115: init_per_suite(Config) ->
  116:     Config.
  117: 
  118: end_per_suite(_Config) ->
  119:     ok.
  120: 
  121: init_per_group(_GroupName, Config) ->
  122:     Config.
  123: 
  124: end_per_group(_GroupName, Config) ->
  125:     Config.
  126: 
  127: 
  128: init_per_testcase(_Case, Config) ->
  129:     ?line Dog=test_server:timetrap(?default_timeout),
  130:     [{watchdog, Dog}|Config].
  131: 
  132: end_per_testcase(_Case, Config) ->
  133:     Dog=?config(watchdog, Config),
  134:     test_server:timetrap_cancel(Dog),
  135:     ok.
  136: 
  137: %
  138: % Test cases starts here.
  139: %
  140: 
  141: append_1(doc) ->   [];
  142: append_1(suite) -> [];
  143: append_1(Config) when is_list(Config) ->
  144:     ?line "abcdef"=lists:append(["abc","def"]),
  145:     ?line [hej, du,[glade, [bagare]]]=
  146: 	lists:append([[hej], [du], [[glade, [bagare]]]]),
  147:     ?line [10, [elem]]=lists:append([[10], [[elem]]]),
  148:     ok.
  149: 
  150: append_2(doc) ->   [];
  151: append_2(suite) -> [];
  152: append_2(Config) when is_list(Config) ->
  153:     ?line "abcdef"=lists:append("abc", "def"),
  154:     ?line [hej, du]=lists:append([hej], [du]),
  155:     ?line [10, [elem]]=lists:append([10], [[elem]]),
  156:     ok.
  157: 
  158: reverse(suite) ->
  159:     [];
  160: reverse(doc) ->
  161:     ["Tests the lists:reverse() implementation. The function is "
  162:      "`non-blocking', and only processes a fixed number of elements "
  163:      "at a time."];
  164: reverse(Config) when is_list(Config) ->
  165:     ?line reverse_test(0),
  166:     ?line reverse_test(1),
  167:     ?line reverse_test(2),
  168:     ?line reverse_test(128),
  169:     ?line reverse_test(256),
  170:     ?line reverse_test(1000),
  171:     ?line reverse_test(1998),
  172:     ?line reverse_test(1999),
  173:     ?line reverse_test(2000),
  174:     ?line reverse_test(2001),
  175:     ?line reverse_test(3998),
  176:     ?line reverse_test(3999),
  177:     ?line reverse_test(4000),
  178:     ?line reverse_test(4001),
  179:     ?line reverse_test(60001),
  180:     ?line reverse_test(100007),
  181:     ok.
  182: 
  183: reverse_test(0) ->
  184:     case lists:reverse([]) of
  185: 	[] ->
  186: 	    ok;
  187: 	_Other ->
  188: 	    error
  189:     end;
  190: reverse_test(Num) ->
  191:     List0 = ['The Element'|lists:duplicate(Num, 'Ele')],
  192:     List = lists:reverse(List0),
  193:     ['Ele'|_] = List,
  194:     'The Element' = lists:last(List),
  195:     List0 = lists:reverse(List),
  196:     ok.
  197: 
  198: member(doc) ->
  199:     ["Tests the lists:member() implementation."
  200:      "This test case depends on lists:reverse() to work, "
  201:      "wich is tested in a separate test case."];
  202: member(Config) when is_list(Config) ->
  203:     ?line {'EXIT',{badarg,_}} = (catch lists:member(45, {a,b,c})),
  204:     ?line {'EXIT',{badarg,_}} = (catch lists:member(45, [0|non_list_tail])),
  205:     ?line false = lists:member(4233, []),
  206:     ?line member_test(1),
  207:     ?line member_test(100),
  208:     ?line member_test(256),
  209:     ?line member_test(1000),
  210:     ?line member_test(1998),
  211:     ?line member_test(1999),
  212:     ?line member_test(2000),
  213:     ?line member_test(2001),
  214:     ?line member_test(3998),
  215:     ?line member_test(3999),
  216:     ?line member_test(4000),
  217:     ?line member_test(4001),
  218:     ?line member_test(100008),
  219:     ok.
  220: 
  221: member_test(Num) ->
  222:     List0 = ['The Element'|lists:duplicate(Num, 'Elem')],
  223:     true = lists:member('The Element', List0),
  224:     true = lists:member('Elem', List0),
  225:     false = lists:member(arne_anka, List0),
  226:     false = lists:member({a,b,c}, List0),
  227:     List = lists:reverse(List0),
  228:     true = lists:member('The Element', List),
  229:     true = lists:member('Elem', List),
  230:     false = lists:member(arne_anka, List),
  231:     false = lists:member({a,b,c}, List).
  232: 
  233: keymember(Config) when is_list(Config) ->
  234:     ?line false = lists:keymember(anything_goes, 1, []),
  235:     ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, -1, [])),
  236:     ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, 0, [])),
  237:     ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, 1, {1,2,3})),
  238:     List = [{52.0,a},{-19,b,c},{37.5,d},an_atom,42.0,{39},{45,{x,y,z}}],
  239: 
  240:     ?line false = lists:keymember(333, 5, List),
  241:     ?line false = lists:keymember(333, 999, List),
  242:     ?line false = lists:keymember(37, 1, List),
  243: 
  244:     ?line true = lists:keymember(52.0, 1, List),
  245:     ?line true = lists:keymember(52, 1, List),
  246:     ?line true = lists:keymember(-19, 1, List),
  247:     ?line true = lists:keymember(-19.0, 1, List),
  248:     ?line true = lists:keymember(37.5, 1, List),
  249:     ?line true = lists:keymember(39, 1, List),
  250:     ?line true = lists:keymember(39.0, 1, List),
  251:     ?line true = lists:keymember(45, 1, List),
  252:     ?line true = lists:keymember(45.0, 1, List),
  253: 
  254:     ?line true = lists:keymember(a, 2, List),
  255:     ?line true = lists:keymember(b, 2, List),
  256:     ?line true = lists:keymember(c, 3, List),
  257:     ?line true = lists:keymember(d, 2, List),
  258:     ?line true = lists:keymember({x,y,z}, 2, List),
  259: 
  260:     ?line Long0 = lists:seq(1, 100007),
  261:     ?line false = lists:keymember(kalle, 1, Long0),
  262:     ?line Long = lists:foldl(fun(E, A) -> [{1/E,E}|A] end, [], Long0),
  263:     ?line true = lists:keymember(1, 2, Long),
  264:     ?line true = lists:keymember(2, 2, Long),
  265:     ?line true = lists:keymember(1.0, 2, Long),
  266:     ?line true = lists:keymember(2.0, 2, Long),
  267:     ?line true = lists:keymember(100006, 2, Long),
  268:     ok.
  269: 
  270: keysearch_keyfind(Config) when is_list(Config) ->
  271:     ?line false = key_search_find(anything_goes, 1, []),
  272:     ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, -1, [])),
  273:     ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, 0, [])),
  274:     ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, 1, {1,2,3})),
  275: 
  276:     First = {x,42.0},
  277:     Second = {y,-77},
  278:     Third = {z,[a,b,c],{5.0}},
  279:     List = [First,Second,Third],
  280:     
  281:     ?line false = key_search_find(333, 1, []),
  282:     ?line false = key_search_find(333, 5, List),
  283:     ?line false = key_search_find(333, 999, List),
  284:     ?line false = key_search_find(37, 1, List),
  285: 
  286:     ?line {value,First} = key_search_find(42, 2, List),
  287:     ?line {value,First} = key_search_find(42.0, 2, List),
  288: 
  289:     ?line {value,Second} = key_search_find(-77, 2, List),
  290:     ?line {value,Second} = key_search_find(-77.0, 2, List),
  291: 
  292:     ?line {value,Third} = key_search_find(z, 1, List),
  293:     ?line {value,Third} = key_search_find([a,b,c], 2, List),
  294:     ?line {value,Third} = key_search_find({5}, 3, List),
  295:     ?line {value,Third} = key_search_find({5.0}, 3, List),
  296: 
  297:     ?line Long0 = lists:seq(1, 100007),
  298:     ?line false = key_search_find(kalle, 1, Long0),
  299:     ?line Long = lists:foldl(fun(E, A) -> [{1/E,float(E)}|A] end, [], Long0),
  300:     ?line {value,{_,1.0}} = key_search_find(1, 2, Long),
  301:     ?line {value,{_,1.0}} = key_search_find(1.0, 2, Long),
  302:     ?line {value,{_,2.0}} = key_search_find(2, 2, Long),
  303:     ?line {value,{_,2.0}} = key_search_find(2.0, 2, Long),
  304:     ?line {value,{_,33988.0}} = key_search_find(33988, 2, Long),
  305:     ?line {value,{_,33988.0}} = key_search_find(33988.0, 2, Long),
  306:     ok.
  307: 
  308: %% Test both lists:keysearch/3 and lists:keyfind/3. The only
  309: %% difference between these two functions is that lists:keysearch/3
  310: %% wraps a successfully returned tuple in a value tuple.
  311: %%
  312: key_search_find(Key, Pos, List) ->
  313:     case lists:keyfind(Key, Pos, List) of
  314: 	false ->
  315: 	    false = lists:keysearch(Key, Pos, List);
  316: 	Tuple when is_tuple(Tuple) ->
  317: 	    {value,Tuple} = lists:keysearch(Key, Pos, List)
  318:     end.
  319: 
  320: dropwhile(Config) when is_list(Config) ->
  321:     ?line F = fun(C) -> C =:= $@ end,
  322: 
  323:     ?line [] = lists:dropwhile(F, []),
  324:     ?line [a] = lists:dropwhile(F, [a]),
  325:     ?line [a,b] = lists:dropwhile(F, [a,b]),
  326:     ?line [a,b,c] = lists:dropwhile(F, [a,b,c]),
  327: 
  328:     ?line [] = lists:dropwhile(F, [$@]),
  329:     ?line [] = lists:dropwhile(F, [$@,$@]),
  330:     ?line [a,$@] = lists:dropwhile(F, [$@,a,$@]),
  331: 
  332:     ?line [$k] = lists:dropwhile(F, [$@,$k]),
  333:     ?line [$k,$l] = lists:dropwhile(F, [$@,$@,$k,$l]),
  334:     ?line [a] = lists:dropwhile(F, [$@,$@,$@,a]),
  335: 
  336:     ?line [a,$@,b] = lists:dropwhile(F, [$@,a,$@,b]),
  337:     ?line [a,$@,b] = lists:dropwhile(F, [$@,$@,a,$@,b]),
  338:     ?line [a,$@,b] = lists:dropwhile(F, [$@,$@,$@,a,$@,b]),
  339: 
  340:     Long = lists:seq(1, 1024),
  341:     Shorter = lists:seq(800, 1024),
  342: 
  343:     ?line Shorter = lists:dropwhile(fun(E) -> E < 800 end, Long),
  344: 
  345:     ok.
  346: 
  347: keystore(doc) ->
  348:     ["OTP-XXX."];
  349: keystore(suite) -> [];
  350: keystore(Config) when is_list(Config) ->
  351:     ?line {'EXIT',_} = (catch lists:keystore(key, 0, [], {1})),
  352:     ?line {'EXIT',_} = (catch lists:keystore(key, 1, {}, {})),
  353:     ?line {'EXIT',_} = (catch lists:keystore(key, 1, {a,b}, {})),
  354:     ?line {'EXIT', _} = (catch lists:keystore(a, 2, [{1,a}], b)),
  355:     T = {k,17},
  356:     ?line [T] = lists:keystore(a, 2, [], T),
  357:     ?line [{1,a},{2,b},{k,17}] = lists:keystore(c, 2, [{1,a},{2,b}],T),
  358:     L = [{1,a},{2,b},{3,c}],
  359:     ?line [{k,17},{2,b},{3,c}] = lists:keystore(a, 2, L, T),
  360:     ?line [{1,a},{k,17},{3,c}] = lists:keystore(b, 2, L, T),
  361:     ?line [{1,a},{2,b},{k,17}] = lists:keystore(c, 2, L, T),
  362:     ?line [{2,b}] = lists:keystore(a, 2, [{1,a}], {2,b}),
  363:     ?line [{1,a}] = lists:keystore(foo, 1, [], {1,a}),
  364:     ok.
  365: 
  366: keytake(doc) ->
  367:     ["OTP-XXX."];
  368: keytake(suite) -> [];
  369: keytake(Config) when is_list(Config) ->
  370:     ?line {'EXIT',_} = (catch lists:keytake(key, 0, [])),
  371:     ?line {'EXIT',_} = (catch lists:keytake(key, 1, {})),
  372:     ?line {'EXIT',_} = (catch lists:keytake(key, 1, {a,b})),
  373:     ?line false = lists:keytake(key, 2, [{a}]),
  374:     ?line false = lists:keytake(key, 1, [a]),
  375:     ?line false = lists:keytake(k, 1, []),
  376:     ?line false = lists:keytake(k, 1, [{a},{b},{c}]),
  377:     L = [{a,1},{b,2},{c,3}],
  378:     ?line {value,{a,1},[{b,2},{c,3}]} = lists:keytake(1, 2, L),
  379:     ?line {value,{b,2},[{a,1},{c,3}]} = lists:keytake(2, 2, L),
  380:     ?line {value,{c,3},[{a,1},{b,2}]} = lists:keytake(3, 2, L),
  381:     ?line false = lists:keytake(4, 2, L),
  382:     ok.
  383: 
  384: merge(doc) ->   ["merge functions"];
  385: merge(suite) -> [];
  386: merge(Config) when is_list(Config) ->
  387: 
  388:     %% merge list of lists
  389:     ?line [] = lists:merge([]),
  390:     ?line [] = lists:merge([[]]),
  391:     ?line [] = lists:merge([[],[]]),
  392:     ?line [] = lists:merge([[],[],[]]),
  393:     ?line [1] = lists:merge([[1]]),
  394:     ?line [1,1,2,2] = lists:merge([[1,2],[1,2]]),
  395:     ?line [1] = lists:merge([[1],[],[]]),
  396:     ?line [1] = lists:merge([[],[1],[]]),
  397:     ?line [1] = lists:merge([[],[],[1]]),
  398:     ?line [1,2] = lists:merge([[1],[2],[]]),
  399:     ?line [1,2] = lists:merge([[1],[],[2]]),
  400:     ?line [1,2] = lists:merge([[],[1],[2]]),
  401:     ?line [1,2,3,4,5,6] = lists:merge([[1,2],[],[5,6],[],[3,4],[]]),
  402:     ?line [1,2,3,4] = lists:merge([[4],[3],[2],[1]]),
  403:     ?line [1,2,3,4,5] = lists:merge([[1],[2],[3],[4],[5]]),
  404:     ?line [1,2,3,4,5,6] = lists:merge([[1],[2],[3],[4],[5],[6]]),
  405:     ?line [1,2,3,4,5,6,7,8,9] = 
  406: 	lists:merge([[1],[2],[3],[4],[5],[6],[7],[8],[9]]),
  407:     Seq = lists:seq(1,100),
  408:     ?line true = Seq == lists:merge(lists:map(fun(E) -> [E] end, Seq)),
  409: 
  410:     Two = [1,2],
  411:     Six = [1,2,3,4,5,6],
  412: 
  413:     %% 2-way merge
  414:     ?line [] = lists:merge([], []),
  415:     ?line Two = lists:merge(Two, []),
  416:     ?line Two = lists:merge([], Two),
  417:     ?line Six = lists:merge([1,3,5], [2,4,6]),
  418:     ?line Six = lists:merge([2,4,6], [1,3,5]),
  419:     ?line Six = lists:merge([1,2,3], [4,5,6]),
  420:     ?line Six = lists:merge([4,5,6], [1,2,3]),
  421:     ?line Six = lists:merge([1,2,5],[3,4,6]),
  422:     ?line [1,2,3,5,7] = lists:merge([1,3,5,7], [2]),
  423:     ?line [1,2,3,4,5,7] = lists:merge([1,3,5,7], [2,4]),
  424:     ?line [1,2,3,4,5,6,7] = lists:merge([1,3,5,7], [2,4,6]),
  425:     ?line [1,2,3,5,7] = lists:merge([2], [1,3,5,7]),
  426:     ?line [1,2,3,4,5,7] = lists:merge([2,4], [1,3,5,7]),
  427:     ?line [1,2,3,4,5,6,7] = lists:merge([2,4,6], [1,3,5,7]),
  428: 
  429:     %% 3-way merge
  430:     ?line [] = lists:merge3([], [], []),
  431:     ?line Two = lists:merge3([], [], Two),
  432:     ?line Two = lists:merge3([], Two, []),
  433:     ?line Two = lists:merge3(Two, [], []),
  434:     ?line Six = lists:merge3([], [1,3,5], [2,4,6]),
  435:     ?line Six = lists:merge3([1,3,5], [], [2,4,6]),
  436:     ?line Six = lists:merge3([1,3,5], [2,4,6], []),
  437:     ?line Nine = lists:merge3([1,4,7],[2,5,8],[3,6,9]),
  438:     ?line Nine = lists:merge3([1,4,7],[3,6,9],[2,5,8]),
  439:     ?line Nine = lists:merge3([3,6,9],[1,4,7],[2,5,8]),
  440:     ?line Nine = lists:merge3([4,5,6],[1,2,3],[7,8,9]),
  441:     ?line Nine = lists:merge3([1,2,3],[4,5,6],[7,8,9]),
  442:     ?line Nine = lists:merge3([7,8,9],[4,5,6],[1,2,3]),
  443:     ?line Nine = lists:merge3([4,5,6],[7,8,9],[1,2,3]),
  444: 
  445:     ok.
  446: 
  447: rmerge(doc) ->   ["reverse merge functions"];
  448: rmerge(suite) -> [];
  449: rmerge(Config) when is_list(Config) ->
  450: 
  451:     Two = [2,1],
  452:     Six = [6,5,4,3,2,1],
  453: 
  454:     %% 2-way reversed merge
  455:     ?line [] = lists:rmerge([], []),
  456:     ?line Two = lists:rmerge(Two, []),
  457:     ?line Two = lists:rmerge([], Two),
  458:     ?line Six = lists:rmerge([5,3,1], [6,4,2]),
  459:     ?line Six = lists:rmerge([6,4,2], [5,3,1]),
  460:     ?line Six = lists:rmerge([3,2,1], [6,5,4]),
  461:     ?line Six = lists:rmerge([6,5,4], [3,2,1]),
  462:     ?line Six = lists:rmerge([4,3,2],[6,5,1]),
  463:     ?line [7,6,5,3,1] = lists:rmerge([7,5,3,1], [6]),
  464:     ?line [7,6,5,4,3,1] = lists:rmerge([7,5,3,1], [6,4]),
  465:     ?line [7,6,5,4,3,2,1] = lists:rmerge([7,5,3,1], [6,4,2]),
  466:     ?line [7,5,3,2,1] = lists:rmerge([2], [7,5,3,1]),
  467:     ?line [7,5,4,3,2,1] = lists:rmerge([4,2], [7,5,3,1]),
  468:     ?line [7,6,5,4,3,2,1] = lists:rmerge([6,4,2], [7,5,3,1]),
  469: 
  470:     Nine = [9,8,7,6,5,4,3,2,1],
  471: 
  472:     %% 3-way reversed merge
  473:     ?line [] = lists:rmerge3([], [], []),
  474:     ?line Two = lists:rmerge3([], [], Two),
  475:     ?line Two = lists:rmerge3([], Two, []),
  476:     ?line Two = lists:rmerge3(Two, [], []),
  477:     ?line Six = lists:rmerge3([], [5,3,1], [6,4,2]),
  478:     ?line Six = lists:rmerge3([5,3,1], [], [6,4,2]),
  479:     ?line Six = lists:rmerge3([5,3,1], [6,4,2], []),
  480:     ?line Nine = lists:rmerge3([7,4,1],[8,5,2],[9,6,3]),
  481:     ?line Nine = lists:rmerge3([7,4,1],[9,6,3],[8,5,2]),
  482:     ?line Nine = lists:rmerge3([9,6,3],[7,4,1],[8,5,2]),
  483:     ?line Nine = lists:rmerge3([6,5,4],[3,2,1],[9,8,7]),
  484:     ?line Nine = lists:rmerge3([3,2,1],[6,5,4],[9,8,7]),
  485:     ?line Nine = lists:rmerge3([9,8,7],[6,5,4],[3,2,1]),
  486:     ?line Nine = lists:rmerge3([6,5,4],[9,8,7],[3,2,1]),
  487: 
  488:     ok.
  489: 
  490: sort_1(doc) ->   ["sort/1"];
  491: sort_1(suite) -> [];
  492: sort_1(Config) when is_list(Config) ->
  493:     ?line [] = lists:sort([]),
  494:     ?line [a] = lists:sort([a]),
  495:     ?line [a,a] = lists:sort([a,a]),
  496:     ?line [a,b] = lists:sort([a,b]),
  497:     ?line [a,b] = lists:sort([b,a]),
  498:     ?line [1,1] = lists:sort([1,1]),
  499:     ?line [1,1,2,3] = lists:sort([1,1,3,2]),
  500:     ?line [1,2,3,3] = lists:sort([3,3,1,2]),
  501:     ?line [1,1,1,1] = lists:sort([1,1,1,1]),
  502:     ?line [1,1,1,2,2,2,3,3,3] = lists:sort([3,3,3,2,2,2,1,1,1]),
  503:     ?line [1,1,1,2,2,2,3,3,3] = lists:sort([1,1,1,2,2,2,3,3,3]),
  504: 
  505:     ?line lists:foreach(fun check/1, perms([1,2,3])),
  506:     ?line lists:foreach(fun check/1, perms([1,2,3,4,5,6,7,8])),
  507:     ok.
  508: 
  509: sort_rand(doc) ->   ["sort/1 on big randomized lists"];
  510: sort_rand(suite) -> [];
  511: sort_rand(Config) when is_list(Config) ->
  512:     ?line ok = check(biglist(10)),
  513:     ?line ok = check(biglist(100)),
  514:     ?line ok = check(biglist(1000)),
  515:     ?line ok = check(biglist(10000)),
  516:     ok.
  517: 
  518: %% sort/1 was really stable for a while - the order of equal elements
  519: %% was kept - but since the performance suffered a bit, this "feature"
  520: %% was removed.
  521: sort_stable(doc) ->   ["sort/1 should be stable for equal terms."];
  522: sort_stable(suite) -> [];
  523: sort_stable(Config) when is_list(Config) ->
  524:     ?line ok = check_stability(bigfunlist(10)),
  525:     ?line ok = check_stability(bigfunlist(100)),
  526:     ?line ok = check_stability(bigfunlist(1000)),
  527:     ?line case erlang:system_info(modified_timing_level) of
  528:               undefined -> ok = check_stability(bigfunlist(10000));
  529:               _ -> ok
  530:           end,
  531:     ok.
  532: 
  533: check([]) ->
  534:     ok;
  535: check(L) ->
  536:     S = lists:sort(L),
  537:     case {length(L) == length(S), check(hd(S), tl(S))} of
  538: 	{true,ok} ->
  539: 	    ok;
  540: 	_ ->
  541: 	    io:format("~w~n", [L]),
  542: 	    erlang:error(check)
  543:     end.
  544: 
  545: check(_A, []) ->
  546:     ok;
  547: check(A, [B | L]) when A =< B ->
  548:     check(B, L);
  549: check(_A, _L) ->
  550:     no.
  551: 
  552: %% The check that sort/1 is stable is no longer used.
  553: %% Equal elements are no longer always kept in order.
  554: check_stability(L) ->
  555:     S = lists:sort(L),
  556:     LP = explicit_pid(L),
  557:     SP = explicit_pid(S),
  558:     check_sorted(1, 2, LP, SP).
  559: 
  560: explicit_pid(L) ->
  561:     lists:reverse(expl_pid(L, [])).
  562: 
  563: expl_pid([{I,F} | T], L) when is_function(F) ->
  564:     expl_pid(T, [{I,fun_pid(F)} | L]);
  565: expl_pid([], L) ->
  566:     L.
  567: 
  568: 
  569: usort_1(suite) -> [];
  570: usort_1(doc) -> [""];
  571: usort_1(Conf) when is_list(Conf) ->
  572:     ?line [] = lists:usort([]),
  573:     ?line [1] = lists:usort([1]), 
  574:     ?line [1] = lists:usort([1,1]),
  575:     ?line [1] = lists:usort([1,1,1,1,1]),
  576:     ?line [1,2] = lists:usort([1,2]),
  577:     ?line [1,2] = lists:usort([1,2,1]),
  578:     ?line [1,2] = lists:usort([1,2,2]),
  579:     ?line [1,2,3] = lists:usort([1,3,2]),
  580:     ?line [1,3] = lists:usort([3,1,3]),
  581:     ?line [0,1,3] = lists:usort([3,1,0]),
  582:     ?line [1,2,3] = lists:usort([3,1,2]),
  583:     ?line [1,2] = lists:usort([2,1,1]),
  584:     ?line [1,2] = lists:usort([2,1]),
  585:     ?line [0,3,4,8,9] = lists:usort([3,8,9,0,9,4]),
  586: 
  587:     ?line lists:foreach(fun ucheck/1, perms([1,2,3])),
  588:     ?line lists:foreach(fun ucheck/1, perms([1,2,3,4,5,6,2,1])),
  589: 
  590:     ok.
  591: 
  592: umerge(suite) -> [];
  593: umerge(doc) -> [""];
  594: umerge(Conf) when is_list(Conf) ->
  595:     %% merge list of lists
  596:     ?line [] = lists:umerge([]),
  597:     ?line [] = lists:umerge([[]]),
  598:     ?line [] = lists:umerge([[],[]]),
  599:     ?line [] = lists:umerge([[],[],[]]),
  600:     ?line [1] = lists:umerge([[1]]),
  601:     ?line [1,2] = lists:umerge([[1,2],[1,2]]),
  602:     ?line [1] = lists:umerge([[1],[],[]]),
  603:     ?line [1] = lists:umerge([[],[1],[]]),
  604:     ?line [1] = lists:umerge([[],[],[1]]),
  605:     ?line [1,2] = lists:umerge([[1],[2],[]]),
  606:     ?line [1,2] = lists:umerge([[1],[],[2]]),
  607:     ?line [1,2] = lists:umerge([[],[1],[2]]),
  608:     ?line [1,2,3,4,5,6] = lists:umerge([[1,2],[],[5,6],[],[3,4],[]]),
  609:     ?line [1,2,3,4] = lists:umerge([[4],[3],[2],[1]]),
  610:     ?line [1,2,3,4,5] = lists:umerge([[1],[2],[3],[4],[5]]),
  611:     ?line [1,2,3,4,5,6] = lists:umerge([[1],[2],[3],[4],[5],[6]]),
  612:     ?line [1,2,3,4,5,6,7,8,9] = 
  613:         lists:umerge([[1],[2],[3],[4],[5],[6],[7],[8],[9]]),
  614:     ?line [1,2,4,6,8] = lists:umerge([[1,2],[2,4,6,8]]),
  615:     Seq = lists:seq(1,100),
  616:     ?line true = Seq == lists:umerge(lists:map(fun(E) -> [E] end, Seq)),
  617: 
  618:     Two = [1,2],
  619:     Six = [1,2,3,4,5,6],
  620: 
  621:     %% 2-way unique merge
  622:     ?line [] = lists:umerge([], []),
  623:     ?line Two = lists:umerge(Two, []),
  624:     ?line Two = lists:umerge([], Two),
  625:     ?line Six = lists:umerge([1,3,5], [2,4,6]),
  626:     ?line Six = lists:umerge([2,4,6], [1,3,5]),
  627:     ?line Six = lists:umerge([1,2,3], [4,5,6]),
  628:     ?line Six = lists:umerge([4,5,6], [1,2,3]),
  629:     ?line Six = lists:umerge([1,2,5],[3,4,6]),
  630:     ?line [1,2,3,5,7] = lists:umerge([1,3,5,7], [2]),
  631:     ?line [1,2,3,4,5,7] = lists:umerge([1,3,5,7], [2,4]),
  632:     ?line [1,2,3,4,5,6,7] = lists:umerge([1,3,5,7], [2,4,6]),
  633:     ?line [1,2,3,5,7] = lists:umerge([2], [1,3,5,7]),
  634:     ?line [1,2,3,4,5,7] = lists:umerge([2,4], [1,3,5,7]),
  635:     ?line [1,2,3,4,5,6,7] = lists:umerge([2,4,6], [1,3,5,7]),
  636: 
  637:     ?line [1,2,3,5,7] = lists:umerge([1,2,3,5,7], [2]),
  638:     ?line [1,2,3,4,5,7] = lists:umerge([1,2,3,4,5,7], [2,4]),
  639:     ?line [1,2,3,4,5,6,7] = lists:umerge([1,2,3,4,5,6,7], [2,4,6]),
  640:     ?line [1,2,3,5,7] = lists:umerge([2], [1,2,3,5,7]),
  641:     ?line [1,2,3,4,5,7] = lists:umerge([2,4], [1,2,3,4,5,7]),
  642:     ?line [1,2,3,4,5,6,7] = lists:umerge([2,4,6], [1,2,3,4,5,6,7]),
  643: 
  644:     %% 3-way unique merge
  645:     ?line [] = lists:umerge3([], [], []),
  646:     ?line Two = lists:umerge3([], [], Two),
  647:     ?line Two = lists:umerge3([], Two, []),
  648:     ?line Two = lists:umerge3(Two, [], []),
  649:     ?line Six = lists:umerge3([], [1,3,5], [2,4,6]),
  650:     ?line Six = lists:umerge3([1,3,5], [], [2,4,6]),
  651:     ?line Six = lists:umerge3([1,3,5], [2,4,6], []),
  652:     ?line Nine = lists:umerge3([1,4,7],[2,5,8],[3,6,9]),
  653:     ?line Nine = lists:umerge3([1,4,7],[3,6,9],[2,5,8]),
  654:     ?line Nine = lists:umerge3([3,6,9],[1,4,7],[2,5,8]),
  655:     ?line Nine = lists:umerge3([4,5,6],[1,2,3],[7,8,9]),
  656:     ?line Nine = lists:umerge3([1,2,3],[4,5,6],[7,8,9]),
  657:     ?line Nine = lists:umerge3([7,8,9],[4,5,6],[1,2,3]),
  658:     ?line Nine = lists:umerge3([4,5,6],[7,8,9],[1,2,3]),
  659: 
  660:     ?line [1,2,3] = lists:umerge3([1,2,3],[1,2,3],[1,2,3]),
  661:     ?line [1,2,3,4] = lists:umerge3([2,3,4],[1,2,3],[2,3,4]),
  662:     ?line [1,2,3] = lists:umerge3([1,2,3],[2,3],[1,2,3]),
  663:     ?line [1,2,3,4] = lists:umerge3([2,3,4],[3,4],[1,2,3]),
  664: 
  665:     ok.
  666: 
  667: rumerge(suite) -> [];
  668: rumerge(doc) -> [""];
  669: rumerge(Conf) when is_list(Conf) ->
  670:     Two = [2,1],
  671:     Six = [6,5,4,3,2,1],
  672: 
  673:     %% 2-way reversed unique merge
  674:     ?line [] = lists:rumerge([], []),
  675:     ?line Two = lists:rumerge(Two, []),
  676:     ?line Two = lists:rumerge([], Two),
  677:     ?line Six = lists:rumerge([5,3,1], [6,4,2]),
  678:     ?line Six = lists:rumerge([6,4,2], [5,3,1]),
  679:     ?line Six = lists:rumerge([3,2,1], [6,5,4]),
  680:     ?line Six = lists:rumerge([6,5,4], [3,2,1]),
  681:     ?line Six = lists:rumerge([4,3,2],[6,5,1]),
  682:     ?line [7,6,5,3,1] = lists:rumerge([7,5,3,1], [6]),
  683:     ?line [7,6,5,4,3,1] = lists:rumerge([7,5,3,1], [6,4]),
  684:     ?line [7,6,5,4,3,2,1] = lists:rumerge([7,5,3,1], [6,4,2]),
  685:     ?line [7,5,3,2,1] = lists:rumerge([2], [7,5,3,1]),
  686:     ?line [7,5,4,3,2,1] = lists:rumerge([4,2], [7,5,3,1]),
  687:     ?line [7,6,5,4,3,2,1] = lists:rumerge([6,4,2], [7,5,3,1]),
  688: 
  689:     ?line [7,6,5,3,1] = lists:rumerge([7,6,5,3,1], [6]),
  690:     ?line [7,6,5,4,3,1] = lists:rumerge([7,6,5,4,3,1], [6,4]),
  691:     ?line [7,6,5,4,3,2,1] = lists:rumerge([7,6,5,4,3,2,1], [6,4,2]),
  692:     ?line [7,5,3,2,1] = lists:rumerge([2], [7,5,3,2,1]),
  693:     ?line [7,5,4,3,2,1] = lists:rumerge([4,2], [7,5,4,3,2,1]),
  694:     ?line [7,6,5,4,3,2,1] = lists:rumerge([6,4,2], [7,6,5,4,3,2,1]),
  695: 
  696:     Nine = [9,8,7,6,5,4,3,2,1],
  697: 
  698:     %% 3-way reversed unique merge
  699:     ?line [] = lists:rumerge3([], [], []),
  700:     ?line Two = lists:rumerge3([], [], Two),
  701:     ?line Two = lists:rumerge3([], Two, []),
  702:     ?line Two = lists:rumerge3(Two, [], []),
  703:     ?line Six = lists:rumerge3([], [5,3,1], [6,4,2]),
  704:     ?line Six = lists:rumerge3([5,3,1], [], [6,4,2]),
  705:     ?line Six = lists:rumerge3([5,3,1], [6,4,2], []),
  706:     ?line Nine = lists:rumerge3([7,4,1],[8,5,2],[9,6,3]),
  707:     ?line Nine = lists:rumerge3([7,4,1],[9,6,3],[8,5,2]),
  708:     ?line Nine = lists:rumerge3([9,6,3],[7,4,1],[8,5,2]),
  709:     ?line Nine = lists:rumerge3([6,5,4],[3,2,1],[9,8,7]),
  710:     ?line Nine = lists:rumerge3([3,2,1],[6,5,4],[9,8,7]),
  711:     ?line Nine = lists:rumerge3([9,8,7],[6,5,4],[3,2,1]),
  712:     ?line Nine = lists:rumerge3([6,5,4],[9,8,7],[3,2,1]),
  713: 
  714:     ?line [3,2,1] = lists:rumerge3([3,2,1],[3,2,1],[3,2,1]),
  715:     ?line [4,3,2,1] = lists:rumerge3([4,3,2],[3,2,1],[3,2,1]),
  716:     ?line [5,4,3,2,1] = lists:rumerge3([4,3,2],[5,4,3,2],[5,4,3,2,1]),
  717:     ?line [6,5,4,3,2] = lists:rumerge3([4,3,2],[5,4,3,2],[6,5,4,3]),
  718: 
  719:     L1 = [c,d,e],
  720:     L2 = [b,c,d],
  721:     ?line true = 
  722: 	lists:umerge(L1, L2) == 
  723: 	lists:reverse(lists:rumerge(lists:reverse(L1), lists:reverse(L2))),
  724:     ok.
  725: 
  726: usort_rand(doc) ->   ["usort/1 on big randomized lists"];
  727: usort_rand(suite) -> [];
  728: usort_rand(Config) when is_list(Config) ->
  729:     ?line ok = ucheck(biglist(10)),
  730:     ?line ok = ucheck(biglist(100)),
  731:     ?line ok = ucheck(biglist(1000)),
  732:     ?line ok = ucheck(biglist(10000)),
  733: 
  734:     ?line ok = ucheck(ubiglist(10)),
  735:     ?line ok = ucheck(ubiglist(100)),
  736:     ?line ok = ucheck(ubiglist(1000)),
  737:     ?line ok = ucheck(ubiglist(10000)),
  738:     ok.
  739: 
  740: usort_stable(doc) ->   ["usort/1 should keep the first duplicate."];
  741: usort_stable(suite) -> [];
  742: usort_stable(Config) when is_list(Config) ->
  743:     ?line ok = ucheck_stability(bigfunlist(3)),
  744:     ?line ok = ucheck_stability(bigfunlist(10)),
  745:     ?line ok = ucheck_stability(bigfunlist(100)),
  746:     ?line ok = ucheck_stability(bigfunlist(1000)),
  747:     ?line case erlang:system_info(modified_timing_level) of
  748:               undefined -> ok = ucheck_stability(bigfunlist(10000));
  749:               _ -> ok
  750:           end,
  751:     ok.
  752: 
  753: ucheck([]) ->
  754:     ok;
  755: ucheck(L) ->
  756:     S = lists:usort(L),
  757:     case ucheck(hd(S), tl(S)) of
  758: 	ok ->
  759: 	    ok;
  760: 	_ ->
  761: 	    io:format("~w~n", [L]),
  762: 	    erlang:error(ucheck)
  763:     end.
  764: 
  765: ucheck(_A, []) ->
  766:     ok;
  767: ucheck(A, [B | L]) when A < B ->
  768:     ucheck(B, L);
  769: ucheck(_A, _L) ->
  770:     no.
  771: 
  772: %% Check that usort/1 is stable and correct relative ukeysort/2.
  773: ucheck_stability(L) ->
  774:     S = no_dups(lsort(L)),
  775:     U = lists:usort(L),
  776:     check_stab(L, U, S, "usort/1", "ukeysort/2").
  777: 
  778: 
  779: keymerge(doc) -> ["Key merge two lists."];
  780: keymerge(suite) -> [];
  781: keymerge(Config) when is_list(Config) ->
  782: 
  783:     Two = [{1,a},{2,b}],
  784:     Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}],
  785: 
  786:     %% 2-way keymerge
  787:     ?line [] = lists:keymerge(1, [], []),
  788:     ?line Two = lists:keymerge(1, Two, []),
  789:     ?line Two = lists:keymerge(1, [], Two),
  790:     ?line Six = lists:keymerge(1, [{1,a},{3,c},{5,e}], [{2,b},{4,d},{6,f}]),
  791:     ?line Six = lists:keymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e}]),
  792:     ?line Six = lists:keymerge(1, [{1,a},{2,b},{3,c}], [{4,d},{5,e},{6,f}]),
  793:     ?line Six = lists:keymerge(1, [{4,d},{5,e},{6,f}], [{1,a},{2,b},{3,c}]),
  794:     ?line Six = lists:keymerge(1, [{1,a},{2,b},{5,e}],[{3,c},{4,d},{6,f}]),
  795:     ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 
  796: 	lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b}]),
  797:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 
  798: 	lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d}]),
  799:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 
  800: 	lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d},{6,f}]),
  801:     ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 
  802: 	lists:keymerge(1, [{2,b}], [{1,a},{3,c},{5,e},{7,g}]),
  803:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 
  804: 	lists:keymerge(1, [{2,b},{4,d}], [{1,a},{3,c},{5,e},{7,g}]),
  805:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 
  806: 	lists:keymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e},{7,g}]),
  807: 
  808:     ?line [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] =
  809: 	lists:keymerge(1,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]),
  810: 
  811:     ok.
  812: 
  813: rkeymerge(doc) -> ["Reverse key merge two lists."];
  814: rkeymerge(suite) -> [];
  815: rkeymerge(Config) when is_list(Config) ->
  816: 
  817:     Two = [{2,b},{1,a}],
  818:     Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}],
  819: 
  820:     %% 2-way reversed keymerge
  821:     ?line [] = lists:rkeymerge(1, [], []),
  822:     ?line Two = lists:rkeymerge(1, Two, []),
  823:     ?line Two = lists:rkeymerge(1, [], Two),
  824:     ?line Six = lists:rkeymerge(1, [{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]),
  825:     ?line Six = lists:rkeymerge(1, [{6,f},{4,d},{2,b}], [{5,e},{3,c},{1,a}]),
  826:     ?line Six = lists:rkeymerge(1, [{3,c},{2,b},{1,a}], [{6,f},{5,e},{4,d}]),
  827:     ?line Six = lists:rkeymerge(1, [{6,f},{5,e},{4,d}], [{3,c},{2,b},{1,a}]),
  828:     ?line Six = lists:rkeymerge(1, [{4,d},{3,c},{2,b}],[{6,f},{5,e},{1,a}]),
  829:     ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] = 
  830: 	lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f}]),
  831:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] = 
  832: 	lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d}]),
  833:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
  834: 	lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]),
  835:     ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] = 
  836: 	lists:rkeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
  837:     ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
  838: 	lists:rkeymerge(1, [{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
  839:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
  840: 	lists:rkeymerge(1, [{6,f},{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
  841: 
  842:     L1 = [{c,11},{c,12},{e,5}],
  843:     L2 = [{b,2},{c,21},{c,22}],
  844:     ?line true = 
  845: 	lists:keymerge(1, L1, L2) == 
  846: 	lists:reverse(lists:rkeymerge(1,lists:reverse(L1), 
  847: 				      lists:reverse(L2))),
  848: 
  849:     ok.
  850: 
  851: keysort_1(doc) ->   ["keysort"];
  852: keysort_1(suite) -> [];
  853: keysort_1(Config) when is_list(Config) ->
  854:     ?line ok = keysort_check(1, [], []),
  855:     ?line ok = keysort_check(1, [{a,b}], [{a,b}]),
  856:     ?line ok = keysort_check(1, [{a,b},{a,b}], [{a,b},{a,b}]),
  857:     ?line ok = keysort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]),
  858:     ?line ok = keysort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]),
  859:     ?line ok = keysort_check(1,
  860: 			     [{1,e},{3,f},{2,y},{0,z},{x,14}],
  861: 			     [{0,z},{1,e},{2,y},{3,f},{x,14}]),
  862:     ?line ok = keysort_check(1,
  863: 			     [{1,a},{1,a},{1,a},{1,a}],
  864: 			     [{1,a},{1,a},{1,a},{1,a}]),
  865: 
  866:     ?line [{b,1},{c,1}] = lists:keysort(1, [{c,1},{b,1}]),
  867:     ?line [{a,0},{b,2},{c,3},{d,4}] = 
  868: 	  lists:keysort(1, [{d,4},{c,3},{b,2},{a,0}]),
  869:     ?line [{a,0},{b,1},{b,2},{c,1}] =
  870: 	  lists:keysort(1, [{c,1},{b,1},{b,2},{a,0}]),
  871:     ?line [{a,0},{b,1},{b,2},{c,1},{d,4}] =
  872: 	  lists:keysort(1, [{c,1},{b,1},{b,2},{a,0},{d,4}]),
  873: 
  874:     SFun = fun(L) -> fun(X) -> keysort_check(1, X, L) end end,
  875:     L1 = [{1,a},{2,b},{3,c}],
  876:     ?line lists:foreach(SFun(L1), perms(L1)),
  877:     L2 = [{1,a},{1,a},{2,b}],
  878:     ?line lists:foreach(SFun(L2), perms(L2)),
  879:     L3 = [{1,a},{1,a},{1,a},{2,b}],
  880:     ?line lists:foreach(SFun(L3), perms(L3)),
  881:     L4 = [{a,1},{a,1},{b,2},{b,2},{c,3},{d,4},{e,5},{f,6}],
  882:     ?line lists:foreach(SFun(L4), perms(L4)),
  883: 
  884:     ok.
  885: 
  886: keysort_stable(doc) ->   ["keysort should be stable"];
  887: keysort_stable(suite) -> [];
  888: keysort_stable(Config) when is_list(Config) ->
  889:     ?line ok = keysort_check(1, [{1,b},{1,c}], [{1,b},{1,c}]),
  890:     ?line ok = keysort_check(1, [{1,c},{1,b}], [{1,c},{1,b}]),
  891:     ?line ok = keysort_check(1,
  892: 			     [{1,c},{1,b},{2,x},{3,p},{2,a}],
  893: 			     [{1,c},{1,b},{2,x},{2,a},{3,p}]),
  894:     ?line ok = keysort_check(1, 
  895: 			     [{1,a},{1,b},{1,a},{1,a}],
  896: 			     [{1,a},{1,b},{1,a},{1,a}]),
  897:     ok.
  898: 
  899: keysort_error(doc) ->   ["keysort should exit when given bad arguments"];
  900: keysort_error(suite) -> [];
  901: keysort_error(Config) when is_list(Config) ->
  902:     ?line {'EXIT', _} = (catch lists:keysort(0, [{1,b},{1,c}])),
  903:     ?line {'EXIT', _} = (catch lists:keysort(3, [{1,b},{1,c}])),
  904:     ?line {'EXIT', _} = (catch lists:keysort(1.5, [{1,b},{1,c}])),
  905:     ?line {'EXIT', _} = (catch lists:keysort(x, [{1,b},{1,c}])),
  906:     ?line {'EXIT', _} = (catch lists:keysort(x, [])),
  907:     ?line {'EXIT', _} = (catch lists:keysort(x, [{1,b}])),
  908:     ?line {'EXIT', _} = (catch lists:keysort(1, [a,b])),
  909:     ?line {'EXIT', _} = (catch lists:keysort(1, [{1,b} | {1,c}])),
  910:     ok.
  911: 
  912: keysort_i(doc) ->   ["keysort with other key than first element"];
  913: keysort_i(suite) -> [];
  914: keysort_i(Config) when is_list(Config) ->
  915:     ?line ok = keysort_check(2, [{a,2},{b,1},{c,3}], [{b,1},{a,2},{c,3}]),
  916:     ok.
  917: 
  918: keysort_rand(doc) ->   ["keysort on big randomized lists"];
  919: keysort_rand(suite) -> [];
  920: keysort_rand(Config) when is_list(Config) ->
  921:     ?line ok = keysort_check3(1, biglist(10)),
  922:     ?line ok = keysort_check3(1, biglist(100)),
  923:     ?line ok = keysort_check3(1, biglist(1000)),
  924:     ?line ok = keysort_check3(1, biglist(10000)),
  925: 
  926:     ?line ok = keysort_check3(2, biglist(10)),
  927:     ?line ok = keysort_check3(2, biglist(100)),
  928:     ?line ok = keysort_check3(2, biglist(1000)),
  929:     ?line ok = keysort_check3(2, biglist(10000)),
  930:     ok.
  931: 
  932: %%% Keysort a list, check that the returned list is what we expected,
  933: %%% and that it is actually sorted.
  934: keysort_check(I, Input, Expected) ->
  935:     ?line Expected = lists:keysort(I, Input),
  936:     check_sorted(I, Input, Expected).
  937: 
  938: keysort_check3(I, Input) ->
  939:     check_sorted(I, 3, Input, lists:keysort(I, Input)).
  940: 
  941: check_sorted(I, Input, L) ->
  942:     check_sorted(I, I, Input, L).
  943: 
  944: %%% Check that a list is keysorted by element I. Elements comparing equal
  945: %%% should be sorted according to element J.
  946: check_sorted(_I, _J, _Input, []) ->
  947:     ok;
  948: check_sorted(I, J, Input, [A | Rest]) ->
  949:     case catch check_sorted1(I, J, A, Rest) of
  950: 	{'EXIT', _} ->
  951: 	    io:format("~w~n", [Input]),
  952: 	    erlang:error(check_sorted);
  953: 	Reply ->
  954: 	    Reply
  955:     end.
  956: 
  957: check_sorted1(_I, _J, _A, []) ->
  958:     ok;
  959: check_sorted1(I, J, A, [B | Rest]) ->
  960:     ok = keycompare(I, J, A, B),
  961:     check_sorted1(I, J, B, Rest).
  962: 
  963: keycompare(I, _J, A, B) when element(I, A) < element(I, B) ->
  964:     ok;
  965: keycompare(I, J, A, B) when element(I, A) == element(I, B), 
  966: 			    element(J, A) =< element(J, B) ->
  967:     ok.
  968: 
  969: 
  970: ukeymerge(suite) -> [];
  971: ukeymerge(doc) -> ["Merge two lists while removing duplicates."];
  972: ukeymerge(Conf) when is_list(Conf) ->
  973: 
  974:     Two = [{1,a},{2,b}],
  975:     Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}],
  976: 
  977:     %% 2-way unique keymerge
  978:     ?line [] = lists:ukeymerge(1, [], []),
  979:     ?line Two = lists:ukeymerge(1, Two, []),
  980:     ?line Two = lists:ukeymerge(1, [], Two),
  981:     ?line [] = lists:ukeymerge(1, [], []),
  982:     ?line Two = lists:ukeymerge(1, Two, []),
  983:     ?line Two = lists:ukeymerge(1, [], Two),
  984:     ?line Six = lists:ukeymerge(1, [{1,a},{3,c},{5,e}], [{2,b},{4,d},{6,f}]),
  985:     ?line Six = lists:ukeymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e}]),
  986:     ?line Six = lists:ukeymerge(1, [{1,a},{2,b},{3,c}], [{4,d},{5,e},{6,f}]),
  987:     ?line Six = lists:ukeymerge(1, [{4,d},{5,e},{6,f}], [{1,a},{2,b},{3,c}]),
  988:     ?line Six = lists:ukeymerge(1, [{1,a},{2,b},{5,e}],[{3,c},{4,d},{6,f}]),
  989:     ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 
  990: 	lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b}]),
  991:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 
  992: 	lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d}]),
  993:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 
  994: 	lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d},{6,f}]),
  995:     ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 
  996: 	lists:ukeymerge(1, [{2,b}], [{1,a},{3,c},{5,e},{7,g}]),
  997:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 
  998: 	lists:ukeymerge(1, [{2,b},{4,d}], [{1,a},{3,c},{5,e},{7,g}]),
  999:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 
 1000: 	lists:ukeymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e},{7,g}]),
 1001: 
 1002:     ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 
 1003: 	lists:ukeymerge(1, [{1,a},{2,b},{3,c},{5,e},{7,g}], [{2,b}]),
 1004:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 
 1005: 	lists:ukeymerge(1, [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}], 
 1006: 			[{2,b},{4,d}]),
 1007:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 
 1008: 	lists:ukeymerge(1, [{1,a},{3,c},{5,e},{6,f},{7,g}], 
 1009: 			[{2,b},{4,d},{6,f}]),
 1010:     ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 
 1011: 	lists:ukeymerge(1, [{2,b}], [{1,a},{2,b},{3,c},{5,e},{7,g}]),
 1012:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 
 1013: 	lists:ukeymerge(1, [{2,b},{4,d}], 
 1014: 			[{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}]),
 1015:     ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 
 1016: 	lists:ukeymerge(1, [{2,b},{4,d},{6,f}], 
 1017: 		     [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}]),
 1018: 
 1019:     L1 = [{a,1},{a,3},{a,5},{a,7}],
 1020:     L2 = [{b,1},{b,3},{b,5},{b,7}],
 1021:     ?line L1 = lists:ukeymerge(2, L1, L2),
 1022: 
 1023:     ok.
 1024: 
 1025: rukeymerge(suite) -> [];
 1026: rukeymerge(doc) -> 
 1027:     ["Reverse merge two lists while removing duplicates."];
 1028: rukeymerge(Conf) when is_list(Conf) ->
 1029: 
 1030:     Two = [{2,b},{1,a}],
 1031:     Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}],
 1032: 
 1033:     %% 2-way reversed unique keymerge
 1034:     ?line [] = lists:rukeymerge(1, [], []),
 1035:     ?line Two = lists:rukeymerge(1, Two, []),
 1036:     ?line Two = lists:rukeymerge(1, [], Two),
 1037:     ?line Six = lists:rukeymerge(1, [{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]),
 1038:     ?line Six = lists:rukeymerge(1, [{6,f},{4,d},{2,b}], [{5,e},{3,c},{1,a}]),
 1039:     ?line Six = lists:rukeymerge(1, [{3,c},{2,b},{1,a}], [{6,f},{5,e},{4,d}]),
 1040:     ?line Six = lists:rukeymerge(1, [{6,f},{5,e},{4,d}], [{3,c},{2,b},{1,a}]),
 1041:     ?line Six = lists:rukeymerge(1, [{4,d},{3,c},{2,b}],[{6,f},{5,e},{1,a}]),
 1042:     ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] = 
 1043: 	lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f}]),
 1044:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] = 
 1045: 	lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d}]),
 1046:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
 1047: 	lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]),
 1048:     ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] = 
 1049: 	lists:rukeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
 1050:     ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
 1051: 	lists:rukeymerge(1, [{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
 1052:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
 1053: 	lists:rukeymerge(1, [{6,f},{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
 1054: 
 1055:     ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] = 
 1056: 	lists:rukeymerge(1, [{7,g},{6,f},{5,e},{3,c},{1,a}], [{6,f}]),
 1057:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] = 
 1058: 	lists:rukeymerge(1, [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}], 
 1059: 			 [{6,f},{4,d}]),
 1060:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
 1061: 	lists:rukeymerge(1, [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}], 
 1062: 		      [{6,f},{4,d},{2,b}]),
 1063:     ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] = 
 1064: 	lists:rukeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{2,b},{1,a}]),
 1065:     ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
 1066: 	lists:rukeymerge(1, [{4,d},{2,b}], 
 1067: 			 [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}]),
 1068:     ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 
 1069: 	lists:rukeymerge(1, [{6,f},{4,d},{2,b}], 
 1070: 		      [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}]),
 1071: 
 1072:     L1 = [{a,1},{a,3},{a,5},{a,7}],
 1073:     L2 = [{b,1},{b,3},{b,5},{b,7}],
 1074:     ?line true = 
 1075: 	lists:ukeymerge(2, L1, L2) == 
 1076: 	lists:reverse(lists:rukeymerge(2, lists:reverse(L1), 
 1077: 				       lists:reverse(L2))),
 1078: 
 1079:     ok.
 1080: 
 1081: ukeysort_1(doc) ->   ["ukeysort"];
 1082: ukeysort_1(suite) -> [];
 1083: ukeysort_1(Config) when is_list(Config) ->
 1084:     ?line ok = ukeysort_check(1, [], []),
 1085:     ?line ok = ukeysort_check(1, [{a,b}], [{a,b}]),
 1086:     ?line ok = ukeysort_check(1, [{a,b},{a,b}], [{a,b}]),
 1087:     ?line ok = ukeysort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]),
 1088:     ?line ok = ukeysort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]),
 1089:     ?line ok = ukeysort_check(1,
 1090:                               [{1,e},{3,f},{2,y},{0,z},{x,14}],
 1091:                               [{0,z},{1,e},{2,y},{3,f},{x,14}]),
 1092:     ?line ok = ukeysort_check(1, [{1,a},{1,a},{1,a},{1,a}], [{1,a}]),
 1093: 
 1094:     L1 = [{1,a},{1,b},{1,a}],
 1095:     L1u = lists:ukeysort(1, L1),
 1096:     L2 = [{1,a},{1,b},{1,a}],
 1097:     L2u = lists:ukeysort(1, L2),
 1098:     ?line ok = ukeysort_check(1, lists:keymerge(1, L1, L2), 
 1099:                               lists:ukeymerge(1, L1u, L2u)),
 1100:     L3 = [{1,a},{1,b},{1,a},{2,a}],
 1101:     L3u = lists:ukeysort(1, L3),
 1102:     ?line ok = ukeysort_check(1, lists:keymerge(1, L3, L2), 
 1103:                               lists:ukeymerge(1, L3u, L2u)),
 1104:     L4 = [{1,b},{1,a}],
 1105:     L4u = lists:ukeysort(1, L4),
 1106:     ?line ok = ukeysort_check(1, lists:keymerge(1, L1, L4), 
 1107:                               lists:ukeymerge(1, L1u, L4u)),
 1108:     L5 = [{1,a},{1,b},{1,a},{2,a}],
 1109:     L5u = lists:ukeysort(1, L5),
 1110:     ?line ok = ukeysort_check(1, lists:keymerge(1, [], L5), 
 1111:                               lists:ukeymerge(1, [], L5u)),
 1112:     ?line ok = ukeysort_check(1, lists:keymerge(1, L5, []), 
 1113:                               lists:ukeymerge(1, L5u, [])),
 1114:     L6 = [{3,a}],
 1115:     L6u = lists:ukeysort(1, L6),
 1116:     ?line ok = ukeysort_check(1, lists:keymerge(1, L5, L6), 
 1117:                               lists:ukeymerge(1, L5u, L6u)),
 1118: 
 1119:     ?line [{b,1},{c,1}] = lists:ukeysort(1, [{c,1},{c,1},{c,1},{c,1},{b,1}]),
 1120:     ?line [{a,0},{b,2},{c,3},{d,4}] = 
 1121: 	  lists:ukeysort(1, [{d,4},{c,3},{b,2},{b,2},{a,0}]),
 1122:     ?line [{a,0},{b,1},{c,1}] =
 1123: 	  lists:ukeysort(1, [{c,1},{b,1},{b,1},{b,2},{b,2},{a,0}]),
 1124:     ?line [{a,0},{b,1},{c,1},{d,4}] =
 1125: 	  lists:ukeysort(1, [{c,1},{b,1},{b,2},{a,0},{a,0},{d,4},{d,4}]),
 1126: 
 1127:     SFun = fun(L) -> fun(X) -> ukeysort_check(2, X, L) end end,
 1128:     PL = [{a,1},{b,2},{c,3},{d,4},{e,5},{f,6}],
 1129:     Ps = perms([{a,1},{b,2},{c,3},{d,4},{e,5},{f,6},{b,2},{a,1}]),
 1130:     ?line lists:foreach(SFun(PL), Ps),
 1131: 
 1132:     M1L = [{1,a},{1,a},{2,b}],
 1133:     M1s = [{1,a},{2,b}],
 1134:     ?line lists:foreach(SFun(M1s), perms(M1L)),
 1135:     M2L = [{1,a},{2,b},{2,b}],
 1136:     M2s = [{1,a},{2,b}],
 1137:     ?line lists:foreach(SFun(M2s), perms(M2L)),
 1138:     M3 = [{1,a},{2,b},{3,c}],
 1139:     ?line lists:foreach(SFun(M3), perms(M3)),
 1140: 
 1141:     ok.
 1142: 
 1143: ukeysort_stable(doc) ->   ["ukeysort should keep the first duplicate"];
 1144: ukeysort_stable(suite) -> [];
 1145: ukeysort_stable(Config) when is_list(Config) ->
 1146:     ?line ok = ukeysort_check(1, [{1,b},{1,c}], [{1,b}]),
 1147:     ?line ok = ukeysort_check(1, [{1,c},{1,b}], [{1,c}]),
 1148:     ?line ok = ukeysort_check(1,
 1149:                               [{1,c},{1,b},{2,x},{3,p},{2,a}],
 1150:                               [{1,c},{2,x},{3,p}]),
 1151: 
 1152:     ?line ok = ukeysort_check(1, [{1,a},{1,b},{1,b}], [{1,a}]),
 1153:     ?line ok = ukeysort_check(1, [{2,a},{1,b},{2,a}], [{1,b},{2,a}]),
 1154: 
 1155:     ?line ok = ukeysort_check_stability(bigfunlist(3)),
 1156:     ?line ok = ukeysort_check_stability(bigfunlist(10)),
 1157:     ?line ok = ukeysort_check_stability(bigfunlist(100)),
 1158:     ?line ok = ukeysort_check_stability(bigfunlist(1000)),
 1159:     ?line case erlang:system_info(modified_timing_level) of
 1160:               undefined -> ok = ukeysort_check_stability(bigfunlist(10000));
 1161:               _ -> ok
 1162:           end,
 1163:     ok.
 1164: 
 1165: ukeysort_error(doc) ->   ["ukeysort should exit when given bad arguments"];
 1166: ukeysort_error(suite) -> [];
 1167: ukeysort_error(Config) when is_list(Config) ->
 1168:     ?line {'EXIT', _} = (catch lists:ukeysort(0, [{1,b},{1,c}])),
 1169:     ?line {'EXIT', _} = (catch lists:ukeysort(3, [{1,b},{1,c}])),
 1170:     ?line {'EXIT', _} = (catch lists:ukeysort(1.5, [{1,b},{1,c}])),
 1171:     ?line {'EXIT', _} = (catch lists:ukeysort(x, [{1,b},{1,c}])),
 1172:     ?line {'EXIT', _} = (catch lists:ukeysort(x, [])),
 1173:     ?line {'EXIT', _} = (catch lists:ukeysort(x, [{1,b}])),
 1174:     ?line {'EXIT', _} = (catch lists:ukeysort(1, [a,b])),
 1175:     ?line {'EXIT', _} = (catch lists:ukeysort(1, [{1,b} | {1,c}])),
 1176:     ok.
 1177: 
 1178: ukeysort_i(doc) ->   ["ukeysort with other key than first element"];
 1179: ukeysort_i(suite) -> [];
 1180: ukeysort_i(Config) when is_list(Config) ->
 1181:     ?line ok = ukeysort_check(2, [{a,2},{b,1},{c,3}], [{b,1},{a,2},{c,3}]),
 1182:     ok.
 1183: 
 1184: ukeysort_rand(doc) ->   ["ukeysort on big randomized lists"];
 1185: ukeysort_rand(suite) -> [];
 1186: ukeysort_rand(Config) when is_list(Config) ->
 1187:     ?line ok = ukeysort_check3(2, biglist(10)),
 1188:     ?line ok = ukeysort_check3(2, biglist(100)),
 1189:     ?line ok = ukeysort_check3(2, biglist(1000)),
 1190:     ?line ok = ukeysort_check3(2, biglist(10000)),
 1191: 
 1192:     ?line ok = gen_ukeysort_check(1, ubiglist(10)),
 1193:     ?line ok = gen_ukeysort_check(1, ubiglist(100)),
 1194:     ?line ok = gen_ukeysort_check(1, ubiglist(1000)),
 1195:     ?line ok = gen_ukeysort_check(1, ubiglist(10000)),
 1196:     ok.
 1197: 
 1198: %% Check that ukeysort/2 is stable and correct relative keysort/2.
 1199: %% (this is not affected by the fact that keysort/2 is no longer really 
 1200: %%  stable; ucheck_stability/1 checks ukeysort/2 (and usort/1, of course))
 1201: gen_ukeysort_check(I, Input) ->
 1202:     U = lists:ukeysort(I, Input),
 1203:     S = lists:keysort(I, Input),
 1204:     case U == no_dups_keys(S, I) of
 1205: 	true ->
 1206: 	    ok;
 1207: 	false ->
 1208: 	    io:format("~w~n", [Input]),
 1209: 	    erlang:error(gen_ukeysort_check)
 1210:     end.
 1211: 
 1212: %% Used for checking that the first copy is kept.
 1213: ukeysort_check_stability(L) ->
 1214:     I = 1,
 1215:     U = lists:ukeysort(I, L),
 1216:     S = no_dups_keys(lkeysort(I, L), I),
 1217:     check_stab(L, U, S, "ukeysort/2", "usort/2").
 1218: 
 1219: %%% Uniquely keysort a list, check that the returned list is what we
 1220: %%% expected, and that it is actually sorted.
 1221: ukeysort_check(I, Input, Expected) ->
 1222:     ?line Expected = lists:ukeysort(I, Input),
 1223:     ucheck_sorted(I, Input, Expected).
 1224: 
 1225: ukeysort_check3(I, Input) ->
 1226:     ucheck_sorted(I, 3, Input, lists:ukeysort(I, Input)).
 1227: 
 1228: ucheck_sorted(I, Input, L) ->
 1229:     ucheck_sorted(I, I, Input, L).
 1230: 
 1231: %%% Check that a list is ukeysorted by element I. Elements comparing
 1232: %%% equal should be sorted according to element J.
 1233: ucheck_sorted(_I, _J, _Input, []) ->
 1234:     ok;
 1235: ucheck_sorted(I, J, Input, [A | Rest]) ->
 1236:     case catch ucheck_sorted1(I, J, A, Rest) of
 1237: 	{'EXIT', _} ->
 1238: 	    io:format("~w~n", [Input]),
 1239: 	    erlang:error(ucheck_sorted);
 1240: 	Reply ->
 1241: 	    Reply
 1242:     end.
 1243: 
 1244: ucheck_sorted1(_I, _J, _A, []) ->
 1245:     ok;
 1246: ucheck_sorted1(I, J, A, [B | Rest]) ->
 1247:     ok = ukeycompare(I, J, A, B),
 1248:     ucheck_sorted1(I, J, B, Rest).
 1249: 
 1250: ukeycompare(I, _J, A, B) when element(I, A) < element(I, B) ->
 1251:     ok;
 1252: ukeycompare(I, J, A, B) when A =/= B,
 1253: 			     element(I, A) == element(I, B), 
 1254: 			     element(J, A) =< element(J, B) ->
 1255:     ok.
 1256: 
 1257: 
 1258: 
 1259: funmerge(doc) -> ["Merge two lists using a fun."];
 1260: funmerge(suite) -> [];
 1261: funmerge(Config) when is_list(Config) ->
 1262: 
 1263:     Two = [1,2],
 1264:     Six = [1,2,3,4,5,6],
 1265:     F = fun(X, Y) -> X =< Y end,
 1266: 
 1267:     %% 2-way merge
 1268:     ?line [] = lists:merge(F, [], []),
 1269:     ?line Two = lists:merge(F, Two, []),
 1270:     ?line Two = lists:merge(F, [], Two),
 1271:     ?line Six = lists:merge(F, [1,3,5], [2,4,6]),
 1272:     ?line Six = lists:merge(F, [2,4,6], [1,3,5]),
 1273:     ?line Six = lists:merge(F, [1,2,3], [4,5,6]),
 1274:     ?line Six = lists:merge(F, [4,5,6], [1,2,3]),
 1275:     ?line Six = lists:merge(F, [1,2,5],[3,4,6]),
 1276:     ?line [1,2,3,5,7] = lists:merge(F, [1,3,5,7], [2]),
 1277:     ?line [1,2,3,4,5,7] = lists:merge(F, [1,3,5,7], [2,4]),
 1278:     ?line [1,2,3,4,5,6,7] = lists:merge(F, [1,3,5,7], [2,4,6]),
 1279:     ?line [1,2,3,5,7] = lists:merge(F, [2], [1,3,5,7]),
 1280:     ?line [1,2,3,4,5,7] = lists:merge(F, [2,4], [1,3,5,7]),
 1281:     ?line [1,2,3,4,5,6,7] = lists:merge(F, [2,4,6], [1,3,5,7]),
 1282: 
 1283:     F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end,
 1284:     ?line [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] =
 1285: 	lists:merge(F2,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]),
 1286: 
 1287:     ok.
 1288: 
 1289: rfunmerge(doc) -> ["Reverse merge two lists using a fun."];
 1290: rfunmerge(suite) -> [];
 1291: rfunmerge(Config) when is_list(Config) ->
 1292: 
 1293:     Two = [2,1],
 1294:     Six = [6,5,4,3,2,1],
 1295:     F = fun(X, Y) -> X =< Y end,
 1296: 
 1297:     %% 2-way reversed merge
 1298:     ?line [] = lists:rmerge(F, [], []),
 1299:     ?line Two = lists:rmerge(F, Two, []),
 1300:     ?line Two = lists:rmerge(F, [], Two),
 1301:     ?line Six = lists:rmerge(F, [5,3,1], [6,4,2]),
 1302:     ?line Six = lists:rmerge(F, [6,4,2], [5,3,1]),
 1303:     ?line Six = lists:rmerge(F, [3,2,1], [6,5,4]),
 1304:     ?line Six = lists:rmerge(F, [6,5,4], [3,2,1]),
 1305:     ?line Six = lists:rmerge(F, [4,3,2],[6,5,1]),
 1306:     ?line [7,6,5,3,1] = lists:rmerge(F, [7,5,3,1], [6]),
 1307:     ?line [7,6,5,4,3,1] = lists:rmerge(F, [7,5,3,1], [6,4]),
 1308:     ?line [7,6,5,4,3,2,1] = lists:rmerge(F, [7,5,3,1], [6,4,2]),
 1309:     ?line [7,5,3,2,1] = lists:rmerge(F, [2], [7,5,3,1]),
 1310:     ?line [7,5,4,3,2,1] = lists:rmerge(F, [4,2], [7,5,3,1]),
 1311:     ?line [7,6,5,4,3,2,1] = lists:rmerge(F, [6,4,2], [7,5,3,1]),
 1312: 
 1313:     F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end,
 1314:     L1 = [{c,11},{c,12},{e,5}],
 1315:     L2 = [{b,2},{c,21},{c,22}],
 1316:     ?line true = 
 1317: 	lists:merge(F2, L1, L2) == 
 1318: 	lists:reverse(lists:rmerge(F2,lists:reverse(L1), lists:reverse(L2))),
 1319: 
 1320:     ok.
 1321: 
 1322: 
 1323: funsort_1(doc) ->   ["sort/2"];
 1324: funsort_1(suite) -> [];
 1325: funsort_1(Config) when is_list(Config) ->
 1326:     ?line ok = funsort_check(1, [], []),
 1327:     ?line ok = funsort_check(1, [{a,b}], [{a,b}]),
 1328:     ?line ok = funsort_check(1, [{a,b},{a,b}], [{a,b},{a,b}]),
 1329:     ?line ok = funsort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]),
 1330:     ?line ok = funsort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]),
 1331:     ?line ok = funsort_check(1,
 1332: 			     [{1,e},{3,f},{2,y},{0,z},{x,14}],
 1333: 			     [{0,z},{1,e},{2,y},{3,f},{x,14}]),
 1334:     F = funsort_fun(1),
 1335: 
 1336:     ?line [{b,1},{c,1}] = lists:sort(F, [{c,1},{b,1}]),
 1337:     ?line [{a,0},{b,2},{c,3},{d,4}] = 
 1338: 	  lists:sort(F, [{d,4},{c,3},{b,2},{a,0}]),
 1339:     ?line [{a,0},{b,1},{b,2},{c,1}] =
 1340: 	  lists:sort(F, [{c,1},{b,1},{b,2},{a,0}]),
 1341:     ?line [{a,0},{b,1},{b,2},{c,1},{d,4}] =
 1342: 	  lists:sort(F, [{c,1},{b,1},{b,2},{a,0},{d,4}]),
 1343: 
 1344:     SFun = fun(L) -> fun(X) -> funsort_check(1, X, L) end end,
 1345:     L1 = [{1,a},{1,a},{2,b},{2,b},{3,c},{4,d},{5,e},{6,f}],
 1346:     ?line lists:foreach(SFun(L1), perms(L1)),
 1347: 
 1348:     ok.
 1349: 
 1350: funsort_stable(doc) ->   ["sort/2 should be stable"];
 1351: funsort_stable(suite) -> [];
 1352: funsort_stable(Config) when is_list(Config) ->
 1353:     ?line ok = funsort_check(1, [{1,b},{1,c}], [{1,b},{1,c}]),
 1354:     ?line ok = funsort_check(1, [{1,c},{1,b}], [{1,c},{1,b}]),
 1355:     ?line ok = funsort_check(1,
 1356: 			     [{1,c},{1,b},{2,x},{3,p},{2,a}],
 1357: 			     [{1,c},{1,b},{2,x},{2,a},{3,p}]),
 1358:     ok.
 1359: 
 1360: funsort_error(doc) ->   ["sort/2 should exit when given bad arguments"];
 1361: funsort_error(suite) -> [];
 1362: funsort_error(Config) when is_list(Config) ->
 1363:     ?line {'EXIT', _} = (catch lists:sort(1, [{1,b} , {1,c}])),
 1364:     ?line {'EXIT', _} = (catch lists:sort(fun(X,Y) -> X =< Y end, 
 1365: 					  [{1,b} | {1,c}])),
 1366:     ok.
 1367: 
 1368: funsort_rand(doc) ->   ["sort/2 on big randomized lists"];
 1369: funsort_rand(suite) -> [];
 1370: funsort_rand(Config) when is_list(Config) ->
 1371:     ?line ok = funsort_check3(1, biglist(10)),
 1372:     ?line ok = funsort_check3(1, biglist(100)),
 1373:     ?line ok = funsort_check3(1, biglist(1000)),
 1374:     ?line ok = funsort_check3(1, biglist(10000)),
 1375:     ok.
 1376: 
 1377: % Do a keysort
 1378: funsort(I, L) ->
 1379:     lists:sort(funsort_fun(I), L).
 1380: 
 1381: funsort_check3(I, Input) ->
 1382:     check_sorted(I, 3, Input, funsort(I, Input)).
 1383: 
 1384: %%% Keysort a list, check that the returned list is what we expected,
 1385: %%% and that it is actually sorted.
 1386: funsort_check(I, Input, Expected) ->
 1387:     ?line Expected = funsort(I, Input),
 1388:     check_sorted(I, Input, Expected).
 1389: 
 1390: 
 1391: ufunmerge(suite) -> [];
 1392: ufunmerge(doc) -> ["Merge two lists while removing duplicates using a fun."];
 1393: ufunmerge(Conf) when is_list(Conf) ->
 1394: 
 1395:     Two = [1,2],
 1396:     Six = [1,2,3,4,5,6],
 1397:     F = fun(X, Y) -> X =< Y end,
 1398: 
 1399:     %% 2-way unique merge
 1400:     ?line [] = lists:umerge(F, [], []),
 1401:     ?line Two = lists:umerge(F, Two, []),
 1402:     ?line Two = lists:umerge(F, [], Two),
 1403:     ?line Six = lists:umerge(F, [1,3,5], [2,4,6]),
 1404:     ?line Six = lists:umerge(F, [2,4,6], [1,3,5]),
 1405:     ?line Six = lists:umerge(F, [1,2,3], [4,5,6]),
 1406:     ?line Six = lists:umerge(F, [4,5,6], [1,2,3]),
 1407:     ?line Six = lists:umerge(F, [1,2,5],[3,4,6]),
 1408:     ?line [1,2,3,5,7] = lists:umerge(F, [1,3,5,7], [2]),
 1409:     ?line [1,2,3,4,5,7] = lists:umerge(F, [1,3,5,7], [2,4]),
 1410:     ?line [1,2,3,4,5,6,7] = lists:umerge(F, [1,3,5,7], [2,4,6]),
 1411:     ?line [1,2,3,5,7] = lists:umerge(F, [2], [1,3,5,7]),
 1412:     ?line [1,2,3,4,5,7] = lists:umerge(F, [2,4], [1,3,5,7]),
 1413:     ?line [1,2,3,4,5,6,7] = lists:umerge(F, [2,4,6], [1,3,5,7]),
 1414: 
 1415:     ?line [1,2,3,5,7] = lists:umerge(F, [1,2,3,5,7], [2]),
 1416:     ?line [1,2,3,4,5,7] = lists:umerge(F, [1,2,3,4,5,7], [2,4]),
 1417:     ?line [1,2,3,4,5,6,7] = lists:umerge(F, [1,3,5,6,7], [2,4,6]),
 1418:     ?line [1,2,3,5,7] = lists:umerge(F, [2], [1,2,3,5,7]),
 1419:     ?line [1,2,3,4,5,7] = lists:umerge(F, [2,4], [1,2,3,4,5,7]),
 1420:     ?line [1,2,3,4,5,6,7] = lists:umerge(F, [2,4,6], [1,2,3,4,5,6,7]),
 1421: 
 1422:     L1 = [{a,1},{a,3},{a,5},{a,7}],
 1423:     L2 = [{b,1},{b,3},{b,5},{b,7}],
 1424:     F2 = fun(X,Y) -> element(2,X) =< element(2,Y) end,
 1425:     ?line L1 = lists:umerge(F2, L1, L2),
 1426:     ?line [{b,2},{e,5},{c,11},{c,12},{c,21},{c,22}] =
 1427: 	lists:umerge(F2, [{e,5},{c,11},{c,12}], [{b,2},{c,21},{c,22}]),
 1428: 
 1429:     ok.
 1430: 
 1431: rufunmerge(suite) -> [];
 1432: rufunmerge(doc) -> 
 1433:     ["Reverse merge two lists while removing duplicates using a fun."];
 1434: rufunmerge(Conf) when is_list(Conf) ->
 1435:     Two = [2,1],
 1436:     Six = [6,5,4,3,2,1],
 1437:     F = fun(X, Y) -> X =< Y end,
 1438: 
 1439:     %% 2-way reversed unique merge
 1440:     ?line [] = lists:rumerge(F, [], []),
 1441:     ?line Two = lists:rumerge(F, Two, []),
 1442:     ?line Two = lists:rumerge(F, [], Two),
 1443:     ?line Six = lists:rumerge(F, [5,3,1], [6,4,2]),
 1444:     ?line Six = lists:rumerge(F, [6,4,2], [5,3,1]),
 1445:     ?line Six = lists:rumerge(F, [3,2,1], [6,5,4]),
 1446:     ?line Six = lists:rumerge(F, [6,5,4], [3,2,1]),
 1447:     ?line Six = lists:rumerge(F, [4,3,2],[6,5,1]),
 1448:     ?line [7,6,5,3,1] = lists:rumerge(F, [7,5,3,1], [6]),
 1449:     ?line [7,6,5,4,3,1] = lists:rumerge(F, [7,5,3,1], [6,4]),
 1450:     ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [7,5,3,1], [6,4,2]),
 1451:     ?line [7,5,3,2,1] = lists:rumerge(F, [2], [7,5,3,1]),
 1452:     ?line [7,5,4,3,2,1] = lists:rumerge(F, [4,2], [7,5,3,1]),
 1453:     ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [6,4,2], [7,5,3,1]),
 1454: 
 1455:     ?line [7,6,5,3,1] = lists:rumerge(F, [7,6,5,3,1], [6]),
 1456:     ?line [7,6,5,4,3,1] = lists:rumerge(F, [7,6,5,4,3,1], [6,4]),
 1457:     ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [7,6,5,4,3,2,1], [6,4,2]),
 1458:     ?line [7,5,3,2,1] = lists:rumerge(F, [2], [7,5,3,2,1]),
 1459:     ?line [7,5,4,3,2,1] = lists:rumerge(F, [4,2], [7,5,4,3,2,1]),
 1460:     ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [6,4,2], [7,6,5,4,3,2,1]),
 1461: 
 1462:     F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end,
 1463:     L1 = [{1,a},{1,b},{1,a}],
 1464:     L2 = [{1,a},{1,b},{1,a}],
 1465:     ?line true = lists:umerge(F2, L1, L2) == 
 1466: 	lists:reverse(lists:rumerge(F, lists:reverse(L2), lists:reverse(L1))),
 1467: 
 1468:     L3 = [{c,11},{c,12},{e,5}],
 1469:     L4 = [{b,2},{c,21},{c,22}],
 1470:     ?line true = 
 1471: 	lists:umerge(F2, L3, L4) == 
 1472: 	lists:reverse(lists:rumerge(F2,lists:reverse(L3), lists:reverse(L4))),
 1473: 
 1474:     ok.
 1475: 
 1476: ufunsort_1(doc) ->   ["usort/2"];
 1477: ufunsort_1(suite) -> [];
 1478: ufunsort_1(Config) when is_list(Config) ->
 1479:     ?line ok = ufunsort_check(1, [], []),
 1480:     ?line ok = ufunsort_check(1, [{a,b}], [{a,b}]),
 1481:     ?line ok = ufunsort_check(1, [{a,b},{a,b}], [{a,b}]),
 1482:     ?line ok = ufunsort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]),
 1483:     ?line ok = ufunsort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]),
 1484:     ?line ok = ufunsort_check(1,
 1485: 			      [{1,e},{3,f},{2,y},{0,z},{x,14}],
 1486: 			      [{0,z},{1,e},{2,y},{3,f},{x,14}]),
 1487:     ?line ok = ufunsort_check(1,
 1488: 			      [{1,a},{2,b},{3,c},{2,b},{1,a},{2,b},{3,c},
 1489: 			       {2,b},{1,a}],
 1490: 			      [{1,a},{2,b},{3,c}]),
 1491:     ?line ok = ufunsort_check(1, 
 1492: 			      [{1,a},{1,a},{1,b},{1,b},{1,a},{2,a}],
 1493: 			      [{1,a},{2,a}]),
 1494: 
 1495:     F = funsort_fun(1),
 1496:     L1 = [{1,a},{1,b},{1,a}],
 1497:     L2 = [{1,a},{1,b},{1,a}],
 1498:     ?line ok = ufunsort_check(1, lists:keymerge(1, L1, L2), 
 1499:                               lists:umerge(F, lists:usort(F, L1), 
 1500:                                            lists:usort(F, L2))),
 1501:     L3 = [{1,a},{1,b},{1,a},{2,a}],
 1502:     ?line ok = ufunsort_check(1, lists:keymerge(1, L3, L2), 
 1503:                               lists:umerge(F, lists:usort(F, L3), 
 1504:                                            lists:usort(F, L2))),
 1505:     L4 = [{1,b},{1,a}],
 1506:     ?line ok = ufunsort_check(1, lists:keymerge(1, L1, L4), 
 1507:                               lists:umerge(F, lists:usort(F, L1), 
 1508:                                            lists:usort(F, L4))),
 1509:     L5 = [{1,a},{1,b},{1,a},{2,a}],
 1510:     ?line ok = ufunsort_check(1, lists:keymerge(1, L5, []), 
 1511:                               lists:umerge(F, lists:usort(F, L5), [])),
 1512:     L6 = [{3,a}],
 1513:     ?line ok = ufunsort_check(1, lists:keymerge(1, L5, L6), 
 1514:                               lists:umerge(F, lists:usort(F, L5), 
 1515:                                            lists:usort(F, L6))),
 1516: 
 1517:     ?line [{b,1},{c,1}] = lists:usort(F, [{c,1},{c,1},{b,1}]),
 1518:     ?line [{a,0},{b,2},{c,3},{d,4}] = 
 1519: 	  lists:usort(F, [{d,4},{c,3},{b,2},{b,2},{a,0}]),
 1520:     ?line [{a,0},{b,1},{c,1}] =
 1521: 	  lists:usort(F, [{c,1},{b,1},{b,1},{b,2},{b,2},{a,0}]),
 1522:     ?line [{a,0},{b,1},{c,1},{d,4}] =
 1523: 	  lists:usort(F, [{c,1},{b,1},{b,2},{a,0},{a,0},{d,4},{d,4}]),
 1524: 
 1525:     SFun = fun(L) -> fun(X) -> ufunsort_check(1, X, L) end end,
 1526:     PL = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}],
 1527:     Ps = perms([{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{2,b},{1,a}]),
 1528:     ?line lists:foreach(SFun(PL), Ps),
 1529: 
 1530:     ok.
 1531: 
 1532: ufunsort_stable(doc) ->   ["usort/2 should be stable"];
 1533: ufunsort_stable(suite) -> [];
 1534: ufunsort_stable(Config) when is_list(Config) ->
 1535:     ?line ok = ufunsort_check(1, [{1,b},{1,c}], [{1,b}]),
 1536:     ?line ok = ufunsort_check(1, [{1,c},{1,b}], [{1,c}]),
 1537:     ?line ok = ufunsort_check(1,
 1538: 			      [{1,c},{1,b},{2,x},{3,p},{2,a}],
 1539: 			      [{1,c},{2,x},{3,p}]),
 1540: 
 1541:     ?line ok = ufunsort_check_stability(bigfunlist(10)),
 1542:     ?line ok = ufunsort_check_stability(bigfunlist(100)),
 1543:     ?line ok = ufunsort_check_stability(bigfunlist(1000)),
 1544:     ?line case erlang:system_info(modified_timing_level) of
 1545:               undefined -> ok = ufunsort_check_stability(bigfunlist(10000));
 1546:               _ -> ok
 1547:           end,
 1548:     ok.
 1549: 
 1550: ufunsort_error(doc) ->   ["usort/2 should exit when given bad arguments"];
 1551: ufunsort_error(suite) -> [];
 1552: ufunsort_error(Config) when is_list(Config) ->
 1553:     ?line {'EXIT', _} = (catch lists:usort(1, [{1,b} , {1,c}])),
 1554:     ?line {'EXIT', _} = (catch lists:usort(fun(X,Y) -> X =< Y end, 
 1555: 					   [{1,b} | {1,c}])),
 1556:     ok.
 1557: 
 1558: ufunsort_rand(doc) ->   ["usort/2 on big randomized lists"];
 1559: ufunsort_rand(suite) -> [];
 1560: ufunsort_rand(Config) when is_list(Config) ->
 1561:     ?line ok = ufunsort_check3(1, biglist(10)),
 1562:     ?line ok = ufunsort_check3(1, biglist(100)),
 1563:     ?line ok = ufunsort_check3(1, biglist(1000)),
 1564:     ?line ok = ufunsort_check3(1, biglist(10000)),
 1565: 
 1566:     ?line ok = gen_ufunsort_check(1, ubiglist(100)),
 1567:     ?line ok = gen_ufunsort_check(1, ubiglist(1000)),
 1568:     ?line ok = gen_ufunsort_check(1, ubiglist(10000)),
 1569:     ok.
 1570: 
 1571: %% Check that usort/2 is stable and correct relative sort/2.
 1572: gen_ufunsort_check(I, Input) ->
 1573:     U = ufunsort(I, Input),
 1574:     S = funsort(I, Input),
 1575:     case U == no_dups_keys(S, I) of
 1576: 	true ->
 1577: 	    ok;
 1578: 	false ->
 1579: 	    io:format("~w~n", [Input]),
 1580: 	    erlang:error(gen_ufunsort_check)
 1581:     end.
 1582: 
 1583: %% Used for checking that the first copy is kept.
 1584: ufunsort_check_stability(L) ->
 1585:     I = 1,
 1586:     U = ufunsort(I, L),
 1587:     S = no_dups(funsort(I, L)),
 1588:     check_stab(L, U, S, "usort/2", "sort/2").
 1589: 
 1590: ufunsort_check3(I, Input) ->
 1591:     ucheck_sorted(I, 3, Input, ufunsort(I, Input)).
 1592: 
 1593: %%% Keysort a list, check that the returned list is what we expected,
 1594: %%% and that it is actually sorted.
 1595: ufunsort_check(I, Input, Expected) ->
 1596:     ?line Expected = ufunsort(I, Input),
 1597:     ucheck_sorted(I, Input, Expected).
 1598: 
 1599: % Do a keysort
 1600: ufunsort(I, L) ->
 1601:     lists:usort(funsort_fun(I), L).
 1602: 
 1603: funsort_fun(I) ->
 1604:     fun(A, B) when tuple_size(A) >= I, tuple_size(B) >= I ->
 1605:             element(I, A) =< element(I, B)
 1606:     end.
 1607: 
 1608: check_stab(L, U, S, US, SS) ->
 1609:     UP = explicit_pid(U),
 1610:     SP = explicit_pid(S),
 1611:     case UP == SP of
 1612: 	true ->
 1613: 	    ok;
 1614: 	false ->
 1615: 	    io:format("In: ~w~n", [explicit_pid(L)]),
 1616: 	    io:format("~s: ~w~n", [US, UP]),
 1617: 	    io:format("~s:  ~w~n", [SS, SP]),
 1618: 	    erlang:error(unstable)
 1619:     end.
 1620: 
 1621: %%%------------------------------------------------------------
 1622: %%% Generate lists of given length, containing 3-tuples with
 1623: %%% random integer elements in the range 0..44 as elements 1 and 2.
 1624: %%% Element 3 in the tuple is the position of the tuple in the list.
 1625: 
 1626: biglist(N) ->
 1627:     {A, B, C} = get_seed(),
 1628:     random:seed(A, B, C),
 1629:     biglist(N, []).
 1630: 
 1631: biglist(0, L) ->
 1632:     L;
 1633: biglist(N, L) ->
 1634:     E = random_tuple(45, N),
 1635:     biglist(N-1, [E|L]).
 1636: 
 1637: %%%------------------------------------------------------------
 1638: %%% Generate lists of given length, containing 2-tuples with
 1639: %%% random integer elements in the range 0..10 as element 1.
 1640: %%% Element 2 in the tuple is a random integer in the range 0..5.
 1641: %%% No sequence number.
 1642: 
 1643: ubiglist(N) ->
 1644:     {A, B, C} = get_seed(),
 1645:     random:seed(A, B, C),
 1646:     ubiglist(N, []).
 1647: 
 1648: ubiglist(0, L) ->
 1649:     L;
 1650: ubiglist(N, L) ->
 1651:     E = urandom_tuple(11, 6),
 1652:     ubiglist(N-1, [E|L]).
 1653:     
 1654: urandom_tuple(N, I) ->
 1655:     R1 = randint(N),
 1656:     R2 = randint(I),
 1657:     {R1, R2}.
 1658: 
 1659: %%%------------------------------------------------------------
 1660: %%% Generate lists of given length, containing 2-tuples with random
 1661: %%% integer elements in the range 0..10 as elements 1. All tuples have
 1662: %%% the same function as element 2, but every function is created in a
 1663: %%% unique process. ==/2 will return 'true' for any pair of functions,
 1664: %%% but erlang:fun_info(Fun, pid) can be used for distinguishing
 1665: %%% functions created in different processes. The pid acts like a
 1666: %%% sequence number.
 1667: 
 1668: bigfunlist(N) ->
 1669:     {A, B, C} = get_seed(),
 1670:     random:seed(A, B, C),
 1671:     bigfunlist_1(N).
 1672: 
 1673: bigfunlist_1(N) when N < 30000 -> % Now (R8) max 32000 different pids.
 1674:     case catch bigfunlist(N, 0, []) of
 1675: 	{'EXIT', _} ->
 1676: 	    bigfunlist_1(N);
 1677: 	Reply ->
 1678: 	    Reply
 1679:     end.
 1680: 
 1681: bigfunlist(0, _P, L) ->
 1682:     lists:reverse(L);
 1683: bigfunlist(N, P, L) ->
 1684:     {E, NP} = random_funtuple(P, 11),
 1685:     bigfunlist(N-1, NP, [E | L]).
 1686:     
 1687: random_funtuple(P, N) ->
 1688:     R = randint(N),
 1689:     F = make_fun(),
 1690:     NP = fun_pid(F),
 1691:     true = NP > P,
 1692:     {{R, F}, NP}.
 1693: 
 1694: make_fun() ->
 1695:     Pid = spawn(?MODULE, make_fun, [self()]),
 1696:     receive {Pid, Fun} -> Fun end.
 1697:     
 1698: make_fun(Pid) ->
 1699:     Pid ! {self(), fun make_fun/1}.
 1700: 
 1701: fun_pid(Fun) ->
 1702:     erlang:fun_info(Fun, pid).
 1703: 
 1704: get_seed() ->
 1705:     case random:seed() of
 1706: 	undefined ->
 1707: 	    now();
 1708: 	Tuple ->
 1709: 	    Tuple
 1710:     end.
 1711: 
 1712: random_tuple(N, Seq) ->
 1713:     R1 = randint(N),
 1714:     R2 = randint(N),
 1715:     {R1, R2, Seq}.
 1716: 
 1717: randint(N) ->
 1718:     trunc(random:uniform() * N).
 1719: 
 1720: %% The first "duplicate" is kept.
 1721: no_dups([]) ->
 1722:     [];
 1723: no_dups([H | T]) ->
 1724:     no_dups(H, T, []).
 1725: 
 1726: no_dups(H, [H1 | T], L) when H == H1 ->
 1727:     no_dups(H, T, L);
 1728: no_dups(H, [H1 | T], L) ->
 1729:     no_dups(H1, T, [H | L]);
 1730: no_dups(H, [], L) ->
 1731:     lists:reverse([H | L]).
 1732: 
 1733: %% The first "duplicate" is kept.
 1734: no_dups_keys([], _I) ->
 1735:     [];
 1736: no_dups_keys([H | T], I) ->
 1737:     no_dups_keys(H, T, [], I).
 1738: 
 1739: no_dups_keys(H, [H1 | T], L, I) when element(I, H) == element(I, H1) ->
 1740:     no_dups_keys(H, T, L, I);
 1741: no_dups_keys(H, [H1 | T], L, I) ->
 1742:     no_dups_keys(H1, T, [H | L], I);
 1743: no_dups_keys(H, [], L, _I) ->
 1744:     lists:reverse([H | L]).
 1745: 
 1746: perms([]) ->
 1747:     [[]];
 1748: perms(L) ->
 1749:     [[H|T] || H <- L, T <- perms(L--[H])].
 1750: 
 1751: %%%------------------------------------------------------------
 1752: %%% Test the sort routines with randomly generated lists.
 1753: 
 1754: -record(state, {sort = 0, usort = 0, stable = 0}).
 1755: 
 1756: %% Run it interactively. 'stop' or 'info' recognized commands.
 1757: sort_loop() ->
 1758:     sort_loop(5000).
 1759: 
 1760: sort_loop(N) when is_integer(N), N > 0 ->
 1761:     Pid = spawn_link(?MODULE, sloop, [N]),
 1762:     sort_loop_1(Pid).
 1763: 
 1764: sort_loop_1(Pid) ->
 1765:     case io:get_line('? ') of
 1766: 	eof ->
 1767: 	    ok;
 1768: 	"stop\n" ->
 1769: 	    Pid ! {self(), stop},
 1770: 	    receive {Pid, S} -> display_state(S) end;
 1771: 	"info\n" ->
 1772: 	    Pid ! {self(), info},
 1773: 	    receive {Pid, S} -> display_state(S) end,
 1774: 	    sort_loop_1(Pid);
 1775: 	_Other ->
 1776: 	    sort_loop_1(Pid)
 1777:     end.
 1778: 
 1779: sloop(N) ->
 1780:     {A, B, C} = get_seed(),
 1781:     random:seed(A, B, C),
 1782:     sloop(N, #state{}).
 1783: 
 1784: sloop(N, S) ->
 1785:     receive
 1786: 	{From, stop} ->
 1787: 	    From ! {self(), S};
 1788: 	{From, info} ->
 1789: 	    From ! {self(), S},
 1790: 	    sloop(N, S)
 1791:     after 0 ->
 1792: 	    Len = randint(N),
 1793: 	    NS = case randint(3) of
 1794: 		     0 ->
 1795: 			 BL = biglist(Len, []),
 1796: 			 ok = check(BL),
 1797: 			 ok = keysort_check3(1, BL),
 1798: 			 ok = funsort_check3(1, BL),
 1799: 			 S#state{sort = S#state.sort + 1};
 1800: 		     1 ->
 1801: 			 BL = ubiglist(Len, []),
 1802: 			 ok = ucheck(BL),
 1803: 			 ok = gen_ukeysort_check(1, BL),
 1804: 			 ok = gen_ufunsort_check(1, BL),
 1805: 			 S#state{usort = S#state.usort + 1};
 1806: 		     2 ->
 1807: 			 BL = bigfunlist(Len),
 1808: 			 %% ok = check_stability(BL),
 1809: 			 ok = ucheck_stability(BL),
 1810: 			 ok = ukeysort_check_stability(BL),
 1811: 			 ok = ufunsort_check_stability(BL),
 1812: 			 S#state{stable = S#state.stable + 1}
 1813: 		 end,
 1814: 	    sloop(N, NS)
 1815:     end.
 1816: 	    
 1817: display_state(S) ->    
 1818:     io:format("sort:   ~p~n", [S#state.sort]),
 1819:     io:format("usort:  ~p~n", [S#state.usort]),
 1820:     io:format("stable: ~p~n", [S#state.stable]).
 1821: 
 1822: %% This version of sort/1 is really stable; the order of equal
 1823: %% elements is kept. It is used for checking the current
 1824: %% implementation of usort/1 etc.
 1825: 
 1826: lsort([X, Y | L] = L0) when X =< Y ->
 1827:     case L of
 1828: 	[] -> 
 1829: 	    L0;
 1830: 	[Z] when Y =< Z ->
 1831: 	    L0;
 1832: 	[Z] when X =< Z ->
 1833: 	    [X, Z, Y];
 1834: 	[Z] ->
 1835: 	    [Z, X, Y];
 1836: 	_ ->
 1837: 	    split_1(X, Y, L, [], [])
 1838:     end;
 1839: lsort([X, Y | L]) ->
 1840:     case L of
 1841: 	[] ->
 1842: 	    [Y, X];
 1843: 	[Z] when X =< Z ->
 1844: 	    [Y, X | L];
 1845: 	[Z] when Y =< Z ->
 1846: 	    [Y, Z, X];
 1847: 	[Z] ->
 1848: 	    [Z, Y, X];
 1849: 	_ ->
 1850: 	    split_2(X, Y, L, [], [])
 1851:     end;
 1852: lsort([_] = L) ->
 1853:     L;
 1854: lsort([] = L) ->
 1855:     L.
 1856: 
 1857: split_1(X, Y, [Z | L], R, Rs) when Z >= Y ->
 1858:     split_1(Y, Z, L, [X | R], Rs);
 1859: split_1(X, Y, [Z | L], R, Rs) when Z >= X ->
 1860:     split_1(Z, Y, L, [X | R], Rs);
 1861: split_1(X, Y, [Z | L], [], Rs) ->
 1862:     split_1(X, Y, L, [Z], Rs);
 1863: split_1(X, Y, [Z | L], R, Rs) ->
 1864:     split_1_1(X, Y, L, R, Rs, Z);
 1865: split_1(X, Y, [], R, Rs) ->
 1866:     rmergel([[Y, X | R] | Rs], [], asc).
 1867: 
 1868: split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y ->
 1869:     split_1_1(Y, Z, L, [X | R], Rs, S);
 1870: split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X ->
 1871:     split_1_1(Z, Y, L, [X | R], Rs, S);
 1872: split_1_1(X, Y, [Z | L], R, Rs, S) when S =< Z ->
 1873:     split_1(S, Z, L, [], [[Y, X | R] | Rs]);
 1874: split_1_1(X, Y, [Z | L], R, Rs, S) ->
 1875:     split_1(Z, S, L, [], [[Y, X | R] | Rs]);
 1876: split_1_1(X, Y, [], R, Rs, S) ->
 1877:     rmergel([[S], [Y, X | R] | Rs], [], asc).
 1878: 
 1879: split_2(X, Y, [Z | L], R, Rs) when Z < Y ->
 1880:     split_2(Y, Z, L, [X | R], Rs);
 1881: split_2(X, Y, [Z | L], R, Rs) when Z < X ->
 1882:     split_2(Z, Y, L, [X | R], Rs);
 1883: split_2(X, Y, [Z | L], [], Rs) ->
 1884:     split_2(X, Y, L, [Z], Rs);
 1885: split_2(X, Y, [Z | L], R, Rs) ->
 1886:     split_2_1(X, Y, L, R, Rs, Z);
 1887: split_2(X, Y, [], R, Rs) ->
 1888:     mergel([[Y, X | R] | Rs], [], desc).
 1889: 
 1890: split_2_1(X, Y, [Z | L], R, Rs, S) when Z < Y ->
 1891:     split_2_1(Y, Z, L, [X | R], Rs, S);
 1892: split_2_1(X, Y, [Z | L], R, Rs, S) when Z < X ->
 1893:     split_2_1(Z, Y, L, [X | R], Rs, S);
 1894: split_2_1(X, Y, [Z | L], R, Rs, S) when S > Z ->
 1895:     split_2(S, Z, L, [], [[Y, X | R] | Rs]);
 1896: split_2_1(X, Y, [Z | L], R, Rs, S) ->
 1897:     split_2(Z, S, L, [], [[Y, X | R] | Rs]);
 1898: split_2_1(X, Y, [], R, Rs, S) ->
 1899:     mergel([[S], [Y, X | R] | Rs], [], desc).
 1900: 
 1901: mergel([[] | L], Acc, O) ->
 1902:     mergel(L, Acc, O);
 1903: mergel([T1, [H2 | T2] | L], Acc, asc) ->
 1904:     mergel(L, [merge2_1(T1, H2, T2, []) | Acc], asc);
 1905: mergel([[H2 | T2], T1 | L], Acc, desc) ->
 1906:     mergel(L, [merge2_1(T1, H2, T2, []) | Acc], desc);
 1907: mergel([L], [], _O) ->
 1908:     L;
 1909: mergel([L], Acc, O) ->
 1910:     rmergel([lists:reverse(L, []) | Acc], [], O);
 1911: mergel([], [], _O) ->
 1912:     [];
 1913: mergel([], Acc, O) ->
 1914:     rmergel(Acc, [], O);
 1915: mergel([A, [] | L], Acc, O) ->
 1916:     mergel([A | L], Acc, O);
 1917: mergel([A, B, [] | L], Acc, O) ->
 1918:     mergel([A, B | L], Acc, O).
 1919: 
 1920: rmergel([[H2 | T2], T1 | L], Acc, asc) ->
 1921:     rmergel(L, [rmerge2_1(T1, H2, T2, []) | Acc], asc);
 1922: rmergel([T1, [H2 | T2] | L], Acc, desc) ->
 1923:     rmergel(L, [rmerge2_1(T1, H2, T2, []) | Acc], desc);
 1924: rmergel([L], Acc, O) ->
 1925:     mergel([lists:reverse(L, []) | Acc], [], O);
 1926: rmergel([], Acc, O) ->
 1927:     mergel(Acc, [], O).
 1928: 
 1929: merge2_1([H1 | T1], H2, T2, M) when H1 =< H2 ->
 1930:     merge2_1(T1, H2, T2, [H1 | M]);
 1931: merge2_1([H1 | T1], H2, T2, M) ->
 1932:     merge2_2(T1, H1, T2, [H2 | M]);
 1933: merge2_1([], H2, T2, M) ->
 1934:     lists:reverse(T2, [H2 | M]).
 1935: 
 1936: merge2_2(T1, H1, [H2 | T2], M) when H1 =< H2 ->
 1937:     merge2_1(T1, H2, T2, [H1 | M]);
 1938: merge2_2(T1, H1, [H2 | T2], M) ->
 1939:     merge2_2(T1, H1, T2, [H2 | M]);
 1940: merge2_2(T1, H1, [], M) ->
 1941:     lists:reverse(T1, [H1 | M]).
 1942: 
 1943: rmerge2_1([H1 | T1], H2, T2, M) when H1 =< H2 ->
 1944:     rmerge2_2(T1, H1, T2, [H2 | M]);
 1945: rmerge2_1([H1 | T1], H2, T2, M) ->
 1946:     rmerge2_1(T1, H2, T2, [H1 | M]);
 1947: rmerge2_1([], H2, T2, M) ->
 1948:     lists:reverse(T2, [H2 | M]).
 1949: 
 1950: rmerge2_2(T1, H1, [H2 | T2], M) when H1 =< H2 ->
 1951:     rmerge2_2(T1, H1, T2, [H2 | M]);
 1952: rmerge2_2(T1, H1, [H2 | T2], M) ->
 1953:     rmerge2_1(T1, H2, T2, [H1 | M]);
 1954: rmerge2_2(T1, H1, [], M) ->
 1955:     lists:reverse(T1, [H1 | M]).
 1956: 
 1957: 
 1958: 
 1959: %% This version of keysort/2 is really stable; the order of equal
 1960: %% elements is kept. It is used for checking the current
 1961: %% implementation of ukeysort/2 etc.
 1962: 
 1963: lkeysort(Index, L) when is_integer(Index), Index > 0 ->
 1964:     case L of
 1965: 	[] -> L;
 1966: 	[_] -> L;
 1967: 	[X, Y | T] ->
 1968: 	    EX = element(Index, X),
 1969: 	    EY = element(Index, Y),
 1970: 	    if
 1971: 		EX =< EY ->
 1972: 		    keysplit_1(Index, X, EX, Y, EY, T, [], []);
 1973: 		true ->
 1974: 		    keysplit_2(Index, Y, EY, T, [X])
 1975: 	    end
 1976:     end.
 1977: 
 1978: keysplit_1(I, X, EX, Y, EY, [Z | L], R, Rs) ->
 1979:     EZ = element(I, Z),
 1980:     if 
 1981: 	EY =< EZ ->
 1982: 	    keysplit_1(I, Y, EY, Z, EZ, L, [X | R], Rs);
 1983: 	EX =< EZ ->
 1984: 	    keysplit_1(I, Z, EZ, Y, EY, L, [X | R], Rs);
 1985: 	true, R == [] ->
 1986: 	    keysplit_1(I, X, EX, Y, EY, L, [Z], Rs);
 1987: 	true ->
 1988: 	    keysplit_1_1(I, X, EX, Y, EY, L, R, Rs, Z, EZ)
 1989:     end;
 1990: keysplit_1(I, X, _EX, Y, _EY, [], R, Rs) ->
 1991:     rkeymergel(I, [[Y, X | R] | Rs], []).
 1992: 
 1993: %% One out-of-order element, S.
 1994: keysplit_1_1(I, X, EX, Y, EY, [Z | L], R, Rs, S, ES) ->
 1995:     EZ = element(I, Z),
 1996:     if
 1997: 	EY =< EZ ->
 1998: 	    keysplit_1_1(I, Y, EY, Z, EZ, L, [X | R], Rs, S, ES);
 1999: 	EX =< EZ ->
 2000: 	    keysplit_1_1(I, Z, EZ, Y, EY, L, [X | R], Rs, S, ES);
 2001: 	ES =< EZ ->
 2002: 	    keysplit_1(I, S, ES, Z, EZ, L, [], [[Y, X | R] | Rs]);
 2003: 	true ->
 2004: 	    keysplit_1(I, Z, EZ, S, ES, L, [], [[Y, X | R] | Rs])
 2005:     end;
 2006: keysplit_1_1(I, X, _EX, Y, _EY, [], R, Rs, S, _ES) ->
 2007:     rkeymergel(I, [[S], [Y, X | R] | Rs], []).
 2008: 
 2009: %% Descending.
 2010: keysplit_2(I, Y, EY, [Z | L], R) ->
 2011:     EZ = element(I, Z),
 2012:     if
 2013: 	EY =< EZ ->
 2014:             keysplit_1(I, Y, EY, Z, EZ, L, [], [lists:reverse(R, [])]);
 2015:         true ->
 2016:             keysplit_2(I, Z, EZ, L, [Y | R])
 2017:     end;
 2018: keysplit_2(_I, Y, _EY, [], R) ->
 2019:     [Y | R].
 2020: 
 2021: keymergel(I, [T1, [H2 | T2] | L], Acc) ->
 2022:     keymergel(I, L, [keymerge2_1(I, T1, element(I, H2), H2, T2, []) | Acc]);
 2023: keymergel(_I, [L], []) ->
 2024:     L;
 2025: keymergel(I, [L], Acc) ->
 2026:     rkeymergel(I, [lists:reverse(L, []) | Acc], []);
 2027: keymergel(I, [], Acc) ->
 2028:     rkeymergel(I, Acc, []).
 2029: 
 2030: rkeymergel(I, [[H2 | T2], T1 | L], Acc) ->
 2031:     rkeymergel(I, L, [rkeymerge2_1(I, T1, element(I, H2), H2, T2, []) | Acc]);
 2032: rkeymergel(I, [L], Acc) ->
 2033:     keymergel(I, [lists:reverse(L, []) | Acc], []);
 2034: rkeymergel(I, [], Acc) ->
 2035:     keymergel(I, Acc, []).
 2036: 
 2037: keymerge2_1(I, [H1 | T1], E2, H2, T2, M) ->
 2038:     E1 = element(I, H1),
 2039:     if 
 2040: 	E1 =< E2 ->
 2041: 	    keymerge2_1(I, T1, E2, H2, T2, [H1 | M]);
 2042: 	true ->
 2043: 	    keymerge2_2(I, T1, E1, H1, T2, [H2 | M])
 2044:     end;
 2045: keymerge2_1(_I, [], _E2, H2, T2, M) ->
 2046:     lists:reverse(T2, [H2 | M]).
 2047: 
 2048: keymerge2_2(I, T1, E1, H1, [H2 | T2], M) ->
 2049:     E2 = element(I, H2),
 2050:     if
 2051: 	E1 =< E2 ->
 2052: 	    keymerge2_1(I, T1, E2, H2, T2, [H1 | M]);
 2053: 	true ->
 2054: 	    keymerge2_2(I, T1, E1, H1, T2, [H2 | M])
 2055:     end;
 2056: keymerge2_2(_I, T1, _E1, H1, [], M) ->
 2057:     lists:reverse(T1, [H1 | M]).
 2058: 
 2059: rkeymerge2_1(I, [H1 | T1], E2, H2, T2, M) ->
 2060:     E1 = element(I, H1),
 2061:     if
 2062: 	E1 =< E2 ->
 2063: 	    rkeymerge2_2(I, T1, E1, T2, [H2 | M], H1);
 2064: 	true ->
 2065: 	    rkeymerge2_1(I, T1, E2, H2, T2, [H1 | M])
 2066:     end;
 2067: rkeymerge2_1(_I, [], _E2, H2, T2, M) ->
 2068:     lists:reverse(T2, [H2 | M]).
 2069: 
 2070: rkeymerge2_2(I, T1, E1, [H2 | T2], M, H1) ->
 2071:     E2 = element(I, H2),
 2072:     if
 2073: 	E1 =< E2 ->
 2074: 	    rkeymerge2_2(I, T1, E1, T2, [H2 | M], H1);
 2075: 	true ->
 2076: 	    rkeymerge2_1(I, T1, E2, H2, T2, [H1 | M])
 2077:     end;
 2078: rkeymerge2_2(_I, T1, _E1, [], M, H1) ->
 2079:     lists:reverse(T1, [H1 | M]).
 2080: 
 2081: 
 2082: %%%------------------------------------------------------------
 2083: 
 2084: 
 2085: seq_loop(doc) ->
 2086:     ["Test for infinite loop (OTP-2404)."];
 2087: seq_loop(suite) ->
 2088:     [];
 2089: seq_loop(Config) when is_list(Config) ->
 2090:     ?line _ = (catch lists:seq(1, 5, -1)),
 2091:     ok.
 2092: 
 2093: seq_2(doc) ->
 2094:     ["Non-error cases for seq/2"];
 2095: seq_2(suite) ->
 2096:     [];
 2097: seq_2(Config) when is_list(Config) ->
 2098:     ?line [1,2,3] = lists:seq(1,3),
 2099:     ?line [1] = lists:seq(1,1),
 2100:     ?line Big = 748274827583793785928592859,
 2101:     ?line Big1 = Big+1,
 2102:     ?line Big2 = Big+2,
 2103:     ?line [Big, Big1, Big2] = lists:seq(Big, Big+2),
 2104:     ok.
 2105: 
 2106: seq_2_e(doc) ->
 2107:     ["Error cases for seq/2"];
 2108: seq_2_e(suite) ->
 2109:     [];
 2110: seq_2_e(Config) when is_list(Config) ->
 2111:     ?line seq_error([4, 2]),
 2112:     ?line seq_error([1, a]),
 2113:     ?line seq_error([1.0, 2.0]),
 2114:     ok.
 2115: 
 2116: seq_error(Args) ->
 2117:     {'EXIT', _} = (catch apply(lists, seq, Args)).
 2118: 
 2119: seq_3(doc) ->
 2120:     ["Non-error cases for seq/3"];
 2121: seq_3(suite) ->
 2122:     [];
 2123: seq_3(Config) when is_list(Config) ->
 2124:     ?line [1,2,3] = lists:seq(1,3,1),
 2125:     ?line [1] = lists:seq(1,1,1),
 2126:     ?line Big = 748274827583793785928592859,
 2127:     ?line Big1 = Big+1,
 2128:     ?line Big2 = Big+2,
 2129:     ?line [Big, Big1, Big2] = lists:seq(Big, Big+2,1),
 2130: 
 2131:     ?line [3,2,1] = lists:seq(3,1,-1),
 2132:     ?line [1] = lists:seq(1,1,-1),
 2133: 
 2134:     ?line [3,1] = lists:seq(3,1,-2),
 2135:     ?line [1] = lists:seq(1, 10, 10),
 2136:     ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 19, 3),
 2137:     ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 20, 3),
 2138:     ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 21, 3),
 2139: 
 2140:     ?line [1] = lists:seq(1, 1, 0),		%OTP-2613
 2141:     ok.
 2142: 
 2143: seq_3_e(doc) ->
 2144:     ["Error cases for seq/3"];
 2145: seq_3_e(suite) ->
 2146:     [];
 2147: seq_3_e(Config) when is_list(Config) ->
 2148:     ?line seq_error([4, 2, 1]),
 2149:     ?line seq_error([3, 5, -1]),
 2150:     ?line seq_error([1, a, 1]),
 2151:     ?line seq_error([1.0, 2.0, 1]),
 2152: 
 2153:     ?line seq_error([1, 3, 1.0]),
 2154:     ?line seq_error([1, 3, a]),
 2155:     ?line seq_error([1, 3, 0]),
 2156: 
 2157:     ?line seq_error([a, a, 0]),
 2158:     ok.
 2159: 
 2160: otp_7230(doc) -> 
 2161:     ["OTP-7230. seq/1,2 returns the empty list"];
 2162: otp_7230(suite) ->
 2163:     [];
 2164: otp_7230(Config) when is_list(Config) ->
 2165:     From = -10,
 2166:     To = 10,
 2167:     StepFrom = -10,
 2168:     StepTo = 10,
 2169: 
 2170:     L = lists:seq(From, To),
 2171:     SL = lists:seq(StepFrom, StepTo),
 2172:     ?line [] = 
 2173:     [{F, T, S} || 
 2174:         F <- L, T <- L, S <- SL,
 2175:           not check_seq(F, T, S, catch lists:seq(F, T, S))
 2176:         orelse
 2177:           S =:= 1 andalso not check_seq(F, T, S, catch lists:seq(F, T))
 2178:         ].
 2179: 
 2180: check_seq(From, To, 0, R) ->
 2181:       From =:= To andalso R =:= [From]
 2182:     orelse
 2183:       From =/= To andalso is_tuple(R) andalso element(1, R) =:= 'EXIT';
 2184: check_seq(From, To, Step, []) when Step =/= 0 ->
 2185:       0 =:= property(From, To, Step)
 2186:     andalso 
 2187:     (
 2188:       Step > 0 andalso To < From andalso From-To =< Step
 2189:     orelse
 2190:       Step < 0 andalso To > From andalso To-From =< -Step
 2191:     );
 2192: check_seq(From, To, Step, R) when R =/= [], To < From, Step > 0 ->
 2193:     is_tuple(R) andalso element(1, R) =:= 'EXIT';
 2194: check_seq(From, To, Step, R) when R =/= [], To > From, Step < 0 ->
 2195:     is_tuple(R) andalso element(1, R) =:= 'EXIT';
 2196: check_seq(From, To, Step, L) when is_list(L), L =/= [], Step =/= 0 ->
 2197:     First = hd(L),
 2198:     Last = lists:last(L),
 2199:     Min = lists:min(L),
 2200:     Max = lists:max(L),
 2201: 
 2202:       [] =:= [E || E <- L, not is_integer(E)]
 2203:     andalso
 2204:       %% The difference between two consecutive elements is Step:
 2205:       begin
 2206:         LS = [First-Step]++L,
 2207:         LR = L++[Last+Step],
 2208:         [Step] =:= lists:usort([B-A || {A,B} <- lists:zip(LS, LR)])
 2209:       end
 2210:     andalso
 2211:       %% The first element of L is From:
 2212:       From =:= First
 2213:     andalso
 2214:       %% No element outside the given interval:
 2215:       Min >= lists:min([From, To])
 2216:     andalso
 2217:       Max =< lists:max([From, To])
 2218:     andalso
 2219:       %% All elements are present:
 2220:       abs(To-Last) < abs(Step)
 2221:     andalso
 2222:       length(L) =:= property(From, To, Step);
 2223: check_seq(_From, _To, _Step, _R) ->
 2224:     false.
 2225: 
 2226: property(From, To, Step) ->
 2227:     ((To-From+Step) div Step).
 2228: 
 2229: %%%------------------------------------------------------------
 2230: 
 2231: 
 2232: -define(sublist_error2(X,Y), ?line {'EXIT', _} = (catch lists:sublist(X,Y))).
 2233: -define(sublist_error3(X,Y,Z), ?line {'EXIT', _} = (catch lists:sublist(X,Y,Z))).
 2234: 
 2235: sublist_2(doc) ->   ["sublist/2"];
 2236: sublist_2(suite) -> [];
 2237: sublist_2(Config) when is_list(Config) ->
 2238:     ?line [] = lists:sublist([], 0),
 2239:     ?line [] = lists:sublist([], 1),
 2240:     ?line [] = lists:sublist([a], 0),
 2241:     ?line [a] = lists:sublist([a], 1),
 2242:     ?line [a] = lists:sublist([a], 2),
 2243:     ?line [a] = lists:sublist([a|b], 1),
 2244: 
 2245:     ?line [a,b] = lists:sublist([a,b|c], 2),
 2246: 
 2247:     ok.
 2248: 
 2249: sublist_2_e(doc) ->   ["sublist/2 error cases"];
 2250: sublist_2_e(suite) -> [];
 2251: sublist_2_e(Config) when is_list(Config) ->
 2252:     ?sublist_error2([], -1),
 2253:     ?sublist_error2(a, -1),
 2254:     ?sublist_error2(a, 0),
 2255:     ?sublist_error2([a|b], 2),
 2256:     ?sublist_error2([a], x),
 2257:     ?sublist_error2([a], 1.5),
 2258:     ?sublist_error2([], x),
 2259:     ?sublist_error2([], 1.5),
 2260:     ok.
 2261: 
 2262: sublist_3(doc) ->   ["sublist/3"];
 2263: sublist_3(suite) -> [];
 2264: sublist_3(Config) when is_list(Config) ->
 2265:     ?line [] = lists:sublist([], 1, 0),
 2266:     ?line [] = lists:sublist([], 1, 1),
 2267:     ?line [] = lists:sublist([a], 1, 0),
 2268:     ?line [a] = lists:sublist([a], 1, 1),
 2269:     ?line [a] = lists:sublist([a], 1, 2),
 2270:     ?line [a] = lists:sublist([a|b], 1, 1),
 2271: 
 2272:     ?line [] = lists:sublist([], 1, 0),
 2273:     ?line [] = lists:sublist([], 1, 1),
 2274:     ?line [] = lists:sublist([a], 1, 0),
 2275:     ?line [a] = lists:sublist([a], 1, 1),
 2276:     ?line [a] = lists:sublist([a], 1, 2),
 2277:     ?line [] = lists:sublist([a], 2, 1),
 2278:     ?line [] = lists:sublist([a], 2, 2),
 2279:     ?line [] = lists:sublist([a], 2, 79),
 2280:     ?line [] = lists:sublist([a,b|c], 1, 0),
 2281:     ?line [] = lists:sublist([a,b|c], 2, 0),
 2282:     ?line [a] = lists:sublist([a,b|c], 1, 1),
 2283:     ?line [b] = lists:sublist([a,b|c], 2, 1),
 2284:     ?line [a,b] = lists:sublist([a,b|c], 1, 2),
 2285: 
 2286:     ?line [] = lists:sublist([a], 2, 0),
 2287: 
 2288:     ok.
 2289: 
 2290: sublist_3_e(doc) ->   ["sublist/3 error cases"];
 2291: sublist_3_e(suite) -> [];
 2292: sublist_3_e(Config) when is_list(Config) ->
 2293:     ?sublist_error3([], 1, -1),
 2294:     ?sublist_error3(a, 1, -1),
 2295:     ?sublist_error3(a, 1, 0),
 2296:     ?sublist_error3([a|b], 1, 2),
 2297:     ?sublist_error3([a], 1, x),
 2298:     ?sublist_error3([a], 1, 1.5),
 2299:     ?sublist_error3([], 1, x),
 2300:     ?sublist_error3([], 1, 1.5),
 2301: 
 2302:     ?sublist_error3([], -1, 0),
 2303:     ?sublist_error3(a, x, -1),
 2304:     ?sublist_error3([a,b], 0.5, 1),
 2305:     ?sublist_error3([a,b], 1.5, 1),
 2306:     ?sublist_error3([a], 1, x),
 2307:     ?sublist_error3([a], 1, 1.5),
 2308:     ?sublist_error3([], 1, x),
 2309:     ?sublist_error3([], 1, 1.5),
 2310: 
 2311:     ?sublist_error3([a], 0, -1),
 2312:     ?sublist_error3([a], 1, -1),
 2313:     ?sublist_error3([a], 2, -1),
 2314:     ?sublist_error3([a], 0, 0),
 2315:     ?sublist_error3([a], 0, 1),
 2316: 
 2317:     ?sublist_error3([a,b|c], 2, 2),
 2318:     ?sublist_error3([a,b|c], 3, 0),
 2319:     ?sublist_error3([a,b|c], 3, 1),
 2320:     ok.
 2321: 
 2322: %%%------------------------------------------------------------
 2323: 
 2324: 
 2325: -define(flatten_error1(X), ?line {'EXIT', _} = (catch lists:flatten(X))).
 2326: -define(flatten_error2(X,Y), ?line {'EXIT', _} = (catch lists:flatten(X,Y))).
 2327: 
 2328: flatten_1(doc) ->   ["flatten/1"];
 2329: flatten_1(suite) -> [];
 2330: flatten_1(Config) when is_list(Config) ->
 2331:     ?line [] = lists:flatten([]),
 2332:     ?line [1,2] = lists:flatten([1,2]),
 2333:     ?line [1,2] = lists:flatten([1,[2]]),
 2334:     ?line [1,2] = lists:flatten([[1],2]),
 2335:     ?line [1,2] = lists:flatten([[1],[2]]),
 2336:     ?line [1,2] = lists:flatten([[1,2]]),
 2337:     ?line [a,b,c,d] = lists:flatten([[a],[b,c,[d]]]),
 2338: 
 2339:     ok.
 2340: 
 2341: flatten_1_e(doc) ->   ["flatten/1 error cases"];
 2342: flatten_1_e(suite) -> [];
 2343: flatten_1_e(Config) when is_list(Config) ->
 2344:     ?flatten_error1(a),
 2345:     ?flatten_error1([a|b]),
 2346:     ?flatten_error1([[a],[b|c],[d]]),
 2347:     ok.
 2348: 
 2349: %%% [arndt] What if second arg isn't a proper list? This issue isn't
 2350: %%% clear-cut. Right now, I think that any term should be allowed.
 2351: %%% But I also wish this function didn't exist at all.
 2352: 
 2353: flatten_2(doc) ->   ["flatten/2"];
 2354: flatten_2(suite) -> [];
 2355: flatten_2(Config) when is_list(Config) ->
 2356:     ?line [] = lists:flatten([]),
 2357:     ?line [a] = lists:flatten([a]),
 2358:     ok.
 2359: 
 2360: flatten_2_e(doc) ->   ["flatten/2 error cases"];
 2361: flatten_2_e(suite) -> [];
 2362: flatten_2_e(Config) when is_list(Config) ->
 2363:     ok.
 2364: 
 2365: %% Test lists:zip/2, lists:unzip/1.
 2366: zip_unzip(Config) when is_list(Config) ->
 2367:     ?line [] = lists:zip([], []),
 2368:     ?line [{a,b}] = lists:zip([a], [b]),
 2369:     ?line [{42.0,{kalle,nisse}},{a,b}] = lists:zip([42.0,a], [{kalle,nisse},b]),
 2370: 
 2371:     %% Longer lists.
 2372:     ?line SeqA = lists:seq(45, 200),
 2373:     ?line SeqB = [A*A || A <- SeqA],
 2374:     ?line AB = lists:zip(SeqA, SeqB),
 2375:     ?line SeqA = [A || {A,_} <- AB],
 2376:     ?line SeqB = [B || {_,B} <- AB],
 2377:     ?line {SeqA,SeqB} = lists:unzip(AB),
 2378:     
 2379:     %% Some more unzip/1.
 2380:     ?line {[],[]} = lists:unzip([]),
 2381:     ?line {[a],[b]} = lists:unzip([{a,b}]),
 2382:     ?line {[a,c],[b,d]} = lists:unzip([{a,b},{c,d}]),
 2383: 
 2384:     %% Error cases.
 2385:     ?line {'EXIT',{function_clause,_}} = (catch lists:zip([], [b])),
 2386:     ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [])),
 2387:     ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [b,c])),
 2388:     ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [b,c])),
 2389:     ok.
 2390: 
 2391: %% Test lists:zip3/3, lists:unzip3/1.
 2392: zip_unzip3(Config) when is_list(Config) ->
 2393:     ?line [] = lists:zip3([], [], []),
 2394:     ?line [{a,b,c}] = lists:zip3([a], [b], [c]),
 2395: 
 2396:     %% Longer lists.
 2397:     ?line SeqA = lists:seq(45, 200),
 2398:     ?line SeqB = [2*A || A <- SeqA],
 2399:     ?line SeqC = [A*A || A <- SeqA],
 2400:     ?line ABC = lists:zip3(SeqA, SeqB, SeqC),
 2401:     ?line SeqA = [A || {A,_,_} <- ABC],
 2402:     ?line SeqB = [B || {_,B,_} <- ABC],
 2403:     ?line SeqC = [C || {_,_,C} <- ABC],
 2404:     ?line {SeqA,SeqB,SeqC} = lists:unzip3(ABC),
 2405: 
 2406:     %% Some more unzip3/1.
 2407:     ?line {[],[],[]} = lists:unzip3([]),
 2408:     ?line {[a],[b],[c]} = lists:unzip3([{a,b,c}]),
 2409: 
 2410:     %% Error cases.
 2411:     ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([], [], [c])),
 2412:     ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([], [b], [])),
 2413:     ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([a], [], [])),
 2414: 
 2415:     ok.
 2416: 
 2417: %% Test lists:zipwith/3.
 2418: zipwith(Config) when is_list(Config) ->
 2419:     Zip = fun(A, B) -> [A|B] end,
 2420: 
 2421:     ?line [] = lists:zipwith(Zip, [], []),
 2422:     ?line [[a|b]] = lists:zipwith(Zip, [a], [b]),
 2423: 
 2424:     %% Longer lists.
 2425:     ?line SeqA = lists:seq(77, 300),
 2426:     ?line SeqB = [A*A || A <- SeqA],
 2427:     ?line AB = lists:zipwith(Zip, SeqA, SeqB),
 2428:     ?line SeqA = [A || [A|_] <- AB],
 2429:     ?line SeqB = [B || [_|B] <- AB],
 2430:     
 2431:     %% Error cases.
 2432:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(badfun, [], [])),
 2433:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [], [b])),
 2434:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [])),
 2435:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [b,c])),
 2436:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [b,c])),
 2437:     ok.
 2438: 
 2439: %% Test lists:zipwith3/4.
 2440: zipwith3(Config) when is_list(Config) ->
 2441:     Zip = fun(A, B, C) -> [A,B,C] end,
 2442: 
 2443:     ?line [] = lists:zipwith3(Zip, [], [], []),
 2444:     ?line [[a,b,c]] = lists:zipwith3(Zip, [a], [b], [c]),
 2445: 
 2446:     %% Longer lists.
 2447:     ?line SeqA = lists:seq(45, 200),
 2448:     ?line SeqB = [2*A || A <- SeqA],
 2449:     ?line SeqC = [A*A || A <- SeqA],
 2450:     ?line ABC = lists:zipwith3(Zip, SeqA, SeqB, SeqC),
 2451:     ?line SeqA = [A || [A,_,_] <- ABC],
 2452:     ?line SeqB = [B || [_,B,_] <- ABC],
 2453:     ?line SeqC = [C || [_,_,C] <- ABC],
 2454: 
 2455:     %% Error cases.
 2456:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(badfun, [], [], [])),
 2457:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [], [], [c])),
 2458:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [], [b], [])),
 2459:     ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [a], [], [])),
 2460: 
 2461:     ok.
 2462: 
 2463: %% Test lists:filter/2, lists:partition/2.
 2464: filter_partition(Config) when is_list(Config) ->
 2465:     F = fun(I) -> I rem 2 =:= 0 end,
 2466:     ?line filpart(F, [], []),
 2467:     ?line filpart(F, [1], []),
 2468:     ?line filpart(F, [1,3,17], []),
 2469:     ?line filpart(F, [1,2,3,17], [2]),
 2470:     ?line filpart(F, [6,8,1,2,3,17], [6,8,2]),
 2471:     ?line filpart(F, [6,8,1,2,42,3,17], [6,8,2,42]),
 2472: 
 2473:     %% Error cases.
 2474:     ?line {'EXIT',{function_clause,_}} = (catch lists:filter(badfun, [])),
 2475:     ?line {'EXIT',{function_clause,_}} = (catch lists:partition(badfun, [])),
 2476:     ok.
 2477: 
 2478: filpart(F, All, Exp) ->
 2479:     Exp = lists:filter(F, All),
 2480:     Other = lists:filter(fun(E) -> not F(E) end, All),
 2481:     {Exp,Other} = lists:partition(F, All).
 2482: 
 2483: 
 2484: otp_5939(doc) ->   ["OTP-5939. Guard tests added."];
 2485: otp_5939(suite) -> [];
 2486: otp_5939(Config) when is_list(Config) ->
 2487:     Fun1 = fun(A) -> A end,
 2488:     Fun2 = fun(A, B) -> {A,B} end,
 2489:     Fun3 = fun(A, B, C) -> {A,B,C} end,
 2490:     Pred = fun(_A) -> true end,
 2491:     Fold = fun(_E, A) -> A end,
 2492:     MapFold = fun(E, A) -> {E,A} end,
 2493: 
 2494:     ?line {'EXIT', _} = (catch lists:usort( [asd], [qwe])),
 2495: 
 2496:     ?line {'EXIT', _} = (catch lists:zipwith(func, [], [])),
 2497:     ?line [] = lists:zipwith(Fun2, [], []),
 2498:     ?line {'EXIT', _} = (catch lists:zipwith3(func, [], [], [])),
 2499:     ?line [] = lists:zipwith3(Fun3, [], [], []),
 2500:     ?line {'EXIT', _} = (catch lists:keymap(func, 1, [])),
 2501:     ?line {'EXIT', _} = (catch lists:keymap(Fun1, 0, [])),
 2502:     ?line [] = lists:keymap(Fun1, 1, []),
 2503:     ?line {'EXIT', _} = (catch lists:merge(func, [], [1])),
 2504:     ?line {'EXIT', _} = (catch lists:merge(func, [1], [])),
 2505:     ?line [] = lists:merge(Fun2, [], []),
 2506:     ?line {'EXIT', _} = (catch lists:rmerge(func, [], [1])),
 2507:     ?line {'EXIT', _} = (catch lists:rmerge(func, [1], [])),
 2508:     ?line [] = lists:rmerge(Fun2, [], []),
 2509:     ?line {'EXIT', _} = (catch lists:usort(func, [])),
 2510:     ?line {'EXIT', _} = (catch lists:usort(func, [a])),
 2511:     ?line {'EXIT', _} = (catch lists:usort(func, [a, b])),
 2512:     ?line [] = lists:usort(Fun2, []),
 2513:     ?line {'EXIT', _} = (catch lists:umerge(func, [], [1])),
 2514:     ?line {'EXIT', _} = (catch lists:merge(func, [1], [])),
 2515:     ?line [] = lists:umerge(Fun2, [], []),
 2516:     ?line {'EXIT', _} = (catch lists:rumerge(func, [], [1])),
 2517:     ?line {'EXIT', _} = (catch lists:rumerge(func, [1], [])),
 2518:     ?line [] = lists:rumerge(Fun2, [], []),
 2519:     ?line {'EXIT', _} = (catch lists:all(func, [])),
 2520:     ?line true = lists:all(Pred, []),
 2521:     ?line {'EXIT', _} = (catch lists:any(func, [])),
 2522:     ?line false = lists:any(Pred, []),
 2523:     ?line {'EXIT', _} = (catch lists:map(func, [])),
 2524:     ?line [] = lists:map(Fun1, []),
 2525:     ?line {'EXIT', _} = (catch lists:flatmap(func, [])),
 2526:     ?line [] = lists:flatmap(Fun1, []),
 2527:     ?line {'EXIT', _} = (catch lists:foldl(func, [], [])),
 2528:     ?line [] = lists:foldl(Fold, [], []),
 2529:     ?line {'EXIT', _} = (catch lists:foldr(func, [], [])),
 2530:     ?line [] = lists:foldr(Fold, [], []),
 2531:     ?line {'EXIT', _} = (catch lists:filter(func, [])),
 2532:     ?line [] = lists:filter(Pred, []),
 2533:     ?line {'EXIT', _} = (catch lists:partition(func, [])),
 2534:     ?line {[],[]} = lists:partition(Pred, []),
 2535:     ?line {'EXIT', _} = (catch lists:filtermap(func, [])),
 2536:     ?line [] = lists:filtermap(Fun1, []),
 2537:     ?line {'EXIT', _} = (catch lists:foreach(func, [])),
 2538:     ?line ok = lists:foreach(Fun1, []),
 2539:     ?line {'EXIT', _} = (catch lists:mapfoldl(func, [], [])),
 2540:     ?line {[],[]} = lists:mapfoldl(MapFold, [], []),
 2541:     ?line {'EXIT', _} = (catch lists:mapfoldr(func, [], [])),
 2542:     ?line {[],[]} = lists:mapfoldr(MapFold, [], []),
 2543:     ?line {'EXIT', _} = (catch lists:takewhile(func, [])),
 2544:     ?line [] = lists:takewhile(Pred, []),
 2545:     ?line {'EXIT', _} = (catch lists:dropwhile(func, [])),
 2546:     ?line [] = lists:dropwhile(Pred, []),
 2547:     ?line {'EXIT', _} = (catch lists:splitwith(func, [])),
 2548:     ?line {[],[]} = lists:splitwith(Pred, []),
 2549: 
 2550:     ok.
 2551: 
 2552: otp_6023(doc) ->   ["OTP-6023. lists:keyreplace/4, a typecheck."];
 2553: otp_6023(suite) -> [];
 2554: otp_6023(Config) when is_list(Config) ->
 2555:     ?line {'EXIT', _} = (catch lists:keyreplace(a, 2, [{1,a}], b)),
 2556:     ?line [{2,b}] = lists:keyreplace(a, 2, [{1,a}], {2,b}),
 2557: 
 2558:     ok.
 2559: 
 2560: otp_6606(doc) ->   ["OTP-6606. sort and keysort bug"];
 2561: otp_6606(suite) -> [];
 2562: otp_6606(Config) when is_list(Config) ->
 2563:     I = 1,
 2564:     F = float(1),
 2565:     L1 = [{F,I},{F,F},{I,I},{I,F}],
 2566:     ?line L1 = lists:keysort(1, L1),
 2567:     ?line L1 = lists:sort(L1),
 2568:     L2 = [{I,I},{I,F},{F,I},{F,F}],
 2569:     ?line L2 = lists:keysort(1, L2),
 2570:     ?line L2 = lists:sort(L2),
 2571:     ok.
 2572: 
 2573: %% Test lists:suffix/2.
 2574: suffix(Config) when is_list(Config) ->
 2575:     ?line true = lists:suffix([], []),
 2576:     ?line true = lists:suffix([], [a]),
 2577:     ?line true = lists:suffix([], [a,b]),
 2578:     ?line true = lists:suffix([], [a,b,c]),
 2579:     ?line true = lists:suffix([a], lists:duplicate(200000, a)),
 2580:     ?line true = lists:suffix(lists:seq(1, 1024),
 2581: 			      lists:seq(2, 64000) ++ lists:seq(1, 1024)),
 2582:     ?line true = lists:suffix(lists:duplicate(20000, a),
 2583: 			      lists:duplicate(200000, a)),
 2584:     ?line true = lists:suffix([2.0,3.0], [1.0,2.0,3.0]),
 2585: 
 2586:     %% False cases.
 2587:     ?line false = lists:suffix([a], []),
 2588:     ?line false = lists:suffix([a,b,c], []),
 2589:     ?line false = lists:suffix([a,b,c], [b,c]),
 2590:     ?line false = lists:suffix([a,b,c], [a,b,c,a,b]),
 2591:     ?line false = lists:suffix(lists:duplicate(199999, a)++[b],
 2592: 			       lists:duplicate(200000, a)),
 2593:     ?line false = lists:suffix([2.0,3.0], [1,2,3]),
 2594: 
 2595:     %% Error cases.
 2596:     ?line {'EXIT',_} = (catch lists:suffix({a,b,c}, [])),
 2597:     ?line {'EXIT',_} = (catch lists:suffix([], {a,b})),
 2598:     ?line {'EXIT',_} = (catch lists:suffix([a|b], [])),
 2599:     ?line {'EXIT',_} = (catch lists:suffix([a,b|c], [a|b])),
 2600:     ?line {'EXIT',_} = (catch lists:suffix([a|b], [a,b|c])),
 2601:     ?line {'EXIT',_} = (catch lists:suffix([a|b], [a|b])),
 2602:     
 2603:     ok.
 2604: 
 2605: %% Test lists:subtract/2 and the '--' operator.
 2606: subtract(Config) when is_list(Config) ->
 2607:     ?line [] = sub([], []),
 2608:     ?line [] = sub([], [a]),
 2609:     ?line [] = sub([], lists:seq(1, 1024)),
 2610:     ?line sub_non_matching([a], []),
 2611:     ?line sub_non_matching([1,2], [make_ref()]),
 2612:     ?line sub_non_matching(lists:seq(1, 1024), [make_ref(),make_ref()]),
 2613:     
 2614:     %% Matching subtracts.
 2615:     ?line [] = sub([a], [a]),
 2616:     ?line [a] = sub([a,b], [b]),
 2617:     ?line [a] = sub([a,b], [b,c]),
 2618:     ?line [a] = sub([a,b,c], [b,c]),
 2619:     ?line [a] = sub([a,b,c], [b,c]),
 2620:     ?line [d,a,a] = sub([a,b,c,d,a,a], [a,b,c]),
 2621:     ?line [d,x,a] = sub([a,b,c,d,a,x,a], [a,b,c,a]),
 2622:     ?line [1,2,3,4,5,6,7,8,9,9999,10000,20,21,22] =
 2623: 	sub(lists:seq(1, 10000)++[20,21,22], lists:seq(10, 9998)),
 2624: 
 2625:     %% Floats/integers.
 2626:     ?line [42.0,42.0] = sub([42.0,42,42.0], [42,42,42]),
 2627:     ?line [1,2,3,4,43.0] = sub([1,2,3,4,5,42.0,43.0], [42.0,5]),
 2628: 
 2629:     %% Crashing subtracts.
 2630:     ?line {'EXIT',_} = (catch sub([], [a|b])),
 2631:     ?line {'EXIT',_} = (catch sub([a], [a|b])),
 2632:     ?line {'EXIT',_} = (catch sub([a|b], [])),
 2633:     ?line {'EXIT',_} = (catch sub([a|b], [])),
 2634:     ?line {'EXIT',_} = (catch sub([a|b], [a])),
 2635: 
 2636:     ok.
 2637: 
 2638: sub_non_matching(A, B) ->
 2639:     A = sub(A, B).
 2640:     
 2641: sub(A, B) ->
 2642:     Res = A -- B,
 2643:     Res = lists:subtract(A, B).
 2644: