summary refs log tree commit diff stats
path: root/tests/collections
diff options
context:
space:
mode:
Diffstat (limited to 'tests/collections')
-rw-r--r--tests/collections/tactiontable.nim37
-rw-r--r--tests/collections/tcollections.nim81
-rw-r--r--tests/collections/tcollections_to_string.nim11
-rw-r--r--tests/collections/thashsets.nim280
-rw-r--r--tests/collections/tseq.nim242
-rw-r--r--tests/collections/ttables.nim202
-rw-r--r--tests/collections/ttablesthreads.nim115
7 files changed, 824 insertions, 144 deletions
diff --git a/tests/collections/tactiontable.nim b/tests/collections/tactiontable.nim
new file mode 100644
index 000000000..3f15a70bd
--- /dev/null
+++ b/tests/collections/tactiontable.nim
@@ -0,0 +1,37 @@
+discard """
+  output: '''
+action 3 arg
+action 3 arg
+'''
+"""
+
+import tables
+
+proc action1(arg: string) =
+  echo "action 1 ", arg
+
+proc action2(arg: string) =
+  echo "action 2 ", arg
+
+proc action3(arg: string) =
+  echo "action 3 ", arg
+
+proc action4(arg: string) =
+  echo "action 4 ", arg
+
+var
+  actionTable1 = {
+    "A": action1,
+    "B": action2,
+    "C": action3,
+    "D": action4}.toTable
+
+const
+  actionTable2 = {
+    "A": action1,
+    "B": action2,
+    "C": action3,
+    "D": action4}.toTable
+
+actionTable1["C"]("arg")
+actionTable2["C"]("arg")
diff --git a/tests/collections/tcollections.nim b/tests/collections/tcollections.nim
index 2f8cfece7..7677f7c1a 100644
--- a/tests/collections/tcollections.nim
+++ b/tests/collections/tcollections.nim
@@ -1,9 +1,10 @@
 discard """
-  output: ""
+  targets: "c js"
 """
 
-import deques, sequtils
+# see also: tdeques, tlists, tcritbits
 
+import sets, tables, sequtils
 
 block tapply:
   var x = @[1, 2, 3]
@@ -12,19 +13,6 @@ block tapply:
   x.applyIt(it+5000)
   doAssert x == @[5111, 5112, 5113]
 
-
-block tdeques:
-  proc index(self: Deque[int], idx: Natural): int =
-    self[idx]
-
-  proc main =
-    var testDeque = initDeque[int]()
-    testDeque.addFirst(1)
-    assert testDeque.index(0) == 1
-
-  main()
-
-
 block tmapit:
   var x = @[1, 2, 3]
   # This mapIt call will run with preallocation because ``len`` is available.
@@ -52,3 +40,66 @@ block tmapit:
   # since ``len`` is not available
   var r = st.mapIt($(it+10))
   doAssert r == @["10", "11", "12", "13", "14"]
+
+
+
+# Collections to string:
+
+# Tests for tuples
+doAssert $(1, 2, 3) == "(1, 2, 3)"
+doAssert $("1", "2", "3") == """("1", "2", "3")"""
+doAssert $('1', '2', '3') == """('1', '2', '3')"""
+
+# Tests for seqs
+doAssert $(@[1, 2, 3]) == "@[1, 2, 3]"
+doAssert $(@["1", "2", "3"]) == """@["1", "2", "3"]"""
+doAssert $(@['1', '2', '3']) == """@['1', '2', '3']"""
+
+# Tests for sets
+doAssert $(toHashSet([1])) == "{1}"
+doAssert $(toHashSet(["1"])) == """{"1"}"""
+doAssert $(toHashSet(['1'])) == """{'1'}"""
+doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}"
+doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}"""
+doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}"""
+
+# see also: tcritbitsToString, tlistsToString
+
+# Tests for tables
+when defined(nimIntHash1):
+  doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}"""
+else:
+  doAssert $({1: "1", 2: "2"}.toTable) == """{2: "2", 1: "1"}"""
+let tabStr = $({"1": 1, "2": 2}.toTable)
+doAssert (tabStr == """{"2": 2, "1": 1}""" or tabStr == """{"1": 1, "2": 2}""")
+
+# Test escaping behavior
+block:
+  var s = ""
+  s.addQuoted('\0')
+  s.addQuoted('\31')
+  s.addQuoted('\127')
+  doAssert s == "'\\x00''\\x1F''\\x7F'"
+block:
+  var s = ""
+  s.addQuoted('\\')
+  s.addQuoted('\'')
+  s.addQuoted('\"')
+  doAssert s == """'\\''\'''\"'"""
+block:
+  var s = ""
+  s.addQuoted("å")
+  s.addQuoted("ä")
+  s.addQuoted("ö")
+  s.addEscapedChar('\xFF')
+  doAssert s == """"å""ä""ö"\xFF"""
+
+# Test customized element representation
+type CustomString = object
+
+proc addQuoted(s: var string, x: CustomString) =
+  s.add("<CustomString>")
+
+block:
+  let s = @[CustomString()]
+  doAssert $s == "@[<CustomString>]"
diff --git a/tests/collections/tcollections_to_string.nim b/tests/collections/tcollections_to_string.nim
index 686b9916b..62ba87334 100644
--- a/tests/collections/tcollections_to_string.nim
+++ b/tests/collections/tcollections_to_string.nim
@@ -19,15 +19,18 @@ doAssert $(@["1", "2", "3"]) == """@["1", "2", "3"]"""
 doAssert $(@['1', '2', '3']) == """@['1', '2', '3']"""
 
 # Tests for sets
-doAssert $(toSet([1])) == "{1}"
-doAssert $(toSet(["1"])) == """{"1"}"""
-doAssert $(toSet(['1'])) == """{'1'}"""
+doAssert $(toHashSet([1])) == "{1}"
+doAssert $(toHashSet(["1"])) == """{"1"}"""
+doAssert $(toHashSet(['1'])) == """{'1'}"""
 doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}"
 doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}"""
 doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}"""
 
 # Tests for tables
-doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}"""
+when defined(nimIntHash1):
+  doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}"""
+else:
+  doAssert $({1: "1", 2: "2"}.toTable) == """{2: "2", 1: "1"}"""
 doAssert $({"1": 1, "2": 2}.toTable) == """{"1": 1, "2": 2}"""
 
 # Tests for deques
diff --git a/tests/collections/thashsets.nim b/tests/collections/thashsets.nim
index cd4401511..359eaa51e 100644
--- a/tests/collections/thashsets.nim
+++ b/tests/collections/thashsets.nim
@@ -3,9 +3,9 @@ import sets, hashes, algorithm
 
 block setEquality:
   var
-    a = initSet[int]()
-    b = initSet[int]()
-    c = initSet[string]()
+    a = initHashSet[int]()
+    b = initHashSet[int]()
+    c = initHashSet[string]()
 
   for i in 0..5: a.incl(i)
   for i in 1..6: b.incl(i)
@@ -16,27 +16,27 @@ block setEquality:
 
 
 block setsContainingTuples:
-  var set = initSet[tuple[i: int, i64: int64, f: float]]()
+  var set = initHashSet[tuple[i: int, i64: int64, f: float]]()
   set.incl( (i: 123, i64: 123'i64, f: 3.14) )
   doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) )
   doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) )
 
 
 block setWithTuplesWithSeqs:
-  var s = initSet[tuple[s: seq[int]]]()
+  var s = initHashSet[tuple[s: seq[int]]]()
   s.incl( (s: @[1, 2, 3]) )
   doAssert s.contains( (s: @[1, 2, 3]) )
   doAssert( not s.contains((s: @[4, 5, 6])) )
 
 
 block setWithSequences:
-  var s = initSet[seq[int]]()
+  var s = initHashSet[seq[int]]()
   s.incl( @[1, 2, 3] )
   doAssert s.contains(@[1, 2, 3])
   doAssert( not s.contains(@[4, 5, 6]) )
 
 block setClearWorked:
-  var s = initSet[char]()
+  var s = initHashSet[char]()
 
   for c in "this is a test":
     s.incl(c)
@@ -79,9 +79,8 @@ block hashForHashedSet:
   let
     seq1 = "This is the test."
     seq2 = "the test is This."
-    s1 = seq1.toSet()
-    s2 = seq2.toSet()
-  var hashSeq: seq[Hash] = @[]
+    s1 = seq1.toHashSet()
+    s2 = seq2.toHashSet()
   doAssert s1 == s2
   doAssert hash(s1) == hash(s2)
 
@@ -120,3 +119,264 @@ block hashForOrderdSet:
   reversed = !$reversed
   doAssert hash(r) == reversed
   doAssert hash(s1) != reversed
+
+
+proc testModule() =
+  ## Internal micro test to validate docstrings and such.
+  block lenTest:
+    var values: HashSet[int]
+    doAssert values.len == 0
+    doAssert values.card == 0
+
+  block setIterator:
+    type pair = tuple[a, b: int]
+    var a, b = initHashSet[pair]()
+    a.incl((2, 3))
+    a.incl((3, 2))
+    a.incl((2, 3))
+    for x, y in a.items:
+      b.incl((x - 2, y + 1))
+    doAssert a.len == b.card
+    doAssert a.len == 2
+    #echo b
+
+  block setContains:
+    var values = initHashSet[int]()
+    doAssert(not values.contains(2))
+    values.incl(2)
+    doAssert values.contains(2)
+    values.excl(2)
+    doAssert(not values.contains(2))
+
+    values.incl(4)
+    var others = toHashSet([6, 7])
+    values.incl(others)
+    doAssert values.len == 3
+
+    values.init
+    doAssert values.containsOrIncl(2) == false
+    doAssert values.containsOrIncl(2) == true
+    var
+      a = toHashSet([1, 2])
+      b = toHashSet([1])
+    b.incl(2)
+    doAssert a == b
+
+  block exclusions:
+    var s = toHashSet([2, 3, 6, 7])
+    s.excl(2)
+    s.excl(2)
+    doAssert s.len == 3
+
+    var
+      numbers = toHashSet([1, 2, 3, 4, 5])
+      even = toHashSet([2, 4, 6, 8])
+    numbers.excl(even)
+    #echo numbers
+    # --> {1, 3, 5}
+
+  block toSeqAndString:
+    var a = toHashSet([2, 7, 5])
+    var b = initHashSet[int](a.len)
+    for x in [2, 7, 5]: b.incl(x)
+    doAssert($a == $b)
+    #echo a
+    #echo toHashSet(["no", "esc'aping", "is \" provided"])
+
+  #block orderedToSeqAndString:
+  #  echo toOrderedSet([2, 4, 5])
+  #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
+
+  block setOperations:
+    var
+      a = toHashSet(["a", "b"])
+      b = toHashSet(["b", "c"])
+      c = union(a, b)
+    doAssert c == toHashSet(["a", "b", "c"])
+    var d = intersection(a, b)
+    doAssert d == toHashSet(["b"])
+    var e = difference(a, b)
+    doAssert e == toHashSet(["a"])
+    var f = symmetricDifference(a, b)
+    doAssert f == toHashSet(["a", "c"])
+    doAssert d < a and d < b
+    doAssert((a < a) == false)
+    doAssert d <= a and d <= b
+    doAssert((a <= a))
+    # Alias test.
+    doAssert a + b == toHashSet(["a", "b", "c"])
+    doAssert a * b == toHashSet(["b"])
+    doAssert a - b == toHashSet(["a"])
+    doAssert a -+- b == toHashSet(["a", "c"])
+    doAssert disjoint(a, b) == false
+    doAssert disjoint(a, b - a) == true
+
+  block mapSet:
+    var a = toHashSet([1, 2, 3])
+    var b = a.map(proc (x: int): string = $x)
+    doAssert b == toHashSet(["1", "2", "3"])
+
+  block lenTest:
+    var values: OrderedSet[int]
+    doAssert values.len == 0
+    doAssert values.card == 0
+
+  block setIterator:
+    type pair = tuple[a, b: int]
+    var a, b = initOrderedSet[pair]()
+    a.incl((2, 3))
+    a.incl((3, 2))
+    a.incl((2, 3))
+    for x, y in a.items:
+      b.incl((x - 2, y + 1))
+    doAssert a.len == b.card
+    doAssert a.len == 2
+
+  block setPairsIterator:
+    var s = toOrderedSet([1, 3, 5, 7])
+    var items = newSeq[tuple[a: int, b: int]]()
+    for idx, item in s: items.add((idx, item))
+    doAssert items == @[(0, 1), (1, 3), (2, 5), (3, 7)]
+
+  block exclusions:
+    var s = toOrderedSet([1, 2, 3, 6, 7, 4])
+
+    s.excl(3)
+    s.excl(3)
+    s.excl(1)
+    s.excl(4)
+
+    var items = newSeq[int]()
+    for item in s: items.add item
+    doAssert items == @[2, 6, 7]
+
+  block: #9005
+    var s = initOrderedSet[(int, int)]()
+    for i in 0 .. 30: incl(s, (i, 0))
+    for i in 0 .. 30: excl(s, (i, 0))
+    doAssert s.len == 0
+
+  #block orderedSetIterator:
+  #  var a = initOrderedSet[int]()
+  #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
+  #    a.incl(value)
+  #  for value in a.items:
+  #    echo "Got ", value
+
+  block setContains:
+    var values = initOrderedSet[int]()
+    doAssert(not values.contains(2))
+    values.incl(2)
+    doAssert values.contains(2)
+
+  block toSeqAndString:
+    var a = toOrderedSet([2, 4, 5])
+    var b = initOrderedSet[int]()
+    for x in [2, 4, 5]: b.incl(x)
+    doAssert($a == $b)
+    doAssert(a == b) # https://github.com/Araq/Nim/issues/1413
+
+  block initBlocks:
+    var a: OrderedSet[int]
+    a.init(4)
+    a.incl(2)
+    a.init
+    doAssert a.len == 0
+    a = initOrderedSet[int](4)
+    a.incl(2)
+    doAssert a.len == 1
+
+    var b: HashSet[int]
+    b.init(4)
+    b.incl(2)
+    b.init
+    doAssert b.len == 0
+    b = initHashSet[int](4)
+    b.incl(2)
+    doAssert b.len == 1
+
+  block missingOrExcl:
+    var s = toOrderedSet([2, 3, 6, 7])
+    doAssert s.missingOrExcl(4) == true
+    doAssert s.missingOrExcl(6) == false
+
+  block orderedSetEquality:
+    type pair = tuple[a, b: int]
+
+    var aa = initOrderedSet[pair]()
+    var bb = initOrderedSet[pair]()
+
+    var x = (a: 1, b: 2)
+    var y = (a: 3, b: 4)
+
+    aa.incl(x)
+    aa.incl(y)
+
+    bb.incl(x)
+    bb.incl(y)
+    doAssert aa == bb
+
+  block setsWithoutInit:
+    var
+      a: HashSet[int]
+      b: HashSet[int]
+      c: HashSet[int]
+      d: HashSet[int]
+      e: HashSet[int]
+
+    doAssert a.containsOrIncl(3) == false
+    doAssert a.contains(3)
+    doAssert a.len == 1
+    doAssert a.containsOrIncl(3)
+    a.incl(3)
+    doAssert a.len == 1
+    a.incl(6)
+    doAssert a.len == 2
+
+    b.incl(5)
+    doAssert b.len == 1
+    b.excl(5)
+    b.excl(c)
+    doAssert b.missingOrExcl(5)
+    doAssert b.disjoint(c)
+
+    d = b + c
+    doAssert d.len == 0
+    d = b * c
+    doAssert d.len == 0
+    d = b - c
+    doAssert d.len == 0
+    d = b -+- c
+    doAssert d.len == 0
+
+    doAssert (d < e) == false
+    doAssert d <= e
+    doAssert d == e
+
+  block setsWithoutInit:
+    var
+      a: OrderedSet[int]
+      b: OrderedSet[int]
+      c: OrderedSet[int]
+      d: HashSet[int]
+
+
+    doAssert a.containsOrIncl(3) == false
+    doAssert a.contains(3)
+    doAssert a.len == 1
+    doAssert a.containsOrIncl(3)
+    a.incl(3)
+    doAssert a.len == 1
+    a.incl(6)
+    doAssert a.len == 2
+
+    b.incl(5)
+    doAssert b.len == 1
+    doAssert b.missingOrExcl(5) == false
+    doAssert b.missingOrExcl(5)
+
+    doAssert c.missingOrExcl(9)
+    d.incl(c)
+    doAssert d.len == 0
+
+testModule()
diff --git a/tests/collections/tseq.nim b/tests/collections/tseq.nim
new file mode 100644
index 000000000..0f8084c78
--- /dev/null
+++ b/tests/collections/tseq.nim
@@ -0,0 +1,242 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+Hithere, what's your name?Hathere, what's your name?
+fA13msg1falsefB14msg2truefC15msg3false
+Zip: [{"Field0": 1, "Field1": 2}, {"Field0": 3, "Field1": 4}, {"Field0": 5, "Field1": 6}]
+Filter Iterator: 3
+Filter Iterator: 5
+Filter Iterator: 7
+Filter: [3, 5, 7]
+FilterIt: [1, 3, 7]
+Concat: [1, 3, 5, 7, 2, 4, 6]
+Deduplicate: [1, 2, 3, 4, 5, 7]
+@[()]
+Minmax: (1, 7)
+2345623456
+'''
+"""
+
+block tseq2:
+  proc `*`(a, b: seq[int]): seq[int] =
+    # allocate a new sequence:
+    newSeq(result, len(a))
+    # multiply two int sequences:
+    for i in 0..len(a)-1: result[i] = a[i] * b[i]
+
+  doAssert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
+
+
+
+block tseqcon:
+  const nestedFixed = true
+
+  type
+    TRec {.final.} = object
+      x, y: int
+      s: string
+      seq: seq[string]
+    TRecSeq = seq[TRec]
+
+  proc test() =
+    var s, b: seq[string]
+    s = @[]
+    add(s, "Hi")
+    add(s, "there, ")
+    add(s, "what's your name?")
+
+    b = s # deep copying here!
+    b[0][1] = 'a'
+
+    for i in 0 .. len(s)-1:
+      write(stdout, s[i])
+    for i in 0 .. len(b)-1:
+      write(stdout, b[i])
+
+  when nestedFixed:
+    proc nested() =
+      var
+        s: seq[seq[string]]
+      for i in 0..10_000: # test if the garbage collector
+        # now works with sequences
+        s = @[
+          @["A", "B", "C", "D"],
+          @["E", "F", "G", "H"],
+          @["I", "J", "K", "L"],
+          @["M", "N", "O", "P"]]
+
+  test()
+  when nestedFixed:
+    nested()
+  echo ""
+
+
+
+import os
+block tseqcon2:
+  proc rec_dir(dir: string): seq[string] =
+    result = @[]
+    for kind, path in walk_dir(dir):
+      if kind == pcDir:
+        add(result, rec_dir(path))
+      else:
+        add(result, path)
+
+
+
+block tseqtuple:
+  type
+    TMsg = tuple[
+      file: string,
+      line: int,
+      msg: string,
+      err: bool]
+
+  var s: seq[TMsg] = @[]
+
+  s.add(("fA", 13, "msg1", false))
+  s.add(("fB", 14, "msg2", true))
+  s.add(("fC", 15, "msg3", false))
+
+  for file, line, msg, err in items(s):
+    stdout.write(file)
+    stdout.write($line)
+    stdout.write(msg)
+    stdout.write($err)
+  echo ""
+
+
+import sequtils, marshal
+block tsequtils:
+  proc testFindWhere(item : int) : bool =
+    if item != 1: return true
+
+  var seq1: seq[int] = @[]
+
+  seq1.add(1)
+  seq1.add(3)
+  seq1.add(5)
+  seq1.add(7)
+
+  var seq2: seq[int] = @[2, 4, 6]
+  var final = zip(seq1, seq2)
+
+  echo "Zip: ", $$(final)
+
+  #Test findWhere as a iterator
+
+  for itms in filter(seq1, testFindWhere):
+    echo "Filter Iterator: ", $$(itms)
+
+
+  #Test findWhere as a proc
+
+  var fullseq: seq[int] = filter(seq1, testFindWhere)
+
+  echo "Filter: ", $$(fullseq)
+
+  #Test findIt as a template
+
+  var finditval: seq[int] = filterIt(seq1, it!=5)
+
+  echo "FilterIt: ", $$(finditval)
+
+  var concatseq = concat(seq1,seq2)
+  echo "Concat: ", $$(concatseq)
+
+  var seq3 = @[1,2,3,4,5,5,5,7]
+  var dedupseq = deduplicate(seq3)
+  echo "Deduplicate: ", $$(dedupseq)
+  # bug #4973
+  type
+    SomeObj = object
+    OtherObj = object
+      field: SomeObj
+
+  let aSeq = @[OtherObj(field: SomeObj())]
+  let someObjSeq = aSeq.mapIt(it.field)
+  echo someObjSeq
+
+  block minmax:
+    doAssert minmax(@[0]) == (0, 0)
+    doAssert minmax(@[0, 1]) == (0, 1)
+    doAssert minmax(@[1, 0]) == (0, 1)
+    doAssert minmax(@[8,2,1,7,3,9,4,0,5]) == (0, 9)
+    echo "Minmax: ", $(minmax(concat(seq1, seq2)))
+
+
+when not defined(nimseqsv2):
+  block tshallowseq:
+    proc xxx() =
+      var x: seq[int] = @[1, 2, 3]
+      var y: seq[int]
+      system.shallowCopy(y, x)
+      y[1] = 42
+      doAssert y == @[1, 42, 3]
+      doAssert x == @[1, 42, 3]
+    xxx()
+
+
+  block tshallowemptyseq:
+    proc test() =
+      var nilSeq: seq[int] = @[]
+      var emptySeq: seq[int] = newSeq[int]()
+      block:
+        var t = @[1,2,3]
+        when defined(gcRefc):
+          shallow(nilSeq)
+        t = nilSeq
+        doAssert t == @[]
+      block:
+        var t = @[1,2,3]
+        when defined(gcRefc):
+          shallow(emptySeq)
+        t = emptySeq
+        doAssert t == @[]
+      block:
+        var t = @[1,2,3]
+        shallowCopy(t, nilSeq)
+        doAssert t == @[]
+      block:
+        var t = @[1,2,3]
+        shallowCopy(t, emptySeq)
+        doAssert t == @[]
+    test()
+
+
+import strutils
+block ttoseq:
+  for x in toSeq(countup(2, 6)):
+    stdout.write(x)
+  for x in items(toSeq(countup(2, 6))):
+    stdout.write(x)
+  var y: typeof("a b c".split)
+  y = "xzy"
+  stdout.write("\n")
+
+block tseqmapitchain:
+  doAssert @[101, 102] == [1, 2].mapIt(func (x: int): int = it + x).mapIt(it(100))
+
+
+for i in 0..100:
+  # fix #14655
+  var test = newSeqOfCap[uint32](1)
+  test.setLen(1)
+  doAssert test[0] == 0, $(test[0], i)
+
+
+# bug #22560
+doAssert len(newSeqOfCap[int](42)) == 0
+
+block: # bug #17197
+  type Matrix = seq[seq[int]]
+
+  proc needlemanWunsch(sequence1: string, sequence2: string, gap_penal: int8, match: int8, indel_penal: int8): bool =
+    let seq2_len = sequence2.len
+
+    var grid: Matrix
+    for i in sequence1:
+      grid.add(newSeqOfCap[seq[int]](seq2_len))
+    result = true
+
+  doAssert needlemanWunsch("ABC", "DEFG", 1, 2, 3)
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index 9eccf345a..95f9418a0 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -7,15 +7,27 @@ And we get here
 3
 '''
 joinable: false
+targets: "c cpp js"
 """
+
+# xxx wrap in a template to test in VM, see https://github.com/timotheecour/Nim/issues/534#issuecomment-769565033
+
 import hashes, sequtils, tables, algorithm
 
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
+template sortedItems(t: untyped): untyped = sorted(toSeq(t))
+
+block tableDollar:
+  # other tests should use `sortedPairs` to be robust to future table/hash
+  # implementation changes
+  doAssert ${1: 'a', 2: 'b'}.toTable in ["{1: 'a', 2: 'b'}", "{2: 'b', 1: 'a'}"]
+
 # test should not be joined because it takes too long.
 block tableadds:
   proc main =
     var tab = newTable[string, string]()
     for i in 0..1000:
-      tab.add "key", "value " & $i
+      tab["key"] = "value " & $i
 
   main()
   echo "done tableadds"
@@ -42,20 +54,20 @@ block thashes:
     var t = initTable[int,int]()
     t[0] = 42
     t[1] = t[0] + 1
-    assert(t[0] == 42)
-    assert(t[1] == 43)
+    doAssert(t[0] == 42)
+    doAssert(t[1] == 43)
     let t2 = {1: 1, 2: 2}.toTable
-    assert(t2[2] == 2)
+    doAssert(t2[2] == 2)
 
   # Test with char
   block:
     var t = initTable[char,int]()
     t['0'] = 42
     t['1'] = t['0'] + 1
-    assert(t['0'] == 42)
-    assert(t['1'] == 43)
+    doAssert(t['0'] == 42)
+    doAssert(t['1'] == 43)
     let t2 = {'1': 1, '2': 2}.toTable
-    assert(t2['2'] == 2)
+    doAssert(t2['2'] == 2)
 
   # Test with enum
   block:
@@ -64,22 +76,22 @@ block thashes:
     var t = initTable[E,int]()
     t[eA] = 42
     t[eB] = t[eA] + 1
-    assert(t[eA] == 42)
-    assert(t[eB] == 43)
+    doAssert(t[eA] == 42)
+    doAssert(t[eB] == 43)
     let t2 = {eA: 1, eB: 2}.toTable
-    assert(t2[eB] == 2)
+    doAssert(t2[eB] == 2)
 
   # Test with range
   block:
     type
-      R = range[1..10]
+      R = range[0..9]
     var t = initTable[R,int]() # causes warning, why?
     t[1] = 42 # causes warning, why?
     t[2] = t[1] + 1
-    assert(t[1] == 42)
-    assert(t[2] == 43)
+    doAssert(t[1] == 42)
+    doAssert(t[2] == 43)
     let t2 = {1.R: 1, 2.R: 2}.toTable
-    assert(t2[2.R] == 2)
+    doAssert(t2[2.R] == 2)
 
   # Test which combines the generics for tuples + ordinals
   block:
@@ -88,10 +100,10 @@ block thashes:
     var t = initTable[(string, E, int, char), int]()
     t[("a", eA, 0, '0')] = 42
     t[("b", eB, 1, '1')] = t[("a", eA, 0, '0')] + 1
-    assert(t[("a", eA, 0, '0')] == 42)
-    assert(t[("b", eB, 1, '1')] == 43)
+    doAssert(t[("a", eA, 0, '0')] == 42)
+    doAssert(t[("b", eB, 1, '1')] == 43)
     let t2 = {("a", eA, 0, '0'): 1, ("b", eB, 1, '1'): 2}.toTable
-    assert(t2[("b", eB, 1, '1')] == 2)
+    doAssert(t2[("b", eB, 1, '1')] == 2)
 
   # Test to check if overloading is possible
   # Unfortunately, this does not seem to work for int
@@ -125,8 +137,8 @@ block tindexby:
   doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
 
   var tbl1 = initTable[int, int]()
-  tbl1.add(1,1)
-  tbl1.add(2,2)
+  tbl1[1] = 1
+  tbl1[2] = 2
   doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
 
   type
@@ -139,8 +151,8 @@ block tindexby:
     elem2 = TElem(foo: 2, bar: "baz")
 
   var tbl2 = initTable[string, TElem]()
-  tbl2.add("bar", elem1)
-  tbl2.add("baz", elem2)
+  tbl2["bar"] = elem1
+  tbl2["baz"] = elem2
   doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
 
 
@@ -157,23 +169,22 @@ block tableconstr:
   ignoreExpr({2: 3, "key": "value"})
 
   # NEW:
-  assert 56 in 50..100
+  doAssert 56 in 50..100
 
-  assert 56 in ..60
+  doAssert 56 in 0..60
 
 
 block ttables2:
   proc TestHashIntInt() =
     var tab = initTable[int,int]()
-    for i in 1..1_000_000:
+    let n = 10
+    for i in 1..n:
       tab[i] = i
-    for i in 1..1_000_000:
+    for i in 1..n:
       var x = tab[i]
       if x != i : echo "not found ", i
 
-  proc run1() =         # occupied Memory stays constant, but
-    for i in 1 .. 50:   # aborts at run: 44 on win32 with 3.2GB with out of memory
-      TestHashIntInt()
+  TestHashIntInt()
 
   # bug #2107
 
@@ -185,10 +196,8 @@ block ttables2:
   delTab[5] = 5
 
 
-  run1()
   echo "2"
 
-
 block tablesref:
   const
     data = {
@@ -231,9 +240,9 @@ block tablesref:
     t[(1,1)] = "11"
     for x in 0..1:
       for y in 0..1:
-        assert t[(x,y)] == $x & $y
-    assert($t ==
-      "{(x: 1, y: 1): \"11\", (x: 0, y: 0): \"00\", (x: 0, y: 1): \"01\", (x: 1, y: 0): \"10\"}")
+        doAssert t[(x,y)] == $x & $y
+    doAssert t.sortedPairs ==
+      @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")]
 
   block tableTest2:
     var t = newTable[string, float]()
@@ -245,31 +254,31 @@ block tablesref:
     t["012"] = 67.9
     t["123"] = 1.5 # test overwriting
 
-    assert t["123"] == 1.5
+    doAssert t["123"] == 1.5
     try:
       echo t["111"] # deleted
     except KeyError:
       discard
-    assert(not hasKey(t, "111"))
-    assert "111" notin t
+    doAssert(not hasKey(t, "111"))
+    doAssert "111" notin t
 
     for key, val in items(data): t[key] = val.toFloat
-    for key, val in items(data): assert t[key] == val.toFloat
+    for key, val in items(data): doAssert t[key] == val.toFloat
 
 
   block orderedTableTest1:
     var t = newOrderedTable[string, int](2)
     for key, val in items(data): t[key] = val
-    for key, val in items(data): assert t[key] == val
+    for key, val in items(data): doAssert t[key] == val
     var i = 0
     # `pairs` needs to yield in insertion order:
     for key, val in pairs(t):
-      assert key == data[i][0]
-      assert val == data[i][1]
+      doAssert key == data[i][0]
+      doAssert val == data[i][1]
       inc(i)
 
     for key, val in mpairs(t): val = 99
-    for val in mvalues(t): assert val == 99
+    for val in mvalues(t): doAssert val == 99
 
   block countTableTest1:
     var s = data.toTable
@@ -278,11 +287,11 @@ block tablesref:
     for x in [t, r]:
       for k in s.keys:
         x.inc(k)
-        assert x[k] == 1
+        doAssert x[k] == 1
       x.inc("90", 3)
       x.inc("12", 2)
       x.inc("34", 1)
-    assert t.largest()[0] == "90"
+    doAssert t.largest()[0] == "90"
 
     t.sort()
     r.sort(SortOrder.Ascending)
@@ -293,29 +302,43 @@ block tablesref:
       var i = 0
       for (k, v) in ps:
         case i
-        of 0: assert k == "90" and v == 4
-        of 1: assert k == "12" and v == 3
-        of 2: assert k == "34" and v == 2
+        of 0: doAssert k == "90" and v == 4
+        of 1: doAssert k == "12" and v == 3
+        of 2: doAssert k == "34" and v == 2
         else: break
         inc i
 
+  block smallestLargestNamedFieldsTest: # bug #14918
+    const a = [7, 8, 8]
+
+    proc testNamedFields(t: CountTable | CountTableRef) =
+      doAssert t.smallest.key == 7
+      doAssert t.smallest.val == 1
+      doAssert t.largest.key == 8
+      doAssert t.largest.val == 2
+
+    let t1 = toCountTable(a)
+    testNamedFields(t1)
+    let t2 = newCountTable(a)
+    testNamedFields(t2)
+
   block SyntaxTest:
     var x = newTable[int, string]({:})
     discard x
 
   block nilTest:
     var i, j: TableRef[int, int] = nil
-    assert i == j
+    doAssert i == j
     j = newTable[int, int]()
-    assert i != j
-    assert j != i
+    doAssert i != j
+    doAssert j != i
     i = newTable[int, int]()
-    assert i == j
+    doAssert i == j
 
   proc orderedTableSortTest() =
     var t = newOrderedTable[string, int](2)
     for key, val in items(data): t[key] = val
-    for key, val in items(data): assert t[key] == val
+    for key, val in items(data): doAssert t[key] == val
     proc cmper(x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key)
     t.sort(cmper)
     var i = 0
@@ -340,32 +363,95 @@ block tablesref:
   block anonZipTest:
     let keys = @['a','b','c']
     let values = @[1, 2, 3]
-    doAssert "{'c': 3, 'a': 1, 'b': 2}" == $ toTable zip(keys, values)
+    doAssert zip(keys, values).toTable.sortedPairs == @[('a', 1), ('b', 2), ('c', 3)]
 
   block clearTableTest:
     var t = newTable[string, float]()
     t["test"] = 1.2345
     t["111"] = 1.000043
     t["123"] = 1.23
-    assert t.len() != 0
+    doAssert t.len() != 0
     t.clear()
-    assert t.len() == 0
+    doAssert t.len() == 0
 
   block clearOrderedTableTest:
     var t = newOrderedTable[string, int](2)
     for key, val in items(data): t[key] = val
-    assert t.len() != 0
+    doAssert t.len() != 0
     t.clear()
-    assert t.len() == 0
+    doAssert t.len() == 0
 
   block clearCountTableTest:
     var t = newCountTable[string]()
     t.inc("90", 3)
     t.inc("12", 2)
     t.inc("34", 1)
-    assert t.len() != 0
+    doAssert t.len() != 0
     t.clear()
-    assert t.len() == 0
+    doAssert t.len() == 0
 
   orderedTableSortTest()
   echo "3"
+
+
+block: # https://github.com/nim-lang/Nim/issues/13496
+  template testDel(body) =
+    block:
+      body
+      when t is CountTable|CountTableRef:
+        t.inc(15, 1)
+        t.inc(19, 2)
+        t.inc(17, 3)
+        t.inc(150, 4)
+        t.del(150)
+      else:
+        t[15] = 1
+        t[19] = 2
+        t[17] = 3
+        t[150] = 4
+        t.del(150)
+      doAssert t.len == 3
+      doAssert sortedItems(t.values) == @[1, 2, 3]
+      doAssert sortedItems(t.keys) == @[15, 17, 19]
+      doAssert sortedPairs(t) == @[(15, 1), (17, 3), (19, 2)]
+      var s = newSeq[int]()
+      for v in t.values: s.add(v)
+      doAssert s.len == 3
+      doAssert sortedItems(s) == @[1, 2, 3]
+      when t is OrderedTable|OrderedTableRef:
+        doAssert toSeq(t.keys) == @[15, 19, 17]
+        doAssert toSeq(t.values) == @[1,2,3]
+        doAssert toSeq(t.pairs) == @[(15, 1), (19, 2), (17, 3)]
+
+  testDel(): (var t: Table[int, int])
+  testDel(): (let t = newTable[int, int]())
+  testDel(): (var t: OrderedTable[int, int])
+  testDel(): (let t = newOrderedTable[int, int]())
+  testDel(): (var t: CountTable[int])
+  testDel(): (let t = newCountTable[int]())
+
+
+block testNonPowerOf2:
+  var a = initTable[int, int](7)
+  a[1] = 10
+  doAssert a[1] == 10
+
+  var b = initTable[int, int](9)
+  b[1] = 10
+  doAssert b[1] == 10
+
+block emptyOrdered:
+  var t1: OrderedTable[int, string]
+  var t2: OrderedTable[int, string]
+  doAssert t1 == t2
+
+block: # Table[ref, int]
+  type A = ref object
+    x: int
+  var t: OrderedTable[A, int]
+  let a1 = A(x: 3)
+  let a2 = A(x: 3)
+  t[a1] = 10
+  t[a2] = 11
+  doAssert t[a1] == 10
+  doAssert t[a2] == 11
diff --git a/tests/collections/ttablesthreads.nim b/tests/collections/ttablesthreads.nim
index 5553b31ef..2a4e1bf42 100644
--- a/tests/collections/ttablesthreads.nim
+++ b/tests/collections/ttablesthreads.nim
@@ -3,7 +3,9 @@ discard """
   output: '''true'''
 """
 
-import hashes, tables, sharedtables
+import hashes, tables, sharedtables, algorithm, sequtils
+
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
 
 const
   data = {
@@ -46,9 +48,8 @@ block tableTest1:
   t[(1,1)] = "11"
   for x in 0..1:
     for y in 0..1:
-      assert t[(x,y)] == $x & $y
-  assert($t ==
-    "{(x: 1, y: 1): \"11\", (x: 0, y: 0): \"00\", (x: 0, y: 1): \"01\", (x: 1, y: 0): \"10\"}")
+      doAssert t[(x,y)] == $x & $y
+  doAssert t.sortedPairs == @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")]
 
 block tableTest2:
   var t = initTable[string, float]()
@@ -60,74 +61,74 @@ block tableTest2:
   t["012"] = 67.9
   t["123"] = 1.5 # test overwriting
 
-  assert t["123"] == 1.5
+  doAssert t["123"] == 1.5
   try:
     echo t["111"] # deleted
   except KeyError:
     discard
-  assert(not hasKey(t, "111"))
+  doAssert(not hasKey(t, "111"))
 
-  assert "123" in t
-  assert("111" notin t)
+  doAssert "123" in t
+  doAssert("111" notin t)
 
   for key, val in items(data): t[key] = val.toFloat
-  for key, val in items(data): assert t[key] == val.toFloat
+  for key, val in items(data): doAssert t[key] == val.toFloat
 
-  assert(not t.hasKeyOrPut("456", 4.0))     # test absent key
-  assert t.hasKeyOrPut("012", 3.0)          # test present key
+  doAssert(not t.hasKeyOrPut("456", 4.0))     # test absent key
+  doAssert t.hasKeyOrPut("012", 3.0)          # test present key
   var x = t.mgetOrPut("111", 1.5)           # test absent key
   x = x * 2
-  assert x == 3.0
+  doAssert x == 3.0
   x = t.mgetOrPut("test", 1.5)              # test present key
   x = x * 2
-  assert x == 2 * 1.2345
+  doAssert x == 2 * 1.2345
 
 block orderedTableTest1:
   var t = initOrderedTable[string, int](2)
   for key, val in items(data): t[key] = val
-  for key, val in items(data): assert t[key] == val
+  for key, val in items(data): doAssert t[key] == val
   var i = 0
   # `pairs` needs to yield in insertion order:
   for key, val in pairs(t):
-    assert key == data[i][0]
-    assert val == data[i][1]
+    doAssert key == data[i][0]
+    doAssert val == data[i][1]
     inc(i)
 
   for key, val in mpairs(t): val = 99
-  for val in mvalues(t): assert val == 99
+  for val in mvalues(t): doAssert val == 99
 
 block orderedTableTest2:
   var
     s = initOrderedTable[string, int]()
     t = initOrderedTable[string, int]()
-  assert s == t
+  doAssert s == t
   for key, val in items(data): t[key] = val
-  assert s != t
+  doAssert s != t
   for key, val in items(sorteddata): s[key] = val
-  assert s != t
+  doAssert s != t
   t.clear()
-  assert s != t
+  doAssert s != t
   for key, val in items(sorteddata): t[key] = val
-  assert s == t
+  doAssert s == t
 
 block countTableTest1:
   var s = data.toTable
   var t = initCountTable[string]()
 
   for k in s.keys: t.inc(k)
-  for k in t.keys: assert t[k] == 1
+  for k in t.keys: doAssert t[k] == 1
   t.inc("90", 3)
   t.inc("12", 2)
   t.inc("34", 1)
-  assert t.largest()[0] == "90"
+  doAssert t.largest()[0] == "90"
 
   t.sort()
   var i = 0
   for k, v in t.pairs:
     case i
-    of 0: assert k == "90" and v == 4
-    of 1: assert k == "12" and v == 3
-    of 2: assert k == "34" and v == 2
+    of 0: doAssert k == "90" and v == 4
+    of 1: doAssert k == "12" and v == 3
+    of 2: doAssert k == "34" and v == 2
     else: break
     inc i
 
@@ -135,19 +136,19 @@ block countTableTest2:
   var
     s = initCountTable[int]()
     t = initCountTable[int]()
-  assert s == t
+  doAssert s == t
   s.inc(1)
-  assert s != t
+  doAssert s != t
   t.inc(2)
-  assert s != t
+  doAssert s != t
   t.inc(1)
-  assert s != t
+  doAssert s != t
   s.inc(2)
-  assert s == t
+  doAssert s == t
   s.inc(1)
-  assert s != t
+  doAssert s != t
   t.inc(1)
-  assert s == t
+  doAssert s == t
 
 block mpairsTableTest1:
   var t = initTable[string, int]()
@@ -161,9 +162,9 @@ block mpairsTableTest1:
 
   for k, v in t.pairs:
     if k == "a" or k == "c":
-      assert v == 9
+      doAssert v == 9
     else:
-      assert v != 1 and v != 3
+      doAssert v != 1 and v != 3
 
 block SyntaxTest:
   var x = toTable[int, string]({:})
@@ -173,10 +174,10 @@ block zeroHashKeysTest:
     let initialLen = t.len
     var testTable = t
     testTable[nullHashKey] = value
-    assert testTable[nullHashKey] == value
-    assert testTable.len == initialLen + 1
+    doAssert testTable[nullHashKey] == value
+    doAssert testTable.len == initialLen + 1
     testTable.del(nullHashKey)
-    assert testTable.len == initialLen
+    doAssert testTable.len == initialLen
 
   # with empty table
   doZeroHashValueTest(toTable[int,int]({:}), 0, 42)
@@ -193,46 +194,46 @@ block zeroHashKeysTest:
 
 block clearTableTest:
   var t = data.toTable
-  assert t.len() != 0
+  doAssert t.len() != 0
   t.clear()
-  assert t.len() == 0
+  doAssert t.len() == 0
 
 block clearOrderedTableTest:
   var t = data.toOrderedTable
-  assert t.len() != 0
+  doAssert t.len() != 0
   t.clear()
-  assert t.len() == 0
+  doAssert t.len() == 0
 
 block clearCountTableTest:
   var t = initCountTable[string]()
   t.inc("90", 3)
   t.inc("12", 2)
   t.inc("34", 1)
-  assert t.len() != 0
+  doAssert t.len() != 0
   t.clear()
-  assert t.len() == 0
+  doAssert t.len() == 0
 
 block withKeyTest:
   var t: SharedTable[int, int]
   t.init()
   t.withKey(1) do (k: int, v: var int, pairExists: var bool):
-    assert(v == 0)
+    doAssert(v == 0)
     pairExists = true
     v = 42
-  assert(t.mget(1) == 42)
+  doAssert(t.mget(1) == 42)
   t.withKey(1) do (k: int, v: var int, pairExists: var bool):
-    assert(v == 42)
+    doAssert(v == 42)
     pairExists = false
   try:
     discard t.mget(1)
-    assert(false, "KeyError expected")
+    doAssert(false, "KeyError expected")
   except KeyError:
     discard
   t.withKey(2) do (k: int, v: var int, pairExists: var bool):
     pairExists = false
   try:
     discard t.mget(2)
-    assert(false, "KeyError expected")
+    doAssert(false, "KeyError expected")
   except KeyError:
     discard
 
@@ -241,20 +242,20 @@ block takeTest:
   t["key"] = 123
 
   var val = 0
-  assert(t.take("key", val))
-  assert(val == 123)
+  doAssert(t.take("key", val))
+  doAssert(val == 123)
 
   val = -1
-  assert(not t.take("key", val))
-  assert(val == -1)
+  doAssert(not t.take("key", val))
+  doAssert(val == -1)
 
-  assert(not t.take("otherkey", val))
-  assert(val == -1)
+  doAssert(not t.take("otherkey", val))
+  doAssert(val == -1)
 
 proc orderedTableSortTest() =
   var t = initOrderedTable[string, int](2)
   for key, val in items(data): t[key] = val
-  for key, val in items(data): assert t[key] == val
+  for key, val in items(data): doAssert t[key] == val
   t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
   var i = 0
   # `pairs` needs to yield in sorted order: