;; lists-ext tests — lists:sort/1, lists:sort/2, lists:usort/1. ;; Each case evaluates an Erlang expression that reduces to the bool ;; atom `true` (via =:= on the sorted result) and checks its name. (define er-lx-test-count 0) (define er-lx-test-pass 0) (define er-lx-test-fails (list)) (define er-lx-test (fn (name actual expected) (set! er-lx-test-count (+ er-lx-test-count 1)) (if (= actual expected) (set! er-lx-test-pass (+ er-lx-test-pass 1)) (append! er-lx-test-fails {:name name :expected expected :actual actual})))) ;; eval an Erlang source string and return the result atom's name (define er-lx-nm (fn (src) (get (erlang-eval-ast src) :name))) ;; ── lists:sort/1 ────────────────────────────────────────────────── (er-lx-test "sort/1 ascending" (er-lx-nm "lists:sort([3,1,2]) =:= [1,2,3]") "true") (er-lx-test "sort/1 already sorted" (er-lx-nm "lists:sort([1,2,3]) =:= [1,2,3]") "true") (er-lx-test "sort/1 empty" (er-lx-nm "lists:sort([]) =:= []") "true") (er-lx-test "sort/1 singleton" (er-lx-nm "lists:sort([7]) =:= [7]") "true") (er-lx-test "sort/1 keeps duplicates" (er-lx-nm "lists:sort([3,1,2,1]) =:= [1,1,2,3]") "true") (er-lx-test "sort/1 length preserved" (erlang-eval-ast "length(lists:sort([5,4,3,2,1]))") 5) (er-lx-test "sort/1 term order: number < atom" (er-lx-nm "lists:sort([b,a,1]) =:= [1,a,b]") "true") (er-lx-test "sort/1 tuples elementwise" (er-lx-nm "lists:sort([{2,a},{1,b},{1,a}]) =:= [{1,a},{1,b},{2,a}]") "true") ;; ── lists:sort/2 ────────────────────────────────────────────────── (er-lx-test "sort/2 ascending =<" (er-lx-nm "lists:sort(fun(A,B) -> A =< B end, [3,1,2]) =:= [1,2,3]") "true") (er-lx-test "sort/2 descending >=" (er-lx-nm "lists:sort(fun(A,B) -> A >= B end, [1,3,2]) =:= [3,2,1]") "true") (er-lx-test "sort/2 stable on equal keys" (er-lx-nm "lists:sort(fun({A,_},{B,_}) -> A =< B end, [{1,x},{1,y},{0,z}]) =:= [{0,z},{1,x},{1,y}]") "true") (er-lx-test "sort/2 empty" (er-lx-nm "lists:sort(fun(A,B) -> A =< B end, []) =:= []") "true") ;; ── lists:usort/1 ───────────────────────────────────────────────── (er-lx-test "usort/1 removes duplicates" (er-lx-nm "lists:usort([3,1,2,1,3]) =:= [1,2,3]") "true") (er-lx-test "usort/1 empty" (er-lx-nm "lists:usort([]) =:= []") "true") (er-lx-test "usort/1 all equal collapses to one" (er-lx-nm "lists:usort([5,5,5]) =:= [5]") "true") (er-lx-test "usort/1 already unique" (er-lx-nm "lists:usort([1,2,3]) =:= [1,2,3]") "true") (er-lx-test "usort/1 length after dedup" (erlang-eval-ast "length(lists:usort([4,4,2,2,1,1,4]))") 3) ;; ── lists:keyfind/3 ─────────────────────────────────────────────── (er-lx-test "keyfind hit" (erlang-eval-ast "element(2, lists:keyfind(b, 1, [{a,1},{b,2},{c,3}]))") 2) (er-lx-test "keyfind first match only" (erlang-eval-ast "element(2, lists:keyfind(a, 1, [{a,1},{a,9}]))") 1) (er-lx-test "keyfind miss returns false" (er-lx-nm "lists:keyfind(z, 1, [{a,1},{b,2}])") "false") (er-lx-test "keyfind on second element" (er-lx-nm "element(1, lists:keyfind(2, 2, [{a,1},{b,2}]))") "b") (er-lx-test "keyfind skips short tuples" (er-lx-nm "lists:keyfind(x, 2, [{x},{y,x}]) =:= {y,x}") "true") ;; ── lists:keymember/3 ───────────────────────────────────────────── (er-lx-test "keymember true" (er-lx-nm "lists:keymember(b, 1, [{a,1},{b,2}])") "true") (er-lx-test "keymember false" (er-lx-nm "lists:keymember(z, 1, [{a,1},{b,2}])") "false") ;; ── lists:keydelete/3 ───────────────────────────────────────────── (er-lx-test "keydelete removes first match" (er-lx-nm "lists:keydelete(b, 1, [{a,1},{b,2},{c,3}]) =:= [{a,1},{c,3}]") "true") (er-lx-test "keydelete only first" (er-lx-nm "lists:keydelete(a, 1, [{a,1},{a,2},{b,3}]) =:= [{a,2},{b,3}]") "true") (er-lx-test "keydelete miss unchanged" (er-lx-nm "lists:keydelete(z, 1, [{a,1},{b,2}]) =:= [{a,1},{b,2}]") "true") ;; ── lists:keyreplace/4 ──────────────────────────────────────────── (er-lx-test "keyreplace hit" (er-lx-nm "lists:keyreplace(b, 1, [{a,1},{b,2},{c,3}], {b,99}) =:= [{a,1},{b,99},{c,3}]") "true") (er-lx-test "keyreplace miss unchanged" (er-lx-nm "lists:keyreplace(z, 1, [{a,1}], {z,0}) =:= [{a,1}]") "true") ;; ── lists:keystore/4 ────────────────────────────────────────────── (er-lx-test "keystore replaces existing" (er-lx-nm "lists:keystore(b, 1, [{a,1},{b,2}], {b,99}) =:= [{a,1},{b,99}]") "true") (er-lx-test "keystore appends when absent" (er-lx-nm "lists:keystore(z, 1, [{a,1},{b,2}], {z,0}) =:= [{a,1},{b,2},{z,0}]") "true") ;; ── lists:keytake/3 ─────────────────────────────────────────────── (er-lx-test "keytake hit value tag" (er-lx-nm "element(1, lists:keytake(b, 1, [{a,1},{b,2},{c,3}]))") "value") (er-lx-test "keytake hit tuple" (er-lx-nm "element(2, lists:keytake(b, 1, [{a,1},{b,2},{c,3}])) =:= {b,2}") "true") (er-lx-test "keytake hit rest" (er-lx-nm "element(3, lists:keytake(b, 1, [{a,1},{b,2},{c,3}])) =:= [{a,1},{c,3}]") "true") (er-lx-test "keytake miss false" (er-lx-nm "lists:keytake(z, 1, [{a,1}])") "false") ;; ── lists:keysort/2 ─────────────────────────────────────────────── (er-lx-test "keysort by element 1" (er-lx-nm "lists:keysort(1, [{c,3},{a,1},{b,2}]) =:= [{a,1},{b,2},{c,3}]") "true") (er-lx-test "keysort by element 2" (er-lx-nm "lists:keysort(2, [{a,3},{b,1},{c,2}]) =:= [{b,1},{c,2},{a,3}]") "true") (er-lx-test "keysort stable on equal keys" (er-lx-nm "lists:keysort(1, [{a,1},{a,2},{a,3}]) =:= [{a,1},{a,2},{a,3}]") "true") ;; ── lists:foldr/3 ───────────────────────────────────────────────── (er-lx-test "foldr preserves order" (er-lx-nm "lists:foldr(fun(X,Acc) -> [X|Acc] end, [], [1,2,3]) =:= [1,2,3]") "true") (er-lx-test "foldr sum" (erlang-eval-ast "lists:foldr(fun(X,A) -> X+A end, 0, [1,2,3,4])") 10) (er-lx-test "foldr empty returns acc" (erlang-eval-ast "lists:foldr(fun(X,A) -> X+A end, 42, [])") 42) ;; ── lists:partition/2 ───────────────────────────────────────────── (er-lx-test "partition evens/odds" (er-lx-nm "lists:partition(fun(X) -> X rem 2 =:= 0 end, [1,2,3,4,5]) =:= {[2,4],[1,3,5]}") "true") (er-lx-test "partition all satisfy" (er-lx-nm "lists:partition(fun(_) -> true end, [1,2]) =:= {[1,2],[]}") "true") (er-lx-test "partition empty" (er-lx-nm "lists:partition(fun(_) -> true end, []) =:= {[],[]}") "true") ;; ── lists:takewhile/2 ───────────────────────────────────────────── (er-lx-test "takewhile prefix" (er-lx-nm "lists:takewhile(fun(X) -> X < 3 end, [1,2,3,4,1]) =:= [1,2]") "true") (er-lx-test "takewhile none" (er-lx-nm "lists:takewhile(fun(X) -> X < 0 end, [1,2]) =:= []") "true") (er-lx-test "takewhile all" (er-lx-nm "lists:takewhile(fun(X) -> X < 9 end, [1,2,3]) =:= [1,2,3]") "true") ;; ── lists:dropwhile/2 ───────────────────────────────────────────── (er-lx-test "dropwhile prefix" (er-lx-nm "lists:dropwhile(fun(X) -> X < 3 end, [1,2,3,4,1]) =:= [3,4,1]") "true") (er-lx-test "dropwhile all" (er-lx-nm "lists:dropwhile(fun(X) -> X < 9 end, [1,2,3]) =:= []") "true") (er-lx-test "dropwhile none" (er-lx-nm "lists:dropwhile(fun(X) -> X < 0 end, [1,2]) =:= [1,2]") "true") ;; ── lists:splitwith/2 ───────────────────────────────────────────── (er-lx-test "splitwith" (er-lx-nm "lists:splitwith(fun(X) -> X < 3 end, [1,2,3,4,1]) =:= {[1,2],[3,4,1]}") "true") (er-lx-test "splitwith empty" (er-lx-nm "lists:splitwith(fun(_) -> true end, []) =:= {[],[]}") "true") ;; ── lists:flatten/1 ─────────────────────────────────────────────── (er-lx-test "flatten nested" (er-lx-nm "lists:flatten([1,[2,[3,4]],5]) =:= [1,2,3,4,5]") "true") (er-lx-test "flatten already flat" (er-lx-nm "lists:flatten([1,2,3]) =:= [1,2,3]") "true") (er-lx-test "flatten empty" (er-lx-nm "lists:flatten([]) =:= []") "true") (er-lx-test "flatten deep empties" (er-lx-nm "lists:flatten([[],[1],[[]]]) =:= [1]") "true") (er-lx-test "flatten length" (erlang-eval-ast "length(lists:flatten([[1,2],[3],[4,5,6]]))") 6) ;; ── lists:max/1 ─────────────────────────────────────────────────── (er-lx-test "max ints" (erlang-eval-ast "lists:max([3,1,4,1,5,9,2,6])") 9) (er-lx-test "max single" (erlang-eval-ast "lists:max([7])") 7) (er-lx-test "max atoms term order" (er-lx-nm "lists:max([a,c,b]) =:= c") "true") ;; ── lists:min/1 ─────────────────────────────────────────────────── (er-lx-test "min ints" (erlang-eval-ast "lists:min([3,1,4,1,5])") 1) (er-lx-test "min mixed term order" (er-lx-nm "lists:min([a,1,b]) =:= 1") "true") ;; ── lists:zip/2 ─────────────────────────────────────────────────── (er-lx-test "zip pairs" (er-lx-nm "lists:zip([a,b,c],[1,2,3]) =:= [{a,1},{b,2},{c,3}]") "true") (er-lx-test "zip empty" (er-lx-nm "lists:zip([],[]) =:= []") "true") (er-lx-test "zip length" (erlang-eval-ast "length(lists:zip([1,2],[3,4]))") 2) ;; ── lists:zipwith/3 ─────────────────────────────────────────────── (er-lx-test "zipwith sum" (er-lx-nm "lists:zipwith(fun(X,Y) -> X+Y end, [1,2,3], [10,20,30]) =:= [11,22,33]") "true") (er-lx-test "zipwith tuple" (er-lx-nm "lists:zipwith(fun(X,Y) -> {X,Y} end, [a], [1]) =:= [{a,1}]") "true") ;; ── lists:unzip/1 ───────────────────────────────────────────────── (er-lx-test "unzip" (er-lx-nm "lists:unzip([{a,1},{b,2},{c,3}]) =:= {[a,b,c],[1,2,3]}") "true") (er-lx-test "unzip empty" (er-lx-nm "lists:unzip([]) =:= {[],[]}") "true") (er-lx-test "zip/unzip roundtrip" (er-lx-nm "lists:unzip(lists:zip([1,2],[3,4])) =:= {[1,2],[3,4]}") "true") ;; ── lists:sublist/2,3 ───────────────────────────────────────────── (er-lx-test "sublist/2 first n" (er-lx-nm "lists:sublist([1,2,3,4,5],3) =:= [1,2,3]") "true") (er-lx-test "sublist/2 over length" (er-lx-nm "lists:sublist([1,2],5) =:= [1,2]") "true") (er-lx-test "sublist/2 zero" (er-lx-nm "lists:sublist([1,2,3],0) =:= []") "true") (er-lx-test "sublist/3 mid" (er-lx-nm "lists:sublist([1,2,3,4,5],2,3) =:= [2,3,4]") "true") (er-lx-test "sublist/3 to end" (er-lx-nm "lists:sublist([1,2,3],2,10) =:= [2,3]") "true") ;; ── lists:nthtail/2 ─────────────────────────────────────────────── (er-lx-test "nthtail mid" (er-lx-nm "lists:nthtail(2,[1,2,3,4]) =:= [3,4]") "true") (er-lx-test "nthtail zero" (er-lx-nm "lists:nthtail(0,[1,2]) =:= [1,2]") "true") (er-lx-test "nthtail full" (er-lx-nm "lists:nthtail(3,[1,2,3]) =:= []") "true") ;; ── lists:split/2 ───────────────────────────────────────────────── (er-lx-test "split mid" (er-lx-nm "lists:split(2,[1,2,3,4,5]) =:= {[1,2],[3,4,5]}") "true") (er-lx-test "split zero" (er-lx-nm "lists:split(0,[1,2]) =:= {[],[1,2]}") "true") (er-lx-test "split full" (er-lx-nm "lists:split(3,[1,2,3]) =:= {[1,2,3],[]}") "true") ;; ── lists:droplast/1 ────────────────────────────────────────────── (er-lx-test "droplast" (er-lx-nm "lists:droplast([1,2,3]) =:= [1,2]") "true") (er-lx-test "droplast single" (er-lx-nm "lists:droplast([9]) =:= []") "true")