diff --git a/test/assocListTest.mo b/test/assocListTest.mo new file mode 100644 index 00000000..a4e7210b --- /dev/null +++ b/test/assocListTest.mo @@ -0,0 +1,255 @@ +import AssocList "mo:base/AssocList"; +import List "mo:base/List"; +import Nat "mo:base/Nat"; +import Debug "mo:base/Debug"; + +import Suite "mo:matchers/Suite"; +import T "mo:matchers/Testable"; +import M "mo:matchers/Matchers"; + +type AssocList = AssocList.AssocList; + +// Utility functions for testing +func assocListTest(array : [(Nat, Nat)]) : M.Matcher { + let map = List.fromArray(array); + let testableItem : T.TestableItem = { + display = func l { debug_show l }; + equals = func(l1, l2) { + List.equal<(Nat, Nat)>(l1, l2, func(p1, p2) = p1.0 == p2.0 and p1.1 == p2.1) + }; + item = map + }; + + M.equals(testableItem) +}; +func natOptAdd(v1 : ?Nat, v2 : ?Nat) : Nat { + switch (v1, v2) { + case (?v1, ?v2) v1 + v2; + case (?v1, null) v1; + case (null, ?v2) v2; + case (null, null) Debug.trap "Unreachable in assocListTest" + } +}; + +// Sample association lists for testing +let map1 = List.fromArray([(0, 10), (2, 12), (4, 14)]); +let map2 = List.fromArray([(1, 11), (2, 12)]); +let map3 = List.fromArray([(1, 11), (3, 13), (5, 15)]); + +let suite = Suite.suite( + "AssocList", + [ + Suite.test( + "find", + AssocList.find(map1, 0, Nat.equal), + M.equals(T.optional(T.natTestable, ?10 : ?Nat)) + ), + Suite.test( + "find empty", + AssocList.find(List.nil(), 0, Nat.equal), + M.equals(T.optional(T.natTestable, null : ?Nat)) + ), + Suite.test( + "replace", + AssocList.replace(map1, 4, Nat.equal, ?24).0, + assocListTest([(0, 10), (2, 12), (4, 24)]) + ), + Suite.test( + "replace empty", + AssocList.replace(List.nil(), 4, Nat.equal, ?24).0, + assocListTest([(4, 24)]) + ), + Suite.test( + "replace new entry", + AssocList.replace(map1, 1, Nat.equal, ?11).0, + assocListTest([(0, 10), (2, 12), (4, 14), (1, 11)]) + ), + Suite.test( + "diff no overlap", + AssocList.diff(map1, map3, Nat.equal), + assocListTest([(0, 10), (2, 12), (4, 14)]) + ), + Suite.test( + "diff empty first", + AssocList.diff(List.nil(), map3, Nat.equal), + assocListTest([]) + ), + Suite.test( + "diff empty second", + AssocList.diff(map1, List.nil(), Nat.equal), + assocListTest([(0, 10), (2, 12), (4, 14)]) + ), + Suite.test( + "diff both empty", + AssocList.diff(List.nil(), List.nil(), Nat.equal), + assocListTest([]) + ), + Suite.test( + "mapAppend", + AssocList.mapAppend( + map1, + map2, + natOptAdd + ), + assocListTest([(0, 10), (2, 12), (4, 14), (1, 11), (2, 12)]) + ), + Suite.test( + "mapAppend no overlap", + AssocList.mapAppend( + map1, + map3, + natOptAdd + ), + assocListTest([(0, 10), (2, 12), (4, 14), (1, 11), (3, 13), (5, 15)]) + ), + Suite.test( + "mapAppend first empty", + AssocList.mapAppend( + List.nil(), + map3, + natOptAdd + ), + assocListTest([(1, 11), (3, 13), (5, 15)]) + ), + Suite.test( + "mapAppend second empty", + AssocList.mapAppend( + map3, + List.nil(), + natOptAdd + ), + assocListTest([(1, 11), (3, 13), (5, 15)]) + ), + Suite.test( + "mapAppend both empty", + AssocList.mapAppend( + List.nil(), + List.nil(), + natOptAdd + ), + assocListTest([]) + ), + // FIXME disjDisjoint is equivalent to mapAppend + Suite.test( + "disj", + AssocList.disj( + map1, + map2, + Nat.equal, + natOptAdd + ), + assocListTest([(0, 10), (4, 14), (1, 11), (2, 24)]) + ), + Suite.test( + "disj no overlap", + AssocList.disj( + map1, + map3, + Nat.equal, + natOptAdd + ), + assocListTest([(0, 10), (2, 12), (4, 14), (1, 11), (3, 13), (5, 15)]) + ), + Suite.test( + "disj first empty", + AssocList.disj( + List.nil(), + map3, + Nat.equal, + natOptAdd + ), + assocListTest([(1, 11), (3, 13), (5, 15)]) + ), + Suite.test( + "disj second empty", + AssocList.disj( + map1, + List.nil(), + Nat.equal, + natOptAdd + ), + assocListTest([(0, 10), (2, 12), (4, 14)]) + ), + Suite.test( + "disj both empty", + AssocList.disj( + List.nil(), + List.nil(), + Nat.equal, + natOptAdd + ), + assocListTest([]) + ), + Suite.test( + "join", + AssocList.join( + map1, + map2, + Nat.equal, + Nat.add + ), + assocListTest([(2, 24)]) + ), + Suite.test( + "join no overlap", + AssocList.join( + map1, + map3, + Nat.equal, + Nat.add + ), + assocListTest([]) + ), + Suite.test( + "join first empty", + AssocList.join( + List.nil(), + map3, + Nat.equal, + Nat.add + ), + assocListTest([]) + ), + Suite.test( + "join second empty", + AssocList.join( + map1, + List.nil(), + Nat.equal, + Nat.add + ), + assocListTest([]) + ), + Suite.test( + "join both empty", + AssocList.join( + List.nil(), + List.nil(), + Nat.equal, + Nat.add + ), + assocListTest([]) + ), + Suite.test( + "fold", + AssocList.fold( + map1, + 0, + func(k, v, acc) = k * v + acc + ), + M.equals(T.nat((0 * 10) + (2 * 12) + (4 * 14))) + ), + Suite.test( + "fold empty", + AssocList.fold( + List.nil(), + 0, + func(k, v, acc) = k * v + acc + ), + M.equals(T.nat(0)) + ) + ] +); + +// FIXME formatter enforcing 4 space indentation +Suite.run(suite)