motoko 0.0.32

A library for parsing and running Motoko in Rust
Documentation
1
{"name":"base-test","version":"master","files":{"assocListTest.mo":{"content":"import AssocList \"mo:base/AssocList\";\nimport List \"mo:base/List\";\nimport Nat \"mo:base/Nat\";\nimport Debug \"mo:base/Debug\";\n\nimport Suite \"mo:matchers/Suite\";\nimport T \"mo:matchers/Testable\";\nimport M \"mo:matchers/Matchers\";\n\ntype AssocList = AssocList.AssocList<Nat, Nat>;\n\n// Utility functions for testing\nfunc assocListTest(array : [(Nat, Nat)]) : M.Matcher<AssocList> {\n    let map = List.fromArray(array);\n    let testableItem : T.TestableItem<AssocList> = {\n        display = func l { debug_show l };\n        equals = func(l1, l2) {\n            List.equal<(Nat, Nat)>(l1, l2, func(p1, p2) = p1.0 == p2.0 and p1.1 == p2.1)\n        };\n        item = map\n    };\n\n    M.equals<AssocList>(testableItem)\n};\nfunc natOptAdd(v1 : ?Nat, v2 : ?Nat) : Nat {\n    switch (v1, v2) {\n        case (?v1, ?v2) v1 + v2;\n        case (?v1, null) v1;\n        case (null, ?v2) v2;\n        case (null, null) Debug.trap \"Unreachable in assocListTest\"\n    }\n};\n\n// Sample association lists for testing\nlet map1 = List.fromArray([(0, 10), (2, 12), (4, 14)]);\nlet map2 = List.fromArray([(1, 11), (2, 12)]);\nlet map3 = List.fromArray([(1, 11), (3, 13), (5, 15)]);\n\nlet suite = Suite.suite(\n    \"AssocList\",\n    [\n        Suite.test(\n            \"find\",\n            AssocList.find(map1, 0, Nat.equal),\n            M.equals(T.optional(T.natTestable, ?10 : ?Nat))\n        ),\n        Suite.test(\n            \"find empty\",\n            AssocList.find(List.nil(), 0, Nat.equal),\n            M.equals(T.optional(T.natTestable, null : ?Nat))\n        ),\n        Suite.test(\n            \"replace\",\n            AssocList.replace(map1, 4, Nat.equal, ?24).0,\n            assocListTest([(0, 10), (2, 12), (4, 24)])\n        ),\n        Suite.test(\n            \"replace empty\",\n            AssocList.replace(List.nil(), 4, Nat.equal, ?24).0,\n            assocListTest([(4, 24)])\n        ),\n        Suite.test(\n            \"replace new entry\",\n            AssocList.replace(map1, 1, Nat.equal, ?11).0,\n            assocListTest([(0, 10), (2, 12), (4, 14), (1, 11)])\n        ),\n        Suite.test(\n            \"diff no overlap\",\n            AssocList.diff(map1, map3, Nat.equal),\n            assocListTest([(0, 10), (2, 12), (4, 14)])\n        ),\n        Suite.test(\n            \"diff empty first\",\n            AssocList.diff(List.nil(), map3, Nat.equal),\n            assocListTest([])\n        ),\n        Suite.test(\n            \"diff empty second\",\n            AssocList.diff(map1, List.nil(), Nat.equal),\n            assocListTest([(0, 10), (2, 12), (4, 14)])\n        ),\n        Suite.test(\n            \"diff both empty\",\n            AssocList.diff(List.nil(), List.nil(), Nat.equal),\n            assocListTest([])\n        ),\n        Suite.test(\n            \"mapAppend\",\n            AssocList.mapAppend<Nat, Nat, Nat, Nat>(\n                map1,\n                map2,\n                natOptAdd\n            ),\n            assocListTest([(0, 10), (2, 12), (4, 14), (1, 11), (2, 12)])\n        ),\n        Suite.test(\n            \"mapAppend no overlap\",\n            AssocList.mapAppend<Nat, Nat, Nat, Nat>(\n                map1,\n                map3,\n                natOptAdd\n            ),\n            assocListTest([(0, 10), (2, 12), (4, 14), (1, 11), (3, 13), (5, 15)])\n        ),\n        Suite.test(\n            \"mapAppend first empty\",\n            AssocList.mapAppend<Nat, Nat, Nat, Nat>(\n                List.nil(),\n                map3,\n                natOptAdd\n            ),\n            assocListTest([(1, 11), (3, 13), (5, 15)])\n        ),\n        Suite.test(\n            \"mapAppend second empty\",\n            AssocList.mapAppend<Nat, Nat, Nat, Nat>(\n                map3,\n                List.nil(),\n                natOptAdd\n            ),\n            assocListTest([(1, 11), (3, 13), (5, 15)])\n        ),\n        Suite.test(\n            \"mapAppend both empty\",\n            AssocList.mapAppend<Nat, Nat, Nat, Nat>(\n                List.nil(),\n                List.nil(),\n                natOptAdd\n            ),\n            assocListTest([])\n        ),\n        // FIXME disjDisjoint is equivalent to mapAppend\n        Suite.test(\n            \"disj\",\n            AssocList.disj<Nat, Nat, Nat, Nat>(\n                map1,\n                map2,\n                Nat.equal,\n                natOptAdd\n            ),\n            assocListTest([(0, 10), (4, 14), (1, 11), (2, 24)])\n        ),\n        Suite.test(\n            \"disj no overlap\",\n            AssocList.disj<Nat, Nat, Nat, Nat>(\n                map1,\n                map3,\n                Nat.equal,\n                natOptAdd\n            ),\n            assocListTest([(0, 10), (2, 12), (4, 14), (1, 11), (3, 13), (5, 15)])\n        ),\n        Suite.test(\n            \"disj first empty\",\n            AssocList.disj<Nat, Nat, Nat, Nat>(\n                List.nil(),\n                map3,\n                Nat.equal,\n                natOptAdd\n            ),\n            assocListTest([(1, 11), (3, 13), (5, 15)])\n        ),\n        Suite.test(\n            \"disj second empty\",\n            AssocList.disj<Nat, Nat, Nat, Nat>(\n                map1,\n                List.nil(),\n                Nat.equal,\n                natOptAdd\n            ),\n            assocListTest([(0, 10), (2, 12), (4, 14)])\n        ),\n        Suite.test(\n            \"disj both empty\",\n            AssocList.disj<Nat, Nat, Nat, Nat>(\n                List.nil(),\n                List.nil(),\n                Nat.equal,\n                natOptAdd\n            ),\n            assocListTest([])\n        ),\n        Suite.test(\n            \"join\",\n            AssocList.join<Nat, Nat, Nat, Nat>(\n                map1,\n                map2,\n                Nat.equal,\n                Nat.add\n            ),\n            assocListTest([(2, 24)])\n        ),\n        Suite.test(\n            \"join no overlap\",\n            AssocList.join<Nat, Nat, Nat, Nat>(\n                map1,\n                map3,\n                Nat.equal,\n                Nat.add\n            ),\n            assocListTest([])\n        ),\n        Suite.test(\n            \"join first empty\",\n            AssocList.join<Nat, Nat, Nat, Nat>(\n                List.nil(),\n                map3,\n                Nat.equal,\n                Nat.add\n            ),\n            assocListTest([])\n        ),\n        Suite.test(\n            \"join second empty\",\n            AssocList.join<Nat, Nat, Nat, Nat>(\n                map1,\n                List.nil(),\n                Nat.equal,\n                Nat.add\n            ),\n            assocListTest([])\n        ),\n        Suite.test(\n            \"join both empty\",\n            AssocList.join<Nat, Nat, Nat, Nat>(\n                List.nil(),\n                List.nil(),\n                Nat.equal,\n                Nat.add\n            ),\n            assocListTest([])\n        ),\n        Suite.test(\n            \"fold\",\n            AssocList.fold<Nat, Nat, Nat>(\n                map1,\n                0,\n                func(k, v, acc) = k * v + acc\n            ),\n            M.equals(T.nat((0 * 10) + (2 * 12) + (4 * 14)))\n        ),\n        Suite.test(\n            \"fold empty\",\n            AssocList.fold<Nat, Nat, Nat>(\n                List.nil(),\n                0,\n                func(k, v, acc) = k * v + acc\n            ),\n            M.equals(T.nat(0))\n        )\n    ]\n);\n\n// FIXME formatter enforcing 4 space indentation\nSuite.run(suite)\n"},"charTest.mo":{"content":"import Debug \"mo:base/Debug\";\nimport Char \"mo:base/Char\";\nimport Prim \"mo:⛔\";\n\n/*\n//\n// Char.toUpper\n//\n\nassert(Char.toUpper('ö') == 'Ö');\nassert(Char.toUpper('σ') == 'Σ');\nassert(Char.toUpper('💩') == '💩');\n\n//\n// Char.toLower\n//\n\nassert(Char.toLower('Ö') == 'ö');\nassert(Char.toLower('Σ') == 'σ');\nassert(Char.toLower('💩') == '💩');\n*/\n\n//\n// Char.isWhitespace\n//\n\nassert (Char.isWhitespace(' '));\n\nassert (not Char.isWhitespace('x'));\n\n// 12288 (U+3000) = ideographic space\nassert (Char.isWhitespace(Prim.nat32ToChar(12288)));\n\nassert (Char.isWhitespace('\\t'));\n\n// Vertical tab ('\\v')\nassert (Char.isWhitespace(Prim.nat32ToChar(0x0B)));\n\n// Form feed ('\\f')\nassert (Char.isWhitespace(Prim.nat32ToChar(0x0C)));\n\nassert (Char.isWhitespace('\\r'));\n\n//\n// Char.isLowercase\n//\n\nassert (Char.isLowercase('x'));\nassert (not Char.isLowercase('X'));\n\n//\n// Char.isUppercase\n//\n\nassert (Char.isUppercase('X'));\nassert (not Char.isUppercase('x'));\n\n//\n// Char.isAlphabetic\n//\n\nassert (Char.isAlphabetic('a'));\nassert (Char.isAlphabetic('京'));\nassert (not Char.isAlphabetic('㋡'))\n"},"dequeTest.mo":{"content":"import Deque \"mo:base/Deque\";\nimport Iter \"mo:base/Iter\";\nimport O \"mo:base/Option\";\nimport D \"mo:base/Debug\";\n\n// test for Queue\ndo {\n  var l = Deque.empty<Nat>();\n  for (i in Iter.range(0, 100)) {\n    l := Deque.pushBack(l, i)\n  };\n  for (i in Iter.range(0, 100)) {\n    let x = Deque.peekFront(l);\n    switch (Deque.popFront(l)) {\n      case (?(y, l2)) {\n        l := l2;\n        switch x {\n          case null assert false;\n          case (?x) assert (x == y)\n        }\n      };\n      case null { assert false }\n    };\n    assert (O.unwrap(x) == i)\n  };\n  O.assertNull(Deque.peekFront<Nat>(l))\n};\n\n// test for Deque\ndo {\n  var l = Deque.empty<Int>();\n  for (i in Iter.range(1, 100)) {\n    l := Deque.pushFront(l, -i);\n    l := Deque.pushBack(l, i)\n  };\n  label F for (i in Iter.revRange(100, -100)) {\n    if (i == 0) continue F;\n    let x = Deque.peekBack(l);\n    switch (Deque.popBack(l)) {\n      case (?(l2, y)) {\n        l := l2;\n        switch x {\n          case null assert false;\n          case (?x) assert (x == y)\n        }\n      };\n      case null { assert false }\n    };\n    assert (O.unwrap(x) == i)\n  }\n}\n"},"funcTest.mo":{"content":"import Function \"mo:base/Func\";\nimport Debug \"mo:base/Debug\";\nimport Text \"mo:base/Text\";\n\nDebug.print(\"Function\");\n\ndo {\n  Debug.print(\"  compose\");\n\n  func isEven(x : Int) : Bool { x % 2 == 0 };\n  func not_(x : Bool) : Bool { not x };\n  let isOdd = Function.compose<Int, Bool, Bool>(not_, isEven);\n\n  assert (isOdd(0) == false);\n  assert (isOdd(1))\n};\n\ndo {\n  Debug.print(\"  const\");\n\n  assert (Function.const<Bool, Text>(true)(\"abc\"));\n  assert (Function.const<Bool, Text>(false)(\"abc\") == false);\n  assert (Function.const<Bool, (Text, Text)>(false)(\"abc\", \"abc\") == false)\n}\n"},"intTest.mo":{"content":"import Int \"mo:base/Int\";\nimport Order \"mo:base/Order\";\n\nimport Suite \"mo:matchers/Suite\";\nimport T \"mo:matchers/Testable\";\nimport M \"mo:matchers/Matchers\";\n\nlet { run; test; suite } = Suite;\n\nlet largeNumber = 123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000_123_456_789_000;\nlet largeNumberText = \"123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000123456789000\";\n\ntype Order = { #less; #equal; #greater };\n\nclass OrderTestable(value : Order) : T.TestableItem<Order> {\n  public let item = value;\n  public func display(value : Order) : Text {\n    debug_show (value)\n  };\n  public let equals = func(x : Order, y : Order) : Bool {\n    x == y\n  }\n};\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"abs\",\n    [\n      test(\n        \"positive number\",\n        Int.abs(123),\n        M.equals(T.int(123))\n      ),\n      test(\n        \"negative number\",\n        Int.abs(-123),\n        M.equals(T.int(+123))\n      ),\n      test(\n        \"zero\",\n        Int.abs(0),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"large positive int\",\n        Int.abs(largeNumber),\n        M.equals(T.int(largeNumber))\n      ),\n      test(\n        \"large negative int\",\n        Int.abs(-largeNumber),\n        M.equals(T.int(largeNumber))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"toText\",\n    [\n      test(\n        \"all digits\",\n        Int.toText(1234567890),\n        M.equals(T.text(\"1234567890\"))\n      ),\n      test(\n        \"positive number\",\n        Int.toText(1234),\n        M.equals(T.text(\"1234\"))\n      ),\n      test(\n        \"negative number\",\n        Int.toText(-1234),\n        M.equals(T.text(\"-1234\"))\n      ),\n      test(\n        \"zero\",\n        Int.toText(0),\n        M.equals(T.text(\"0\"))\n      ),\n      test(\n        \"large number\",\n        Int.toText(largeNumber),\n        M.equals(T.text(largeNumberText))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"min\",\n    [\n      test(\n        \"both positive\",\n        Int.min(2, 3),\n        M.equals(T.int(2))\n      ),\n      test(\n        \"positive, negative\",\n        Int.min(+2, -3),\n        M.equals(T.int(-3))\n      ),\n      test(\n        \"both negative\",\n        Int.min(-2, -3),\n        M.equals(T.int(-3))\n      ),\n      test(\n        \"negative, positive\",\n        Int.min(-2, 3),\n        M.equals(T.int(-2))\n      ),\n      test(\n        \"equal values\",\n        Int.min(123, 123),\n        M.equals(T.int(123))\n      ),\n      test(\n        \"large numbers\",\n        Int.min(largeNumber, largeNumber + 1),\n        M.equals(T.int(largeNumber))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"max\",\n    [\n      test(\n        \"both positive\",\n        Int.max(2, 3),\n        M.equals(T.int(3))\n      ),\n      test(\n        \"positive, negative\",\n        Int.max(2, -3),\n        M.equals(T.int(2))\n      ),\n      test(\n        \"both negative\",\n        Int.max(-2, -3),\n        M.equals(T.int(-2))\n      ),\n      test(\n        \"negative, positive\",\n        Int.max(-2, 3),\n        M.equals(T.int(3))\n      ),\n      test(\n        \"equal values\",\n        Int.max(+123, 123),\n        M.equals(T.int(123))\n      ),\n      test(\n        \"large numbers\",\n        Int.max(largeNumber, largeNumber + 1),\n        M.equals(T.int(largeNumber + 1))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"equal\",\n    [\n      test(\n        \"positive equal\",\n        Int.equal(123, 123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"negative equal\",\n        Int.equal(-123, -123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"zero\",\n        Int.equal(0, 0),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"positive not equal\",\n        Int.equal(123, 124),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"negative not equal\",\n        Int.equal(-123, -124),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"mixed signs\",\n        Int.equal(123, -123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"large equal\",\n        Int.equal(largeNumber, largeNumber),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"large not equal\",\n        Int.equal(largeNumber, largeNumber + 1),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"notEqual\",\n    [\n      test(\n        \"positive equal\",\n        Int.notEqual(123, 123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"negative equal\",\n        Int.notEqual(-123, -123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"zero\",\n        Int.notEqual(0, 0),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"positive not equal\",\n        Int.notEqual(123, 124),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"negative not equal\",\n        Int.notEqual(-123, -124),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"mixed signs\",\n        Int.notEqual(123, -123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"large equal\",\n        Int.notEqual(largeNumber, largeNumber),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"large not equal\",\n        Int.notEqual(largeNumber, largeNumber + 1),\n        M.equals(T.bool(true))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"less\",\n    [\n      test(\n        \"positive equal\",\n        Int.less(123, 123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"positive less\",\n        Int.less(123, 245),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"positive greater\",\n        Int.less(245, 123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"negative equal\",\n        Int.less(-123, -123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"negative less\",\n        Int.less(-245, -123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"negative greater\",\n        Int.less(-123, -245),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"zero\",\n        Int.less(0, 0),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"mixed signs less\",\n        Int.less(-123, 123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"mixed signs greater\",\n        Int.less(123, -123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"large numbers less\",\n        Int.less(largeNumber, largeNumber + 1),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"large numbers equal\",\n        Int.less(largeNumber, largeNumber),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"large numbers greater\",\n        Int.less(largeNumber + 1, largeNumber),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"lessOrEqual\",\n    [\n      test(\n        \"positive equal\",\n        Int.lessOrEqual(123, 123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"positive less\",\n        Int.lessOrEqual(123, 245),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"positive greater\",\n        Int.lessOrEqual(245, 123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"negative equal\",\n        Int.lessOrEqual(-123, -123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"negative less\",\n        Int.lessOrEqual(-245, -123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"negative greater\",\n        Int.lessOrEqual(-123, -245),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"zero\",\n        Int.lessOrEqual(0, 0),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"mixed signs less\",\n        Int.lessOrEqual(-123, 123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"mixed signs greater\",\n        Int.lessOrEqual(123, -123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"large numbers less\",\n        Int.lessOrEqual(largeNumber, largeNumber + 1),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"large numbers equal\",\n        Int.lessOrEqual(largeNumber, largeNumber),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"large numbers greater\",\n        Int.lessOrEqual(largeNumber + 1, largeNumber),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"greater\",\n    [\n      test(\n        \"positive equal\",\n        Int.greater(123, 123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"positive less\",\n        Int.greater(123, 245),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"positive greater\",\n        Int.greater(245, 123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"negative equal\",\n        Int.greater(-123, -123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"negative less\",\n        Int.greater(-245, -123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"negative greater\",\n        Int.greater(-123, -245),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"zero\",\n        Int.greater(0, 0),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"mixed signs less\",\n        Int.greater(-123, 123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"mixed signs greater\",\n        Int.greater(123, -123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"large numbers less\",\n        Int.greater(largeNumber, largeNumber + 1),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"large numbers equal\",\n        Int.greater(largeNumber, largeNumber),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"large numbers greater\",\n        Int.greater(largeNumber + 1, largeNumber),\n        M.equals(T.bool(true))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"greaterOrEqual\",\n    [\n      test(\n        \"positive equal\",\n        Int.greaterOrEqual(123, 123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"positive less\",\n        Int.greaterOrEqual(123, 245),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"positive greater\",\n        Int.greaterOrEqual(245, 123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"negative equal\",\n        Int.greaterOrEqual(-123, -123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"negative less\",\n        Int.greaterOrEqual(-245, -123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"negative greater\",\n        Int.greaterOrEqual(-123, -245),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"zero\",\n        Int.greaterOrEqual(0, 0),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"mixed signs less\",\n        Int.greaterOrEqual(-123, 123),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"mixed signs greater\",\n        Int.greaterOrEqual(123, -123),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"large numbers less\",\n        Int.greaterOrEqual(largeNumber, largeNumber + 1),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"large numbers equal\",\n        Int.greaterOrEqual(largeNumber, largeNumber),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"large numbers greater\",\n        Int.greaterOrEqual(largeNumber + 1, largeNumber),\n        M.equals(T.bool(true))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"compare\",\n    [\n      test(\n        \"positive equal\",\n        Int.compare(123, 123),\n        M.equals(OrderTestable(#equal))\n      ),\n      test(\n        \"positive less\",\n        Int.compare(123, 245),\n        M.equals(OrderTestable(#less))\n      ),\n      test(\n        \"positive greater\",\n        Int.compare(245, 123),\n        M.equals(OrderTestable(#greater))\n      ),\n      test(\n        \"negative equal\",\n        Int.compare(-123, -123),\n        M.equals(OrderTestable(#equal))\n      ),\n      test(\n        \"negative less\",\n        Int.compare(-245, -123),\n        M.equals(OrderTestable(#less))\n      ),\n      test(\n        \"negative greater\",\n        Int.compare(-123, -245),\n        M.equals(OrderTestable(#greater))\n      ),\n      test(\n        \"zero\",\n        Int.compare(0, 0),\n        M.equals(OrderTestable(#equal))\n      ),\n      test(\n        \"mixed signs less\",\n        Int.compare(-123, 123),\n        M.equals(OrderTestable(#less))\n      ),\n      test(\n        \"mixed signs greater\",\n        Int.compare(123, -123),\n        M.equals(OrderTestable(#greater))\n      ),\n      test(\n        \"large numbers less\",\n        Int.compare(largeNumber, largeNumber + 1),\n        M.equals(OrderTestable(#less))\n      ),\n      test(\n        \"large numbers equal\",\n        Int.compare(largeNumber, largeNumber),\n        M.equals(OrderTestable(#equal))\n      ),\n      test(\n        \"large numbers greater\",\n        Int.compare(largeNumber + 1, largeNumber),\n        M.equals(OrderTestable(#greater))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"neg\",\n    [\n      test(\n        \"positive number\",\n        Int.neg(123),\n        M.equals(T.int(-123))\n      ),\n      test(\n        \"negative number\",\n        Int.neg(-123),\n        M.equals(T.int(123))\n      ),\n      test(\n        \"zero\",\n        Int.neg(0),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"positive large number\",\n        Int.neg(largeNumber),\n        M.equals(T.int(-largeNumber))\n      ),\n      test(\n        \"negative large number\",\n        Int.neg(-largeNumber),\n        M.equals(T.int(largeNumber))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"add\",\n    [\n      test(\n        \"positive\",\n        Int.add(123, 123),\n        M.equals(T.int(246))\n      ),\n      test(\n        \"negative\",\n        Int.add(-123, -123),\n        M.equals(T.int(-246))\n      ),\n      test(\n        \"mixed signs\",\n        Int.add(-123, 223),\n        M.equals(T.int(100))\n      ),\n      test(\n        \"zero\",\n        Int.add(0, 0),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"large addition\",\n        Int.add(largeNumber, largeNumber),\n        M.equals(T.int(2 * largeNumber))\n      ),\n      test(\n        \"large subtraction\",\n        Int.add(largeNumber, -largeNumber),\n        M.equals(T.int(0))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"sub\",\n    [\n      test(\n        \"positive\",\n        Int.sub(123, 123),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"negative\",\n        Int.sub(-123, -123),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"mixed signs\",\n        Int.sub(-123, 223),\n        M.equals(T.int(-346))\n      ),\n      test(\n        \"zero\",\n        Int.sub(0, 0),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"large addition\",\n        Int.sub(largeNumber, largeNumber),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"large subtraction\",\n        Int.sub(largeNumber, -largeNumber),\n        M.equals(T.int(2 * largeNumber))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"mul\",\n    [\n      test(\n        \"positive\",\n        Int.mul(123, 234),\n        M.equals(T.int(28782))\n      ),\n      test(\n        \"negative\",\n        Int.mul(-123, -234),\n        M.equals(T.int(28782))\n      ),\n      test(\n        \"mixed signs\",\n        Int.mul(-123, 234),\n        M.equals(T.int(-28782))\n      ),\n      test(\n        \"zeros\",\n        Int.mul(0, 0),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"zero and large number\",\n        Int.mul(0, largeNumber),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"large number and zero\",\n        Int.mul(largeNumber, 0),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"large numbers\",\n        Int.mul(largeNumber, largeNumber),\n        M.equals(T.int(largeNumber ** 2))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"div\",\n    [\n      test(\n        \"positive multiple\",\n        Int.div(156, 13),\n        M.equals(T.int(12))\n      ),\n      test(\n        \"positive remainder\",\n        Int.div(1234, 100),\n        M.equals(T.int(12))\n      ),\n      test(\n        \"negative multiple\",\n        Int.div(-156, -13),\n        M.equals(T.int(12))\n      ),\n      test(\n        \"negative remainder\",\n        Int.div(-1234, -100),\n        M.equals(T.int(12))\n      ),\n      test(\n        \"mixed signs\",\n        Int.div(-123, 23),\n        M.equals(T.int(-5))\n      ),\n      test(\n        \"zero and number\",\n        Int.div(0, -123),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"zero and large number\",\n        Int.div(0, largeNumber),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"large number and number\",\n        Int.div(largeNumber, 123),\n        M.equals(T.int(largeNumber / 123))\n      ),\n      test(\n        \"equal large numbers\",\n        Int.div(largeNumber, largeNumber),\n        M.equals(T.int(1))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"rem\",\n    [\n      test(\n        \"positive multiple\",\n        Int.rem(156, 13),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"positive/positive remainder\",\n        Int.rem(1234, 100),\n        M.equals(T.int(34))\n      ),\n      test(\n        \"positive/negative remainder\",\n        Int.rem(1234, -100),\n        M.equals(T.int(34))\n      ),\n      test(\n        \"negative multiple\",\n        Int.rem(-156, -13),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"negative/positive remainder\",\n        Int.rem(-1234, 100),\n        M.equals(T.int(-34))\n      ),\n      test(\n        \"negative/negative remainder\",\n        Int.rem(-1234, -100),\n        M.equals(T.int(-34))\n      ),\n      test(\n        \"zero and large number\",\n        Int.rem(0, largeNumber),\n        M.equals(T.int(0))\n      ),\n      test(\n        \"large number and number\",\n        Int.rem(largeNumber * 123 + 100, 123),\n        M.equals(T.int(100))\n      ),\n      test(\n        \"equal large numbers\",\n        Int.rem(largeNumber, largeNumber),\n        M.equals(T.int(0))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nrun(\n  suite(\n    \"pow\",\n    [\n      test(\n        \"positive base, positive exponent\",\n        Int.pow(72, 3),\n        M.equals(T.int(373248))\n      ),\n      test(\n        \"positive base, zero exponent\",\n        Int.pow(72, 0),\n        M.equals(T.int(1))\n      ),\n      test(\n        \"negative base, positive exponent\",\n        Int.pow(-72, 3),\n        M.equals(T.int(-373248))\n      ),\n      test(\n        \"negative base, zero exponent\",\n        Int.pow(-72, 0),\n        M.equals(T.int(1))\n      ),\n      test(\n        \"large number and zero\",\n        Int.pow(largeNumber, 0),\n        M.equals(T.int(1))\n      ),\n      test(\n        \"positive large number and small number\",\n        Int.pow(largeNumber, 3),\n        M.equals(T.int(largeNumber * largeNumber * largeNumber))\n      ),\n      test(\n        \"negative large number and small number\",\n        Int.pow(-largeNumber, 2),\n        M.equals(T.int(largeNumber * largeNumber))\n      ),\n      test(\n        \"one and max Nat\",\n        Int.pow(1, 2 ** 32 - 1),\n        M.equals(T.int(1))\n      ),\n      test(\n        \"zero and max Nat\",\n        Int.pow(0, 2 ** 32 - 1),\n        M.equals(T.int(0))\n      )\n    ]\n  )\n)\n"},"errorTest.mo":{"content":"import Error \"mo:base/Error\";\n\nimport Suite \"mo:matchers/Suite\";\nimport T \"mo:matchers/Testable\";\nimport M \"mo:matchers/Matchers\";\n\nlet { run; test; suite } = Suite;\n\nclass ErrorCodeTestable() : T.Testable<Error.ErrorCode> {\n    public func display(code : Error.ErrorCode) : Text {\n        debug_show (code)\n    };\n    public func equals(first : Error.ErrorCode, second : Error.ErrorCode) : Bool {\n        first == second\n    }\n};\n\nlet testMessage = \"Test error message\";\n\nrun(\n    suite(\n        \"reject\",\n        [\n            test(\n                \"error code\",\n                Error.code(Error.reject(testMessage)),\n                M.equals({ { item = #canister_reject } and ErrorCodeTestable() })\n            ),\n            test(\n                \"error message\",\n                Error.message(Error.reject(testMessage)),\n                M.equals(T.text(testMessage))\n            )\n        ]\n    )\n)\n"},"iterTest.mo":{"content":"import Iter \"mo:base/Iter\";\nimport Array \"mo:base/Array\";\nimport List \"mo:base/List\";\nimport Nat \"mo:base/Nat\";\nimport Int \"mo:base/Int\";\nimport Debug \"mo:base/Debug\";\n\nDebug.print(\"Iter\");\n\ndo {\n  Debug.print(\"  range\");\n\n  let tests = [((0, -1), \"\", \"0-1\"), ((0, 0), \"0\", \"0\"), ((0, 5), \"012345\", \"\"), ((5, 0), \"\", \"543210\")];\n  for ((range, expected, revExpected) in tests.vals()) {\n    var x = \"\";\n    for (i in Iter.range(range)) {\n      x := x # Nat.toText(i)\n    };\n    assert (x == expected);\n    x := \"\";\n    for (i in Iter.revRange(range)) {\n      x := x # Int.toText(i)\n    };\n    assert (x == revExpected)\n  }\n};\n\ndo {\n  Debug.print(\"  iterate\");\n\n  let xs = [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"];\n\n  var y = \"\";\n  var z = 0;\n\n  Iter.iterate<Text>(\n    xs.vals(),\n    func(x : Text, i : Nat) {\n      y := y # x;\n      z += i\n    }\n  );\n\n  assert (y == \"abcdef\");\n  assert (z == 15)\n};\n\ndo {\n  Debug.print(\"  map\");\n\n  let isEven = func(x : Int) : Bool {\n    x % 2 == 0\n  };\n\n  let _actual = Iter.map<Nat, Bool>([1, 2, 3].vals(), isEven);\n  let actual = [var true, false, true];\n  Iter.iterate<Bool>(_actual, func(x, i) { actual[i] := x });\n\n  let expected = [false, true, false];\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\ndo {\n  Debug.print(\"  filter\");\n\n  let isOdd = func(x : Int) : Bool {\n    x % 2 == 1\n  };\n\n  let _actual = Iter.filter<Nat>([1, 2, 3].vals(), isOdd);\n  let actual = [var 0, 0];\n  Iter.iterate<Nat>(_actual, func(x, i) { actual[i] := x });\n\n  let expected = [1, 3];\n\n  assert (Array.freeze(actual) == expected)\n};\n\ndo {\n  Debug.print(\"  make\");\n\n  let x = 1;\n  let y = Iter.make<Nat>(x);\n\n  switch (y.next()) {\n    case null { assert false };\n    case (?z) { assert (x == z) }\n  }\n};\n\ndo {\n  Debug.print(\"  fromArray\");\n\n  let expected = [1, 2, 3];\n  let _actual = Iter.fromArray<Nat>(expected);\n  let actual = [var 0, 0, 0];\n\n  Iter.iterate<Nat>(_actual, func(x, i) { actual[i] := x });\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\ndo {\n  Debug.print(\"  fromArrayMut\");\n\n  let expected = [var 1, 2, 3];\n  let _actual = Iter.fromArrayMut<Nat>(expected);\n  let actual = [var 0, 0, 0];\n\n  Iter.iterate<Nat>(_actual, func(x, i) { actual[i] := x });\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\ndo {\n  Debug.print(\"  fromList\");\n\n  let list : List.List<Nat> = ?(1, ?(2, ?(3, List.nil<Nat>())));\n  let _actual = Iter.fromList<Nat>(list);\n  let actual = [var 0, 0, 0];\n  let expected = [1, 2, 3];\n\n  Iter.iterate<Nat>(_actual, func(x, i) { actual[i] := x });\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\ndo {\n  Debug.print(\"  toArray\");\n\n  let expected = [1, 2, 3];\n  let actual = Iter.toArray<Nat>(expected.vals());\n\n  assert (actual.size() == expected.size());\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\ndo {\n  Debug.print(\"  toArrayMut\");\n\n  let expected = [var 1, 2, 3];\n  let actual = Iter.toArrayMut<Nat>(expected.vals());\n\n  assert (actual.size() == expected.size());\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\ndo {\n  Debug.print(\"  toList\");\n\n  let expected : List.List<Nat> = ?(1, ?(2, ?(3, List.nil<Nat>())));\n  let actual = Iter.toList<Nat>([1, 2, 3].vals());\n  assert List.equal<Nat>(expected, actual, func(x1, x2) { x1 == x2 })\n};\n\ndo {\n  Debug.print(\"  sort\");\n\n  let input : [Nat] = [4, 3, 1, 2, 5];\n  let expected : [Nat] = [1, 2, 3, 4, 5];\n  let actual = Iter.toArray(Iter.sort<Nat>(input.vals(), Nat.compare));\n  assert Array.equal<Nat>(expected, actual, func(x1, x2) { x1 == x2 })\n}\n"},"noneTest.mo":{"content":"import Array \"mo:base/Array\";\nimport None \"mo:base/None\";\nimport Debug \"mo:base/Debug\";\n\nDebug.print(\"None\");\n\ndo {\n  Debug.print(\"  impossible\");\n\n  func showNone(x : None) : Text {\n    None.impossible<Text>(x)\n  }\n}\n"},"listTest.mo":{"content":"import List \"mo:base/List\";\nimport Nat \"mo:base/Nat\";\nimport Order \"mo:base/Order\";\nimport Debug \"mo:base/Debug\";\nimport Int \"mo:base/Int\";\nimport Iter \"mo:base/Iter\";\nimport Result \"mo:base/Result\";\nimport Suite \"mo:matchers/Suite\";\nimport M \"mo:matchers/Matchers\";\nimport T \"mo:matchers/Testable\";\n\n/*\n\nFIXME:\n\n* flatten is quadratic\n* Array.mo doesn't implement `all`, `some`, `compare`\n* merge takes lte predicate of type (T,T)-> Bool, not comparison of type: (T,T) -> Ord\n* split is not tail recursive and calls redundant helpers\n\nTODO:\n  * most of these test don't test evaluation order or short-circuiting.\n  * from/to(Var)Array functions could use matchers tests beyond the existing assert only tests\n*/\n\nfunc ordT(o : Order.Order) : T.TestableItem<Order.Order> = {\n  item = o;\n  display = func(o : Order.Order) : Text { debug_show (o) };\n  equals = Order.equal\n};\n\ntype X = Nat;\n\nfunc opnatEq(a : ?Nat, b : ?Nat) : Bool {\n  switch (a, b) {\n    case (null, null) { true };\n    case (?aaa, ?bbb) { aaa == bbb };\n    case (_, _) { false }\n  }\n};\nfunc opnat_isnull(a : ?Nat) : Bool {\n  switch a {\n    case (null) { true };\n    case (?aaa) { false }\n  }\n};\n\n// ## Construction\nlet l1 = List.nil<X>();\nlet l2 = List.push<X>(2, l1);\nlet l3 = List.push<X>(3, l2);\n\n// ## Projection -- use nth\nassert (opnatEq(List.get<X>(l3, 0), ?3));\nassert (opnatEq(List.get<X>(l3, 1), ?2));\nassert (opnatEq(List.get<X>(l3, 2), null));\n//assert (opnatEq (hd<X>(l3), ?3));\n//assert (opnatEq (hd<X>(l2), ?2));\n//assert (opnat_isnull(hd<X>(l1)));\n\n/*\n   // ## Projection -- use nth\n   assert (opnatEq(nth<X>(l3, 0), ?3));\n   assert (opnatEq(nth<X>(l3, 1), ?2));\n   assert (opnatEq(nth<X>(l3, 2), null));\n   assert (opnatEq (hd<X>(l3), ?3));\n   assert (opnatEq (hd<X>(l2), ?2));\n   assert (opnat_isnull(hd<X>(l1)));\n   */\n\n// ## Deconstruction\nlet (a1, t1) = List.pop<X>(l3);\nassert (opnatEq(a1, ?3));\nlet (a2, t2) = List.pop<X>(l2);\nassert (opnatEq(a2, ?2));\nlet (a3, t3) = List.pop<X>(l1);\nassert (opnatEq(a3, null));\nassert (List.isNil<X>(t3));\n\n// ## List functions\nassert (List.size<X>(l1) == 0);\nassert (List.size<X>(l2) == 1);\nassert (List.size<X>(l3) == 2);\n\n// ## List functions\nassert (List.size<X>(l1) == 0);\nassert (List.size<X>(l2) == 1);\nassert (List.size<X>(l3) == 2);\n\ndo {\n  Debug.print(\"  flatten\");\n\n  let expected : List.List<Nat> = ?(1, ?(2, ?(3, null)));\n  // [[1, 2], [3]]\n  let nested : List.List<List.List<Nat>> = ?(?(1, ?(2, null)), ?(?(3, null), null));\n  let actual = List.flatten<Nat>(nested);\n\n  assert List.equal<Nat>(expected, actual, func(x1, x2) { x1 == x2 });\n\n};\n\ndo {\n  Debug.print(\"  fromArray\");\n\n  let expected : List.List<Nat> = ?(1, ?(2, ?(3, List.nil<Nat>())));\n  let array = [1, 2, 3];\n  let actual = List.fromArray<Nat>(array);\n\n  assert List.equal<Nat>(expected, actual, func(x1, x2) { x1 == x2 })\n};\n\ndo {\n  Debug.print(\"  fromVarArray\");\n\n  let expected : List.List<Nat> = ?(1, ?(2, ?(3, List.nil<Nat>())));\n  let array = [var 1, 2, 3];\n  let actual = List.fromVarArray<Nat>(array);\n\n  assert List.equal<Nat>(expected, actual, func(x1, x2) { x1 == x2 })\n};\n\ndo {\n  Debug.print(\"  toArray\");\n\n  let expected = [1, 2, 3];\n  let list : List.List<Nat> = ?(1, ?(2, ?(3, List.nil<Nat>())));\n  let actual = List.toArray<Nat>(list);\n\n  assert (actual.size() == expected.size());\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\ndo {\n  Debug.print(\"  toVarArray\");\n\n  let expected = [var 1, 2, 3];\n  let list : List.List<Nat> = ?(1, ?(2, ?(3, List.nil<Nat>())));\n  let actual = List.toVarArray<Nat>(list);\n\n  assert (actual.size() == expected.size());\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\ndo {\n  Debug.print(\"  toIter\");\n\n  let list : List.List<Nat> = ?(1, ?(2, ?(3, List.nil<Nat>())));\n  let _actual = List.toIter<Nat>(list);\n  let actual = [var 0, 0, 0];\n  let expected = [1, 2, 3];\n\n  Iter.iterate<Nat>(_actual, func(x, i) { actual[i] := x });\n\n  for (i in actual.keys()) {\n    assert (actual[i] == expected[i])\n  }\n};\n\nfunc makeNatural(x : Int) : Result.Result<Nat, Text> = if (x >= 0) {\n  #ok(Int.abs(x))\n} else { #err(Int.toText(x) # \" is not a natural number.\") };\n\nfunc listRes(itm : Result.Result<List.List<Nat>, Text>) : T.TestableItem<Result.Result<List.List<Nat>, Text>> {\n  let resT = T.resultTestable(T.listTestable<Nat>(T.intTestable), T.textTestable);\n  { display = resT.display; equals = resT.equals; item = itm }\n};\n\n\n\nlet mapResult = Suite.suite(\n  \"mapResult\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.mapResult<Int, Nat, Text>(List.nil(), makeNatural),\n      M.equals(listRes(#ok(List.nil())))\n    ),\n    Suite.test(\n      \"success\",\n      List.mapResult<Int, Nat, Text>(?(1, ?(2, ?(3, null))), makeNatural),\n      M.equals(listRes(#ok(?(1, ?(2, ?(3, null))))))\n    ),\n    Suite.test(\n      \"fail fast\",\n      List.mapResult<Int, Nat, Text>(?(-1, ?(2, ?(3, null))), makeNatural),\n      M.equals(listRes(#err(\"-1 is not a natural number.\")))\n    ),\n    Suite.test(\n      \"fail last\",\n      List.mapResult<Int, Nat, Text>(?(1, ?(2, ?(-3, null))), makeNatural),\n      M.equals(listRes(#err(\"-3 is not a natural number.\")))\n    )\n  ]\n);\n\nSuite.run(Suite.suite(\"List\", [mapResult]));\n\nlet replicate = Suite.suite(\n  \"replicate\",\n  [\n    Suite.test(\n      \"empty-list\",\n      List.replicate<Nat>(0, 0),\n      M.equals(\n        T.list(T.natTestable, List.nil<Nat>())\n      )\n    ),\n    Suite.test(\n      \"small-list\",\n      List.replicate(3, 0),\n      M.equals(\n        T.list<Nat>(T.natTestable, ?(0, ?(0, ?(0, null))))\n      )\n    )\n  ]\n);\n\nlet tabulate = Suite.suite(\n  \"tabulate\",\n  [\n    Suite.test(\n      \"empty-list\",\n      List.tabulate<Nat>(0, func i { i }),\n      M.equals(\n        T.list(T.natTestable, List.nil<Nat>())\n      )\n    ),\n    Suite.test(\n      \"small-list\",\n      List.tabulate<Nat>(3, func i { i * 2 }),\n      M.equals(\n        T.list<Nat>(T.natTestable, ?(0, ?(2, ?(4, null))))\n      )\n    ),\n    Suite.test(\n      \"large-list\",\n      List.tabulate<Nat>(10000, func i { 0 }),\n      M.equals(\n        T.list<Nat>(T.natTestable, List.replicate(10000, 0))\n      )\n    )\n  ]\n);\n\nlet append = Suite.suite(\n  \"append\",\n  [\n    Suite.test(\n      \"small-list\",\n      List.append(\n        List.tabulate<Nat>(10, func i { i }),\n        List.tabulate<Nat>(10, func i { i + 10 })\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(20, func i { i }))\n      )\n    ),\n    Suite.test(\n      \"large-list\",\n      List.append(\n        List.tabulate<Nat>(10000, func i { i }),\n        List.tabulate<Nat>(10000, func i { i + 10000 })\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(20000, func i { i }))\n      )\n    )\n  ]\n);\n\nlet isNil = Suite.suite(\n  \"isNil\",\n  [\n    Suite.test(\n      \"empty\",\n      List.isNil(List.nil<Nat>()),\n       M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"singleton\",\n      List.isNil(?(3, null)),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"nary\",\n      List.isNil(?(1, ?(2, ?(3, null)))),\n      M.equals(T.bool(false))\n    )\n  ]\n);\n\nlet push = Suite.suite(\n  \"push\",\n  [\n    Suite.test(\n      \"empty\",\n      List.push(0, List.nil<Nat>()),\n      M.equals(T.list(T.natTestable, ?(0, null)))\n    ),\n    Suite.test(\n      \"singleton\",\n      List.push(1, List.push(0, List.nil<Nat>())),\n      M.equals(T.list(T.natTestable, ?(1, ?(0, null))))\n    ),\n    Suite.test(\n      \"nary\",\n      List.push(2, List.push(1, List.push(0, List.nil<Nat>()))),\n      M.equals(T.list(T.natTestable, ?(2, ?(1, ?(0, null)))))\n    )\n  ]\n);\n\n\nlet last = Suite.suite(\n  \"last\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.last(List.nil<Nat>()),\n       M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"singleton\",\n      List.last(?(3, null)),\n      M.equals(T.optional(T.natTestable, ?3))\n    ),\n    Suite.test(\n      \"threesome\",\n      List.last(?(1, ?(2, ?(3, null)))),\n      M.equals(T.optional(T.natTestable, ?3))\n    )\n  ]\n);\n\nlet pop = Suite.suite(\n  \"pop\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.pop(List.nil<Nat>()),\n      M.equals(T.tuple2(T.optionalTestable(T.natTestable),\n                        T.listTestable(T.natTestable),\n                        (null, null) : (?Nat, List.List<Nat>) ))\n    ),\n    Suite.test(\n      \"singleton\",\n      List.pop(?(3, null)),\n      M.equals(T.tuple2(T.optionalTestable(T.natTestable),\n                        T.listTestable(T.natTestable),\n                        (?3, null) : (?Nat, List.List<Nat>) ))\n    ),\n    Suite.test(\n      \"threesome\",\n      List.pop(?(1, ?(2, ?(3, null)))),\n      M.equals(T.tuple2(T.optionalTestable(T.natTestable),\n                        T.listTestable(T.natTestable),\n                        (?1, ?(2, ?(3, null))) : (?Nat, List.List<Nat>) ))\n    ),\n  ]\n);\n\nlet size = Suite.suite(\n  \"size\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.size(List.nil<Nat>()),\n      M.equals(T.nat(0))\n    ),\n    Suite.test(\n      \"singleton\",\n      List.size(?(3, null)),\n      M.equals(T.nat(1))\n    ),\n    Suite.test(\n      \"threesome\",\n      List.size(?(1, ?(2, ?(3, null)))),\n      M.equals(T.nat(3))\n    ),\n  ]\n);\n\nlet get = Suite.suite(\n  \"get\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.get(List.nil<Nat>(), 0),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"singleton-0\",\n      List.get(?(3, null), 0),\n      M.equals(T.optional(T.natTestable, ?3 : ?Nat))\n    ),\n     Suite.test(\n      \"singleton-1\",\n      List.get(?(3, null), 1),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"singleton-2\",\n      List.get(?(3, null), 2),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"threesome-0\",\n      List.get(?(1, ?(2, ?(3, null))), 0),\n      M.equals(T.optional(T.natTestable, ?1 : ?Nat))\n    ),\n     Suite.test(\n      \"threesome-1\",\n      List.get(?(1, ?(2, ?(3, null))), 1),\n      M.equals(T.optional(T.natTestable, ?2 : ?Nat))\n    ),\n     Suite.test(\n      \"threesome-3\",\n      List.get(?(1, ?(2, ?(3, null))), 3),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"threesome-4\",\n      List.get(?(1, ?(2, ?(3, null))), 4),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    )\n  ]\n);\n\n\nlet reverse = Suite.suite(\n  \"reverse\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.reverse(List.nil<Nat>()),\n      M.equals(T.list(T.natTestable, null : List.List<Nat>))\n\n    ),\n    Suite.test(\n      \"singleton\",\n      List.reverse(?(3, null)),\n      M.equals(T.list(T.natTestable, ?(3, null)))\n    ),\n    Suite.test(\n      \"threesome\",\n      List.reverse(?(1, ?(2, ?(3, null)))),\n      M.equals(T.list(T.natTestable, ?(3, ?(2, ?(1, null)))))\n    ),\n  ]\n);\n\nlet iterate = Suite.suite(\n  \"iterate\",\n  [\n    Suite.test(\n      \"empty list\",\n      do {\n        var t = \"\";\n        List.iterate<Nat>(List.nil<Nat>(), func n { t #= debug_show n });\n        t\n      },\n      M.equals(T.text(\"\"))\n    ),\n    Suite.test(\n      \"singleton\",\n      do {\n        var t = \"\";\n        List.iterate<Nat>(?(3, null), func n { t #= debug_show n });\n        t\n      },\n      M.equals(T.text(\"3\"))\n    ),\n    Suite.test(\n      \"threesome\",\n      do {\n        var t = \"\";\n        List.iterate<Nat>(?(1, ?(2, ?(3, null))), func n { t #= debug_show n });\n        t\n      },\n      M.equals(T.text(\"123\"))\n    ),\n  ]\n);\n\nlet map = Suite.suite(\n  \"map\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.map<Nat,Nat>(\n       List.nil<Nat>(),\n      func n { n + 1 }),\n      M.equals(T.list(T.natTestable, null : List.List<Nat>))\n    ),\n    Suite.test(\n      \"singleton\",\n      List.map<Nat,Nat>(\n        ?(3, null),\n        func n { n + 1 }),\n      M.equals(T.list(T.natTestable, ?(4, null)))\n    ),\n    Suite.test(\n      \"threesome\",\n      List.map<Nat,Nat>(\n        ?(1, ?(2, ?(3, null))),\n        func n { n + 1 }),\n      M.equals(T.list(T.natTestable, ?(2, ?(3, ?(4, null)))))\n    ),\n  ]\n);\n\n\nlet filter = Suite.suite(\n  \"filter\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.filter<Nat>(\n       List.nil<Nat>(),\n       func n { n % 2 == 0 }),\n      M.equals(T.list(T.natTestable, null : List.List<Nat>))\n    ),\n    Suite.test(\n      \"singleton\",\n      List.filter<Nat>(\n        ?(3, null),\n      func n { n % 2 == 0 }),\n      M.equals(T.list(T.natTestable, null : List.List<Nat>))\n    ),\n    Suite.test(\n      \"threesome\",\n      List.filter<Nat>(\n        ?(1, ?(2, ?(3, null))),\n        func n { n % 2 == 0 }),\n      M.equals(T.list(T.natTestable, ?(2, null)))\n    ),\n    Suite.test(\n      \"foursome\",\n      List.filter<Nat>(\n        ?(1, ?(2, ?(3, ?(4, null)))),\n        func n { n % 2 == 0 }),\n      M.equals(T.list(T.natTestable, ?(2, ?(4, null))))\n    ),\n  ]\n);\n\nlet partition = Suite.suite(\n  \"partition\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.partition<Nat>(\n       List.nil<Nat>(),\n       func n { n % 2 == 0 }),\n      M.equals(T.tuple2(T.listTestable(T.natTestable),\n                        T.listTestable(T.natTestable),\n                        (null, null) : (List.List<Nat>, List.List<Nat>)))\n    ),\n    Suite.test(\n      \"singleton-false\",\n      List.partition<Nat>(\n        ?(3, null),\n      func n { n % 2 == 0 }),\n      M.equals(T.tuple2(T.listTestable(T.natTestable),\n                        T.listTestable(T.natTestable),\n                        (null, ?(3, null)) : (List.List<Nat>, List.List<Nat>)))\n\n    ),\n    Suite.test(\n      \"singleton-true\",\n      List.partition<Nat>(\n        ?(2, null),\n      func n { n % 2 == 0 }),\n      M.equals(T.tuple2(T.listTestable(T.natTestable),\n                        T.listTestable(T.natTestable),\n                        (?(2, null), null) : (List.List<Nat>, List.List<Nat>)))\n    ),\n    Suite.test(\n      \"threesome\",\n      List.partition<Nat>(\n        ?(1, ?(2, ?(3, null))),\n        func n { n % 2 == 0 }),\n      M.equals(T.tuple2(T.listTestable(T.natTestable),\n                        T.listTestable(T.natTestable),\n                        (?(2, null), ?(1, ?(3, null))) : (List.List<Nat>, List.List<Nat>)))\n    ),\n    Suite.test(\n      \"foursome\",\n      List.partition<Nat>(\n        ?(1, ?(2, ?(3, ?(4, null)))),\n        func n { n % 2 == 0 }),\n      M.equals(T.tuple2(T.listTestable(T.natTestable),\n                        T.listTestable(T.natTestable),\n                        (?(2, ?(4, null)),\n                         ?(1, ?(3, null))) : (List.List<Nat>, List.List<Nat>)))\n    ),\n  ]\n);\n\n\nlet mapFilter = Suite.suite(\n  \"mapFilter\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.mapFilter<Nat, Text>(\n       List.nil<Nat>(),\n       func n { if (n % 2 == 0) ?(debug_show n) else null }),\n      M.equals(T.list(T.textTestable, null : List.List<Text>))\n    ),\n    Suite.test(\n      \"singleton\",\n      List.mapFilter<Nat, Text>(\n        ?(3, null),\n       func n { if (n % 2 == 0) ?(debug_show n) else null }),\n      M.equals(T.list(T.textTestable, null : List.List<Text>))\n    ),\n    Suite.test(\n      \"threesome\",\n      List.mapFilter<Nat, Text>(\n        ?(1, ?(2, ?(3, null))),\n       func n { if (n % 2 == 0) ?(debug_show n) else null }),\n      M.equals(T.list(T.textTestable, ?(\"2\", null)))\n    ),\n    Suite.test(\n      \"foursome\",\n      List.mapFilter<Nat, Text>(\n        ?(1, ?(2, ?(3, ?(4, null)))),\n        func n { if (n % 2 == 0) ?(debug_show n) else null }),\n      M.equals(T.list(T.textTestable, ?(\"2\", ?(\"4\", null))))\n    ),\n  ]\n);\n\n\nlet flatten = Suite.suite(\n  \"flatten\",\n  [\n    Suite.test(\n      \"small-list\",\n      List.flatten(\n        List.tabulate<List.List<Nat>>(10, func i { List.tabulate<Nat>(10, func j { i * 10 + j })})\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(100, func i { i }))\n      )\n    ),\n    Suite.test(\n      \"small-nulls\",\n      List.flatten(\n        List.tabulate<List.List<Nat>>(10, func i { null : List.List<Nat> })\n      ),\n      M.equals(\n        T.list(T.natTestable, null : List.List<Nat>)\n      )\n    ),\n   Suite.test(\n      \"flatten\",\n      List.flatten<Int>(?(?(1, ?(2, ?(3, null))),\n                          ?(null,\n                            ?(?(1, null),\n                              null)))),\n      M.equals(T.list<Int>(T.intTestable, ?(1, ?(2, ?(3, ?(1, null))))))\n    ),\n    Suite.test(\n      \"flatten empty start\",\n      List.flatten<Int>(?(null,\n                         ?(?(1, ?(2, (?(3, null)))),\n                           ?(null,\n                             ?(?(1, null),\n                               null))))),\n      M.equals(T.list<Int>(T.intTestable, ?(1, ?(2, ?(3, ?(1, null))))))\n    ),\n    Suite.test(\n      \"flatten empty end\",\n      List.flatten<Int>(?(?(1, ?(2, (?(3, null)))),\n                          ?(null,\n                            ?(?(1, null),\n                              ?(null,\n                                null))))),\n      M.equals(T.list<Int>(T.intTestable, ?(1, ?(2, ?(3, ?(1, null))))))\n    ),\n    Suite.test(\n      \"flatten singleton\",\n      List.flatten<Int>(?(?(1, ?(2, (?(3, null)))),\n                          null)),\n      M.equals(T.list<Int>(T.intTestable, ?(1, ?(2, (?(3, null))))))\n    ),\n    Suite.test(\n      \"flatten singleton empty\",\n      List.flatten<Int>(?(null, null)),\n      M.equals(T.list<Int>(T.intTestable, null))\n    ),\n    Suite.test(\n      \"flatten empty\",\n      List.flatten<Int>(null),\n      M.equals(T.list<Int>(T.intTestable, null))\n    ),\n  ]\n);\n\nlet make = Suite.suite(\n  \"make\",\n  [\n    Suite.test(\n      \"make\",\n      List.make<Int>(0),\n      M.equals(T.list<Int>(T.intTestable, ?(0, null)))\n    ),\n  ]\n);\n\nlet take = Suite.suite(\n  \"take\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.take(List.nil<Nat>(), 0),\n      M.equals(T.list<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"singleton-0\",\n      List.take(?(3, null), 0),\n      M.equals(T.list<Nat>(T.natTestable, null))\n    ),\n     Suite.test(\n      \"singleton-1\",\n      List.take(?(3, null), 1),\n      M.equals(T.list(T.natTestable, ?(3, null)))\n    ),\n    Suite.test(\n      \"singleton-2\",\n      List.take(?(3, null), 2),\n      M.equals(T.list(T.natTestable, ?(3, null)))\n    ),\n    Suite.test(\n      \"threesome-0\",\n      List.take(?(1, ?(2, ?(3, null))), 0),\n      M.equals(T.list(T.natTestable, null : List.List<Nat>))\n    ),\n     Suite.test(\n      \"threesome-1\",\n      List.take(?(1, ?(2, ?(3, null))), 1),\n      M.equals(T.list(T.natTestable, ?(1, null)))\n    ),\n     Suite.test(\n      \"threesome-3\",\n      List.take(?(1, ?(2, ?(3, null))), 3),\n      M.equals(T.list(T.natTestable, ?(1, ?(2, ?(3, null)))))\n    ),\n    Suite.test(\n      \"threesome-4\",\n      List.take(?(1, ?(2, ?(3, null))), 4),\n      M.equals(T.list(T.natTestable, ?(1, ?(2, ?(3, null)))))\n    )\n  ]\n);\n\nlet drop = Suite.suite(\n  \"drop\",\n  [\n    Suite.test(\n      \"empty list\",\n      List.drop(List.nil<Nat>(), 0),\n      M.equals(T.list<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"singleton-0\",\n      List.drop(?(3, null), 0),\n      M.equals(T.list<Nat>(T.natTestable, ?(3,null)))\n    ),\n     Suite.test(\n      \"singleton-1\",\n      List.drop(?(3, null), 1),\n      M.equals(T.list<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"singleton-2\",\n      List.drop(?(3, null), 2),\n      M.equals(T.list<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"threesome-0\",\n      List.drop(?(1, ?(2, ?(3, null))), 0),\n      M.equals(T.list<Nat>(T.natTestable, ?(1, ?(2, ?(3, null)))))\n    ),\n     Suite.test(\n      \"threesome-1\",\n      List.drop(?(1, ?(2, ?(3, null))), 1),\n      M.equals(T.list(T.natTestable, ?(2, ?(3, null))))\n    ),\n     Suite.test(\n      \"threesome-2\",\n      List.drop(?(1, ?(2, ?(3, null))), 2),\n      M.equals(T.list(T.natTestable, ?(3, null)))\n    ),\n    Suite.test(\n      \"threesome-3\",\n      List.drop(?(1, ?(2, ?(3, null))), 3),\n      M.equals(T.list<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"threesome-4\",\n      List.drop(?(1, ?(2, ?(3, null))), 4),\n      M.equals(T.list<Nat>(T.natTestable, null))\n    )\n  ]\n);\n\nlet foldLeft = Suite.suite(\n  \"foldLeft\", [\n  Suite.test(\n      \"foldLeft\",\n      List.foldLeft<Text, Text>(?(\"a\", ?(\"b\", ?(\"c\", null))), \"\", func(acc, x) = acc # x),\n      M.equals(T.text(\"abc\"))\n    ),\n    Suite.test(\n      \"foldLeft empty\",\n      List.foldLeft<Text, Text>(null, \"base\", func(x, acc) = acc # x),\n      M.equals(T.text(\"base\"))\n    ),\n  ]\n);\n\nlet foldRight = Suite.suite(\n  \"foldRight\", [\n    Suite.test(\n      \"foldRight\",\n      List.foldRight<Text, Text>(?(\"a\", ?(\"b\", ?(\"c\", null))), \"\", func(x, acc) = acc # x),\n      M.equals(T.text(\"cba\"))\n    ),\n    Suite.test(\n      \"foldRight empty\",\n      List.foldRight<Text, Text>(null, \"base\", func(x, acc) = acc # x),\n      M.equals(T.text(\"base\"))\n    ),\n  ]\n);\n\nlet find = Suite.suite(\n  \"find\", [\n    Suite.test(\n      \"find\",\n      List.find<Nat>(?(1, ?(9, ?(4, ?(8, null)))), func x = x == 9),\n      M.equals(T.optional(T.natTestable, ?9))\n    ),\n    Suite.test(\n      \"find fail\",\n      List.find<Nat>(?(1, ?(9, ?(4, ?(8, null)))), func _ = false),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"find empty\",\n      List.find<Nat>(null, func _ = true),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n  ]\n);\n\nlet all = Suite.suite(\n  \"all\", [\n    Suite.test(\n      \"all non-empty true\",\n      List.all<Nat>(?(1, ?(9, ?(4, ?(8, null)))), func x = x > 0),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"all non-empty false\",\n      List.all<Nat>(?(1, ?(9, ?(4, ?(8, null)))), func x =  x > 1),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"all empty\",\n      List.all<Nat>(null, func x = x >= 1),\n      M.equals(T.bool(true))\n    ),\n  ]\n);\n\nlet some = Suite.suite(\n  \"some\", [\n    Suite.test(\n      \"non-empty true\",\n      List.some<Nat>(?(1, ?(9, ?(4, ?(8, null)))), func x = x >= 8),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"non-empty false\",\n      List.some<Nat>(?(1, ?(9, ?(4, ?(8, null)))), func x =  x > 9),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"empty\",\n      List.some<Nat>(null, func x = true),\n      M.equals(T.bool(false))\n    ),\n  ]\n);\n\n\nlet merge = Suite.suite(\n  \"merge\",\n  [\n    Suite.test(\n      \"small-list\",\n      List.merge<Nat>(\n        List.tabulate<Nat>(10, func i { 2 * i  }),\n        List.tabulate<Nat>(10, func i { 2 * i + 1 }),\n        func (i, j) { i <= j }\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(20, func i { i }))\n      )\n    ),\n\n    Suite.test(\n      \"small-list-alternating\",\n      List.merge<Nat>(\n        List.tabulate<Nat>(10, func i {\n          if (i % 2 == 0)\n            { 2 * i }\n          else\n            { 2 * i + 1 } }),\n        List.tabulate<Nat>(10, func i {\n          if (not (i % 2 == 0)) // flipped!\n            { 2 * i }\n          else\n            { 2 * i + 1 }\n        }),\n        func (i, j) { i <= j }\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(20, func i { i }))\n      )\n    ),\n\n    Suite.test(\n      \"small-list-equal\",\n      List.merge<Nat>(\n        List.tabulate<Nat>(10, func i { 2 * i  }),\n        List.tabulate<Nat>(10, func i { 2 * i }),\n        func (i, j) { i <= j }\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(20, func i { 2 * (i / 2) }))\n      )\n    ),\n\n    Suite.test(\n      \"large-list\",\n      List.merge<Nat>(\n        List.tabulate<Nat>(1000, func i { 2 * i }),\n        List.tabulate<Nat>(1000, func i { 2 * i + 1 }),\n        func (i, j) { i <= j }\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(2000, func i { i }))\n      )\n    )\n  ]\n);\n\n\nlet compare = Suite.suite(\n  \"compare\",\n  [\n    Suite.test(\n      \"small-list-equal\",\n      List.compare<Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(10, func i { i }),\n        Nat.compare\n      ),\n      M.equals(ordT(#equal))\n      ),\n    Suite.test(\n      \"small-list-less\",\n      List.compare<Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(11, func i { i }),\n        Nat.compare\n      ),\n      M.equals(ordT(#less))\n     ),\n    Suite.test(\n      \"small-list-less\",\n      List.compare<Nat>(\n        List.tabulate<Nat>(11, func i { i  }),\n        List.tabulate<Nat>(10, func i { i }),\n        Nat.compare\n      ),\n      M.equals(ordT(#greater))\n     ),\n    Suite.test(\n      \"empty-list-equal\",\n      List.compare<Nat>(\n        null,\n        null,\n        Nat.compare\n      ),\n      M.equals(ordT(#equal))\n      ),\n    Suite.test(\n      \"small-list-less\",\n      List.compare<Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(10, func i { if (i < 9) { i } else { i + 1 } }),\n        Nat.compare\n      ),\n      M.equals(ordT(#less))\n     ),\n    Suite.test(\n      \"small-list-greater\",\n      List.compare<Nat>(\n        List.tabulate<Nat>(10, func i { if (i < 9) { i } else { i + 1 } }),\n        List.tabulate<Nat>(10, func i { i }),\n        Nat.compare\n      ),\n      M.equals(ordT(#greater))\n     ),\n  ]\n);\n\nlet equal = Suite.suite(\n  \"equal\",\n  [\n    Suite.test(\n      \"small-list-equal\",\n      List.equal<Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(10, func i { i }),\n        Nat.equal\n      ),\n      M.equals(T.bool(true))\n      ),\n    Suite.test(\n      \"small-list-less\",\n      List.equal<Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(11, func i { i }),\n        Nat.equal\n      ),\n      M.equals(T.bool(false))\n     ),\n    Suite.test(\n      \"small-list-less\",\n      List.equal<Nat>(\n        List.tabulate<Nat>(11, func i { i  }),\n        List.tabulate<Nat>(10, func i { i }),\n        Nat.equal\n      ),\n      M.equals(T.bool(false))\n     ),\n    Suite.test(\n      \"empty-list-equal\",\n      List.equal<Nat>(\n        null,\n        null,\n        Nat.equal\n      ),\n      M.equals(T.bool(true))\n      ),\n    Suite.test(\n      \"small-list-less\",\n      List.equal<Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(10, func i { if (i < 9) { i } else { i + 1 } }),\n        Nat.equal\n      ),\n      M.equals(T.bool(false))\n     ),\n    Suite.test(\n      \"small-list-greater\",\n      List.equal<Nat>(\n        List.tabulate<Nat>(10, func i { if (i < 9) { i } else { i + 1 } }),\n        List.tabulate<Nat>(10, func i { i }),\n        Nat.equal\n      ),\n      M.equals(T.bool(false))\n     ),\n  ]\n);\n\nlet zipWith = Suite.suite(\n  \"zipWith\",\n  [\n    Suite.test(\n      \"small-list-equal-len\",\n      List.zipWith<Nat, Nat, Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(10, func i { i }),\n        func (i, j) { i * j }\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(10, func i { i  *  i}))\n      )),\n    Suite.test(\n      \"small-list-shorter\",\n      List.zipWith<Nat, Nat, Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(11, func i { i }),\n        func (i, j) { i * j }\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(10, func i { i  *  i}))\n      )),\n    Suite.test(\n      \"small-list-longer\",\n      List.zipWith<Nat, Nat, Nat>(\n        List.tabulate<Nat>(11, func i { i  }),\n        List.tabulate<Nat>(10, func i { i }),\n        func (i, j) { i * j }\n      ),\n      M.equals(\n        T.list(T.natTestable, List.tabulate<Nat>(10, func i { i  *  i}))\n      )),\n    Suite.test(\n      \"small-list-empty-left\",\n      List.zipWith<Nat, Nat, Nat>(\n        null,\n        List.tabulate<Nat>(10, func i { i }),\n        func (i, j) { i * j }\n      ),\n      M.equals(\n        T.list(T.natTestable, null : List.List<Nat>)\n      )),\n    Suite.test(\n      \"small-list-empty-right\",\n      List.zipWith<Nat, Nat, Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        null,\n        func (i, j) { i * j }\n      ),\n      M.equals(\n        T.list(T.natTestable, null : List.List<Nat>)\n      )),\n    Suite.test(\n      \"small-list-both-empty\",\n      List.zipWith<Nat, Nat, Nat>(\n        null,\n        null,\n        func (i, j) { i * j }\n      ),\n      M.equals(\n        T.list(T.natTestable, null : List.List<Nat>)\n      )),\n  ]\n);\n\nlet zip = Suite.suite(\n  \"zip\",\n  [\n    Suite.test(\n      \"small-list-equal-len\",\n      List.zip<Nat, Nat>(\n        List.tabulate<Nat>(10, func i { i }),\n        List.tabulate<Nat>(10, func i { i })\n      ),\n      M.equals(\n        T.list(T.tuple2Testable(T.natTestable,T.natTestable),\n          List.tabulate<(Nat, Nat)>(10, func i { (i, i) }))\n      )),\n    Suite.test(\n      \"small-list-shorter\",\n      List.zip<Nat, Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        List.tabulate<Nat>(11, func i { i })\n      ),\n      M.equals(\n        T.list(T.tuple2Testable(T.natTestable,T.natTestable),\n          List.tabulate<(Nat, Nat)>(10, func i { (i, i) }))\n      )),\n    Suite.test(\n      \"small-list-longer\",\n      List.zip<Nat, Nat>(\n        List.tabulate<Nat>(11, func i { i  }),\n        List.tabulate<Nat>(10, func i { i })\n      ),\n      M.equals(\n        T.list(T.tuple2Testable(T.natTestable,T.natTestable),\n          List.tabulate<(Nat, Nat)>(10, func i { (i, i) }))\n      )),\n    Suite.test(\n      \"small-list-empty-left\",\n      List.zip<Nat, Nat>(\n        null,\n        List.tabulate<Nat>(10, func i { i })\n      ),\n      M.equals(\n        T.list(T.tuple2Testable(T.natTestable,T.natTestable),\n          null : List.List<(Nat, Nat)>)\n      )),\n    Suite.test(\n      \"small-list-empty-right\",\n      List.zip<Nat, Nat>(\n        List.tabulate<Nat>(10, func i { i  }),\n        null\n      ),\n      M.equals(\n        T.list(T.tuple2Testable(T.natTestable,T.natTestable),\n          null : List.List<(Nat, Nat)>)\n      )),\n    Suite.test(\n      \"small-list-both-empty\",\n      List.zip<Nat, Nat>(\n        null,\n        null\n      ),\n      M.equals(\n        T.list(T.tuple2Testable(T.natTestable,T.natTestable),\n          null : List.List<(Nat, Nat)>)\n      )),\n  ]\n);\n\nlet split = Suite.suite(\n  \"split\",\n  [\n    Suite.test(\n      \"split-zero-nonempty\",\n      List.split<Nat>(0,\n        List.tabulate<Nat>(10, func i { i }),\n      ),\n      M.equals(\n        T.tuple2(\n          T.listTestable(T.natTestable),\n          T.listTestable(T.natTestable),\n          (null : List.List<Nat>,\n           List.tabulate<Nat>(10, func i { i })))\n      )),\n\n    Suite.test(\n      \"split-zero-empty\",\n      List.split<Nat>(0,\n        null\n      ),\n      M.equals(\n        T.tuple2(\n          T.listTestable(T.natTestable),\n          T.listTestable(T.natTestable),\n          (null : List.List<Nat>,\n           null : List.List<Nat>))\n      )),\n\n    Suite.test(\n      \"split-nonzero-empty\",\n      List.split<Nat>(15,\n        null\n      ),\n      M.equals(\n        T.tuple2(\n          T.listTestable(T.natTestable),\n          T.listTestable(T.natTestable),\n          (null : List.List<Nat>,\n           null : List.List<Nat>))\n      )),\n\n    Suite.test(\n      \"split-too-few\",\n      List.split<Nat>(15,\n        List.tabulate<Nat>(10, func i { i }),\n      ),\n      M.equals(\n        T.tuple2(\n          T.listTestable(T.natTestable),\n          T.listTestable(T.natTestable),\n          (List.tabulate<Nat>(10, func i { i }),\n           null : List.List<Nat>\n           ))\n      )),\n\n    Suite.test(\n      \"split-too-many\",\n      List.split<Nat>(10,\n        List.tabulate<Nat>(15, func i { i }),\n      ),\n      M.equals(\n        T.tuple2(\n          T.listTestable(T.natTestable),\n          T.listTestable(T.natTestable),\n          (List.tabulate<Nat>(10, func i { i }),\n           List.tabulate<Nat>(5, func i { 10 + i })\n           ))\n      )),\n\n    Suite.test(\n      \"split-one\",\n      List.split<Nat>(1,\n        List.tabulate<Nat>(15, func i { i }),\n      ),\n      M.equals(\n        T.tuple2(\n          T.listTestable(T.natTestable),\n          T.listTestable(T.natTestable),\n          (List.tabulate<Nat>(1, func i { i }),\n           List.tabulate<Nat>(14, func i { 1 + i })\n           ))\n      )),\n\n  ]\n);\n\nlet chunks = Suite.suite(\n  \"chunks\",\n  [\n    Suite.test(\n      \"five-even-split\",\n      List.chunks<Nat>(5,\n        List.tabulate<Nat>(10, func i { i }),\n      ),\n      M.equals(\n        T.list(\n          T.listTestable(T.natTestable),\n          (List.tabulate<List.List<Nat>>(2, func i {\n            List.tabulate<Nat>(5, func j { i * 5 + j }) })))\n      )),\n    Suite.test(\n      \"five-remainder\",\n      List.chunks<Nat>(5,\n        List.tabulate<Nat>(13, func i { i }),\n      ),\n      M.equals(\n        T.list(\n          T.listTestable(T.natTestable),\n          (List.tabulate<List.List<Nat>>((13+4)/5, func i {\n            List.tabulate<Nat>(if (i < 13 / 5) 5 else 13 % 5, func j { i * 5 + j }) })))\n      )),\n    Suite.test(\n      \"five-too-few\",\n      List.chunks<Nat>(5,\n        List.tabulate<Nat>(3, func i { i }),\n      ),\n      M.equals(\n        T.list(\n          T.listTestable(T.natTestable),\n          (List.tabulate<List.List<Nat>>(1, func i {\n            List.tabulate<Nat>(3, func j { i * 5 + j }) })))\n      )),\n    Suite.test(\n      \"split-zero\",\n      List.chunks<Nat>(0,\n        List.tabulate<Nat>(5, func i { i }),\n      ),\n      M.equals(\n        T.list(\n          T.listTestable(T.natTestable),\n          (null : List.List<List.List<Nat>>))\n      )),\n  ]\n);\n\n\nSuite.run(Suite.suite(\"List\", [\n  mapResult,\n  replicate,\n  tabulate,\n  append,\n  isNil,\n  push,\n  last,\n  pop,\n  size,\n  get,\n  reverse,\n  iterate,\n  map,\n  filter,\n  partition,\n  mapFilter,\n  flatten,\n  make,\n  take,\n  drop,\n  foldLeft,\n  foldRight,\n  find,\n  all,\n  some,\n  merge,\n  compare,\n  equal,\n  zipWith,\n  zip,\n  split,\n  chunks\n  ]))\n\n"},"optionTest.mo":{"content":"import Option \"mo:base/Option\";\nimport Debug \"mo:base/Debug\";\n\nDebug.print(\"Option\");\n\ndo {\n  Debug.print(\"  apply\");\n\n  do {\n    Debug.print(\"    null function, null value\");\n\n    let actual = Option.apply<Int, Bool>(null, null);\n    let expected : ?Bool = null;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (false)\n      };\n      case (_, _) {\n        assert (true)\n      }\n    }\n  };\n\n  do {\n    Debug.print(\"    null function, non-null value\");\n\n    let actual = Option.apply<Int, Bool>(?0, null);\n    let expected : ?Bool = null;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (false)\n      };\n      case (_, _) {\n        assert (true)\n      }\n    }\n  };\n\n  do {\n    Debug.print(\"    non-null function, null value\");\n\n    let isEven = func(x : Int) : Bool {\n      x % 2 == 0\n    };\n\n    let actual = Option.apply<Int, Bool>(null, ?isEven);\n    let expected : ?Bool = null;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (false)\n      };\n      case (_, _) {\n        assert (true)\n      }\n    }\n  };\n\n  do {\n    Debug.print(\"    non-null function, non-null value\");\n\n    let isEven = func(x : Int) : Bool {\n      x % 2 == 0\n    };\n\n    let actual = Option.apply<Int, Bool>(?0, ?isEven);\n    let expected = ?true;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (actual_ == expected_)\n      };\n      case (_, _) {\n        assert (false)\n      }\n    }\n  };\n\n};\n\ndo {\n  Debug.print(\"  bind\");\n\n  do {\n    Debug.print(\"    null value to null value\");\n\n    let safeInt = func(x : Int) : ?Int {\n      if (x > 9007199254740991) {\n        null\n      } else {\n        ?x\n      }\n    };\n\n    let actual = Option.chain<Int, Int>(null, safeInt);\n    let expected : ?Int = null;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (false)\n      };\n      case (_, _) {\n        assert (true)\n      }\n    }\n  };\n\n  do {\n    Debug.print(\"    non-null value to null value\");\n\n    let safeInt = func(x : Int) : ?Int {\n      if (x > 9007199254740991) {\n        null\n      } else {\n        ?x\n      }\n    };\n\n    let actual = Option.chain<Int, Int>(?9007199254740992, safeInt);\n    let expected : ?Int = null;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (false)\n      };\n      case (_, _) {\n        assert (true)\n      }\n    }\n  };\n\n  do {\n    Debug.print(\"    non-null value to non-null value\");\n\n    let safeInt = func(x : Int) : ?Int {\n      if (x > 9007199254740991) {\n        null\n      } else {\n        ?x\n      }\n    };\n\n    let actual = Option.chain<Int, Int>(?0, safeInt);\n    let expected = ?0;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (actual_ == expected_)\n      };\n      case (_, _) {\n        assert (false)\n      }\n    }\n  };\n\n};\n\ndo {\n  Debug.print(\"  flatten\");\n\n  do {\n    Debug.print(\"    null value\");\n\n    let actual = Option.flatten<Int>(?null);\n    let expected : ?Int = null;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (false)\n      };\n      case (_, _) {\n        assert (true)\n      }\n    }\n  };\n\n  do {\n    Debug.print(\"    non-null value\");\n    let actual = Option.flatten<Int>(??0);\n    let expected = ?0;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (actual_ == expected_)\n      };\n      case (_, _) {\n        assert (false)\n      }\n    }\n  };\n\n};\n\ndo {\n  Debug.print(\"  map\");\n\n  do {\n    Debug.print(\"    null value\");\n\n    let isEven = func(x : Int) : Bool {\n      x % 2 == 0\n    };\n\n    let actual = Option.map<Int, Bool>(null, isEven);\n    let expected : ?Bool = null;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (false)\n      };\n      case (_, _) {\n        assert (true)\n      }\n    }\n  };\n\n  do {\n    Debug.print(\"    non-null value\");\n\n    let isEven = func(x : Int) : Bool {\n      x % 2 == 0\n    };\n\n    let actual = Option.map<Int, Bool>(?0, isEven);\n    let expected = ?true;\n\n    switch (actual, expected) {\n      case (?actual_, ?expected_) {\n        assert (actual_ == expected_)\n      };\n      case (_, _) {\n        assert (false)\n      }\n    }\n  };\n\n};\ndo {\n  Debug.print(\"  iterate\");\n\n  do {\n    var witness = 0;\n    Option.iterate<Nat>(?(1), func(x : Nat) { witness += 1 });\n    assert (witness == 1);\n    Option.iterate<Nat>(null, func(x : Nat) { witness += 1 });\n    assert (witness == 1)\n  }\n};\n\ndo {\n  Debug.print(\"  make\");\n\n  let actual = Option.make<Int>(0);\n  let expected = ?0;\n\n  switch (actual, expected) {\n    case (?actual_, ?expected_) {\n      assert (actual_ == expected_)\n    };\n    case (_, _) {\n      assert (false)\n    }\n  }\n}\n"},"stackTest.mo":{"content":"import Stack \"mo:base/Stack\";\nimport Iter \"mo:base/Iter\";\nimport O \"mo:base/Option\";\n\ndo {\n  var s = Stack.Stack<Nat>();\n  for (i in Iter.range(0, 100)) {\n    s.push(i)\n  };\n  for (i in Iter.revRange(100, 0)) {\n    let x = s.pop();\n    assert (O.unwrap(x) == i)\n  };\n  assert (s.isEmpty())\n}\n"},"trieMapTest.mo":{"content":"import Prim \"mo:⛔\";\nimport TrieMap \"mo:base/TrieMap\";\nimport Iter \"mo:base/Iter\";\nimport Hash \"mo:base/Hash\";\nimport Text \"mo:base/Text\";\nimport Nat \"mo:base/Nat\";\n\nimport Suite \"mo:matchers/Suite\";\nimport T \"mo:matchers/Testable\";\nimport M \"mo:matchers/Matchers\";\n\n// Utilities to work with Matchers\nfunc arrayTest(array : [(Nat, Nat)]) : M.Matcher<[(Nat, Nat)]> {\n  M.equals<[(Nat, Nat)]>(T.array<(Nat, Nat)>(T.tuple2Testable<Nat, Nat>(T.natTestable, T.natTestable), array))\n};\n\n// Sample maps to use for testing\nlet map1 = TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash);\n// resulting map is {(0, 10), (2, 12), (4, 14)}\nmap1.put(0, 10);\nmap1.put(2, 12);\nmap1.put(3, 13);\nmap1.put(4, 24);\nmap1.delete(3);\nmap1.delete(4);\nmap1.put(4, 14);\n\nlet suite = Suite.suite(\n  \"TrieMap\",\n  [\n    Suite.test(\n      \"size\",\n      map1.size(),\n      M.equals(T.nat(3))\n    ),\n    Suite.test(\n      \"size empty\",\n      TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash).size(),\n      M.equals(T.nat(0))\n    ),\n    Suite.test(\n      \"put\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        map.put(5, 15);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 10), (2, 12), (4, 14), (5, 15)])\n    ),\n    Suite.test(\n      \"put overwrite\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        map.put(0, 20);\n        map.put(4, 24);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 20), (2, 12), (4, 24)])\n    ),\n    Suite.test(\n      \"put empty\",\n      do {\n        let map = TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash);\n        map.put(0, 10);\n        map.put(2, 12);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 10), (2, 12)])\n    ),\n    Suite.test(\n      \"replace old value\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        map.replace(5, 15)\n      },\n      M.equals(T.optional<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"replace new map\",\n      do {\n        let map = TrieMap.clone<Nat, Nat>(map1, Nat.equal, Hash.hash);\n        ignore map.replace(5, 15);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 10), (2, 12), (4, 14), (5, 15)])\n    ),\n    Suite.test(\n      \"replace overwrite old value\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        map.replace(0, 20)\n      },\n      M.equals(T.optional(T.natTestable, ?10))\n    ),\n    Suite.test(\n      \"replace overwrite new map\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        ignore map.replace(0, 20);\n        ignore map.replace(4, 24);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 20), (2, 12), (4, 24)])\n    ),\n    Suite.test(\n      \"replace empty\",\n      do {\n        let map = TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash);\n        ignore map.replace(0, 20);\n        ignore map.replace(4, 24);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 20), (4, 24)])\n    ),\n    Suite.test(\n      \"get\",\n      map1.get(4),\n      M.equals(T.optional(T.natTestable, ?14))\n    ),\n    Suite.test(\n      \"get key not present\",\n      map1.get(3),\n      M.equals(T.optional<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"get empty\",\n      TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash).get(3),\n      M.equals(T.optional<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"delete\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        map.delete(2);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 10), (4, 14)])\n    ),\n    Suite.test(\n      \"delete key not present\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        map.delete(3);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"delete empty\",\n      do {\n        let map = TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash);\n        map.delete(3);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([])\n    ),\n    Suite.test(\n      \"remove old value\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        map.remove(4)\n      },\n      M.equals(T.optional(T.natTestable, ?14))\n    ),\n    Suite.test(\n      \"remove new map\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        ignore map.remove(4);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 10), (2, 12)])\n    ),\n    Suite.test(\n      \"remove key not present old value\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        map.remove(3)\n      },\n      M.equals(T.optional<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"remove key not present new map\",\n      do {\n        let map = TrieMap.clone(map1, Nat.equal, Hash.hash);\n        ignore map.remove(3);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"remove empty old value\",\n      do {\n        let map = TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash);\n        map.remove(3)\n      },\n      M.equals(T.optional<Nat>(T.natTestable, null))\n    ),\n    Suite.test(\n      \"remove empty new map\",\n      do {\n        let map = TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash);\n        ignore map.remove(3);\n        Iter.toArray(map.entries())\n      },\n      arrayTest([])\n    ),\n    Suite.test(\n      \"keys\",\n      Iter.toArray(map1.keys()),\n      M.equals(T.array(T.natTestable, [0, 2, 4]))\n    ),\n    Suite.test(\n      \"keys empty\",\n      Iter.toArray(TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash).keys()),\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"vals\",\n      Iter.toArray(map1.vals()),\n      M.equals(T.array(T.natTestable, [10, 12, 14]))\n    ),\n    Suite.test(\n      \"vals empty\",\n      Iter.toArray(TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash).vals()),\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"entries\",\n      Iter.toArray(map1.entries()),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"entries empty\",\n      Iter.toArray(TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash).entries()),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"clone\",\n      Iter.toArray(TrieMap.clone<Nat, Nat>(map1, Nat.equal, Hash.hash).entries()),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"clone empty\",\n      Iter.toArray(\n        TrieMap.clone(\n          TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash),\n          Nat.equal,\n          Hash.hash\n        ).entries()\n      ),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"fromEntries round trip\",\n      Iter.toArray(\n        TrieMap.fromEntries<Nat, Nat>(\n          [(0, 10), (2, 12), (4, 14)].vals(),\n          Nat.equal,\n          Hash.hash\n        ).entries()\n      ),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"fromEntries empty round trip\",\n      Iter.toArray(\n        TrieMap.fromEntries<Nat, Nat>(\n          [].vals(),\n          Nat.equal,\n          Hash.hash\n        ).entries()\n      ),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"map\",\n      Iter.toArray(\n        TrieMap.map<Nat, Nat, Nat>(\n          map1,\n          Nat.equal,\n          Hash.hash,\n          Nat.add\n        ).entries()\n      ),\n      arrayTest([(0, 10), (2, 14), (4, 18)])\n    ),\n    Suite.test(\n      \"map empty\",\n      Iter.toArray(\n        TrieMap.map<Nat, Nat, Nat>(\n          TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash),\n          Nat.equal,\n          Hash.hash,\n          Nat.add\n        ).entries()\n      ),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"mapFilter\",\n      Iter.toArray(\n        TrieMap.mapFilter<Nat, Nat, Nat>(\n          map1,\n          Nat.equal,\n          Hash.hash,\n          func(k, v) {\n            if (k == 0) {\n              null\n            } else {\n              ?(k + v)\n            }\n          }\n        ).entries()\n      ),\n      arrayTest([(2, 14), (4, 18)])\n    ),\n    Suite.test(\n      \"mapFilter all\",\n      Iter.toArray(\n        TrieMap.mapFilter<Nat, Nat, Nat>(\n          map1,\n          Nat.equal,\n          Hash.hash,\n          func _ = null\n        ).entries()\n      ),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"mapFilter none\",\n      Iter.toArray(\n        TrieMap.mapFilter<Nat, Nat, Nat>(\n          map1,\n          Nat.equal,\n          Hash.hash,\n          func(k, v) = ?(k + v)\n        ).entries()\n      ),\n      arrayTest([(0, 10), (2, 14), (4, 18)])\n    ),\n    Suite.test(\n      \"mapFilter empty\",\n      Iter.toArray(\n        TrieMap.mapFilter<Nat, Nat, Nat>(\n          TrieMap.TrieMap<Nat, Nat>(Nat.equal, Hash.hash),\n          Nat.equal,\n          Hash.hash,\n          func(k, v) = ?(k + v)\n        ).entries()\n      ),\n      arrayTest([])\n    )\n  ]\n);\n\nSuite.run(suite);\n\ndebug {\n  let a = TrieMap.TrieMap<Text, Nat>(Text.equal, Text.hash);\n\n  assert a.size() == 0;\n  ignore a.remove(\"apple\");\n  assert a.size() == 0;\n\n  a.put(\"apple\", 1);\n  assert a.size() == 1;\n  ignore a.remove(\"apple\");\n  assert a.size() == 0;\n\n  a.put(\"apple\", 1);\n  a.put(\"banana\", 2);\n  a.put(\"pear\", 3);\n  a.put(\"avocado\", 4);\n  a.put(\"Apple\", 11);\n  a.put(\"Banana\", 22);\n  a.put(\"Pear\", 33);\n  a.put(\"Avocado\", 44);\n  a.put(\"ApplE\", 111);\n  a.put(\"BananA\", 222);\n  a.put(\"PeaR\", 333);\n  a.put(\"AvocadO\", 444);\n\n  // need to resupply the constructor args; they are private to the object; but, should they be?\n  let b = TrieMap.clone<Text, Nat>(a, Text.equal, Text.hash);\n\n  // ensure clone has each key-value pair present in original\n  for ((k, v) in a.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (b.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // ensure clone has each key present in original\n  for (k in a.keys()) {\n    switch (b.get(k)) {\n      case null { assert false };\n      case (?_) {}\n    }\n  };\n\n  // ensure clone has each value present in original\n  for (v in a.vals()) {\n    var foundMatch = false;\n    for (w in b.vals()) {\n      if (v == w) { foundMatch := true }\n    };\n    assert foundMatch\n  };\n\n  // ensure original has each key-value pair present in clone\n  for ((k, v) in b.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (a.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // do some more operations:\n  a.put(\"apple\", 1111);\n  a.put(\"banana\", 2222);\n  a.delete(\"pear\");\n  a.delete(\"avocado\");\n\n  // check them:\n  switch (a.get(\"apple\")) {\n    case (?1111) {};\n    case _ { assert false }\n  };\n  switch (a.get(\"banana\")) {\n    case (?2222) {};\n    case _ { assert false }\n  };\n  switch (a.get(\"pear\")) {\n    case null {};\n    case (?_) { assert false }\n  };\n  switch (a.get(\"avocado\")) {\n    case null {};\n    case (?_) { assert false }\n  };\n\n  // undo operations above:\n  a.put(\"apple\", 1);\n  a.put(\"banana\", 2);\n  a.put(\"pear\", 3);\n  a.put(\"avocado\", 4);\n\n  // ensure clone has each key-value pair present in original\n  for ((k, v) in a.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (b.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // ensure original has each key-value pair present in clone\n  for ((k, v) in b.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (a.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // test fromEntries method\n  let c = TrieMap.fromEntries<Text, Nat>(b.entries(), Text.equal, Text.hash);\n\n  // c agrees with each entry of b\n  for ((k, v) in b.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (c.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // b agrees with each entry of c\n  for ((k, v) in c.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (b.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  }\n}\n"},"hashMapTest.mo":{"content":"import Prim \"mo:⛔\";\nimport H \"mo:base/HashMap\";\nimport Hash \"mo:base/Hash\";\nimport Text \"mo:base/Text\";\n\ndebug {\n  let a = H.HashMap<Text, Nat>(3, Text.equal, Text.hash);\n\n  a.put(\"apple\", 1);\n  a.put(\"banana\", 2);\n  a.put(\"pear\", 3);\n  a.put(\"avocado\", 4);\n  a.put(\"Apple\", 11);\n  a.put(\"Banana\", 22);\n  a.put(\"Pear\", 33);\n  a.put(\"Avocado\", 44);\n  a.put(\"ApplE\", 111);\n  a.put(\"BananA\", 222);\n  a.put(\"PeaR\", 333);\n  a.put(\"AvocadO\", 444);\n\n  // need to resupply the constructor args; they are private to the object; but, should they be?\n  let b = H.clone<Text, Nat>(a, Text.equal, Text.hash);\n\n  // ensure clone has each key-value pair present in original\n  for ((k, v) in a.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (b.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // ensure original has each key-value pair present in clone\n  for ((k, v) in b.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (a.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // ensure clone has each key present in original\n  for (k in a.keys()) {\n    switch (b.get(k)) {\n      case null { assert false };\n      case (?_) {}\n    }\n  };\n\n  // ensure clone has each value present in original\n  for (v in a.vals()) {\n    var foundMatch = false;\n    for (w in b.vals()) {\n      if (v == w) { foundMatch := true }\n    };\n    assert foundMatch\n  };\n\n  // do some more operations:\n  a.put(\"apple\", 1111);\n  a.put(\"banana\", 2222);\n  switch (a.remove(\"pear\")) {\n    case null { assert false };\n    case (?three) { assert three == 3 }\n  };\n  a.delete(\"avocado\");\n\n  // check them:\n  switch (a.get(\"apple\")) {\n    case (?1111) {};\n    case _ { assert false }\n  };\n  switch (a.get(\"banana\")) {\n    case (?2222) {};\n    case _ { assert false }\n  };\n  switch (a.get(\"pear\")) {\n    case null {};\n    case (?_) { assert false }\n  };\n  switch (a.get(\"avocado\")) {\n    case null {};\n    case (?_) { assert false }\n  };\n\n  // undo operations above:\n  a.put(\"apple\", 1);\n  // .. and test that replace works\n  switch (a.replace(\"apple\", 666)) {\n    case null { assert false };\n    case (?one) {\n      assert one == 1; // ...and revert\n      a.put(\"apple\", 1)\n    }\n  };\n  a.put(\"banana\", 2);\n  a.put(\"pear\", 3);\n  a.put(\"avocado\", 4);\n\n  // ensure clone has each key-value pair present in original\n  for ((k, v) in a.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (b.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // ensure original has each key-value pair present in clone\n  for ((k, v) in b.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (a.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // test fromIter method\n  let c = H.fromIter<Text, Nat>(b.entries(), 0, Text.equal, Text.hash);\n\n  // c agrees with each entry of b\n  for ((k, v) in b.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (c.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // b agrees with each entry of c\n  for ((k, v) in c.entries()) {\n    Prim.debugPrint(debug_show (k, v));\n    switch (b.get(k)) {\n      case null { assert false };\n      case (?w) { assert v == w }\n    }\n  };\n\n  // Issue #228\n  let d = H.HashMap<Text, Nat>(50, Text.equal, Text.hash);\n  switch (d.remove(\"test\")) {\n    case null {};\n    case (?_) { assert false }\n  }\n}\n"},"testLenClamp.mo":{"content":"import List \"mo:base/List\";\nimport Trie \"mo:base/Trie\";\nimport Debug \"mo:base/Debug\";\n\ntype List<T> = List.List<T>;\n\n/* copied because private to Trie.mo */\nfunc lenClamp<T>(l : List<T>, max : Nat) : ?Nat {\n  func rec(l : List<T>, max : Nat, i : Nat) : ?Nat {\n    switch l {\n      case null { ?i };\n      case (?(_, t)) {\n        if (i >= max) { null } else { rec(t, max, i + 1) }\n      }\n    }\n  };\n  rec(l, max, 0)\n};\n\nvar s = 0;\nvar l = List.nil<Nat>();\n\nwhile (s < 10) {\n  var m = 0;\n  while (m <= s + 3) {\n    let o = lenClamp(l, m);\n    Debug.print(debug_show ({ l = List.toArray(l); m; o }));\n    assert (s == List.size(l));\n    assert (if (s <= m) { o == ?s } else { o == null });\n    m += 1\n  };\n  l := List.push(s +1, l);\n  s += 1\n}\n"},"natTest.mo":{"content":"import Debug \"mo:base/Debug\";\nimport Nat \"mo:base/Nat\";\n\nDebug.print(\"Nat\");\n\ndo {\n  Debug.print(\"  add\");\n\n  assert (Nat.add(1, Nat.add(2, 3)) == Nat.add(1, Nat.add(2, 3)));\n  assert (Nat.add(0, 1) == 1);\n  assert (1 == Nat.add(1, 0));\n  assert (Nat.add(0, 1) == Nat.add(1, 0));\n  assert (Nat.add(1, 2) == Nat.add(2, 1))\n};\n\ndo {\n  Debug.print(\"  toText\");\n\n  assert (Nat.toText(0) == \"0\");\n  assert (Nat.toText(1234) == \"1234\")\n}\n"},"trieSetTest.mo":{"content":"import Nat \"mo:base/Nat\";\nimport TrieSet \"mo:base/TrieSet\";\nimport Nat32 \"mo:base/Nat32\";\nimport Hash \"mo:base/Hash\";\nimport Suite \"mo:matchers/Suite\";\nimport M \"mo:matchers/Matchers\";\nimport T \"mo:matchers/Testable\";\n\nlet simpleTests = do {\n  let set1 = TrieSet.fromArray<Nat>([1, 2, 3, 1, 2, 3, 1], Nat32.fromNat, Nat.equal);\n\n  let suite = Suite.suite(\n    \"TrieSet fromArray\",\n    [\n      Suite.test(\n        \"mem\",\n        TrieSet.mem<Nat>(set1, 1, 1, Nat.equal),\n        M.equals(T.bool true)\n      ),\n      Suite.test(\n        \"size\",\n        TrieSet.size(set1),\n        M.equals(T.nat 3)\n      ),\n      Suite.test(\n        \"toArray\",\n        TrieSet.toArray<Nat>(set1),\n        M.equals(T.array<Nat>(T.natTestable, [1, 2, 3]))\n      )\n    ]\n  );\n  Suite.run(suite)\n};\n\nlet binopTests = do {\n  let a = TrieSet.fromArray<Nat>([1, 3], Hash.hash, Nat.equal);\n  let b = TrieSet.fromArray<Nat>([2, 3], Hash.hash, Nat.equal);\n\n  let suite = Suite.suite(\n    \"TrieSet -- binary operations\",\n    [\n      Suite.test(\n        \"union\",\n        TrieSet.toArray(TrieSet.union(a, b, Nat.equal)),\n        M.equals(T.array<Nat>(T.natTestable, [1, 2, 3]))\n      ),\n      Suite.test(\n        \"intersect\",\n        TrieSet.toArray(TrieSet.intersect(a, b, Nat.equal)),\n        M.equals(T.array<Nat>(T.natTestable, [3]))\n      ),\n      Suite.test(\n        \"diff\",\n        TrieSet.toArray(TrieSet.diff(a, b, Nat.equal)),\n        M.equals(T.array<Nat>(T.natTestable, [1]))\n      )\n    ]\n  );\n  Suite.run(suite)\n}\n"},"RBTreeTest.mo":{"content":"import Debug \"mo:base/Debug\";\nimport Nat \"mo:base/Nat\";\nimport I \"mo:base/Iter\";\nimport List \"mo:base/List\";\nimport RBT \"mo:base/RBTree\";\n\nlet sorted = [\n  (1, \"reformer\"),\n  (2, \"helper\"),\n  (3, \"achiever\"),\n  (4, \"individualist\"),\n  (5, \"investigator\"),\n  (6, \"loyalist\"),\n  (7, \"enthusiast\"),\n  (8, \"challenger\"),\n  (9, \"peacemaker\")\n];\n\nlet unsort = [\n  (6, \"loyalist\"),\n  (3, \"achiever\"),\n  (9, \"peacemaker\"),\n  (1, \"reformer\"),\n  (4, \"individualist\"),\n  (2, \"helper\"),\n  (8, \"challenger\"),\n  (5, \"investigator\"),\n  (7, \"enthusiast\")\n];\n\nvar t = RBT.RBTree<Nat, Text>(Nat.compare);\n\nassert RBT.size(t.share()) == 0;\n\nfor ((num, lab) in unsort.vals()) {\n  Debug.print(Nat.toText num);\n  Debug.print lab;\n  t.put(num, lab)\n};\n\ndo {\n  var i = 1;\n  for ((num, lab) in t.entries()) {\n    assert (num == i);\n    i += 1\n  }\n};\n\nassert RBT.size(t.share()) == 9;\n\ndo {\n  var i = 9;\n  for ((num, lab) in t.entriesRev()) {\n    assert (num == i);\n    i -= 1\n  }\n};\n\nassert RBT.size(t.share()) == 9;\n\nt.delete(5);\n\nassert RBT.size(t.share()) == 8\n"},"arrayTest.mo":{"content":"import Array \"mo:base/Array\";\nimport Int \"mo:base/Int\";\nimport Nat \"../src/Nat\";\nimport Text \"mo:base/Text\";\nimport Result \"mo:base/Result\";\nimport Suite \"mo:matchers/Suite\";\nimport T \"mo:matchers/Testable\";\nimport M \"mo:matchers/Matchers\";\n\nlet suite = Suite.suite(\n  \"Array\",\n  [\n    Suite.test(\n      \"init\",\n      Array.freeze(Array.init<Int>(3, 4)),\n      M.equals(T.array<Int>(T.intTestable, [4, 4, 4]))\n    ),\n    Suite.test(\n      \"init empty\",\n      Array.freeze(Array.init<Int>(0, 4)),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"tabulate\",\n      Array.tabulate<Int>(3, func(i : Nat) = i * 2),\n      M.equals(T.array<Int>(T.intTestable, [0, 2, 4]))\n    ),\n    Suite.test(\n      \"tabulate empty\",\n      Array.tabulate<Int>(0, func(i : Nat) = i),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"tabulateVar\",\n      Array.freeze(Array.tabulateVar<Int>(3, func(i : Nat) = i * 2)),\n      M.equals(T.array<Int>(T.intTestable, [0, 2, 4]))\n    ),\n    Suite.test(\n      \"tabulateVar empty\",\n      Array.freeze(Array.tabulateVar<Int>(0, func(i : Nat) = i)),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"freeze\",\n      Array.freeze<Int>([var 1, 2, 3]),\n      M.equals(T.array<Int>(T.intTestable, [1, 2, 3]))\n    ),\n    Suite.test(\n      \"freeze empty\",\n      Array.freeze<Int>([var]),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"thaw round trip\",\n      Array.freeze(Array.thaw<Int>([1, 2, 3])),\n      M.equals(T.array<Int>(T.intTestable, [1, 2, 3]))\n    ),\n    Suite.test(\n      \"thaw round trip empty\",\n      Array.freeze(Array.thaw<Int>([])),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"equal\",\n      Array.equal<Int>([1, 2, 3], [1, 2, 3], Int.equal),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"equal empty\",\n      Array.equal<Int>([], [], Int.equal),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"not equal one empty\",\n      Array.equal<Int>([], [2, 3], Int.equal),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"not equal different lengths\",\n      Array.equal<Int>([1, 2, 3], [2, 4], Int.equal),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"not equal same lengths\",\n      Array.equal<Int>([1, 2, 3], [1, 2, 4], Int.equal),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"find\",\n      Array.find<Nat>([1, 9, 4, 8], func x = x == 9),\n      M.equals(T.optional(T.natTestable, ?9))\n    ),\n    Suite.test(\n      \"find fail\",\n      Array.find<Nat>([1, 9, 4, 8], func _ = false),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"find empty\",\n      Array.find<Nat>([], func _ = true),\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"append\",\n      Array.append<Int>([1, 2, 3], [4, 5, 6]),\n      M.equals(T.array<Int>(T.intTestable, [1, 2, 3, 4, 5, 6]))\n    ),\n    Suite.test(\n      \"append first empty\",\n      Array.append<Int>([], [4, 5, 6]),\n      M.equals(T.array<Int>(T.intTestable, [4, 5, 6]))\n    ),\n    Suite.test(\n      \"append second empty\",\n      Array.append<Int>([1, 2, 3], []),\n      M.equals(T.array<Int>(T.intTestable, [1, 2, 3]))\n    ),\n    Suite.test(\n      \"append both empty\",\n      Array.append<Int>([], []),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"sort\",\n      Array.sort([2, 3, 1], Nat.compare),\n      M.equals(T.array<Nat>(T.natTestable, [1, 2, 3]))\n    ),\n    Suite.test(\n      \"sort empty array\",\n      Array.sort([], Nat.compare),\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"sort already sorted\",\n      Array.sort([1, 2, 3, 4, 5], Nat.compare),\n      M.equals(T.array<Nat>(T.natTestable, [1, 2, 3, 4, 5]))\n    ),\n    Suite.test(\n      \"sort repeated elements\",\n      Array.sort([2, 2, 2, 2, 2], Nat.compare),\n      M.equals(T.array<Nat>(T.natTestable, [2, 2, 2, 2, 2]))\n    ),\n    Suite.test(\n      \"sortInPlace\",\n      do {\n        let array = [var 2, 3, 1];\n        Array.sortInPlace(array, Nat.compare);\n        Array.freeze(array)\n      },\n      M.equals(T.array<Nat>(T.natTestable, [1, 2, 3]))\n    ),\n    Suite.test(\n      \"sortInPlace empty\",\n      do {\n        let array = [var];\n        Array.sortInPlace(array, Nat.compare);\n        Array.freeze(array)\n      },\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"sortInPlace already sorted\",\n      do {\n        let array = [var 1, 2, 3, 4, 5];\n        Array.sortInPlace(array, Nat.compare);\n        Array.freeze(array)\n      },\n      M.equals(T.array<Nat>(T.natTestable, [1, 2, 3, 4, 5]))\n    ),\n    Suite.test(\n      \"sortInPlace repeated elements\",\n      do {\n        let array = [var 2, 2, 2, 2, 2];\n        Array.sortInPlace(array, Nat.compare);\n        Array.freeze(array)\n      },\n      M.equals(T.array<Nat>(T.natTestable, [2, 2, 2, 2, 2]))\n    ),\n    Suite.test(\n      \"reverse\",\n      Array.reverse<Nat>([0, 1, 2, 2, 3]),\n      M.equals(T.array<Nat>(T.natTestable, [3, 2, 2, 1, 0]))\n    ),\n    Suite.test(\n      \"reverse empty\",\n      Array.reverse<Nat>([]),\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"reverse singleton\",\n      Array.reverse<Nat>([0]),\n      M.equals(T.array<Nat>(T.natTestable, [0]))\n    ),\n    Suite.test(\n      \"map\",\n      Array.map<Nat, Bool>([1, 2, 3], func x = x % 2 == 0),\n      M.equals(T.array<Bool>(T.boolTestable, [false, true, false]))\n    ),\n    Suite.test(\n      \"map empty\",\n      Array.map<Nat, Bool>([], func x = x % 2 == 0),\n      M.equals(T.array<Bool>(T.boolTestable, []))\n    ),\n    Suite.test(\n      \"filter\",\n      Array.filter<Nat>([1, 2, 3, 4, 5, 6], func x = x % 2 == 0),\n      M.equals(T.array<Nat>(T.natTestable, [2, 4, 6]))\n    ),\n    Suite.test(\n      \"filter empty\",\n      Array.filter<Nat>([], func x = x % 2 == 0),\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"mapEntries\",\n      Array.mapEntries<Nat, Nat>([1, 2, 3], func(x, i) = x + i),\n      M.equals(T.array<Nat>(T.natTestable, [1, 3, 5]))\n    ),\n    Suite.test(\n      \"mapEntries empty\",\n      Array.mapEntries<Nat, Nat>([], func(x, i) = x + i),\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"mapFilter\",\n      Array.mapFilter<Nat, Nat>([1, 2, 3, 4, 5, 6], func x { if (x % 2 == 0) ?x else null }),\n      M.equals(T.array<Nat>(T.natTestable, [2, 4, 6]))\n    ),\n    Suite.test(\n      \"mapFilter keep all\",\n      Array.mapFilter<Nat, Nat>([1, 2, 3], func x = ?x),\n      M.equals(T.array<Nat>(T.natTestable, [1, 2, 3]))\n    ),\n    Suite.test(\n      \"mapFilter keep none\",\n      Array.mapFilter<Nat, Nat>([1, 2, 3], func _ = null),\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"mapFilter empty\",\n      Array.mapFilter<Nat, Nat>([], func x { if (x % 2 == 0) ?x else null }),\n      M.equals(T.array<Nat>(T.natTestable, []))\n    ),\n    Suite.test(\n      \"mapResult\",\n      Array.mapResult<Int, Nat, Text>(\n        [1, 2, 3],\n        func x { if (x >= 0) { #ok(Int.abs x) } else { #err \"error message\" } }\n      ),\n      M.equals(T.result<[Nat], Text>(T.arrayTestable(T.natTestable), T.textTestable, #ok([1, 2, 3])))\n    ),\n    Suite.test(\n      \"mapResult fail first\",\n      Array.mapResult<Int, Nat, Text>(\n        [-1, 2, 3],\n        func x { if (x >= 0) { #ok(Int.abs x) } else { #err \"error message\" } }\n      ),\n      M.equals(T.result<[Nat], Text>(T.arrayTestable(T.natTestable), T.textTestable, #err \"error message\"))\n    ),\n    Suite.test(\n      \"mapResult fail last\",\n      Array.mapResult<Int, Nat, Text>(\n        [1, 2, -3],\n        func x { if (x >= 0) { #ok(Int.abs x) } else { #err \"error message\" } }\n      ),\n      M.equals(T.result<[Nat], Text>(T.arrayTestable(T.natTestable), T.textTestable, #err \"error message\"))\n    ),\n    Suite.test(\n      \"mapResult empty\",\n      Array.mapResult<Nat, Nat, Text>(\n        [],\n        func x = #ok x\n      ),\n      M.equals(T.result<[Nat], Text>(T.arrayTestable(T.natTestable), T.textTestable, #ok([])))\n    ),\n    Suite.test(\n      \"chain\",\n      Array.chain<Int, Int>([0, 1, 2], func x = [x, -x]),\n      M.equals(T.array<Int>(T.intTestable, [0, 0, 1, -1, 2, -2]))\n    ),\n    Suite.test(\n      \"chain empty\",\n      Array.chain<Int, Int>([], func x = [x, -x]),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"foldLeft\",\n      Array.foldLeft<Text, Text>([\"a\", \"b\", \"c\"], \"\", Text.concat),\n      M.equals(T.text(\"abc\"))\n    ),\n    Suite.test(\n      \"foldLeft empty\",\n      Array.foldLeft<Text, Text>([], \"base\", Text.concat),\n      M.equals(T.text(\"base\"))\n    ),\n    Suite.test(\n      \"foldRight\",\n      Array.foldRight<Text, Text>([\"a\", \"b\", \"c\"], \"\", func(x, acc) = acc # x),\n      M.equals(T.text(\"cba\"))\n    ),\n    Suite.test(\n      \"foldRight empty\",\n      Array.foldRight<Text, Text>([], \"base\", Text.concat),\n      M.equals(T.text(\"base\"))\n    ),\n    Suite.test(\n      \"flatten\",\n      Array.flatten<Int>([[1, 2, 3], [], [1]]),\n      M.equals(T.array<Int>(T.intTestable, [1, 2, 3, 1]))\n    ),\n    Suite.test(\n      \"flatten empty start\",\n      Array.flatten<Int>([[], [1, 2, 3], [], [1]]),\n      M.equals(T.array<Int>(T.intTestable, [1, 2, 3, 1]))\n    ),\n    Suite.test(\n      \"flatten empty end\",\n      Array.flatten<Int>([[1, 2, 3], [], [1], []]),\n      M.equals(T.array<Int>(T.intTestable, [1, 2, 3, 1]))\n    ),\n    Suite.test(\n      \"flatten singleton\",\n      Array.flatten<Int>([[1, 2, 3]]),\n      M.equals(T.array<Int>(T.intTestable, [1, 2, 3]))\n    ),\n    Suite.test(\n      \"flatten empty\",\n      Array.flatten<Int>([[]]),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"flatten empty\",\n      Array.flatten<Int>([]),\n      M.equals(T.array<Int>(T.intTestable, []))\n    ),\n    Suite.test(\n      \"make\",\n      Array.make<Int>(0),\n      M.equals(T.array<Int>(T.intTestable, [0]))\n    ),\n    Suite.test(\n      \"vals\",\n      do {\n        var sum = 0;\n        for (x in Array.vals([1, 2, 3])) {\n          sum += x\n        };\n        sum\n      },\n      M.equals(T.nat(6))\n    ),\n    Suite.test(\n      \"vals empty\",\n      do {\n        var sum = 0;\n        for (x in Array.vals([])) {\n          sum += x\n        };\n        sum\n      },\n      M.equals(T.nat(0))\n    ),\n    Suite.test(\n      \"keys\",\n      do {\n        var sum = 0;\n        for (x in Array.keys([1, 2, 3])) {\n          sum += x\n        };\n        sum\n      },\n      M.equals(T.nat(3))\n    ),\n    Suite.test(\n      \"keys empty\",\n      do {\n        var sum = 0;\n        for (x in Array.keys([])) {\n          sum += x\n        };\n        sum\n      },\n      M.equals(T.nat(0))\n    )\n  ]\n);\n\nSuite.run(suite)\n"},"resultTest.mo":{"content":"import Result \"mo:base/Result\";\nimport Int \"mo:base/Int\";\nimport Array \"mo:base/Array\";\nimport List \"mo:base/List\";\n\nimport Suite \"mo:matchers/Suite\";\nimport M \"mo:matchers/Matchers\";\nimport T \"mo:matchers/Testable\";\n\nfunc makeNatural(x : Int) : Result.Result<Nat, Text> = if (x >= 0) {\n  #ok(Int.abs(x))\n} else { #err(Int.toText(x) # \" is not a natural number.\") };\n\nfunc largerThan10(x : Nat) : Result.Result<Nat, Text> = if (x > 10) { #ok(x) } else {\n  #err(Int.toText(x) # \" is not larger than 10.\")\n};\n\nlet chain = Suite.suite(\n  \"chain\",\n  [\n    Suite.test(\n      \"ok -> ok\",\n      Result.chain<Nat, Nat, Text>(makeNatural(11), largerThan10),\n      M.equals(T.result<Nat, Text>(T.natTestable, T.textTestable, #ok(11)))\n    ),\n    Suite.test(\n      \"ok -> err\",\n      Result.chain<Nat, Nat, Text>(makeNatural(5), largerThan10),\n      M.equals(T.result<Nat, Text>(T.natTestable, T.textTestable, #err(\"5 is not larger than 10.\")))\n    ),\n    Suite.test(\n      \"err\",\n      Result.chain<Nat, Nat, Text>(makeNatural(-5), largerThan10),\n      M.equals(T.result<Nat, Text>(T.natTestable, T.textTestable, #err(\"-5 is not a natural number.\")))\n    )\n  ]\n);\n\nlet flatten = Suite.suite(\n  \"flatten\",\n  [\n    Suite.test(\n      \"ok -> ok\",\n      Result.flatten<Nat, Text>(#ok(#ok(10))),\n      M.equals(T.result<Nat, Text>(T.natTestable, T.textTestable, #ok(10)))\n    ),\n    Suite.test(\n      \"err\",\n      Result.flatten<Nat, Text>(#err(\"wrong\")),\n      M.equals(T.result<Nat, Text>(T.natTestable, T.textTestable, #err(\"wrong\")))\n    ),\n    Suite.test(\n      \"ok -> err\",\n      Result.flatten<Nat, Text>(#ok(#err(\"wrong\"))),\n      M.equals(T.result<Nat, Text>(T.natTestable, T.textTestable, #err(\"wrong\")))\n    )\n  ]\n);\n\nlet iterate = Suite.suite(\n  \"iterate\",\n  do {\n    var tests : [Suite.Suite] = [];\n    var counter : Nat = 0;\n    Result.iterate(makeNatural(5), func(x : Nat) { counter += x });\n    tests := Array.append(tests, [Suite.test(\"ok\", counter, M.equals(T.nat(5)))]);\n    Result.iterate(makeNatural(-10), func(x : Nat) { counter += x });\n    tests := Array.append(tests, [Suite.test(\"err\", counter, M.equals(T.nat(5)))]);\n    tests\n  }\n);\n\nlet suite = Suite.suite(\n  \"Result\",\n  [\n    chain,\n    flatten,\n    iterate\n  ]\n);\n\nSuite.run(suite)\n"},"trieTest.mo":{"content":"import Trie \"mo:base/Trie\";\nimport List \"mo:base/List\";\nimport Nat \"mo:base/Nat\";\nimport Hash \"mo:base/Hash\";\nimport Option \"mo:base/Option\";\nimport Iter \"mo:base/Iter\";\nimport Text \"mo:base/Text\";\nimport Debug \"mo:base/Debug\";\nimport Array \"mo:base/Array\";\n\nimport Suite \"mo:matchers/Suite\";\nimport T \"mo:matchers/Testable\";\nimport M \"mo:matchers/Matchers\";\n\nlet test = Suite;\n\n// Utilities to massage types between Trie and Matchers\nfunc prettyArray(trie : Trie.Trie<Nat, Nat>) : [(Nat, Nat)] {\n  Trie.toArray<Nat, Nat, (Nat, Nat)>(trie, func kv = kv)\n};\n\nfunc prettyArray2D(trie2D1 : Trie.Trie2D<Nat, Nat, Nat>) : [((Nat, Nat), Nat)] {\n  Array.flatten(\n    Trie.toArray<Nat, Trie.Trie<Nat, Nat>, [((Nat, Nat), Nat)]>(\n      trie2D1,\n      func(k1, trie) {\n        let innerArray = prettyArray trie;\n        Array.map<(Nat, Nat), ((Nat, Nat), Nat)>(innerArray, func(k2, v) = ((k1, k2), v))\n      }\n    )\n  )\n};\n\nfunc prettyArray3D(trie3D : Trie.Trie3D<Nat, Nat, Nat, Nat>) : [((Nat, Nat, Nat), Nat)] {\n  Array.flatten(\n    Trie.toArray<Nat, Trie.Trie<Nat, Trie.Trie<Nat, Nat>>, [((Nat, Nat, Nat), Nat)]>(\n      trie3D,\n      func(k1, trie2D1) {\n        let innerArray = prettyArray2D trie2D1;\n        Array.map<((Nat, Nat), Nat), ((Nat, Nat, Nat), Nat)>(innerArray, func((k2, k3), v) = ((k1, k2, k3), v))\n      }\n    )\n  )\n};\n\nfunc arrayTest(array : [(Nat, Nat)]) : M.Matcher<[(Nat, Nat)]> {\n  M.equals<[(Nat, Nat)]>(T.array<(Nat, Nat)>(T.tuple2Testable<Nat, Nat>(T.natTestable, T.natTestable), array))\n};\n\nfunc arrayTest2D(array : [((Nat, Nat), Nat)]) : M.Matcher<[((Nat, Nat), Nat)]> {\n  M.equals<[((Nat, Nat), Nat)]>(\n    T.array<((Nat, Nat), Nat)>(\n      T.tuple2Testable<(Nat, Nat), Nat>(\n        T.tuple2Testable<Nat, Nat>(T.natTestable, T.natTestable),\n        T.natTestable\n      ),\n      array\n    )\n  )\n};\n\nfunc arrayTest3D(array : [((Nat, Nat, Nat), Nat)]) : M.Matcher<[((Nat, Nat, Nat), Nat)]> {\n  let tuple3Testable : T.Testable<(Nat, Nat, Nat)> = {\n    display = func t { debug_show t };\n    equals = func(t1, t2) { t1 == t2 }\n  };\n\n  M.equals<[((Nat, Nat, Nat), Nat)]>(\n    T.array<((Nat, Nat, Nat), Nat)>(\n      T.tuple2Testable<(Nat, Nat, Nat), Nat>(\n        tuple3Testable,\n        T.natTestable\n      ),\n      array\n    )\n  )\n};\n\nfunc natKey(nat : Nat) : Trie.Key<Nat> { { hash = Hash.hash(nat); key = nat } };\nlet natKeyTestable : T.Testable<Trie.Key<Nat>> = {\n  display = func k { debug_show k.key };\n  equals = func(k1, k2) { k1 == k2 }\n};\n\n// Sample tries for testing\n// FIXME tweak the keys to force collisions here\nvar trie1 = Trie.empty<Nat, Nat>();\ntrie1 := Trie.put<Nat, Nat>(trie1, natKey(0), Nat.equal, 10).0;\ntrie1 := Trie.put<Nat, Nat>(trie1, natKey(2), Nat.equal, 12).0;\ntrie1 := Trie.put<Nat, Nat>(trie1, natKey(4), Nat.equal, 14).0;\n\nvar trie2 = Trie.empty<Nat, Nat>();\ntrie2 := Trie.put<Nat, Nat>(trie2, natKey(1), Nat.equal, 11).0;\ntrie2 := Trie.put<Nat, Nat>(trie2, natKey(3), Nat.equal, 13).0;\n\nvar trie3 = Trie.empty<Nat, Nat>();\ntrie3 := Trie.put<Nat, Nat>(trie3, natKey(1), Nat.equal, 21).0;\ntrie3 := Trie.put<Nat, Nat>(trie3, natKey(2), Nat.equal, 22).0;\n\n// Sample 2D trie for testing\nvar trie2D1 = Trie.empty<Nat, Trie.Trie<Nat, Nat>>();\ntrie2D1 := Trie.put2D<Nat, Nat, Nat>(trie2D1, natKey(0), Nat.equal, natKey(10), Nat.equal, 100);\ntrie2D1 := Trie.put2D<Nat, Nat, Nat>(trie2D1, natKey(2), Nat.equal, natKey(12), Nat.equal, 102);\ntrie2D1 := Trie.put2D<Nat, Nat, Nat>(trie2D1, natKey(4), Nat.equal, natKey(14), Nat.equal, 104);\n\nvar trie2D2 = Trie.empty<Nat, Trie.Trie<Nat, Nat>>();\ntrie2D2 := Trie.put2D<Nat, Nat, Nat>(trie2D2, natKey(1), Nat.equal, natKey(11), Nat.equal, 101);\ntrie2D2 := Trie.put2D<Nat, Nat, Nat>(trie2D2, natKey(1), Nat.equal, natKey(21), Nat.equal, 201);\ntrie2D2 := Trie.put2D<Nat, Nat, Nat>(trie2D2, natKey(2), Nat.equal, natKey(12), Nat.equal, 102);\ntrie2D2 := Trie.put2D<Nat, Nat, Nat>(trie2D2, natKey(3), Nat.equal, natKey(13), Nat.equal, 103);\ntrie2D2 := Trie.put2D<Nat, Nat, Nat>(trie2D2, natKey(3), Nat.equal, natKey(23), Nat.equal, 203);\ntrie2D2 := Trie.put2D<Nat, Nat, Nat>(trie2D2, natKey(3), Nat.equal, natKey(33), Nat.equal, 303);\n\n// Sample 3D trie for testing\nvar trie3D = Trie.empty<Nat, Trie.Trie<Nat, Trie.Trie<Nat, Nat>>>();\ntrie3D := Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(0), Nat.equal, natKey(10), Nat.equal, natKey(100), Nat.equal, 1000);\ntrie3D := Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(2), Nat.equal, natKey(12), Nat.equal, natKey(102), Nat.equal, 1002);\ntrie3D := Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(4), Nat.equal, natKey(14), Nat.equal, natKey(104), Nat.equal, 1004);\n\n// Matchers tests\nlet suite = Suite.suite(\n  \"Trie\",\n  [\n    Suite.test(\n      \"empty trie size 0\",\n      Trie.size(Trie.empty()),\n      M.equals(T.nat(0))\n    ),\n    Suite.test(\n      \"empty trie array roundtrip\",\n      prettyArray(Trie.empty()),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"put 1\",\n      prettyArray(Trie.put<Nat, Nat>(Trie.empty(), natKey(0), Nat.equal, 10).0),\n      arrayTest([(0, 10)])\n    ),\n    Suite.test(\n      \"put get 1\",\n      Trie.get(Trie.put<Nat, Nat>(Trie.empty(), natKey(0), Nat.equal, 10).0, natKey(0), Nat.equal),\n      M.equals(T.optional(T.natTestable, ?10))\n    ),\n    Suite.test(\n      \"put find 1\",\n      Trie.find(Trie.put<Nat, Nat>(Trie.empty(), natKey(0), Nat.equal, 10).0, natKey(0), Nat.equal),\n      M.equals(T.optional(T.natTestable, ?10))\n    ),\n    Suite.test(\n      \"merge\",\n      prettyArray(Trie.merge(trie1, trie3, Nat.equal)),\n      arrayTest([(0, 10), (4, 14), (1, 21), (2, 12)])\n    ),\n    Suite.test(\n      \"merge with empty\",\n      prettyArray(Trie.merge(trie1, Trie.empty(), Nat.equal)),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"merge two empties\",\n      prettyArray(Trie.merge(Trie.empty(), Trie.empty(), Nat.equal)),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"merge disjoint\",\n      prettyArray(Trie.mergeDisjoint(trie1, trie2, Nat.equal)),\n      arrayTest([(0, 10), (2, 12), (4, 14), (1, 11), (3, 13)])\n    ),\n    Suite.test(\n      \"merge disjoint one empty\",\n      prettyArray(Trie.mergeDisjoint(trie1, Trie.empty(), Nat.equal)),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"merge disjoint two empties\",\n      prettyArray(Trie.mergeDisjoint(Trie.empty(), Trie.empty(), Nat.equal)),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"diff\",\n      prettyArray(Trie.diff(trie1, trie3, Nat.equal)),\n      arrayTest([(0, 10), (4, 14)])\n    ),\n    Suite.test(\n      \"diff non-commutative\",\n      prettyArray(Trie.diff(trie3, trie1, Nat.equal)),\n      arrayTest([(1, 21)])\n    ),\n    Suite.test(\n      \"diff empty right\",\n      prettyArray(Trie.diff(trie1, Trie.empty(), Nat.equal)),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"diff empty left\",\n      prettyArray(Trie.diff(Trie.empty(), trie1, Nat.equal)),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"disj\",\n      prettyArray(\n        Trie.disj<Nat, Nat, Nat, Nat>(\n          trie1,\n          trie3,\n          Nat.equal,\n          func(v1, v2) {\n            switch (v1, v2) {\n              case (?v1, ?v2) v1 + v2; // add values to combine\n              case (?v1, null) v1;\n              case (null, ?v2) v2;\n              case (null, null) Debug.trap \"unreachable in disj\"\n            }\n          }\n        )\n      ),\n      arrayTest([(0, 10), (4, 14), (1, 21), (2, 34)])\n    ),\n    Suite.test(\n      \"disj with empty first\",\n      prettyArray(\n        Trie.disj<Nat, Nat, Nat, Nat>(\n          Trie.empty(),\n          trie1,\n          Nat.equal,\n          func(v1, v2) {\n            switch (v1, v2) {\n              case (?v1, ?v2) v1 + v2; // add values to combine\n              case (?v1, null) v1;\n              case (null, ?v2) v2;\n              case (null, null) Debug.trap \"unreachable in disj\"\n            }\n          }\n        )\n      ),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"disj with empty second\",\n      prettyArray(\n        Trie.disj<Nat, Nat, Nat, Nat>(\n          trie1,\n          Trie.empty(),\n          Nat.equal,\n          func(v1, v2) {\n            switch (v1, v2) {\n              case (?v1, ?v2) v1 + v2; // add values to combine\n              case (?v1, null) v1;\n              case (null, ?v2) v2;\n              case (null, null) Debug.trap \"unreachable in disj\"\n            }\n          }\n        )\n      ),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"disj two empties\",\n      prettyArray(\n        Trie.disj<Nat, Nat, Nat, Nat>(\n          Trie.empty(),\n          Trie.empty(),\n          Nat.equal,\n          func(v1, v2) {\n            switch (v1, v2) {\n              case (?v1, ?v2) v1 + v2; // add values to combine\n              case (?v1, null) v1;\n              case (null, ?v2) v2;\n              case (null, null) Debug.trap \"unreachable in disj\"\n            }\n          }\n        )\n      ),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"join\",\n      prettyArray(\n        Trie.join<Nat, Nat, Nat, Nat>(trie1, trie3, Nat.equal, Nat.add)\n      ),\n      arrayTest([(2, 34)])\n    ),\n    Suite.test(\n      \"join with empty first\",\n      prettyArray(\n        Trie.join<Nat, Nat, Nat, Nat>(Trie.empty(), trie1, Nat.equal, Nat.add)\n      ),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"join with empty second\",\n      prettyArray(\n        Trie.join<Nat, Nat, Nat, Nat>(trie1, Trie.empty(), Nat.equal, Nat.add)\n      ),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"join with two empties\",\n      prettyArray(\n        Trie.join<Nat, Nat, Nat, Nat>(Trie.empty(), Trie.empty(), Nat.equal, Nat.add)\n      ),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"foldUp\",\n      Trie.foldUp<Nat, Nat, Nat>(trie1, Nat.mul, Nat.add, 1),\n      M.equals(T.nat(2520))\n    ), // 1 * (0 + 10) * (2 + 12) * (4 + 14)\n    Suite.test(\n      \"foldUp empty\",\n      Trie.foldUp<Nat, Nat, Nat>(Trie.empty(), Nat.mul, Nat.add, 1),\n      M.equals(T.nat(1))\n    ),\n    Suite.test(\n      \"prod\",\n      prettyArray(Trie.prod<Nat, Nat, Nat, Nat, Nat, Nat>(trie1, trie3, func(k1, v1, k2, v2) = ?(natKey(k1 + k2), v1 + v2), Nat.equal)),\n      arrayTest([(1, 31), (2, 32), (3, 33), (4, 34), (5, 35), (6, 36)])\n    ),\n    Suite.test(\n      \"prod first empty\",\n      prettyArray(Trie.prod<Nat, Nat, Nat, Nat, Nat, Nat>(Trie.empty(), trie3, func(k1, v1, k2, v2) = ?(natKey(k1 + k2), v1 + v2), Nat.equal)),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"prod second empty\",\n      prettyArray(Trie.prod<Nat, Nat, Nat, Nat, Nat, Nat>(trie1, Trie.empty(), func(k1, v1, k2, v2) = ?(natKey(k1 + k2), v1 + v2), Nat.equal)),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"prod both empty\",\n      prettyArray(Trie.prod<Nat, Nat, Nat, Nat, Nat, Nat>(Trie.empty(), Trie.empty(), func(k1, v1, k2, v2) = ?(natKey(k1 + k2), v1 + v2), Nat.equal)),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"iter\",\n      Iter.toArray(Trie.iter(trie1)),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"iter empty\",\n      Iter.toArray(Trie.iter(Trie.empty())),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"fold\",\n      Trie.fold<Nat, Nat, Nat>(trie1, func(k, v, acc) = k + v + acc, 0),\n      M.equals(T.nat(42))\n    ), // 0 + 10 + 2 + 12 + 4 + 14\n    Suite.test(\n      \"fold empty\",\n      Trie.fold<Nat, Nat, Nat>(Trie.empty(), func(k, v, acc) = k + v + acc, 0),\n      M.equals(T.nat(0))\n    ),\n    Suite.test(\n      \"some true\",\n      Trie.some<Nat, Nat>(trie1, func(k, v) = k * v == 0),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"some false\",\n      Trie.some<Nat, Nat>(trie1, func(k, _) = k % 2 != 0),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"some empty\",\n      Trie.some<Nat, Nat>(Trie.empty(), func _ = true),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"all true\",\n      Trie.all<Nat, Nat>(trie1, func(k, _) = k % 2 == 0),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"all false\",\n      Trie.all<Nat, Nat>(trie1, func(k, v) = k * v == 0),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"all empty\",\n      Trie.all<Nat, Nat>(Trie.empty(), func _ = false),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"nth\",\n      Trie.nth<Nat, Nat>(trie1, 1),\n      M.equals(\n        T.optional(\n          T.tuple2Testable(\n            natKeyTestable,\n            T.natTestable\n          ),\n          ?(natKey(2), 12)\n        )\n      )\n    ),\n    Suite.test(\n      \"nth OOB\",\n      Trie.nth<Nat, Nat>(trie1, 3),\n      M.equals(\n        T.optional(\n          T.tuple2Testable(\n            natKeyTestable,\n            T.natTestable\n          ),\n          null : ?(Trie.Key<Nat>, Nat)\n        )\n      )\n    ),\n    Suite.test(\n      \"nth empty\",\n      Trie.nth<Nat, Nat>(Trie.empty(), 0),\n      M.equals(\n        T.optional(\n          T.tuple2Testable(\n            natKeyTestable,\n            T.natTestable\n          ),\n          null : ?(Trie.Key<Nat>, Nat)\n        )\n      )\n    ),\n    Suite.test(\n      \"isEmpty false\",\n      Trie.isEmpty<Nat, Nat>(trie1),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"isEmpty true\",\n      Trie.isEmpty<Nat, Nat>(Trie.empty()),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"isEmpty put remove\",\n      Trie.isEmpty<Nat, Nat>(\n        Trie.remove<Nat, Nat>(Trie.put<Nat, Nat>(Trie.empty(), natKey(0), Nat.equal, 10).0, natKey(0), Nat.equal).0\n      ),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"filter\",\n      prettyArray(Trie.filter<Nat, Nat>(trie1, func(k, v) = k * v == 0)),\n      arrayTest([(0, 10)])\n    ),\n    Suite.test(\n      \"filter all\",\n      prettyArray(Trie.filter<Nat, Nat>(trie1, func _ = false)),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"filter none\",\n      prettyArray(Trie.filter<Nat, Nat>(trie1, func _ = true)),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"mapFilter\",\n      prettyArray(Trie.mapFilter<Nat, Nat, Nat>(trie1, func(k, v) = if (k * v != 0) { ?(k * v) } else { null })),\n      arrayTest([(2, 24), (4, 56)])\n    ),\n    Suite.test(\n      \"mapFilter all\",\n      prettyArray(Trie.mapFilter<Nat, Nat, Nat>(trie1, func _ = null)),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"mapFilter none\",\n      prettyArray(Trie.mapFilter<Nat, Nat, Nat>(trie1, func(k, v) = ?v)),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"equalStructure reflexivity\",\n      Trie.equalStructure<Nat, Nat>(trie1, trie1, Nat.equal, Nat.equal),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"equalStructure not equal maps\",\n      Trie.equalStructure<Nat, Nat>(trie1, trie2, Nat.equal, Nat.equal),\n      M.equals(T.bool(false))\n    ),\n    // FIXME add case for maps that are equivalent (map-wise) but structually non-equal\n    Suite.test(\n      \"equalStructure first empty\",\n      Trie.equalStructure<Nat, Nat>(Trie.empty(), trie2, Nat.equal, Nat.equal),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"equalStructure second empty\",\n      Trie.equalStructure<Nat, Nat>(trie1, Trie.empty(), Nat.equal, Nat.equal),\n      M.equals(T.bool(false))\n    ),\n    Suite.test(\n      \"equalStructure both empty\",\n      Trie.equalStructure<Nat, Nat>(Trie.empty(), Trie.empty(), Nat.equal, Nat.equal),\n      M.equals(T.bool(true))\n    ),\n    Suite.test(\n      \"replaceThen success old value\",\n      Trie.replaceThen<Nat, Nat, Nat>(\n        trie1,\n        natKey(0),\n        Nat.equal,\n        100,\n        func(newTrie, oldV) = oldV,\n        func _ = Debug.trap \"unreachable\"\n      ),\n      M.equals(T.nat(10))\n    ),\n    Suite.test(\n      \"replaceThen success new trie\",\n      prettyArray(\n        Trie.replaceThen<Nat, Nat, Trie.Trie<Nat, Nat>>(\n          trie1,\n          natKey(0),\n          Nat.equal,\n          100,\n          func(newTrie, oldV) = newTrie,\n          func _ = Debug.trap \"unreachable\"\n        )\n      ),\n      arrayTest([(0, 100), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"replaceThen failure\",\n      Trie.replaceThen<Nat, Nat, Nat>(\n        trie1,\n        natKey(3),\n        Nat.equal,\n        13,\n        func _ = Debug.trap \"unreachable\",\n        func() = 99\n      ),\n      M.equals(T.nat(99))\n    ),\n    Suite.test(\n      \"replaceThen empty\",\n      Trie.replaceThen<Nat, Nat, Nat>(\n        Trie.empty(),\n        natKey(0),\n        Nat.equal,\n        100,\n        func _ = Debug.trap \"unreachable\",\n        func() = 99\n      ),\n      M.equals(T.nat(99))\n    ),\n    Suite.test(\n      \"putFresh success\",\n      prettyArray(Trie.putFresh<Nat, Nat>(trie1, natKey(6), Nat.equal, 16)),\n      arrayTest([(0, 10), (2, 12), (4, 14), (6, 16)])\n    ),\n    Suite.test(\n      \"putFresh empty\",\n      prettyArray(Trie.putFresh<Nat, Nat>(Trie.empty(), natKey(6), Nat.equal, 16)),\n      arrayTest([(6, 16)])\n    ),\n    Suite.test(\n      \"put2D\",\n      prettyArray2D(Trie.put2D<Nat, Nat, Nat>(trie2D1, natKey(1), Nat.equal, natKey(11), Nat.equal, 101)),\n      arrayTest2D([((0, 10), 100), ((2, 12), 102), ((4, 14), 104), ((1, 11), 101)])\n    ),\n    Suite.test(\n      \"put2D overlapping k1\",\n      prettyArray2D(Trie.put2D<Nat, Nat, Nat>(trie2D1, natKey(0), Nat.equal, natKey(11), Nat.equal, 101)),\n      arrayTest2D([((0, 10), 100), ((0, 11), 101), ((2, 12), 102), ((4, 14), 104)])\n    ),\n    Suite.test(\n      \"put2D overlapping k2\",\n      prettyArray2D(Trie.put2D<Nat, Nat, Nat>(trie2D1, natKey(1), Nat.equal, natKey(10), Nat.equal, 101)),\n      arrayTest2D([((0, 10), 100), ((2, 12), 102), ((4, 14), 104), ((1, 10), 101)])\n    ),\n    Suite.test(\n      \"put2D overlapping both\",\n      prettyArray2D(Trie.put2D<Nat, Nat, Nat>(trie2D1, natKey(0), Nat.equal, natKey(10), Nat.equal, 1001)),\n      arrayTest2D([((0, 10), 1001), ((2, 12), 102), ((4, 14), 104)])\n    ),\n    Suite.test(\n      \"put2D empty\",\n      prettyArray2D(Trie.put2D<Nat, Nat, Nat>(Trie.empty(), natKey(0), Nat.equal, natKey(10), Nat.equal, 100)),\n      arrayTest2D([((0, 10), 100)])\n    ),\n    Suite.test(\n      \"put3D\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(1), Nat.equal, natKey(11), Nat.equal, natKey(101), Nat.equal, 1001)),\n      arrayTest3D([((0, 10, 100), 1000), ((2, 12, 102), 1002), ((4, 14, 104), 1004), ((1, 11, 101), 1001)])\n    ),\n    Suite.test(\n      \"put3D overlapping k1\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(0), Nat.equal, natKey(11), Nat.equal, natKey(101), Nat.equal, 1001)),\n      arrayTest3D([((0, 10, 100), 1000), ((0, 11, 101), 1001), ((2, 12, 102), 1002), ((4, 14, 104), 1004)])\n    ),\n    Suite.test(\n      \"put3D overlapping k2\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(1), Nat.equal, natKey(12), Nat.equal, natKey(101), Nat.equal, 1001)),\n      arrayTest3D([((0, 10, 100), 1000), ((2, 12, 102), 1002), ((4, 14, 104), 1004), ((1, 12, 101), 1001)])\n    ),\n    Suite.test(\n      \"put3D overlapping k3\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(1), Nat.equal, natKey(11), Nat.equal, natKey(102), Nat.equal, 1001)),\n      arrayTest3D([((0, 10, 100), 1000), ((2, 12, 102), 1002), ((4, 14, 104), 1004), ((1, 11, 102), 1001)])\n    ),\n    Suite.test(\n      \"put3D overlapping k1 and k2\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(0), Nat.equal, natKey(10), Nat.equal, natKey(101), Nat.equal, 1001)),\n      arrayTest3D([((0, 10, 100), 1000), ((0, 10, 101), 1001), ((2, 12, 102), 1002), ((4, 14, 104), 1004)])\n    ),\n    Suite.test(\n      \"put3D overlapping k1 and k3\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(0), Nat.equal, natKey(11), Nat.equal, natKey(100), Nat.equal, 1001)),\n      arrayTest3D([((0, 10, 100), 1000), ((0, 11, 100), 1001), ((2, 12, 102), 1002), ((4, 14, 104), 1004)])\n    ),\n    Suite.test(\n      \"put3D overlapping k2 and k3\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(1), Nat.equal, natKey(10), Nat.equal, natKey(100), Nat.equal, 1001)),\n      arrayTest3D([((0, 10, 100), 1000), ((2, 12, 102), 1002), ((4, 14, 104), 1004), ((1, 10, 100), 1001)])\n    ),\n    Suite.test(\n      \"put3D overlapping all\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(trie3D, natKey(0), Nat.equal, natKey(10), Nat.equal, natKey(100), Nat.equal, 1001)),\n      arrayTest3D([((0, 10, 100), 1001), ((2, 12, 102), 1002), ((4, 14, 104), 1004)])\n    ),\n    Suite.test(\n      \"put3D empty\",\n      prettyArray3D(Trie.put3D<Nat, Nat, Nat, Nat>(Trie.empty(), natKey(1), Nat.equal, natKey(11), Nat.equal, natKey(101), Nat.equal, 1001)),\n      arrayTest3D([((1, 11, 101), 1001)])\n    ),\n    Suite.test(\n      \"remove success, new trie\",\n      prettyArray(Trie.remove<Nat, Nat>(trie1, natKey(2), Nat.equal).0),\n      arrayTest([(0, 10), (4, 14)])\n    ),\n    Suite.test(\n      \"remove success, old value\",\n      Trie.remove<Nat, Nat>(trie1, natKey(2), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, ?12))\n    ),\n    Suite.test(\n      \"remove failure, new trie\",\n      prettyArray(Trie.remove<Nat, Nat>(trie1, natKey(1), Nat.equal).0),\n      arrayTest([(0, 10), (2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"remove failure, old value\",\n      Trie.remove<Nat, Nat>(trie1, natKey(1), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"remove empty, new trie\",\n      prettyArray(Trie.remove<Nat, Nat>(Trie.empty(), natKey(1), Nat.equal).0),\n      arrayTest([])\n    ),\n    Suite.test(\n      \"remove empty, old value\",\n      Trie.remove<Nat, Nat>(Trie.empty(), natKey(1), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"removeThen success old value\",\n      Trie.removeThen<Nat, Nat, Nat>(\n        trie1,\n        natKey(0),\n        Nat.equal,\n        func(newTrie, oldV) = oldV,\n        func _ = Debug.trap \"unreachable\"\n      ),\n      M.equals(T.nat(10))\n    ),\n    Suite.test(\n      \"removeThen success new trie\",\n      prettyArray(\n        Trie.removeThen<Nat, Nat, Trie.Trie<Nat, Nat>>(\n          trie1,\n          natKey(0),\n          Nat.equal,\n          func(newTrie, oldV) = newTrie,\n          func _ = Debug.trap \"unreachable\"\n        )\n      ),\n      arrayTest([(2, 12), (4, 14)])\n    ),\n    Suite.test(\n      \"removeThen failure\",\n      Trie.removeThen<Nat, Nat, Nat>(\n        trie1,\n        natKey(1),\n        Nat.equal,\n        func _ = Debug.trap \"unreachable\",\n        func() = 99\n      ),\n      M.equals(T.nat(99))\n    ),\n    Suite.test(\n      \"removeThen empty\",\n      Trie.removeThen<Nat, Nat, Nat>(\n        Trie.empty() : Trie.Trie<Nat, Nat>,\n        natKey(1),\n        Nat.equal,\n        func _ = Debug.trap \"unreachable\",\n        func() = 99\n      ),\n      M.equals(T.nat(99))\n    ),\n    Suite.test(\n      \"remove2D success, new trie\",\n      prettyArray2D(Trie.remove2D<Nat, Nat, Nat>(trie2D1, natKey(2), Nat.equal, natKey(12), Nat.equal).0),\n      arrayTest2D([((0, 10), 100), ((4, 14), 104)])\n    ),\n    Suite.test(\n      \"remove2D success, old value\",\n      Trie.remove2D<Nat, Nat, Nat>(trie2D1, natKey(2), Nat.equal, natKey(12), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, ?102))\n    ),\n    Suite.test(\n      \"remove2D failure, new trie\",\n      prettyArray2D(Trie.remove2D<Nat, Nat, Nat>(trie2D1, natKey(1), Nat.equal, natKey(11), Nat.equal).0),\n      arrayTest2D([((0, 10), 100), ((2, 12), 102), ((4, 14), 104)])\n    ),\n    Suite.test(\n      \"remove2D failure, old value\",\n      Trie.remove2D<Nat, Nat, Nat>(trie2D1, natKey(1), Nat.equal, natKey(11), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"remove2D failure empty, new trie\",\n      prettyArray2D(Trie.remove2D<Nat, Nat, Nat>(Trie.empty(), natKey(1), Nat.equal, natKey(11), Nat.equal).0),\n      arrayTest2D([])\n    ),\n    Suite.test(\n      \"remove2D failure empty, old value\",\n      Trie.remove2D<Nat, Nat, Nat>(Trie.empty(), natKey(1), Nat.equal, natKey(11), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"remove3D success, new trie\",\n      prettyArray3D(Trie.remove3D<Nat, Nat, Nat, Nat>(trie3D, natKey(2), Nat.equal, natKey(12), Nat.equal, natKey(102), Nat.equal).0),\n      arrayTest3D([((0, 10, 100), 1000), ((4, 14, 104), 1004)])\n    ),\n    Suite.test(\n      \"remove3D success, old value\",\n      Trie.remove3D<Nat, Nat, Nat, Nat>(trie3D, natKey(2), Nat.equal, natKey(12), Nat.equal, natKey(102), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, ?1002 : ?Nat))\n    ),\n    Suite.test(\n      \"remove3D failure, new trie\",\n      prettyArray3D(Trie.remove3D<Nat, Nat, Nat, Nat>(trie3D, natKey(1), Nat.equal, natKey(11), Nat.equal, natKey(101), Nat.equal).0),\n      arrayTest3D([((0, 10, 100), 1000), ((2, 12, 102), 1002), ((4, 14, 104), 1004)])\n    ),\n    Suite.test(\n      \"remove3D failure, old value\",\n      Trie.remove3D<Nat, Nat, Nat, Nat>(trie3D, natKey(1), Nat.equal, natKey(11), Nat.equal, natKey(101), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"remove3D failure empty, new trie\",\n      prettyArray3D(Trie.remove3D<Nat, Nat, Nat, Nat>(Trie.empty(), natKey(1), Nat.equal, natKey(11), Nat.equal, natKey(101), Nat.equal).0),\n      arrayTest3D([])\n    ),\n    Suite.test(\n      \"remove3D failure empty, old value\",\n      Trie.remove3D<Nat, Nat, Nat, Nat>(Trie.empty(), natKey(1), Nat.equal, natKey(11), Nat.equal, natKey(101), Nat.equal).1,\n      M.equals(T.optional(T.natTestable, null : ?Nat))\n    ),\n    Suite.test(\n      \"mergeDisjoint2D\",\n      prettyArray(Trie.mergeDisjoint2D<Nat, Nat, Nat>(trie2D2, Nat.equal, Nat.equal)),\n      arrayTest([(11, 101), (21, 201), (12, 102), (13, 103), (23, 203), (33, 303)])\n    ),\n    Suite.test(\n      \"mergeDisjoint2D empty\",\n      prettyArray(Trie.mergeDisjoint2D<Nat, Nat, Nat>(Trie.empty(), Nat.equal, Nat.equal)),\n      arrayTest([])\n    )\n  ]\n);\n\n// FIXME add tests for bitpos functions\n// FIXME test structure of resulting trie, instead of flattening to array\n\nSuite.run(suite);\n\n// Assertion tests\ndebug {\n  type Trie<K, V> = Trie.Trie<K, V>;\n  type Key<K> = Trie.Key<K>;\n\n  func key(i : Nat) : Key<Text> {\n    let t = Nat.toText i;\n    { key = t; hash = Text.hash t }\n  };\n\n  let max = 100;\n\n  // put k-v elements, one by one (but hashes are expected random).\n  Debug.print \"Trie.put\";\n  var t : Trie<Text, Nat> = Trie.empty();\n  for (i in Iter.range(0, max - 1)) {\n    let (t1_, x) = Trie.put<Text, Nat>(t, key i, Text.equal, i);\n    assert (Option.isNull(x));\n    assert Trie.isValid(t1_, false);\n    t := t1_\n  };\n  assert Trie.size(t) == max;\n\n  // remove all elements, one by one (but hashes are expected random).\n  do {\n    Debug.print \"Trie.remove\";\n    var t1 = t;\n    for (i in Iter.range(0, max - 1)) {\n      let (t1_, x) = Trie.remove<Text, Nat>(t1, key i, Text.equal);\n      assert Trie.isValid(t1_, false);\n      assert (Option.isSome(x));\n      t1 := t1_\n    }\n  };\n\n  // filter all elements away, one by one (but hashes are expected random).\n  do {\n    Debug.print \"Trie.filter\";\n    var t1 = t;\n    for (i in Iter.range(0, max - 1)) {\n      t1 := Trie.filter(t1, func(t : Text, n : Nat) : Bool { n != i });\n      assert Trie.isValid(t1, false);\n      assert Trie.size(t1) == (max - (i + 1) : Nat)\n    }\n  };\n\n  // filter-map all elements away, one by one (but hashes are expected random).\n  do {\n    Debug.print \"Trie.mapFilter\";\n    var t1 = t;\n    for (i in Iter.range(0, max - 1)) {\n      t1 := Trie.mapFilter(\n        t1,\n        func(t : Text, n : Nat) : ?Nat {\n          if (n != i) ?n else null\n        }\n      );\n      assert Trie.isValid(t1, false);\n      assert Trie.size(t1) == (max - (i + 1) : Nat)\n    }\n  }\n}\n"},"int8Test.mo":{"content":"import Debug \"mo:base/Debug\";\nimport Int8 \"mo:base/Int8\";\n\nassert (Int8.fromIntWrap(256) == (0 : Int8));\nassert (Int8.fromIntWrap(-256) == (0 : Int8));\nassert (Int8.fromIntWrap(128) == (-128 : Int8));\nassert (Int8.fromIntWrap(255) == (-1 : Int8))\n"},"orderTest.mo":{"content":"import Order \"mo:base/Order\";\nimport Debug \"mo:base/Debug\";\n\nDebug.print(\"Order\");\n\ndo {\n  Debug.print(\"  isLess\");\n\n  assert (Order.isLess(#less));\n  assert (not Order.isLess(#equal));\n  assert (not Order.isLess(#greater))\n};\n\ndo {\n  Debug.print(\"  isEqual\");\n\n  assert (not Order.isEqual(#less));\n  assert (Order.isEqual(#equal));\n  assert (not Order.isEqual(#greater))\n};\n\ndo {\n  Debug.print(\"  isGreater\");\n\n  assert (not Order.isGreater(#less));\n  assert (not Order.isGreater(#equal));\n  assert (Order.isGreater(#greater))\n}\n"},"textTest.mo":{"content":"import Debug \"mo:base/Debug\";\nimport Text \"mo:base/Text\";\nimport Blob \"mo:base/Blob\";\nimport Iter \"mo:base/Iter\";\nimport Char \"mo:base/Char\";\nimport Order \"mo:base/Order\";\nimport Array \"mo:base/Array\";\nimport Nat32 \"mo:base/Nat32\";\n\nimport Suite \"mo:matchers/Suite\";\nimport M \"mo:matchers/Matchers\";\nimport T \"mo:matchers/Testable\";\n\nlet { run; test; suite } = Suite;\n\nfunc charT(c : Char) : T.TestableItem<Char> = {\n  item = c;\n  display = Text.fromChar;\n  equals = Char.equal\n};\n\nfunc blobT(b : Blob) : T.TestableItem<Blob> = {\n  item = b;\n  display = func(b : Blob) : Text { debug_show (b) };\n  equals = Blob.equal\n};\n\nfunc ordT(o : Order.Order) : T.TestableItem<Order.Order> = {\n  item = o;\n  display = func(o : Order.Order) : Text { debug_show (o) };\n  equals = Order.equal\n};\n\nfunc optTextT(ot : ?Text) : T.TestableItem<?Text> = T.optional(T.textTestable, ot);\n\n// TODO: generalize and move to Iter.mo\nfunc iterT(c : [Char]) : T.TestableItem<Iter.Iter<Char>> = {\n  item = c.vals();\n  display = Text.fromIter; // not this will only print the remainder of cs1 below\n  equals = func(cs1 : Iter.Iter<Char>, cs2 : Iter.Iter<Char>) : Bool {\n    loop {\n      switch (cs1.next(), cs2.next()) {\n        case (null, null) return true;\n        case (?c1, ?c2) if (c1 != c2) return false;\n        case (_, _) return false\n      }\n    }\n  }\n};\n\n// TODO: generalize and move to Iter.mo\nfunc textIterT(c : [Text]) : T.TestableItem<Iter.Iter<Text>> = {\n  item = c.vals();\n  display = func(ts : Iter.Iter<Text>) : Text { Text.join(\",\", ts) };\n  // not this will only print the remainder of cs1 below\n  equals = func(ts1 : Iter.Iter<Text>, ts2 : Iter.Iter<Text>) : Bool {\n    loop {\n      switch (ts1.next(), ts2.next()) {\n        case (null, null) return true;\n        case (?t1, ?t2) if (t1 != t2) return false;\n        case (_, _) return false\n      }\n    }\n  }\n};\n\nrun(\n  suite(\n    \"size\",\n    [\n      test(\n        \"size-0\",\n        Text.size(\"\"),\n        M.equals(T.nat 0)\n      ),\n      test(\n        \"size-1\",\n        Text.size(\"a\"),\n        M.equals(T.nat 1)\n      ),\n      test(\n        \"size-2\",\n        Text.size(\"abcdefghijklmnopqrstuvwxyz\"),\n        M.equals(T.nat 26)\n      ),\n      test(\n        \"size-3\",\n        Text.size(\"☃\"),\n        M.equals(T.nat 1)\n      ),\n      test(\n        \"size-4\",\n        Text.size(\"☃☃\"),\n        M.equals(T.nat 2)\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"toIter\",\n    [\n      test(\n        \"toIter-0\",\n        Text.toIter(\"\"),\n        M.equals(iterT([]))\n      ),\n      test(\n        \"toIter-1\",\n        Text.toIter(\"a\"),\n        M.equals(iterT(['a']))\n      ),\n      test(\n        \"toIter-2\",\n        Text.toIter(\"abc\"),\n        M.equals(iterT(['a', 'b', 'c']))\n      ),\n      do {\n        let a = Array.tabulate<Char>(1000, func i = Char.fromNat32(65 +% Nat32.fromIntWrap(i % 26)));\n        test(\n          \"fromIter-2\",\n          Text.toIter(Text.join(\"\", Array.map(a, Char.toText).vals())),\n          M.equals(iterT a)\n        )\n      }\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"fromIter\",\n    [\n      test(\n        \"fromIter-0\",\n        Text.fromIter(([].vals())),\n        M.equals(T.text(\"\"))\n      ),\n      test(\n        \"fromIter-1\",\n        Text.fromIter((['a'].vals())),\n        M.equals(T.text \"a\")\n      ),\n      test(\n        \"fromIter-2\",\n        Text.fromIter((['a', 'b', 'c'].vals())),\n        M.equals(T.text \"abc\")\n      ),\n      do {\n        let a = Array.tabulate<Char>(1000, func i = Char.fromNat32(65 +% Nat32.fromIntWrap(i % 26)));\n        test(\n          \"fromIter-3\",\n          Text.fromIter(a.vals()),\n          M.equals(T.text(Text.join(\"\", Array.map(a, Char.toText).vals())))\n        )\n      }\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"concat\",\n    [\n      test(\n        \"concat-0\",\n        Text.concat(\"\", \"\"),\n        M.equals(T.text(\"\"))\n      ),\n      test(\n        \"concat-1\",\n        Text.concat(\"\", \"b\"),\n        M.equals(T.text \"b\")\n      ),\n      test(\n        \"concat-2\",\n        Text.concat(\"a\", \"b\"),\n        M.equals(T.text \"ab\")\n      ),\n      test(\n        \"concat-3\",\n        Text.concat(\"abcdefghijklmno\", \"pqrstuvwxyz\"),\n        M.equals(T.text \"abcdefghijklmnopqrstuvwxyz\")\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"join\",\n    [\n      test(\n        \"join-0\",\n        Text.join(\"\", ([\"\", \"\"].vals())),\n        M.equals(T.text(\"\"))\n      ),\n      test(\n        \"join-1\",\n        Text.join(\"\", ([\"\", \"b\"].vals())),\n        M.equals(T.text \"b\")\n      ),\n      test(\n        \"join-2\",\n        Text.join(\"\", ([\"a\", \"bb\", \"ccc\", \"dddd\"].vals())),\n        M.equals(T.text \"abbcccdddd\")\n      ),\n      do {\n        let a = Array.tabulate<Char>(1000, func i = Char.fromNat32(65 +% Nat32.fromIntWrap(i % 26)));\n        test(\n          \"join-3\",\n          Text.join(\"\", Array.map(a, Char.toText).vals()),\n          M.equals(T.text(Text.fromIter(a.vals())))\n        )\n      },\n      test(\n        \"join-4\",\n        Text.join(\"\", ([].vals())),\n        M.equals(T.text \"\")\n      ),\n      test(\n        \"join-5\",\n        Text.join(\"\", ([\"aaa\"].vals())),\n        M.equals(T.text \"aaa\")\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"join\",\n    [\n      test(\n        \"join-0\",\n        Text.join(\",\", ([\"\", \"\"].vals())),\n        M.equals(T.text(\",\"))\n      ),\n      test(\n        \"join-1\",\n        Text.join(\",\", ([\"\", \"b\"].vals())),\n        M.equals(T.text \",b\")\n      ),\n      test(\n        \"join-2\",\n        Text.join(\",\", ([\"a\", \"bb\", \"ccc\", \"dddd\"].vals())),\n        M.equals(T.text \"a,bb,ccc,dddd\")\n      ),\n      do {\n        let a = Array.tabulate<Char>(1000, func i = Char.fromNat32(65 +% Nat32.fromIntWrap(i % 26)));\n        test(\n          \"join-3\",\n          Text.join(\"\", Array.map(a, Char.toText).vals()),\n          M.equals(T.text(Text.fromIter(a.vals())))\n        )\n      },\n      test(\n        \"join-4\",\n        Text.join(\",\", ([].vals())),\n        M.equals(T.text \"\")\n      ),\n      test(\n        \"join-5\",\n        Text.join(\",\", ([\"aaa\"].vals())),\n        M.equals(T.text \"aaa\")\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"split\",\n    [\n      test(\n        \"split-char-empty\",\n        Text.split(\"\", #char ';'),\n        M.equals(textIterT([]))\n      ),\n      test(\n        \"split-char-none\",\n        Text.split(\"abc\", #char ';'),\n        M.equals(textIterT([\"abc\"]))\n      ),\n      test(\n        \"split-char-empties2\",\n        Text.split(\";\", #char ';'),\n        M.equals(textIterT([\"\", \"\"]))\n      ),\n      test(\n        \"split-char-empties3\",\n        Text.split(\";;\", #char ';'),\n        M.equals(textIterT([\"\", \"\", \"\"]))\n      ),\n      test(\n        \"split-char-singles\",\n        Text.split(\"a;b;;c;;;d\", #char ';'),\n        M.equals(textIterT([\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"]))\n      ),\n      test(\n        \"split-char-mixed\",\n        Text.split(\"a;;;ab;;abc;\", #char ';'),\n        M.equals(textIterT([\"a\", \"\", \"\", \"ab\", \"\", \"abc\", \"\"]))\n      ),\n      do {\n        let a = Array.tabulate<Text>(1000, func _ = \"abc\");\n        let t = Text.join(\";\", a.vals());\n        test(\n          \"split-char-large\",\n          Text.split(t, #char ';'),\n          M.equals(textIterT a)\n        )\n      },\n      do {\n        let a = Array.tabulate<Text>(100000, func _ = \"abc\");\n        let t = Text.join(\";\", a.vals());\n        test(\n          \"split-char-very-large\",\n          Text.split(t, #char ';'),\n          M.equals(textIterT a)\n        )\n      }\n    ]\n  )\n);\n\ndo {\n  let pat : Text.Pattern = #predicate(func(c : Char) : Bool { c == ';' or c == '!' });\n  run(\n    suite(\n      \"split\",\n      [\n        test(\n          \"split-pred-empty\",\n          Text.split(\"\", pat),\n          M.equals(textIterT([]))\n        ),\n        test(\n          \"split-pred-none\",\n          Text.split(\"abc\", pat),\n          M.equals(textIterT([\"abc\"]))\n        ),\n        test(\n          \"split-pred-empties2\",\n          Text.split(\";\", pat),\n          M.equals(textIterT([\"\", \"\"]))\n        ),\n        test(\n          \"split-pred-empties3\",\n          Text.split(\";!\", pat),\n          M.equals(textIterT([\"\", \"\", \"\"]))\n        ),\n        test(\n          \"split-pred-singles\",\n          Text.split(\"a;b;!c!;;d\", pat),\n          M.equals(textIterT([\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"]))\n        ),\n        test(\n          \"split-pred-mixed\",\n          Text.split(\"a;!;ab;!abc;\", pat),\n          M.equals(textIterT([\"a\", \"\", \"\", \"ab\", \"\", \"abc\", \"\"]))\n        ),\n        do {\n          let a = Array.tabulate<Text>(1000, func _ = \"abc\");\n          let t = Text.join(\";\", a.vals());\n          test(\n            \"split-pred-large\",\n            Text.split(t, pat),\n            M.equals(textIterT a)\n          )\n        },\n        do {\n          let a = Array.tabulate<Text>(10000, func _ = \"abc\");\n          let t = Text.join(\";\", a.vals());\n          test(\n            \"split-pred-very-large\",\n            Text.split(t, pat),\n            M.equals(textIterT a)\n          )\n        }\n      ]\n    )\n  )\n};\n\ndo {\n  let pat : Text.Pattern = #text \"PAT\";\n  run(\n    suite(\n      \"split\",\n      [\n        test(\n          \"split-pat-empty\",\n          Text.split(\"\", pat),\n          M.equals(textIterT([]))\n        ),\n        test(\n          \"split-pat-none\",\n          Text.split(\"abc\", pat),\n          M.equals(textIterT([\"abc\"]))\n        ),\n        test(\n          \"split-pat-empties2\",\n          Text.split(\"PAT\", pat),\n          M.equals(textIterT([\"\", \"\"]))\n        ),\n        test(\n          \"split-pat-empties3\",\n          Text.split(\"PATPAT\", pat),\n          M.equals(textIterT([\"\", \"\", \"\"]))\n        ),\n        test(\n          \"split-pat-singles\",\n          Text.split(\"aPATbPATPATcPATPATPATd\", pat),\n          M.equals(textIterT([\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"]))\n        ),\n        test(\n          \"split-pat-mixed\",\n          Text.split(\"aPATPATPATabPATPATabcPAT\", pat),\n          M.equals(textIterT([\"a\", \"\", \"\", \"ab\", \"\", \"abc\", \"\"]))\n        ),\n        do {\n          let a = Array.tabulate<Text>(1000, func _ = \"abc\");\n          let t = Text.join(\"PAT\", a.vals());\n          test(\n            \"split-pat-large\",\n            Text.split(t, pat),\n            M.equals(textIterT a)\n          )\n        },\n        do {\n          let a = Array.tabulate<Text>(10000, func _ = \"abc\");\n          let t = Text.join(\"PAT\", a.vals());\n          test(\n            \"split-pat-very-large\",\n            Text.split(t, pat),\n            M.equals(textIterT a)\n          )\n        }\n      ]\n    )\n  )\n};\n\nrun(\n  suite(\n    \"tokens\",\n    [\n      test(\n        \"tokens-char-empty\",\n        Text.tokens(\"\", #char ';'),\n        M.equals(textIterT([]))\n      ),\n      test(\n        \"tokens-char-none\",\n        Text.tokens(\"abc\", #char ';'),\n        M.equals(textIterT([\"abc\"]))\n      ),\n      test(\n        \"tokens-char-empties2\",\n        Text.tokens(\";\", #char ';'),\n        M.equals(textIterT([]))\n      ),\n      test(\n        \"tokens-char-empties3\",\n        Text.tokens(\";;\", #char ';'),\n        M.equals(textIterT([]))\n      ),\n      test(\n        \"tokens-char-singles\",\n        Text.tokens(\"a;b;;c;;;d\", #char ';'),\n        M.equals(textIterT([\"a\", \"b\", \"c\", \"d\"]))\n      ),\n      test(\n        \"tokens-char-mixed\",\n        Text.tokens(\"a;;;ab;;abc;\", #char ';'),\n        M.equals(textIterT([\"a\", \"ab\", \"abc\"]))\n      ),\n      do {\n        let a = Array.tabulate<Text>(1000, func _ = \"abc\");\n        let t = Text.join(\";;\", a.vals());\n        test(\n          \"tokens-char-large\",\n          Text.tokens(t, #char ';'),\n          M.equals(textIterT a)\n        )\n      },\n      do {\n        let a = Array.tabulate<Text>(100000, func _ = \"abc\");\n        let t = Text.join(\";;\", a.vals());\n        test(\n          \"tokens-char-very-large\",\n          Text.tokens(t, #char ';'),\n          M.equals(textIterT a)\n        )\n      }\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"startsWith\",\n    [\n      test(\n        \"startsWith-both-empty\",\n        Text.startsWith(\"\", #text \"\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"startsWith-empty-text\",\n        Text.startsWith(\"\", #text \"abc\"),\n        M.equals(T.bool false)\n      ),\n      test(\n        \"startsWith-empty-pat\",\n        Text.startsWith(\"abc\", #text \"\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"startsWith-1\",\n        Text.startsWith(\"a\", #text \"b\"),\n        M.equals(T.bool false)\n      ),\n      test(\n        \"startsWith-2\",\n        Text.startsWith(\"abc\", #text \"abc\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"startsWith-3\",\n        Text.startsWith(\"abcd\", #text \"ab\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"startsWith-4\",\n        Text.startsWith(\"abcdefghijklmnopqrstuvwxyz\", #text \"abcdefghijklmno\"),\n        M.equals(T.bool true)\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"endsWith\",\n    [\n      test(\n        \"endsWith-both-empty\",\n        Text.endsWith(\"\", #text \"\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"endsWith-empty-text\",\n        Text.endsWith(\"\", #text \"abc\"),\n        M.equals(T.bool false)\n      ),\n      test(\n        \"endsWith-empty-pat\",\n        Text.endsWith(\"abc\", #text \"\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"endsWith-1\",\n        Text.endsWith(\"a\", #text \"b\"),\n        M.equals(T.bool false)\n      ),\n      test(\n        \"endsWith-2\",\n        Text.endsWith(\"abc\", #text \"abc\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"endsWith-3\",\n        Text.endsWith(\"abcd\", #text \"cd\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"endsWith-4\",\n        Text.endsWith(\"abcdefghijklmnopqrstuvwxyz\", #text \"pqrstuvwxyz\"),\n        M.equals(T.bool true)\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"contains\",\n    [\n      test(\n        \"contains-start\",\n        Text.contains(\"abcd\", #text \"ab\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"contains-empty\",\n        Text.contains(\"abc\", #text \"\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"contains-false\",\n        Text.contains(\"ab\", #text \"bc\"),\n        M.equals(T.bool false)\n      ),\n      test(\n        \"contains-exact\",\n        Text.contains(\"abc\", #text \"abc\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"contains-within\",\n        Text.contains(\"abcdefghijklmnopqrstuvwxyz\", #text \"qrst\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"contains-front\",\n        Text.contains(\"abcdefghijklmnopqrstuvwxyz\", #text \"abcdefg\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"contains-end\",\n        Text.contains(\"abcdefghijklmnopqrstuvwxyz\", #text \"xyz\"),\n        M.equals(T.bool true)\n      ),\n      test(\n        \"contains-false\",\n        Text.contains(\"abcdefghijklmnopqrstuvwxyz\", #text \"lkj\"),\n        M.equals(T.bool false)\n      ),\n      test(\n        \"contains-empty-nonempty\",\n        Text.contains(\"\", #text \"xyz\"),\n        M.equals(T.bool false)\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"replace\",\n    [\n      test(\n        \"replace-start\",\n        Text.replace(\"abcd\", #text \"ab\", \"AB\"),\n        M.equals(T.text \"ABcd\")\n      ),\n      test(\n        \"replace-empty\",\n        Text.replace(\"abc\", #text \"\", \"AB\"),\n        M.equals(T.text \"ABaABbABcAB\")\n      ),\n      test(\n        \"replace-none\",\n        Text.replace(\"ab\", #text \"bc\", \"AB\"),\n        M.equals(T.text \"ab\")\n      ),\n      test(\n        \"replace-exact\",\n        Text.replace(\"ab\", #text \"ab\", \"AB\"),\n        M.equals(T.text \"AB\")\n      ),\n      test(\n        \"replace-several\",\n        Text.replace(\"abcdabghijabmnopqrstuabwxab\", #text \"ab\", \"AB\"),\n        M.equals(T.text \"ABcdABghijABmnopqrstuABwxAB\")\n      ),\n      test(\n        \"replace-delete\",\n        Text.replace(\"abcdabghijabmnopqrstuabwxab\", #text \"ab\", \"\"),\n        M.equals(T.text \"cdghijmnopqrstuwx\")\n      ),\n      test(\n        \"replace-pred\",\n        Text.replace(\"abcdefghijklmnopqrstuvwxyz\", #predicate(func(c : Char) : Bool { c < 'm' }), \"\"),\n        M.equals(T.text \"mnopqrstuvwxyz\")\n      ),\n      test(\n        \"replace-partial\",\n        Text.replace(\"123\", #text \"124\", \"ABC\"),\n        M.equals(T.text \"123\")\n      ),\n      test(\n        \"replace-partial-2\",\n        Text.replace(\"12341235124\", #text \"124\", \"ABC\"),\n        M.equals(T.text \"12341235ABC\")\n      ),\n      test(\n        \"replace-partial-3\",\n        Text.replace(\"111234123511124\", #text \"124\", \"ABC\"),\n        M.equals(T.text \"111234123511ABC\")\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"stripStart\",\n    [\n      test(\n        \"stripStart-none\",\n        Text.stripStart(\"cd\", #text \"ab\"),\n        M.equals(optTextT(null))\n      ),\n      test(\n        \"stripStart-one\",\n        Text.stripStart(\"abcd\", #text \"ab\"),\n        M.equals(optTextT(?\"cd\"))\n      ),\n      test(\n        \"stripStart-two\",\n        Text.stripStart(\"abababcd\", #text \"ab\"),\n        M.equals(optTextT(?\"ababcd\"))\n      ),\n      test(\n        \"stripStart-only\",\n        Text.stripStart(\"ababababab\", #text \"ab\"),\n        M.equals(optTextT(?\"abababab\"))\n      ),\n      test(\n        \"stripStart-empty\",\n        Text.stripStart(\"abcdef\", #text \"\"),\n        M.equals(optTextT(?\"abcdef\"))\n      ),\n      test(\n        \"stripStart-tooshort\",\n        Text.stripStart(\"abcdef\", #text \"abcdefg\"),\n        M.equals(optTextT(null))\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"stripEnd\",\n    [\n      test(\n        \"stripEnd-exact\",\n        Text.stripEnd(\"cd\", #text \"cd\"),\n        M.equals(optTextT(?\"\"))\n      ),\n      test(\n        \"stripEnd-one\",\n        Text.stripEnd(\"abcd\", #text \"cd\"),\n        M.equals(optTextT(?\"ab\"))\n      ),\n      test(\n        \"stripEnd-three\",\n        Text.stripEnd(\"abcdcdcd\", #text \"cd\"),\n        M.equals(optTextT(?\"abcdcd\"))\n      ),\n      test(\n        \"stripEnd-many\",\n        Text.stripEnd(\"cdcdcdcdcdcdcd\", #text \"cd\"),\n        M.equals(optTextT(?\"cdcdcdcdcdcd\"))\n      ),\n      test(\n        \"stripEnd-empty-pat\",\n        Text.stripEnd(\"abcdef\", #text \"\"),\n        M.equals(optTextT(?\"abcdef\"))\n      ),\n      test(\n        \"stripEnd-empty\",\n        Text.stripEnd(\"\", #text \"cd\"),\n        M.equals(optTextT null)\n      ),\n      test(\n        \"stripEnd-tooshort\",\n        Text.stripEnd(\"bcdef\", #text \"abcdef\"),\n        M.equals(optTextT null)\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"trimStart\",\n    [\n      test(\n        \"trimStart-none\",\n        Text.trimStart(\"cd\", #text \"ab\"),\n        M.equals(T.text \"cd\")\n      ),\n      test(\n        \"trimStart-one\",\n        Text.trimStart(\"abcd\", #text \"ab\"),\n        M.equals(T.text \"cd\")\n      ),\n      test(\n        \"trimStart-two\",\n        Text.trimStart(\"abababcd\", #text \"ab\"),\n        M.equals(T.text \"cd\")\n      ),\n      test(\n        \"trimStart-only\",\n        Text.trimStart(\"ababababab\", #text \"ab\"),\n        M.equals(T.text \"\")\n      ),\n      test(\n        \"trimStart-empty\",\n        Text.trimStart(\"abcdef\", #text \"\"),\n        M.equals(T.text \"abcdef\")\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"trimEnd\",\n    [\n      test(\n        \"trimEnd-exact\",\n        Text.trimEnd(\"cd\", #text \"cd\"),\n        M.equals(T.text \"\")\n      ),\n      test(\n        \"trimEnd-one\",\n        Text.trimEnd(\"abcd\", #text \"cd\"),\n        M.equals(T.text \"ab\")\n      ),\n      test(\n        \"trimEnd-three\",\n        Text.trimEnd(\"abcdcdcd\", #text \"cd\"),\n        M.equals(T.text \"ab\")\n      ),\n      test(\n        \"trimEnd-many\",\n        Text.trimEnd(\"cdcdcdcdcdcdcd\", #text \"cd\"),\n        M.equals(T.text \"\")\n      ),\n      test(\n        \"trimEnd-empty-pat\",\n        Text.trimEnd(\"abcdef\", #text \"\"),\n        M.equals(T.text \"abcdef\")\n      ),\n      test(\n        \"trimEnd-empty\",\n        Text.trimEnd(\"\", #text \"cd\"),\n        M.equals(T.text \"\")\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"trim\",\n    [\n      test(\n        \"trim-exact\",\n        Text.trim(\"cd\", #text \"cd\"),\n        M.equals(T.text \"\")\n      ),\n      test(\n        \"trim-one\",\n        Text.trim(\"cdabcd\", #text \"cd\"),\n        M.equals(T.text \"ab\")\n      ),\n      test(\n        \"trim-three\",\n        Text.trim(\"cdcdcdabcdcdcd\", #text \"cd\"),\n        M.equals(T.text \"ab\")\n      ),\n      test(\n        \"trim-many\",\n        Text.trim(\"cdcdcdcdcdcdcd\", #text \"cd\"),\n        M.equals(T.text \"\")\n      ),\n      test(\n        \"trim-empty-pat\",\n        Text.trim(\"abcdef\", #text \"\"),\n        M.equals(T.text \"abcdef\")\n      ),\n      test(\n        \"trim-empty\",\n        Text.trim(\"\", #text \"cd\"),\n        M.equals(T.text \"\")\n      )\n    ]\n  )\n);\n\nrun(\n  suite(\n    \"compare\",\n    [\n      test(\n        \"compare-empties\",\n        Text.compare(\"\", \"\"),\n        M.equals(ordT(#equal))\n      ),\n      test(\n        \"compare-empty-nonempty\",\n        Text.compare(\"\", \"a\"),\n        M.equals(ordT(#less))\n      ),\n      test(\n        \"compare-nonempty-empty\",\n        Text.compare(\"a\", \"\"),\n        M.equals(ordT(#greater))\n      ),\n      test(\n        \"compare-a-a\",\n        Text.compare(\"a\", \"a\"),\n        M.equals(ordT(#equal))\n      ),\n      test(\n        \"compare-a-b\",\n        Text.compare(\"a\", \"b\"),\n        M.equals(ordT(#less))\n      ),\n      test(\n        \"compare-b-a\",\n        Text.compare(\"b\", \"a\"),\n        M.equals(ordT(#greater))\n      )\n    ]\n  )\n);\n\ndo {\n  let cmp = Char.compare;\n  run(\n    suite(\n      \"compareWith\",\n      [\n        test(\n          \"compareWith-empties\",\n          Text.compareWith(\"\", \"\", cmp),\n          M.equals(ordT(#equal))\n        ),\n        test(\n          \"compareWith-empty\",\n          Text.compareWith(\"abc\", \"\", cmp),\n          M.equals(ordT(#greater))\n        ),\n        test(\n          \"compareWith-equal-nonempty\",\n          Text.compareWith(\"abc\", \"abc\", cmp),\n          M.equals(ordT(#equal))\n        ),\n        test(\n          \"compareWith-less-nonempty\",\n          Text.compareWith(\"abc\", \"abd\", cmp),\n          M.equals(ordT(#less))\n        ),\n        test(\n          \"compareWith-less-nonprefix\",\n          Text.compareWith(\"abc\", \"abcd\", cmp),\n          M.equals(ordT(#less))\n        ),\n        test(\n          \"compareWith-empty-nonempty\",\n          Text.compareWith(\"\", \"abcd\", cmp),\n          M.equals(ordT(#less))\n        ),\n        test(\n          \"compareWith-prefix\",\n          Text.compareWith(\"abcd\", \"abc\", cmp),\n          M.equals(ordT(#greater))\n        )\n      ]\n    )\n  )\n};\n\ndo {\n  let cmp = func(c1 : Char, c2 : Char) : Order.Order {\n    switch (Char.compare(c1, c2)) {\n      case (#less) #greater;\n      case (#equal) #equal;\n      case (#greater) #less\n    }\n  };\n  run(\n    suite(\n      \"compareWith-flip\",\n      [\n        test(\n          \"compareWith-flip-greater\",\n          Text.compareWith(\"abc\", \"abd\", cmp),\n          M.equals(ordT(#greater))\n        ),\n        test(\n          \"compareWith-flip-less\",\n          Text.compareWith(\"abd\", \"abc\", cmp),\n          M.equals(ordT(#less))\n        )\n      ]\n    )\n  )\n};\n\nrun(\n  suite(\n    \"utf8\",\n    [\n      test(\n        \"encode-literal\",\n        Text.encodeUtf8(\"FooBär☃\"),\n        M.equals(blobT(\"FooBär☃\"))\n      ),\n      test(\n        \"encode-concat\",\n        Text.encodeUtf8(\"Foo\" # \"Bär\" # \"☃\"),\n        M.equals(blobT(\"FooBär☃\"))\n      ),\n      test(\n        \"decode-literal-good\",\n        Text.decodeUtf8(\"FooBär☃\"),\n        M.equals(optTextT(?\"FooBär☃\"))\n      ),\n      test(\n        \"decode-literal-bad1\",\n        Text.decodeUtf8(\"\\FF\"),\n        M.equals(optTextT(null))\n      ),\n      test(\n        \"decode-literal-bad2\",\n        Text.decodeUtf8(\"\\D8\\00t d\"),\n        M.equals(optTextT(null))\n      )\n    ]\n  )\n)\n"},"TrieExampleTest.mo":{"content":"import Trie \"mo:base/Trie\";\nimport Text \"mo:base/Text\";\nimport Iter \"mo:base/Iter\";\n\ndebug {\n  type Trie<K, V> = Trie.Trie<K, V>;\n  type Key<K> = Trie.Key<K>;\n\n  func key(t : Text) : Key<Text> { { key = t; hash = Text.hash t } };\n\n  let t0 : Trie<Text, Nat> = Trie.empty();\n  let t1 : Trie<Text, Nat> = Trie.put(t0, key \"hello\", Text.equal, 42).0;\n  let t2 : Trie<Text, Nat> = Trie.put(t1, key \"world\", Text.equal, 24).0;\n  let n : ?Nat = Trie.put(t1, key \"hello\", Text.equal, 0).1;\n  assert (n == ?42);\n\n  /// True if elements of a form a subset of those of b.\n  func isSubSet<X>(a : [X], b : [X], eq : (X, X) -> Bool) : Bool {\n    for (x in a.vals()) {\n      var found = false;\n      label here : () {\n        for (y in b.vals()) {\n          if (eq(x, y)) { found := true; break here }\n        }\n      };\n      if (not found) { return false }\n    };\n    return true\n  };\n\n  // note that `put(\"hello\", ..., 0)` happens \"after\" t2, but map is immutable (applicative).\n  let actual : [(Text, Nat)] = Iter.toArray(Trie.iter(t2));\n  let expected : [(Text, Nat)] = [(\"hello\", 42), (\"world\", 24)];\n  func equalKV(a : (Text, Nat), b : (Text, Nat)) : Bool { a == b };\n  assert (isSubSet(actual, expected, equalKV));\n  assert (isSubSet(expected, actual, equalKV));\n  assert Trie.isValid(t2, false)\n}\n"},"floatTest.mo":{"content":"import Debug \"mo:base/Debug\";\nimport Float \"mo:base/Float\";\n\nDebug.print(\"Float\");\n\ndo {\n  Debug.print(\"  abs\");\n\n  assert (Float.abs(1.1) == 1.1);\n  assert (Float.abs(-1.1) == 1.1)\n};\n\ndo {\n  Debug.print(\"  ceil\");\n\n  assert (Float.ceil(1.1) == 2.0)\n};\n\ndo {\n  Debug.print(\"  floor\");\n\n  assert (Float.floor(1.1) == 1.0)\n};\n\ndo {\n  Debug.print(\"  trunc\");\n\n  assert (Float.trunc(1.0012345789) == 1.0)\n};\n\ndo {\n  Debug.print(\"  nearest\");\n\n  assert (Float.nearest(1.00001) == 1.0);\n  assert (Float.nearest(1.99999) == 2.0)\n};\n\ndo {\n  Debug.print(\"  min\");\n\n  assert (Float.min(1.1, 2.2) == 1.1)\n};\n\ndo {\n  Debug.print(\"  max\");\n\n  assert (Float.max(1.1, 2.2) == 2.2)\n};\n\ndo {\n  Debug.print(\"  sin\");\n\n  assert (Float.sin(0.0) == 0.0)\n};\n\ndo {\n  Debug.print(\"  cos\");\n\n  assert (Float.cos(0.0) == 1.0)\n};\n\ndo {\n  Debug.print(\"  toFloat64\");\n\n  assert (Float.toInt64(1e10) == (10000000000 : Int64));\n  assert (Float.toInt64(-1e10) == (-10000000000 : Int64))\n};\n\ndo {\n  Debug.print(\"  ofFloat64\");\n\n  assert (Float.fromInt64(10000000000) == 1e10);\n  assert (Float.fromInt64(-10000000000) == -1e10)\n};\n\ndo {\n  Debug.print(\"  format\");\n\n  assert (Float.format(#exact, 20.12345678901) == \"20.12345678901\");\n  assert (Float.format(#fix 6, 20.12345678901) == \"20.123457\");\n  assert (Float.format(#exp 9, 20.12345678901) == \"2.012345679e+01\");\n  assert (Float.format(#gen 12, 20.12345678901) == \"20.123456789\");\n  assert (Float.format(#hex 10, 20.12345678901) == \"0x1.41f9add374p+4\")\n};\n\ndo {\n  Debug.print(\"  Pi: \" # Float.toText(Float.pi));\n  Debug.print(\"  arccos(-1.0): \" # Float.toText(Float.arccos(-1.)));\n\n  assert (Float.pi == Float.arccos(-1.))\n};\n\ndo {\n  Debug.print(\"  e: \" # debug_show (Float.toText(Float.e)));\n  Debug.print(\"  exp(1): \" # debug_show (Float.toText(Float.exp(1))));\n\n  assert (Float.e == Float.exp(1))\n}\n"},"bufTest.mo":{"content":"import Prim \"mo:⛔\";\nimport B \"mo:base/Buffer\";\nimport Iter \"mo:base/Iter\";\nimport Option \"mo:base/Option\";\nimport Nat \"mo:base/Nat\";\nimport Hash \"mo:base/Hash\";\nimport Nat32 \"mo:base/Nat32\";\nimport Order \"mo:base/Order\";\n\nimport Suite \"mo:matchers/Suite\";\nimport T \"mo:matchers/Testable\";\nimport M \"mo:matchers/Matchers\";\n\nlet { run; test; suite } = Suite;\n\nlet NatBufferTestable : T.Testable<B.Buffer<Nat>> = object {\n  public func display(buffer : B.Buffer<Nat>) : Text {\n    B.toText(buffer, Nat.toText)\n  };\n  public func equals(buffer1 : B.Buffer<Nat>, buffer2 : B.Buffer<Nat>) : Bool {\n    B.equal(buffer1, buffer2, Nat.equal)\n  }\n};\n\nclass OrderTestable(initItem : Order.Order) : T.TestableItem<Order.Order> {\n  public let item = initItem;\n  public func display(order : Order.Order) : Text {\n    switch (order) {\n      case (#less) {\n        \"#less\"\n      };\n      case (#greater) {\n        \"#greater\"\n      };\n      case (#equal) {\n        \"#equal\"\n      }\n    }\n  };\n  public let equals = Order.equal\n};\n\n/* --------------------------------------- */\nrun(\n  suite(\n    \"construct\",\n    [\n      test(\n        \"initial size\",\n        B.Buffer<Nat>(10).size(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"initial capacity\",\n        B.Buffer<Nat>(10).capacity(),\n        M.equals(T.nat(10))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nvar buffer = B.Buffer<Nat>(10);\nfor (i in Iter.range(0, 3)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"add\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(4))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(10))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(2);\nfor (i in Iter.range(0, 3)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"add with capacity change\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(4))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(0);\nfor (i in Iter.range(0, 3)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"add with capacity change, initial capacity 0\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(4))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(2);\n\nrun(\n  suite(\n    \"removeLast on empty buffer\",\n    [\n      test(\n        \"return value\",\n        buffer.removeLast(),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      ),\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(2);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"removeLast\",\n    [\n      test(\n        \"return value\",\n        buffer.removeLast(),\n        M.equals(T.optional<Nat>(T.natTestable, ?5))\n      ),\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nfor (i in Iter.range(0, 5)) {\n  ignore buffer.removeLast()\n};\n\nrun(\n  suite(\n    \"removeLast until empty\",\n    [\n      test(\n        \"return value\",\n        buffer.removeLast(),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      ),\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(0);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"remove\",\n    [\n      test(\n        \"return value\",\n        buffer.remove(2),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 3, 4, 5]))\n      ),\n      test(\n        \"return value\",\n        buffer.remove(0),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(4))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [1, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\nfor (i in Iter.range(0, 2)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"remove last element at capacity\",\n    [\n      test(\n        \"return value\",\n        buffer.remove(2),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(3))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(0);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nfor (i in Iter.range(0, 5)) {\n  ignore buffer.remove(5 - i)\n};\n\nrun(\n  suite(\n    \"remove until empty\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(1);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer.filterEntries(func(_, x) = x % 2 == 0);\n\nrun(\n  suite(\n    \"filterEntries\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(3))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 2, 4]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(1);\nbuffer.filterEntries(func(_, x) = x % 2 == 0);\n\nrun(\n  suite(\n    \"filterEntries on empty\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(12);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\nbuffer.filterEntries(func(i, x) = i + x == 2);\n\nrun(\n  suite(\n    \"filterEntries size down\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [1]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(5);\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\nbuffer.filterEntries(func(_, _) = false);\n\nrun(\n  suite(\n    \"filterEntries size down to empty\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(10);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"get and getOpt\",\n    [\n      test(\n        \"get\",\n        buffer.get(2),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"getOpt success\",\n        buffer.getOpt(0),\n        M.equals(T.optional(T.natTestable, ?0))\n      ),\n      test(\n        \"getOpt out of bounds\",\n        buffer.getOpt(10),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(10);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer.put(2, 20);\n\nrun(\n  suite(\n    \"put\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 20, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(10);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer.reserve(6);\n\nrun(\n  suite(\n    \"decrease capacity\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(10);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer.reserve(20);\n\nrun(\n  suite(\n    \"increase capacity\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(20))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(10);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nvar buffer2 = B.Buffer<Nat>(20);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.append(buffer2);\n\nrun(\n  suite(\n    \"append\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(12))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(18))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(10);\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(0);\n\nbuffer.append(buffer2);\n\nrun(\n  suite(\n    \"append empty buffer\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(10))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(10);\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(0, 5)) {\n  buffer2.add(i)\n};\n\nbuffer.append(buffer2);\n\nrun(\n  suite(\n    \"append to empty buffer\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(10))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(8);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer.insert(3, 30);\n\nrun(\n  suite(\n    \"insert\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(7))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 30, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(8);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer.insert(6, 60);\n\nrun(\n  suite(\n    \"insert at back\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(7))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5, 60]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(8);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer.insert(0, 10);\n\nrun(\n  suite(\n    \"insert at front\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(7))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [10, 0, 1, 2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(6);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer.insert(3, 30);\n\nrun(\n  suite(\n    \"insert with capacity change\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(7))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(9))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 30, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(5);\n\nbuffer.insert(0, 0);\n\nrun(\n  suite(\n    \"insert into empty buffer\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(0);\n\nbuffer.insert(0, 0);\n\nrun(\n  suite(\n    \"insert into empty buffer with capacity change\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(15);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.insertBuffer(3, buffer2);\n\nrun(\n  suite(\n    \"insertBuffer\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(12))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(15))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 10, 11, 12, 13, 14, 15, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(15);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.insertBuffer(0, buffer2);\n\nrun(\n  suite(\n    \"insertBuffer at start\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(12))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(15))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(15);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.insertBuffer(6, buffer2);\n\nrun(\n  suite(\n    \"insertBuffer at end\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(12))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(15))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(8);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.insertBuffer(3, buffer2);\n\nrun(\n  suite(\n    \"insertBuffer with capacity change\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(12))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(18))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 10, 11, 12, 13, 14, 15, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(8);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.insertBuffer(0, buffer2);\n\nrun(\n  suite(\n    \"insertBuffer at start with capacity change\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(12))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(18))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(8);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.insertBuffer(6, buffer2);\n\nrun(\n  suite(\n    \"insertBuffer at end with capacity change\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(12))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(18))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(7);\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.insertBuffer(0, buffer2);\n\nrun(\n  suite(\n    \"insertBuffer to empty buffer\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(7))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [10, 11, 12, 13, 14, 15]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nbuffer2 := B.Buffer<Nat>(10);\n\nfor (i in Iter.range(10, 15)) {\n  buffer2.add(i)\n};\n\nbuffer.insertBuffer(0, buffer2);\n\nrun(\n  suite(\n    \"insertBuffer to empty buffer with capacity change\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(9))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [10, 11, 12, 13, 14, 15]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nbuffer.clear();\n\nrun(\n  suite(\n    \"clear\",\n    [\n      test(\n        \"size\",\n        buffer.size(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.clone(buffer);\n\nrun(\n  suite(\n    \"clone\",\n    [\n      test(\n        \"size\",\n        buffer2.size(),\n        M.equals(T.nat(buffer.size()))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(buffer2.capacity()))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, B.toArray(buffer2)))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nvar size = 0;\n\nfor (element in buffer.vals()) {\n  M.assertThat(element, M.equals(T.nat(size)));\n  size += 1\n};\n\nrun(\n  suite(\n    \"vals\",\n    [\n      test(\n        \"size\",\n        size,\n        M.equals(T.nat(7))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nrun(\n  suite(\n    \"array round trips\",\n    [\n      test(\n        \"fromArray and toArray\",\n        B.toArray<Nat>(B.fromArray<Nat>([0, 1, 2, 3])),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3]))\n      ),\n      test(\n        \"fromVarArray\",\n        B.toArray<Nat>(B.fromVarArray<Nat>([var 0, 1, 2, 3])),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nrun(\n  suite(\n    \"empty array round trips\",\n    [\n      test(\n        \"fromArray and toArray\",\n        B.toArray<Nat>(B.fromArray<Nat>([])),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      ),\n      test(\n        \"fromVarArray\",\n        B.toArray<Nat>(B.fromVarArray<Nat>([var])),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"iter round trips\",\n    [\n      test(\n        \"fromIter and vals\",\n        B.toArray(B.fromIter<Nat>(buffer.vals())),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5, 6]))\n      ),\n      test(\n        \"empty\",\n        B.toArray(B.fromIter<Nat>(B.Buffer<Nat>(2).vals())),\n        M.equals(T.array<Nat>(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nB.trimToSize(buffer);\n\nrun(\n  suite(\n    \"trimToSize\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(7))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5, 6]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nB.trimToSize(buffer);\n\nrun(\n  suite(\n    \"trimToSize on empty\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.map<Nat, Nat>(buffer, func x = x * 2);\n\nrun(\n  suite(\n    \"map\",\n    [\n      test(\n        \"capacity\",\n        buffer2.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer2),\n        M.equals(T.array<Nat>(T.natTestable, [0, 2, 4, 6, 8, 10, 12]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(0);\n\nbuffer2 := B.map<Nat, Nat>(buffer, func x = x * 2);\n\nrun(\n  suite(\n    \"map empty\",\n    [\n      test(\n        \"capacity\",\n        buffer2.capacity(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer2),\n        M.equals(T.array<Nat>(T.natTestable, []))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nvar sum = 0;\n\nB.iterate<Nat>(buffer, func x = sum += x);\n\nrun(\n  suite(\n    \"iterate\",\n    [\n      test(\n        \"sum\",\n        sum,\n        M.equals(T.nat(21))\n      ),\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 2, 3, 4, 5, 6]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.chain<Nat, Nat>(buffer, func x = B.make<Nat> x);\n\nrun(\n  suite(\n    \"chain\",\n    [\n      test(\n        \"elements\",\n        B.toArray(buffer2),\n        M.equals(T.array<Nat>(T.natTestable, B.toArray(buffer)))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.mapFilter<Nat, Nat>(buffer, func x = if (x % 2 == 0) { ?x } else { null });\n\nrun(\n  suite(\n    \"mapFilter\",\n    [\n      test(\n        \"capacity\",\n        buffer2.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer2),\n        M.equals(T.array<Nat>(T.natTestable, [0, 2, 4, 6]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.mapEntries<Nat, Nat>(buffer, func(i, x) = i * x);\n\nrun(\n  suite(\n    \"mapEntries\",\n    [\n      test(\n        \"capacity\",\n        buffer2.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer2),\n        M.equals(T.array<Nat>(T.natTestable, [0, 1, 4, 9, 16, 25, 36]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nvar bufferResult = B.mapResult<Nat, Nat, Text>(buffer, func x = #ok x);\n\nrun(\n  suite(\n    \"mapResult success\",\n    [\n      test(\n        \"return value\",\n        #ok buffer,\n        M.equals(T.result<B.Buffer<Nat>, Text>(NatBufferTestable, T.textTestable, bufferResult))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nbufferResult := B.mapResult<Nat, Nat, Text>(\n  buffer,\n  func x = if (x == 4) { #err \"error\" } else { #ok x }\n);\n\nrun(\n  suite(\n    \"mapResult failure\",\n    [\n      test(\n        \"return value\",\n        #err \"error\",\n        M.equals(T.result<B.Buffer<Nat>, Text>(NatBufferTestable, T.textTestable, bufferResult))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"foldLeft\",\n    [\n      test(\n        \"return value\",\n        B.foldLeft<Text, Nat>(buffer, \"\", func(acc, x) = acc # Nat.toText(x)),\n        M.equals(T.text(\"0123456\"))\n      ),\n      test(\n        \"return value empty\",\n        B.foldLeft<Text, Nat>(B.Buffer<Nat>(4), \"\", func(acc, x) = acc # Nat.toText(x)),\n        M.equals(T.text(\"\"))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"foldRight\",\n    [\n      test(\n        \"return value\",\n        B.foldRight<Nat, Text>(buffer, \"\", func(x, acc) = acc # Nat.toText(x)),\n        M.equals(T.text(\"6543210\"))\n      ),\n      test(\n        \"return value empty\",\n        B.foldRight<Nat, Text>(B.Buffer<Nat>(4), \"\", func(x, acc) = acc # Nat.toText(x)),\n        M.equals(T.text(\"\"))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"forAll\",\n    [\n      test(\n        \"true\",\n        B.forAll<Nat>(buffer, func x = x >= 0),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"false\",\n        B.forAll<Nat>(buffer, func x = x % 2 == 0),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"default\",\n        B.forAll<Nat>(B.Buffer<Nat>(2), func _ = false),\n        M.equals(T.bool(true))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nrun(\n  suite(\n    \"forSome\",\n    [\n      test(\n        \"true\",\n        B.forSome<Nat>(buffer, func x = x % 2 == 0),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"false\",\n        B.forSome<Nat>(buffer, func x = x < 0),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"default\",\n        B.forSome<Nat>(B.Buffer<Nat>(2), func _ = false),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nrun(\n  suite(\n    \"forNone\",\n    [\n      test(\n        \"true\",\n        B.forNone<Nat>(buffer, func x = x < 0),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"false\",\n        B.forNone<Nat>(buffer, func x = x % 2 != 0),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"default\",\n        B.forNone<Nat>(B.Buffer<Nat>(2), func _ = true),\n        M.equals(T.bool(true))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.make<Nat>(1);\n\nrun(\n  suite(\n    \"make\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [1]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"contains\",\n    [\n      test(\n        \"true\",\n        B.contains<Nat>(buffer, 2, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"true\",\n        B.contains<Nat>(buffer, 9, Nat.equal),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.Buffer<Nat>(3);\n\nrun(\n  suite(\n    \"contains empty\",\n    [\n      test(\n        \"true\",\n        B.contains<Nat>(buffer, 2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"true\",\n        B.contains<Nat>(buffer, 9, Nat.equal),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.Buffer<Nat>(3);\n\nbuffer.add(2);\nbuffer.add(1);\nbuffer.add(10);\nbuffer.add(1);\nbuffer.add(0);\nbuffer.add(3);\n\nrun(\n  suite(\n    \"max\",\n    [\n      test(\n        \"return value\",\n        B.max<Nat>(buffer, Nat.compare),\n        M.equals(T.optional(T.natTestable, ?10))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.Buffer<Nat>(3);\n\nbuffer.add(2);\nbuffer.add(1);\nbuffer.add(10);\nbuffer.add(1);\nbuffer.add(0);\nbuffer.add(3);\nbuffer.add(0);\n\nrun(\n  suite(\n    \"min\",\n    [\n      test(\n        \"return value\",\n        B.min<Nat>(buffer, Nat.compare),\n        M.equals(T.optional(T.natTestable, ?0))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.Buffer<Nat>(3);\nbuffer.add(2);\n\nrun(\n  suite(\n    \"isEmpty\",\n    [\n      test(\n        \"true\",\n        B.isEmpty(B.Buffer<Nat>(2)),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"false\",\n        B.isEmpty(buffer),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.Buffer<Nat>(3);\n\nbuffer.add(2);\nbuffer.add(1);\nbuffer.add(10);\nbuffer.add(1);\nbuffer.add(0);\nbuffer.add(3);\nbuffer.add(0);\n\nB.removeDuplicates<Nat>(buffer, Nat.compare);\n\nrun(\n  suite(\n    \"removeDuplicates\",\n    [\n      test(\n        \"elements (stable ordering)\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [2, 1, 10, 0, 3]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.Buffer<Nat>(3);\n\nB.removeDuplicates<Nat>(buffer, Nat.compare);\n\nrun(\n  suite(\n    \"removeDuplicates empty\",\n    [\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(2)\n};\n\nB.removeDuplicates<Nat>(buffer, Nat.compare);\n\nrun(\n  suite(\n    \"removeDuplicates repeat singleton\",\n    [\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [2]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"hash\",\n    [\n      test(\n        \"empty buffer\",\n        Nat32.toNat(B.hash<Nat>(B.Buffer<Nat>(8), Hash.hash)),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"non-empty buffer\",\n        Nat32.toNat(B.hash<Nat>(buffer, Hash.hash)),\n        M.equals(T.nat(3365238326))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"toText\",\n    [\n      test(\n        \"empty buffer\",\n        B.toText<Nat>(B.Buffer<Nat>(3), Nat.toText),\n        M.equals(T.text(\"[]\"))\n      ),\n      test(\n        \"singleton buffer\",\n        B.toText<Nat>(B.make<Nat>(3), Nat.toText),\n        M.equals(T.text(\"[3]\"))\n      ),\n      test(\n        \"non-empty buffer\",\n        B.toText<Nat>(buffer, Nat.toText),\n        M.equals(T.text(\"[0, 1, 2, 3, 4, 5]\"))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 2)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"equal\",\n    [\n      test(\n        \"empty buffers\",\n        B.equal<Nat>(B.Buffer<Nat>(3), B.Buffer<Nat>(2), Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"non-empty buffers\",\n        B.equal<Nat>(buffer, B.clone(buffer), Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"non-empty and empty buffers\",\n        B.equal<Nat>(buffer, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"non-empty buffers mismatching lengths\",\n        B.equal<Nat>(buffer, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer2 := B.Buffer<Nat>(3);\n\nfor (i in Iter.range(0, 2)) {\n  buffer.add(i)\n};\n\nvar buffer3 = B.Buffer<Nat>(3);\n\nfor (i in Iter.range(2, 5)) {\n  buffer3.add(i)\n};\n\nrun(\n  suite(\n    \"compare\",\n    [\n      test(\n        \"empty buffers\",\n        B.compare<Nat>(B.Buffer<Nat>(3), B.Buffer<Nat>(2), Nat.compare),\n        M.equals(OrderTestable(#equal))\n      ),\n      test(\n        \"non-empty buffers equal\",\n        B.compare<Nat>(buffer, B.clone(buffer), Nat.compare),\n        M.equals(OrderTestable(#equal))\n      ),\n      test(\n        \"non-empty and empty buffers\",\n        B.compare<Nat>(buffer, B.Buffer<Nat>(3), Nat.compare),\n        M.equals(OrderTestable(#greater))\n      ),\n      test(\n        \"non-empty buffers mismatching lengths\",\n        B.compare<Nat>(buffer, buffer2, Nat.compare),\n        M.equals(OrderTestable(#greater))\n      ),\n      test(\n        \"non-empty buffers lexicographic difference\",\n        B.compare<Nat>(buffer, buffer3, Nat.compare),\n        M.equals(OrderTestable(#less))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nvar nestedBuffer = B.Buffer<B.Buffer<Nat>>(3);\nfor (i in Iter.range(0, 4)) {\n  let innerBuffer = B.Buffer<Nat>(2);\n  for (j in if (i % 2 == 0) { Iter.range(0, 4) } else { Iter.range(0, 3) }) {\n    innerBuffer.add(j)\n  };\n  nestedBuffer.add(innerBuffer)\n};\nnestedBuffer.add(B.Buffer<Nat>(2));\n\nbuffer := B.flatten<Nat>(nestedBuffer);\n\nrun(\n  suite(\n    \"flatten\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(45))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [0, 1, 2, 3, 4, 0, 1, 2, 3, 0, 1, 2, 3, 4, 0, 1, 2, 3, 0, 1, 2, 3, 4]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nnestedBuffer := B.Buffer<B.Buffer<Nat>>(3);\nfor (i in Iter.range(0, 4)) {\n  nestedBuffer.add(B.Buffer<Nat>(2))\n};\n\nbuffer := B.flatten<Nat>(nestedBuffer);\n\nrun(\n  suite(\n    \"flatten all empty inner buffers\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nnestedBuffer := B.Buffer<B.Buffer<Nat>>(3);\nbuffer := B.flatten<Nat>(nestedBuffer);\n\nrun(\n  suite(\n    \"flatten empty outer buffer\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(0))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 7)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\n\nfor (i in Iter.range(0, 6)) {\n  buffer2.add(i)\n};\n\nbuffer3.clear();\n\nvar buffer4 = B.make<Nat>(3);\n\nB.reverse<Nat>(buffer);\nB.reverse<Nat>(buffer2);\nB.reverse<Nat>(buffer3);\nB.reverse<Nat>(buffer4);\n\nrun(\n  suite(\n    \"reverse\",\n    [\n      test(\n        \"even elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [7, 6, 5, 4, 3, 2, 1, 0]))\n      ),\n      test(\n        \"odd elements\",\n        B.toArray(buffer2),\n        M.equals(T.array(T.natTestable, [6, 5, 4, 3, 2, 1, 0]))\n      ),\n      test(\n        \"empty\",\n        B.toArray(buffer3),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      ),\n      test(\n        \"singleton\",\n        B.toArray(buffer4),\n        M.equals(T.array(T.natTestable, [3]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer.clear();\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nvar partition = B.partition<Nat>(buffer, func x = x % 2 == 0);\nbuffer2 := partition.0;\nbuffer3 := partition.1;\n\nrun(\n  suite(\n    \"partition\",\n    [\n      test(\n        \"capacity of true buffer\",\n        buffer2.capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements of true buffer\",\n        B.toArray(buffer2),\n        M.equals(T.array(T.natTestable, [0, 2, 4]))\n      ),\n      test(\n        \"capacity of false buffer\",\n        buffer3.capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements of false buffer\",\n        B.toArray(buffer3),\n        M.equals(T.array(T.natTestable, [1, 3, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer.clear();\nfor (i in Iter.range(0, 3)) {\n  buffer.add(i)\n};\n\nfor (i in Iter.range(10, 13)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\nfor (i in Iter.range(2, 5)) {\n  buffer2.add(i)\n};\nfor (i in Iter.range(13, 15)) {\n  buffer2.add(i)\n};\n\nbuffer := B.merge<Nat>(buffer, buffer2, Nat.compare);\n\nrun(\n  suite(\n    \"merge\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(23))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [0, 1, 2, 2, 3, 3, 4, 5, 10, 11, 12, 13, 13, 14, 15]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer.clear();\nfor (i in Iter.range(0, 3)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\n\nbuffer := B.merge<Nat>(buffer, buffer2, Nat.compare);\n\nrun(\n  suite(\n    \"merge with empty\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [0, 1, 2, 3]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\n\nbuffer.clear();\nbuffer2.clear();\n\nbuffer := B.merge<Nat>(buffer, buffer2, Nat.compare);\n\nrun(\n  suite(\n    \"merge two empty\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nbuffer.add(0);\nbuffer.add(2);\nbuffer.add(1);\nbuffer.add(1);\nbuffer.add(5);\nbuffer.add(4);\n\nbuffer.sort(Nat.compare);\n\nrun(\n  suite(\n    \"sort even\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [0, 1, 1, 2, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nbuffer.add(0);\nbuffer.add(2);\nbuffer.add(1);\nbuffer.add(1);\nbuffer.add(5);\n\nbuffer.sort(Nat.compare);\n\nrun(\n  suite(\n    \"sort odd\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [0, 1, 1, 2, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nbuffer.sort(Nat.compare);\n\nrun(\n  suite(\n    \"sort empty\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\nbuffer.add(2);\n\nbuffer.sort(Nat.compare);\n\nrun(\n  suite(\n    \"sort singleton\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [2] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\npartition := B.split<Nat>(buffer, 2);\nbuffer2 := partition.0;\nbuffer3 := partition.1;\n\nrun(\n  suite(\n    \"split\",\n    [\n      test(\n        \"capacity prefix\",\n        buffer2.capacity(),\n        M.equals(T.nat(3))\n      ),\n      test(\n        \"elements prefix\",\n        B.toArray(buffer2),\n        M.equals(T.array(T.natTestable, [0, 1]))\n      ),\n      test(\n        \"capacity suffix\",\n        buffer3.capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements suffix\",\n        B.toArray(buffer3),\n        M.equals(T.array(T.natTestable, [2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\npartition := B.split<Nat>(buffer, 0);\nbuffer2 := partition.0;\nbuffer3 := partition.1;\n\nrun(\n  suite(\n    \"split at index 0\",\n    [\n      test(\n        \"capacity prefix\",\n        buffer2.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements prefix\",\n        B.toArray(buffer2),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      ),\n      test(\n        \"capacity suffix\",\n        buffer3.capacity(),\n        M.equals(T.nat(9))\n      ),\n      test(\n        \"elements suffix\",\n        B.toArray(buffer3),\n        M.equals(T.array(T.natTestable, [0, 1, 2, 3, 4, 5]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\npartition := B.split<Nat>(buffer, 6);\nbuffer2 := partition.0;\nbuffer3 := partition.1;\n\nrun(\n  suite(\n    \"split at last index\",\n    [\n      test(\n        \"capacity prefix\",\n        buffer2.capacity(),\n        M.equals(T.nat(9))\n      ),\n      test(\n        \"elements prefix\",\n        B.toArray(buffer2),\n        M.equals(T.array(T.natTestable, [0, 1, 2, 3, 4, 5]))\n      ),\n      test(\n        \"capacity suffix\",\n        buffer3.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements suffix\",\n        B.toArray(buffer3),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\nbuffer2.clear();\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\nfor (i in Iter.range(0, 3)) {\n  buffer2.add(i)\n};\n\nvar bufferPairs = B.zip<Nat, Nat>(buffer, buffer2);\n\nrun(\n  suite(\n    \"zip\",\n    [\n      test(\n        \"capacity\",\n        bufferPairs.capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements\",\n        B.toArray(bufferPairs),\n        M.equals(T.array(T.tuple2Testable(T.natTestable, T.natTestable), [(0, 0), (1, 1), (2, 2), (3, 3)]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\nbuffer2.clear();\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbufferPairs := B.zip<Nat, Nat>(buffer, buffer2);\n\nrun(\n  suite(\n    \"zip empty\",\n    [\n      test(\n        \"capacity\",\n        bufferPairs.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements\",\n        B.toArray(bufferPairs),\n        M.equals(T.array(T.tuple2Testable(T.natTestable, T.natTestable), [] : [(Nat, Nat)]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\nbuffer2.clear();\n\nbufferPairs := B.zip<Nat, Nat>(buffer, buffer2);\n\nrun(\n  suite(\n    \"zip both empty\",\n    [\n      test(\n        \"capacity\",\n        bufferPairs.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements\",\n        B.toArray(bufferPairs),\n        M.equals(T.array(T.tuple2Testable(T.natTestable, T.natTestable), [] : [(Nat, Nat)]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\nbuffer2.clear();\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\nfor (i in Iter.range(0, 3)) {\n  buffer2.add(i)\n};\n\nbuffer3 := B.zipWith<Nat, Nat, Nat>(buffer, buffer2, Nat.add);\n\nrun(\n  suite(\n    \"zipWith\",\n    [\n      test(\n        \"capacity\",\n        buffer3.capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer3),\n        M.equals(T.array(T.natTestable, [0, 2, 4, 6]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\nbuffer2.clear();\n\nfor (i in Iter.range(0, 5)) {\n  buffer.add(i)\n};\n\nbuffer3 := B.zipWith<Nat, Nat, Nat>(buffer, buffer2, Nat.add);\n\nrun(\n  suite(\n    \"zipWithEmpty\",\n    [\n      test(\n        \"capacity\",\n        buffer3.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer3),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 8)) {\n  buffer.add(i)\n};\n\nvar chunks = B.chunk<Nat>(buffer, 2);\n\nrun(\n  suite(\n    \"chunk\",\n    [\n      test(\n        \"num chunks\",\n        chunks.size(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"chunk 0 capacity\",\n        chunks.get(0).capacity(),\n        M.equals(T.nat(3))\n      ),\n      test(\n        \"chunk 0 elements\",\n        B.toArray(chunks.get(0)),\n        M.equals(T.array(T.natTestable, [0, 1]))\n      ),\n      test(\n        \"chunk 2 capacity\",\n        chunks.get(2).capacity(),\n        M.equals(T.nat(3))\n      ),\n      test(\n        \"chunk 2 elements\",\n        B.toArray(chunks.get(2)),\n        M.equals(T.array(T.natTestable, [4, 5]))\n      ),\n      test(\n        \"chunk 4 capacity\",\n        chunks.get(4).capacity(),\n        M.equals(T.nat(3))\n      ),\n      test(\n        \"chunk 4 elements\",\n        B.toArray(chunks.get(4)),\n        M.equals(T.array(T.natTestable, [8]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nchunks := B.chunk<Nat>(buffer, 3);\n\nrun(\n  suite(\n    \"chunk empty\",\n    [\n      test(\n        \"num chunks\",\n        chunks.size(),\n        M.equals(T.nat(0))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nchunks := B.chunk<Nat>(buffer, 10);\n\nrun(\n  suite(\n    \"chunk larger than buffer\",\n    [\n      test(\n        \"num chunks\",\n        chunks.size(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"chunk 0 elements\",\n        B.toArray(chunks.get(0)),\n        M.equals(T.array(T.natTestable, [0, 1, 2, 3, 4]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nbuffer.add(2);\nbuffer.add(2);\nbuffer.add(2);\nbuffer.add(1);\nbuffer.add(0);\nbuffer.add(0);\nbuffer.add(2);\nbuffer.add(1);\nbuffer.add(1);\n\nvar groups = B.groupBy<Nat>(buffer, Nat.equal);\n\nrun(\n  suite(\n    \"groupBy\",\n    [\n      test(\n        \"num groups\",\n        groups.size(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"group 0 capacity\",\n        groups.get(0).capacity(),\n        M.equals(T.nat(9))\n      ),\n      test(\n        \"group 0 elements\",\n        B.toArray(groups.get(0)),\n        M.equals(T.array(T.natTestable, [2, 2, 2]))\n      ),\n      test(\n        \"group 1 capacity\",\n        groups.get(1).capacity(),\n        M.equals(T.nat(6))\n      ),\n      test(\n        \"group 1 elements\",\n        B.toArray(groups.get(1)),\n        M.equals(T.array(T.natTestable, [1]))\n      ),\n      test(\n        \"group 4 capacity\",\n        groups.get(4).capacity(),\n        M.equals(T.nat(2))\n      ),\n      test(\n        \"group 4 elements\",\n        B.toArray(groups.get(4)),\n        M.equals(T.array(T.natTestable, [1, 1]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\ngroups := B.groupBy<Nat>(buffer, Nat.equal);\n\nrun(\n  suite(\n    \"groupBy clear\",\n    [\n      test(\n        \"num groups\",\n        groups.size(),\n        M.equals(T.nat(0))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(0)\n};\n\ngroups := B.groupBy<Nat>(buffer, Nat.equal);\n\nrun(\n  suite(\n    \"groupBy clear\",\n    [\n      test(\n        \"num groups\",\n        groups.size(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"group 0 elements\",\n        B.toArray(groups.get(0)),\n        M.equals(T.array(T.natTestable, [0, 0, 0, 0, 0]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer := B.prefix<Nat>(buffer, 3);\n\nrun(\n  suite(\n    \"prefix\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [0, 1, 2]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nbuffer := B.prefix<Nat>(buffer, 0);\n\nrun(\n  suite(\n    \"prefix of empty\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(1))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer := B.prefix<Nat>(buffer, 5);\n\nrun(\n  suite(\n    \"trivial prefix\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(8))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [0, 1, 2, 3, 4]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\n\nfor (i in Iter.range(0, 2)) {\n  buffer2.add(i)\n};\n\nbuffer3.clear();\n\nbuffer3.add(2);\nbuffer3.add(1);\nbuffer3.add(0);\n\nrun(\n  suite(\n    \"isPrefixOf\",\n    [\n      test(\n        \"normal prefix\",\n        B.isPrefixOf<Nat>(buffer2, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"identical buffers\",\n        B.isPrefixOf<Nat>(buffer, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"one empty buffer\",\n        B.isPrefixOf<Nat>(B.Buffer<Nat>(3), buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"not prefix\",\n        B.isPrefixOf<Nat>(buffer3, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not prefix from length\",\n        B.isPrefixOf<Nat>(buffer, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not prefix of empty\",\n        B.isPrefixOf<Nat>(buffer, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"empty prefix of empty\",\n        B.isPrefixOf<Nat>(B.Buffer<Nat>(4), B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(true))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\n\nfor (i in Iter.range(0, 2)) {\n  buffer2.add(i)\n};\n\nbuffer3.clear();\n\nbuffer3.add(2);\nbuffer3.add(1);\nbuffer3.add(0);\n\nrun(\n  suite(\n    \"isStrictPrefixOf\",\n    [\n      test(\n        \"normal prefix\",\n        B.isStrictPrefixOf<Nat>(buffer2, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"identical buffers\",\n        B.isStrictPrefixOf<Nat>(buffer, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"one empty buffer\",\n        B.isStrictPrefixOf<Nat>(B.Buffer<Nat>(3), buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"not prefix\",\n        B.isStrictPrefixOf<Nat>(buffer3, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not prefix from length\",\n        B.isStrictPrefixOf<Nat>(buffer, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not prefix of empty\",\n        B.isStrictPrefixOf<Nat>(buffer, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"empty prefix of empty\",\n        B.isStrictPrefixOf<Nat>(B.Buffer<Nat>(4), B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer := B.subBuffer<Nat>(buffer, 1, 3);\n\nrun(\n  suite(\n    \"subBuffer\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [1, 2, 3]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"subBuffer edge cases\",\n    [\n      test(\n        \"prefix\",\n        B.prefix(buffer, 3),\n        M.equals({ { item = B.subBuffer(buffer, 0, 3) } and NatBufferTestable })\n      ),\n      test(\n        \"suffix\",\n        B.suffix(buffer, 3),\n        M.equals({ { item = B.subBuffer(buffer, 2, 3) } and NatBufferTestable })\n      ),\n      test(\n        \"empty\",\n        B.toArray(B.subBuffer(buffer, 2, 0)),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      ),\n      test(\n        \"trivial\",\n        B.subBuffer(buffer, 0, buffer.size()),\n        M.equals({ { item = buffer } and NatBufferTestable })\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\n\nfor (i in Iter.range(0, 2)) {\n  buffer2.add(i)\n};\n\nbuffer3.clear();\n\nfor (i in Iter.range(1, 3)) {\n  buffer3.add(i)\n};\n\nrun(\n  suite(\n    \"isSubBufferOf\",\n    [\n      test(\n        \"normal subBuffer\",\n        B.isSubBufferOf<Nat>(buffer3, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"prefix\",\n        B.isSubBufferOf<Nat>(buffer2, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"identical buffers\",\n        B.isSubBufferOf<Nat>(buffer, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"one empty buffer\",\n        B.isSubBufferOf<Nat>(B.Buffer<Nat>(3), buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"not subBuffer\",\n        B.isSubBufferOf<Nat>(buffer3, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not subBuffer from length\",\n        B.isSubBufferOf<Nat>(buffer, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not subBuffer of empty\",\n        B.isSubBufferOf<Nat>(buffer, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"empty subBuffer of empty\",\n        B.isSubBufferOf<Nat>(B.Buffer<Nat>(4), B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(true))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\n\nfor (i in Iter.range(0, 2)) {\n  buffer2.add(i)\n};\n\nbuffer3.clear();\n\nfor (i in Iter.range(1, 3)) {\n  buffer3.add(i)\n};\n\nbuffer4 := B.Buffer<Nat>(4);\n\nfor (i in Iter.range(3, 4)) {\n  buffer4.add(i)\n};\n\nrun(\n  suite(\n    \"isStrictSubBufferOf\",\n    [\n      test(\n        \"normal strict subBuffer\",\n        B.isStrictSubBufferOf<Nat>(buffer3, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"prefix\",\n        B.isStrictSubBufferOf<Nat>(buffer2, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"suffix\",\n        B.isStrictSubBufferOf<Nat>(buffer4, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"identical buffers\",\n        B.isStrictSubBufferOf<Nat>(buffer, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"one empty buffer\",\n        B.isStrictSubBufferOf<Nat>(B.Buffer<Nat>(3), buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"not subBuffer\",\n        B.isStrictSubBufferOf<Nat>(buffer3, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not subBuffer from length\",\n        B.isStrictSubBufferOf<Nat>(buffer, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not subBuffer of empty\",\n        B.isStrictSubBufferOf<Nat>(buffer, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"empty not strict subBuffer of empty\",\n        B.isStrictSubBufferOf<Nat>(B.Buffer<Nat>(4), B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer := B.suffix<Nat>(buffer, 3);\n\nrun(\n  suite(\n    \"suffix\",\n    [\n      test(\n        \"capacity\",\n        buffer.capacity(),\n        M.equals(T.nat(5))\n      ),\n      test(\n        \"elements\",\n        B.toArray(buffer),\n        M.equals(T.array(T.natTestable, [2, 3, 4]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"suffix edge cases\",\n    [\n      test(\n        \"empty\",\n        B.toArray(B.prefix(buffer, 0)),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      ),\n      test(\n        \"trivial\",\n        B.prefix(buffer, buffer.size()),\n        M.equals({ { item = buffer } and NatBufferTestable })\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\nfor (i in Iter.range(3, 4)) {\n  buffer2.add(i)\n};\n\nbuffer3.clear();\n\nbuffer3.add(2);\nbuffer3.add(1);\nbuffer3.add(0);\n\nrun(\n  suite(\n    \"isSuffixOf\",\n    [\n      test(\n        \"normal suffix\",\n        B.isSuffixOf<Nat>(buffer2, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"identical buffers\",\n        B.isSuffixOf<Nat>(buffer, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"one empty buffer\",\n        B.isSuffixOf<Nat>(B.Buffer<Nat>(3), buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"not suffix\",\n        B.isSuffixOf<Nat>(buffer3, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not suffix from length\",\n        B.isSuffixOf<Nat>(buffer, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not suffix of empty\",\n        B.isSuffixOf<Nat>(buffer, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"empty suffix of empty\",\n        B.isSuffixOf<Nat>(B.Buffer<Nat>(4), B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(true))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nbuffer2.clear();\nfor (i in Iter.range(3, 4)) {\n  buffer2.add(i)\n};\n\nbuffer3.clear();\n\nbuffer3.add(2);\nbuffer3.add(1);\nbuffer3.add(0);\n\nrun(\n  suite(\n    \"isStrictSuffixOf\",\n    [\n      test(\n        \"normal suffix\",\n        B.isStrictSuffixOf<Nat>(buffer2, buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"identical buffers\",\n        B.isStrictSuffixOf<Nat>(buffer, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"one empty buffer\",\n        B.isStrictSuffixOf<Nat>(B.Buffer<Nat>(3), buffer, Nat.equal),\n        M.equals(T.bool(true))\n      ),\n      test(\n        \"not suffix\",\n        B.isStrictSuffixOf<Nat>(buffer3, buffer, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not suffix from length\",\n        B.isStrictSuffixOf<Nat>(buffer, buffer2, Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"not suffix of empty\",\n        B.isStrictSuffixOf<Nat>(buffer, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      ),\n      test(\n        \"empty suffix of empty\",\n        B.isStrictSuffixOf<Nat>(B.Buffer<Nat>(4), B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.bool(false))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"takeWhile\",\n    [\n      test(\n        \"normal case\",\n        B.toArray(B.takeWhile<Nat>(buffer, func x = x < 3)),\n        M.equals(T.array(T.natTestable, [0, 1, 2]))\n      ),\n      test(\n        \"empty\",\n        B.toArray(B.takeWhile<Nat>(B.Buffer<Nat>(3), func x = x < 3)),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 4)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"dropWhile\",\n    [\n      test(\n        \"normal case\",\n        B.toArray(B.dropWhile<Nat>(buffer, func x = x < 3)),\n        M.equals(T.array(T.natTestable, [3, 4]))\n      ),\n      test(\n        \"empty\",\n        B.toArray(B.dropWhile<Nat>(B.Buffer<Nat>(3), func x = x < 3)),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      ),\n      test(\n        \"drop all\",\n        B.toArray(B.dropWhile<Nat>(buffer, func _ = true)),\n        M.equals(T.array(T.natTestable, [] : [Nat]))\n      ),\n      test(\n        \"drop none\",\n        B.toArray(B.dropWhile<Nat>(buffer, func _ = false)),\n        M.equals(T.array(T.natTestable, [0, 1, 2, 3, 4]))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(1, 6)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"binarySearch\",\n    [\n      test(\n        \"find in middle\",\n        B.binarySearch<Nat>(2, buffer, Nat.compare),\n        M.equals(T.optional(T.natTestable, ?1))\n      ),\n      test(\n        \"find first\",\n        B.binarySearch<Nat>(1, buffer, Nat.compare),\n        M.equals(T.optional(T.natTestable, ?0))\n      ),\n      test(\n        \"find last\",\n        B.binarySearch<Nat>(6, buffer, Nat.compare),\n        M.equals(T.optional(T.natTestable, ?5))\n      ),\n      test(\n        \"not found to the right\",\n        B.binarySearch<Nat>(10, buffer, Nat.compare),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      ),\n      test(\n        \"not found to the left\",\n        B.binarySearch<Nat>(0, buffer, Nat.compare),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nfor (i in Iter.range(0, 6)) {\n  buffer.add(i)\n};\n\nrun(\n  suite(\n    \"indexOf\",\n    [\n      test(\n        \"find in middle\",\n        B.indexOf<Nat>(2, buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?2))\n      ),\n      test(\n        \"find first\",\n        B.indexOf<Nat>(0, buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?0))\n      ),\n      test(\n        \"find last\",\n        B.indexOf<Nat>(6, buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?6))\n      ),\n      test(\n        \"not found\",\n        B.indexOf<Nat>(10, buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      ),\n      test(\n        \"empty\",\n        B.indexOf<Nat>(100, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nbuffer.add(2); // 0\nbuffer.add(2); // 1\nbuffer.add(1); // 2\nbuffer.add(10); // 3\nbuffer.add(1); // 4\nbuffer.add(0); // 5\nbuffer.add(10); // 6\nbuffer.add(3); // 7\nbuffer.add(0); // 8\n\nrun(\n  suite(\n    \"lastIndexOf\",\n    [\n      test(\n        \"find in middle\",\n        B.lastIndexOf<Nat>(10, buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?6))\n      ),\n      test(\n        \"find only\",\n        B.lastIndexOf<Nat>(3, buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?7))\n      ),\n      test(\n        \"find last\",\n        B.lastIndexOf<Nat>(0, buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?8))\n      ),\n      test(\n        \"not found\",\n        B.lastIndexOf<Nat>(100, buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      ),\n      test(\n        \"empty\",\n        B.lastIndexOf<Nat>(100, B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      )\n    ]\n  )\n);\n\n/* --------------------------------------- */\nbuffer.clear();\n\nbuffer.add(2); // 0\nbuffer.add(2); // 1\nbuffer.add(1); // 2\nbuffer.add(10); // 3\nbuffer.add(1); // 4\nbuffer.add(10); // 5\nbuffer.add(3); // 6\nbuffer.add(0); // 7\n\nrun(\n  suite(\n    \"indexOfBuffer\",\n    [\n      test(\n        \"find in middle\",\n        B.indexOfBuffer<Nat>(B.fromArray<Nat>([1, 10, 1]), buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?2))\n      ),\n      test(\n        \"find first\",\n        B.indexOfBuffer<Nat>(B.fromArray<Nat>([2, 2, 1, 10]), buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?0))\n      ),\n      test(\n        \"find last\",\n        B.indexOfBuffer<Nat>(B.fromArray<Nat>([0]), buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, ?7))\n      ),\n      test(\n        \"not found\",\n        B.indexOfBuffer<Nat>(B.fromArray<Nat>([99, 100, 1]), buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      ),\n      test(\n        \"search for empty buffer\",\n        B.indexOfBuffer<Nat>(B.fromArray<Nat>([]), buffer, Nat.equal),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      ),\n      test(\n        \"search through empty buffer\",\n        B.indexOfBuffer<Nat>(B.fromArray<Nat>([1, 2, 3]), B.Buffer<Nat>(2), Nat.equal),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      ),\n      test(\n        \"search for empty in empty\",\n        B.indexOfBuffer<Nat>(B.Buffer<Nat>(2), B.Buffer<Nat>(3), Nat.equal),\n        M.equals(T.optional(T.natTestable, null : ?Nat))\n      )\n    ]\n  )\n)\n"},"heapTest.mo":{"content":"import H \"mo:base/Heap\";\nimport I \"mo:base/Iter\";\nimport O \"mo:base/Option\";\nimport Int \"mo:base/Int\";\n\nlet order = Int.compare;\n\ndo {\n  var pq = H.Heap<Int>(order);\n  for (i in I.revRange(100, 0)) {\n    pq.put(i);\n    let x = pq.peekMin();\n    assert (O.unwrap(x) == i)\n  };\n  for (i in I.range(0, 100)) {\n    pq.put(i);\n    let x = pq.peekMin();\n    assert (O.unwrap(x) == 0)\n  };\n  for (i in I.range(0, 100)) {\n    pq.deleteMin();\n    let x = pq.peekMin();\n    pq.deleteMin();\n    assert (O.unwrap(x) == i)\n  };\n  O.assertNull(pq.peekMin())\n};\n\n// fromIter\ndo {\n  do {\n    let iter = [5, 10, 9, 7, 3, 8, 1, 0, 2, 4, 6].vals();\n    let pq = H.fromIter<Int>(iter, order);\n    for (i in I.range(0, 10)) {\n      let x = pq.peekMin();\n      assert (O.unwrap(x) == i);\n      pq.deleteMin()\n    };\n    O.assertNull(pq.peekMin())\n  };\n\n  do {\n    let pq = H.fromIter<Int>([].vals(), order);\n    O.assertNull(pq.peekMin())\n  };\n\n  do {\n    let pq = H.fromIter<Int>([100].vals(), order);\n    assert (O.unwrap(pq.peekMin()) == 100)\n  }\n}\n"}}}