summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/async/tasyncawait.nim6
-rw-r--r--tests/async/tasyncdiscard.nim39
-rw-r--r--tests/async/tnestedpfuturetypeparam.nim8
-rw-r--r--tests/ccgbugs/tbug1081.nim17
-rw-r--r--tests/ccgbugs/tcgbug.nim3
-rw-r--r--tests/closure/tclosuremacro.nim8
-rw-r--r--tests/macros/tbug1149.nim20
-rw-r--r--tests/macros/tdumptree.nim3
-rw-r--r--tests/macros/texprcolonexpr.nim19
-rw-r--r--tests/macros/tgentemplates.nim35
-rw-r--r--tests/manyloc/argument_parser/argument_parser.nim4
-rw-r--r--tests/manyloc/keineschweine/lib/estreams.nim4
-rw-r--r--tests/manyloc/nake/nake.nim2
-rw-r--r--tests/misc/tbug1217bracketquotes.nim14
-rw-r--r--tests/notnil/tnotnil4.nim14
-rw-r--r--tests/osproc/ta.nim3
-rw-r--r--tests/osproc/tstdin.nim16
-rw-r--r--tests/parallel/nimrod.cfg1
-rw-r--r--tests/parallel/tdisjoint_slice1.nim21
-rw-r--r--tests/parallel/tdisjoint_slice2.nim33
-rw-r--r--tests/parallel/tflowvar.nim17
-rw-r--r--tests/parallel/tforstmt.nim25
-rw-r--r--tests/parallel/tinvalid_array_bounds.nim25
-rw-r--r--tests/parallel/tinvalid_counter_usage.nim26
-rw-r--r--tests/parallel/tnon_disjoint_slice1.nim25
-rw-r--r--tests/parallel/tpi.nim26
-rw-r--r--tests/parallel/tsysspawn.nim31
-rw-r--r--tests/parallel/tsysspawnbadarg.nim9
-rw-r--r--tests/sets/tsets3.nim81
-rw-r--r--tests/stdlib/tgetfileinfo.nim93
-rw-r--r--tests/table/ptables.nim128
-rw-r--r--tests/table/ptables2.nim20
-rw-r--r--tests/template/annotate.nim113
-rw-r--r--tests/template/otests.nim219
-rw-r--r--tests/template/t_otemplates.nim345
-rw-r--r--tests/testament/caasdriver.nim24
-rw-r--r--tests/testament/categories.nim45
-rw-r--r--tests/testament/specs.nim4
-rw-r--r--tests/testament/tester.nim18
39 files changed, 1494 insertions, 50 deletions
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index ffceeaee6..da4952677 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -23,19 +23,19 @@ proc launchSwarm(port: TPort) {.async.} =
     await connect(sock, "localhost", port)
     when true:
       await sendMessages(sock)
-      close(sock)
+      closeSocket(sock)
     else:
       # Issue #932: https://github.com/Araq/Nimrod/issues/932
       var msgFut = sendMessages(sock)
       msgFut.callback =
         proc () =
-          close(sock)
+          closeSocket(sock)
 
 proc readMessages(client: TAsyncFD) {.async.} =
   while true:
     var line = await recvLine(client)
     if line == "":
-      close(client)
+      closeSocket(client)
       clientCount.inc
       break
     else:
diff --git a/tests/async/tasyncdiscard.nim b/tests/async/tasyncdiscard.nim
new file mode 100644
index 000000000..48d8a8c4d
--- /dev/null
+++ b/tests/async/tasyncdiscard.nim
@@ -0,0 +1,39 @@
+discard """
+  output: '''
+1
+2
+3
+4
+1
+2
+1
+6
+'''
+"""
+import asyncio, asyncdispatch, asyncnet
+
+proc main {.async.} =
+  proc f: PFuture[int] {.async.} =
+    discard
+    echo 1
+    discard
+    result = 2
+    discard
+
+  let x = await f()
+  echo x
+  echo 3
+
+  proc g: PFuture[int] {.async.} =
+    discard
+    echo 4
+    discard
+    result = 6
+    discard
+    echo await f()
+    discard await f()
+
+  discard await g()
+  echo 6
+
+main()
diff --git a/tests/async/tnestedpfuturetypeparam.nim b/tests/async/tnestedpfuturetypeparam.nim
new file mode 100644
index 000000000..d0d87e567
--- /dev/null
+++ b/tests/async/tnestedpfuturetypeparam.nim
@@ -0,0 +1,8 @@
+import asyncdispatch, asyncnet
+
+proc main {.async.} =
+  proc f: PFuture[seq[int]] {.async.} =
+    await newAsyncSocket().connect("www.google.com", TPort(80))
+  let x = await f()
+
+main()
diff --git a/tests/ccgbugs/tbug1081.nim b/tests/ccgbugs/tbug1081.nim
new file mode 100644
index 000000000..71628feec
--- /dev/null
+++ b/tests/ccgbugs/tbug1081.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''1
+0
+0
+0'''
+"""
+
+proc `1/1`() = echo(1 div 1)
+template `1/2`() = echo(1 div 2)
+var `1/3` = 1 div 4
+`1/3` = 1 div 3 # oops, 1/3!=1/4
+let `1/4` = 1 div 4
+
+`1/1`()
+`1/2`()
+echo `1/3`
+echo `1/4`
diff --git a/tests/ccgbugs/tcgbug.nim b/tests/ccgbugs/tcgbug.nim
index 535424a27..3e4755f2f 100644
--- a/tests/ccgbugs/tcgbug.nim
+++ b/tests/ccgbugs/tcgbug.nim
@@ -20,7 +20,8 @@ new(a)
 q(a)
 
 # bug #914
-var x = newWideCString("Hello")
+when defined(windows):
+  var x = newWideCString("Hello")
 
 echo "success"
 
diff --git a/tests/closure/tclosuremacro.nim b/tests/closure/tclosuremacro.nim
index 008078bbb..12e463316 100644
--- a/tests/closure/tclosuremacro.nim
+++ b/tests/closure/tclosuremacro.nim
@@ -5,6 +5,7 @@ discard """
 3
 3
 noReturn
+6
 '''
 """
 
@@ -36,8 +37,7 @@ echo doWithOneAndTwo((x, y) => x + y)
 
 noReturn(() -> void => echo("noReturn"))
 
-when false:
-  proc pass2(f: (int, int) -> int): (int) -> int =
-    (x: int) -> int => f(2, x)
+proc pass2(f: (int, int) -> int): (int) -> int =
+  (x: int) -> int => f(2, x)
 
-  #echo pass2((x, y) => x + y)
+echo pass2((x, y) => x + y)(4)
diff --git a/tests/macros/tbug1149.nim b/tests/macros/tbug1149.nim
new file mode 100644
index 000000000..5c4cb8530
--- /dev/null
+++ b/tests/macros/tbug1149.nim
@@ -0,0 +1,20 @@
+discard """
+msg: '''a
+s
+d
+f'''
+"""
+
+type
+  Foo = object
+    s: char
+
+iterator test2(f: string): Foo =
+  for i in f:
+    yield Foo(s: i)
+
+macro test(): stmt =
+  for i in test2("asdf"):
+    echo i.s
+
+test()
diff --git a/tests/macros/tdumptree.nim b/tests/macros/tdumptree.nim
index 5299a94e3..e5160b7ba 100644
--- a/tests/macros/tdumptree.nim
+++ b/tests/macros/tdumptree.nim
@@ -1,6 +1,5 @@
 discard """
-disabled: true
-output: '''StmtList
+msg: '''StmtList
   VarSection
     IdentDefs
       Ident !"x"
diff --git a/tests/macros/texprcolonexpr.nim b/tests/macros/texprcolonexpr.nim
new file mode 100644
index 000000000..3b2c86b77
--- /dev/null
+++ b/tests/macros/texprcolonexpr.nim
@@ -0,0 +1,19 @@
+discard """
+  msg: '''
+Infix
+  Ident !"=>"
+  Call
+    Ident !"name"
+    Ident !"a"
+    ExprColonExpr
+      Ident !"b"
+      Ident !"cint"
+  NilLit nil
+'''
+"""
+import macros
+
+macro def(x: stmt): stmt {.immediate.} =
+  echo treeRepr(x)
+
+def name(a, b:cint) => nil
diff --git a/tests/macros/tgentemplates.nim b/tests/macros/tgentemplates.nim
new file mode 100644
index 000000000..a7727c597
--- /dev/null
+++ b/tests/macros/tgentemplates.nim
@@ -0,0 +1,35 @@
+# bug #1140
+
+import parseutils, macros
+
+proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool {.compiletime.} =
+    var splitValue: string
+    var read = value.parseUntil(splitValue, '$', index)
+
+    # when false:
+    if false:
+        var identifier: string
+        read = value.parseWhile(identifier, {}, index)
+        node.add newCall("add", ident("result"), newCall("$", ident(identifier)))
+
+    if splitValue.len > 0:
+        node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue))
+
+proc parse_template(node: PNimrodNode, value: string) {.compiletime.} =
+    var index = 0
+    while index < value.len and
+        parse_until_symbol(node, value, index): discard
+
+macro tmpli*(body: expr): stmt =
+    result = newStmtList()
+    result.add parseExpr("result = \"\"")
+    result.parse_template body[1].strVal
+
+
+proc actual: string = tmpli html"""
+    <p>Test!</p>
+    """
+
+proc another: string = tmpli html"""
+    <p>what</p>
+    """
diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim
index 1edda4aa0..6f4fb650e 100644
--- a/tests/manyloc/argument_parser/argument_parser.nim
+++ b/tests/manyloc/argument_parser/argument_parser.nim
@@ -292,9 +292,9 @@ proc parse_parameter(quit_on_failure: bool, param, value: string,
       raise_or_quit(EInvalidValue, ("parameter $1 requires a " &
         "float, but $2 can't be parsed into one") % [param, escape(value)])
   of PK_EMPTY:
-    nil
+    discard
   of PK_HELP:
-    nil
+    discard
 
 
 template build_specification_lookup():
diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim
index bd0a2c31a..ecafaed89 100644
--- a/tests/manyloc/keineschweine/lib/estreams.nim
+++ b/tests/manyloc/keineschweine/lib/estreams.nim
@@ -7,10 +7,6 @@ proc swapEndian16*(outp, inp: pointer) =
   var o = cast[cstring](outp)
   o[0] = i[1]
   o[1] = i[0]
-when cpuEndian == bigEndian:
-  proc bigEndian16(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 2)
-else:
-  proc bigEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp)
 
 import enet
 
diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim
index eade28c70..4b1b35662 100644
--- a/tests/manyloc/nake/nake.nim
+++ b/tests/manyloc/nake/nake.nim
@@ -74,7 +74,7 @@ else:
           echo "Unknown option: ", key, ": ", val
       of cmdArgument:
         task = key
-      else: nil
+      else: discard
     if printTaskList or task.isNil or not(tasks.hasKey(task)):
       echo "Available tasks:"
       for name, task in pairs(tasks):
diff --git a/tests/misc/tbug1217bracketquotes.nim b/tests/misc/tbug1217bracketquotes.nim
new file mode 100644
index 000000000..90e67d45b
--- /dev/null
+++ b/tests/misc/tbug1217bracketquotes.nim
@@ -0,0 +1,14 @@
+discard """
+  output: "13{(.{}}{*4&*$**()&*@1235"
+"""
+
+type
+  Test = enum
+    `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`
+
+let `.}` = 1
+let `(}` = 2
+let `[` = 3
+let `]` = 5
+
+echo `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`, `.}`, `(}`, `[`, `]`
diff --git a/tests/notnil/tnotnil4.nim b/tests/notnil/tnotnil4.nim
new file mode 100644
index 000000000..23968ee48
--- /dev/null
+++ b/tests/notnil/tnotnil4.nim
@@ -0,0 +1,14 @@
+discard ""
+type
+   TObj = ref object
+
+proc check(a: TObj not nil) =
+  echo repr(a)
+
+proc doit() =
+   var x : array[0..1, TObj]
+
+   if x[0] != nil:
+      check(x[0])
+
+doit()
\ No newline at end of file
diff --git a/tests/osproc/ta.nim b/tests/osproc/ta.nim
new file mode 100644
index 000000000..6c1495590
--- /dev/null
+++ b/tests/osproc/ta.nim
@@ -0,0 +1,3 @@
+import strutils
+let x = stdin.readLine()
+echo x.parseInt + 5
\ No newline at end of file
diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim
new file mode 100644
index 000000000..2ea939992
--- /dev/null
+++ b/tests/osproc/tstdin.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tstdin.nim"
+  output: "10"
+"""
+import osproc, os, streams
+
+doAssert fileExists(getCurrentDir() / "tests" / "osproc" / "ta.exe")
+
+var p = startProcess("ta.exe", getCurrentDir() / "tests" / "osproc")
+p.inputStream.write("5\n")
+while true:
+  let line = p.outputStream.readLine()
+  if line != "":
+    echo line
+  else:
+    break
\ No newline at end of file
diff --git a/tests/parallel/nimrod.cfg b/tests/parallel/nimrod.cfg
new file mode 100644
index 000000000..b81c89721
--- /dev/null
+++ b/tests/parallel/nimrod.cfg
@@ -0,0 +1 @@
+threads:on
diff --git a/tests/parallel/tdisjoint_slice1.nim b/tests/parallel/tdisjoint_slice1.nim
new file mode 100644
index 000000000..c1d0e52f8
--- /dev/null
+++ b/tests/parallel/tdisjoint_slice1.nim
@@ -0,0 +1,21 @@
+discard """
+  outputsub: "EVEN 28"
+"""
+
+import threadpool
+
+proc odd(a: int) =  echo "ODD  ", a
+proc even(a: int) = echo "EVEN ", a
+
+proc main() =
+  var a: array[0..30, int]
+  for i in low(a)..high(a): a[i] = i
+  parallel:
+    var i = 0
+    while i <= 29:
+      spawn even(a[i])
+      spawn odd(a[i+1])
+      inc i, 2
+      # is correct here
+
+main()
diff --git a/tests/parallel/tdisjoint_slice2.nim b/tests/parallel/tdisjoint_slice2.nim
new file mode 100644
index 000000000..1e86ea644
--- /dev/null
+++ b/tests/parallel/tdisjoint_slice2.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''0
+1
+2
+3
+4
+5
+6
+7
+8'''
+  sortoutput: true
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9]
+  parallel:
+    spawn f(a[0..2])
+    #spawn f(a[16..30])
+    var i = 3
+    while i <= 8:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i, 2
+      # is correct here
+
+main()
diff --git a/tests/parallel/tflowvar.nim b/tests/parallel/tflowvar.nim
new file mode 100644
index 000000000..77fab14b5
--- /dev/null
+++ b/tests/parallel/tflowvar.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''foobarfoobarbazbearbazbear'''
+  cmd: "nimrod $target --threads:on $options $file"
+"""
+
+import threadpool
+
+proc computeSomething(a, b: string): string = a & b & a & b
+
+proc main =
+  let fvA = spawn computeSomething("foo", "bar")
+  let fvB = spawn computeSomething("baz", "bear")
+
+  echo(^fvA, ^fvB)
+
+main()
+sync()
diff --git a/tests/parallel/tforstmt.nim b/tests/parallel/tforstmt.nim
new file mode 100644
index 000000000..58de833f3
--- /dev/null
+++ b/tests/parallel/tforstmt.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''3
+4
+5
+6
+7'''
+  sortoutput: true
+"""
+
+import threadpool, os
+
+proc p(x: int) =
+  os.sleep(100 - x*10)
+  echo x
+
+proc testFor(a, b: int; foo: var openArray[int]) =
+  parallel:
+    for i in max(a, 0) .. min(b, foo.high):
+      spawn p(foo[i])
+
+var arr = [0, 1, 2, 3, 4, 5, 6, 7]
+
+testFor(3, 10, arr)
+
+
diff --git a/tests/parallel/tinvalid_array_bounds.nim b/tests/parallel/tinvalid_array_bounds.nim
new file mode 100644
index 000000000..4c6065fd6
--- /dev/null
+++ b/tests/parallel/tinvalid_array_bounds.nim
@@ -0,0 +1,25 @@
+discard """
+  errormsg: "can prove: i + 1 > 30"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    spawn f(a[0..15])
+    spawn f(a[16..30])
+    var i = 0
+    while i <= 30:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tinvalid_counter_usage.nim b/tests/parallel/tinvalid_counter_usage.nim
new file mode 100644
index 000000000..c6303c651
--- /dev/null
+++ b/tests/parallel/tinvalid_counter_usage.nim
@@ -0,0 +1,26 @@
+discard """
+  errormsg: "invalid usage of counter after increment"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    spawn f(a[0..15])
+    spawn f(a[16..30])
+    var i = 0
+    while i <= 30:
+      inc i
+      spawn f(a[i])
+      inc i
+      #spawn f(a[i+1])
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tnon_disjoint_slice1.nim b/tests/parallel/tnon_disjoint_slice1.nim
new file mode 100644
index 000000000..72d008bbd
--- /dev/null
+++ b/tests/parallel/tnon_disjoint_slice1.nim
@@ -0,0 +1,25 @@
+discard """
+  errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)"
+  line: 20
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    #spawn f(a[0..15])
+    #spawn f(a[16..30])
+    var i = 0
+    while i <= 29:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tpi.nim b/tests/parallel/tpi.nim
new file mode 100644
index 000000000..dcb9b8fc5
--- /dev/null
+++ b/tests/parallel/tpi.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''3.141792613595791
+3.141792613595791'''
+"""
+
+import strutils, math, threadpool
+
+proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1)
+
+proc piU(n: int): float =
+  var ch = newSeq[FlowVar[float]](n+1)
+  for k in 0..n:
+    ch[k] = spawn term(float(k))
+  for k in 0..n:
+    result += ^ch[k]
+
+proc piS(n: int): float =
+  var ch = newSeq[float](n+1)
+  parallel:
+    for k in 0..ch.high:
+      ch[k] = spawn term(float(k))
+  for k in 0..ch.high:
+    result += ch[k]
+
+echo formatFloat(piU(5000))
+echo formatFloat(piS(5000))
diff --git a/tests/parallel/tsysspawn.nim b/tests/parallel/tsysspawn.nim
new file mode 100644
index 000000000..fc7921b0e
--- /dev/null
+++ b/tests/parallel/tsysspawn.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''4
+8'''
+  cmd: "nimrod $target --threads:on $options $file"
+"""
+
+import threadpool
+
+var
+  x, y = 0
+
+proc p1 =
+  for i in 0 .. 10_000:
+    discard
+
+  atomicInc x
+
+proc p2 =
+  for i in 0 .. 10_000:
+    discard
+
+  atomicInc y, 2
+
+for i in 0.. 3:
+  spawn(p1())
+  spawn(p2())
+
+sync()
+
+echo x
+echo y
diff --git a/tests/parallel/tsysspawnbadarg.nim b/tests/parallel/tsysspawnbadarg.nim
new file mode 100644
index 000000000..ad798a7d3
--- /dev/null
+++ b/tests/parallel/tsysspawnbadarg.nim
@@ -0,0 +1,9 @@
+discard """
+  line: 9
+  errormsg: "'spawn' takes a call expression"
+  cmd: "nimrod $target --threads:on $options $file"
+"""
+
+import threadpool
+
+let foo = spawn(1)
diff --git a/tests/sets/tsets3.nim b/tests/sets/tsets3.nim
new file mode 100644
index 000000000..d2b15d72d
--- /dev/null
+++ b/tests/sets/tsets3.nim
@@ -0,0 +1,81 @@
+include sets
+
+let
+  s1: TSet[int] = toSet([1, 2, 4, 8, 16])
+  s2: TSet[int] = toSet([1, 2, 3, 5, 8])
+  s3: TSet[int] = toSet([3, 5, 7])
+
+block union:
+  let
+    s1_s2 = union(s1, s2)
+    s1_s3 = s1 + s3
+    s2_s3 = s2 + s3
+
+  assert s1_s2.len == 7
+  assert s1_s3.len == 8
+  assert s2_s3.len == 6
+
+  for i in s1:
+    assert i in s1_s2
+    assert i in s1_s3
+  for i in s2:
+    assert i in s1_s2
+    assert i in s2_s3
+  for i in s3:
+    assert i in s1_s3
+    assert i in s2_s3
+
+  assert((s1 + s1) == s1)
+  assert((s2 + s1) == s1_s2)
+
+block intersection:
+  let
+    s1_s2 = intersection(s1, s2)
+    s1_s3 = intersection(s1, s3)
+    s2_s3 = s2 * s3
+
+  assert s1_s2.len == 3
+  assert s1_s3.len == 0
+  assert s2_s3.len == 2
+
+  for i in s1_s2:
+    assert i in s1
+    assert i in s2
+  for i in s1_s3:
+    assert i in s1
+    assert i in s3
+  for i in s2_s3:
+    assert i in s2
+    assert i in s3
+
+  assert((s2 * s2) == s2)
+  assert((s3 * s2) == s2_s3)
+
+block symmetricDifference:
+  let
+    s1_s2 = symmetricDifference(s1, s2)
+    s1_s3 = s1 -+- s3
+    s2_s3 = s2 -+- s3
+
+  assert s1_s2.len == 4
+  assert s1_s3.len == 8
+  assert s2_s3.len == 4
+
+  for i in s1:
+    assert i in s1_s2 xor i in s2
+    assert i in s1_s3 xor i in s3
+  for i in s2:
+    assert i in s1_s2 xor i in s1
+    assert i in s2_s3 xor i in s3
+  for i in s3:
+    assert i in s1_s3 xor i in s1
+    assert i in s2_s3 xor i in s2
+
+  assert((s3 -+- s3) == initSet[int]())
+  assert((s3 -+- s1) == s1_s3)
+
+block disjoint:
+  assert(not disjoint(s1, s2))
+  assert disjoint(s1, s3)
+  assert(not disjoint(s2, s3))
+  assert(not disjoint(s2, s2))
\ No newline at end of file
diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim
new file mode 100644
index 000000000..49a019061
--- /dev/null
+++ b/tests/stdlib/tgetfileinfo.nim
@@ -0,0 +1,93 @@
+discard """
+  output: ""
+"""
+
+import os, strutils
+# Cases
+#  1 - String : Existing File : Symlink true
+#  2 - String : Existing File : Symlink false
+#  3 - String : Non-existing File : Symlink true
+#  4 - String : Non-existing File : Symlink false
+#  5 - Handle : Valid File
+#  6 - Handle : Invalid File
+#  7 - Handle : Valid Handle
+#  8 - Handle : Invalid Handle
+
+proc genBadFileName(limit = 100): string =
+    ## Generates a filename of a nonexistant file.
+    ## Returns "" if generation fails.
+    result = "a"
+    var hitLimit = true
+
+    for i in 0..100:
+      if existsFile(result):
+        result.add("a")
+      else:
+        hitLimit = false
+        break
+    if hitLimit:
+      result = ""
+
+proc caseOneAndTwo(followLink: bool) =
+  try:
+    discard getFileInfo(getAppFilename(), followLink)
+    #echo("String : Existing File : Symlink $# : Success" % $followLink)
+  except EOS:
+    echo("String : Existing File : Symlink $# : Failure" % $followLink)
+
+proc caseThreeAndFour(followLink: bool) =
+  var invalidName = genBadFileName()
+  try:
+    discard getFileInfo(invalidName, true)
+    echo("String : Non-existing File : Symlink $# : Failure" % $followLink)
+  except EOS:
+    #echo("String : Non-existing File : Symlink $# : Success" % $followLink)
+
+proc testGetFileInfo =
+  # Case 1
+  caseOneAndTwo(true)
+
+  # Case 2
+  caseOneAndTwo(false)
+
+  # Case 3
+  caseThreeAndFour(true)
+
+  # Case 4
+  caseThreeAndFour(false)
+
+  # Case 5 and 7
+  block:
+    let
+      testFile = open(getAppFilename())
+      testHandle = fileHandle(testFile)
+    try:
+      discard getFileInfo(testFile)
+      #echo("Handle : Valid File : Success")
+    except EIO:
+      echo("Handle : Valid File : Failure")
+
+    try:
+      discard getFileInfo(testHandle)
+      #echo("Handle : Valid File : Success")
+    except EIO:
+      echo("Handle : Valid File : Failure")
+
+  # Case 6 and 8
+  block:
+    let
+      testFile: TFile = nil
+      testHandle = TFileHandle(-1)
+    try:
+      discard getFileInfo(testFile)
+      echo("Handle : Invalid File : Failure")
+    except EIO, EOS:
+      #echo("Handle : Invalid File : Success")
+
+    try:
+      discard getFileInfo(testHandle)
+      echo("Handle : Invalid File : Failure")
+    except EIO, EOS:
+      #echo("Handle : Invalid File : Success")
+
+testGetFileInfo()
\ No newline at end of file
diff --git a/tests/table/ptables.nim b/tests/table/ptables.nim
new file mode 100644
index 000000000..ec52d08c3
--- /dev/null
+++ b/tests/table/ptables.nim
@@ -0,0 +1,128 @@
+discard """
+  output: '''true'''
+"""
+
+import hashes, tables
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+  sorteddata = {
+    "---00": 346677844,
+    "0": 34404,
+    "1": 344004,
+    "10": 34484, 
+    "11": 34474,
+    "12": 789,
+    "19": 34464,
+    "2": 344774, "20": 34454, 
+    "3": 342244, "30": 34141244,
+    "34": 123456,
+    "4": 3412344, "40": 344114,
+    "5": 341232144, "50": 344490, 
+    "6": 34214544, "60": 344491,
+    "7": 3434544, "70": 344492,
+    "8": 344544, "80": 344497,
+    "9": 34435644,
+    "90": 343}
+
+block tableTest1:
+  var t = newTable[tuple[x, y: int], string]()
+  t[(0,0)] = "00"
+  t[(1,0)] = "10"
+  t[(0,1)] = "01"
+  t[(1,1)] = "11"
+  for x in 0..1:
+    for y in 0..1:
+      assert t[(x,y)] == $x & $y
+  assert($t == 
+    "{(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]()
+  t["test"] = 1.2345
+  t["111"] = 1.000043
+  t["123"] = 1.23
+  t.del("111")
+  
+  t["012"] = 67.9
+  t["123"] = 1.5 # test overwriting
+  
+  assert t["123"] == 1.5
+  assert t["111"] == 0.0 # deleted
+  assert(not hasKey(t, "111"))
+  
+  for key, val in items(data): t[key] = val.toFloat
+  for key, val in items(data): assert 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
+  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]
+    inc(i)
+
+  for key, val in mpairs(t): val = 99
+  for val in mvalues(t): assert val == 99
+
+block countTableTest1:
+  var s = data.toTable
+  var t = newCountTable[string]()
+  for k in s.Keys: t.inc(k)
+  for k in t.keys: assert t[k] == 1
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  assert 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
+    else: break
+    inc i
+
+block SyntaxTest:
+  var x = newTable[int, string]({:})
+
+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
+  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:
+  for key, val in pairs(t):
+    doAssert key == sorteddata[i][0]
+    doAssert val == sorteddata[i][1]
+    inc(i)
+
+  # check that lookup still works:
+  for key, val in pairs(t):
+    doAssert val == t[key]
+  # check that insert still works:
+  t["newKeyHere"] = 80
+
+
+orderedTableSortTest()
+echo "true"
+
diff --git a/tests/table/ptables2.nim b/tests/table/ptables2.nim
new file mode 100644
index 000000000..939de2b84
--- /dev/null
+++ b/tests/table/ptables2.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''true'''
+"""
+
+import tables
+
+proc TestHashIntInt() =
+  var tab = newTable[int,int]()
+  for i in 1..1_000_000:
+    tab[i] = i
+  for i in 1..1_000_000:
+    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()
+
+run1()
+echo "true"
diff --git a/tests/template/annotate.nim b/tests/template/annotate.nim
new file mode 100644
index 000000000..fa58030dc
--- /dev/null
+++ b/tests/template/annotate.nim
@@ -0,0 +1,113 @@
+import macros, parseutils
+
+# Generate tags
+macro make(names: openarray[expr]): stmt {.immediate.} =
+    result = newStmtList()
+
+    for i in 0 .. names.len-1:
+        result.add newProc(
+            name   = ident($names[i]).postfix("*"),
+            params = [
+                ident("string"),
+                newIdentDefs(
+                    ident("content"),
+                    ident("string")
+                )
+            ],
+            body = newStmtList(
+                parseStmt("reindent(content)")
+            )
+        )
+
+
+iterator lines(value: string): string =
+    var i = 0
+    while i < value.len:
+        var line: string
+        inc(i, value.parseUntil(line, 0x0A.char, i) + 1)
+        yield line
+
+
+proc reindent*(value: string, preset_indent = 0): string =
+    var indent = -1
+
+    # Detect indentation!
+    for ln in lines(value):
+        var read = ln.skipWhitespace()
+
+        # If the line is empty, ignore it for indentation
+        if read == ln.len: continue
+
+        indent = if indent < 0: read
+                 else: min(indent, read)
+
+    # Create a precursor indent as-needed
+    var precursor = newString(0)
+    for i in 1 .. preset_indent:
+        precursor.add(' ')
+
+    # Re-indent
+    result = newString(0)
+
+    for ln in lines(value):
+        var value = ln.substr(indent)
+
+        result.add(precursor)
+
+        if value.len > 0:
+            result.add(value)
+            result.add(0x0A.char)
+
+    return result
+
+
+#Define tags
+make([ html, xml, glsl, js, css, rst ])
+
+
+when isMainModule:
+    ## Test tags
+
+    const script = js"""
+        var x = 5;
+        console.log(x.toString());
+    """
+
+    const styles = css"""
+        .someRule {
+            width: 500px;
+        }
+    """
+
+    const body = html"""
+        <ul>
+            <li>1</li>
+            <li>2</li>
+            <li>
+                <a hef="#google">google</a>
+            </li>
+        </ul>
+    """
+
+    const info = xml"""
+        <item>
+            <i>1</i>
+            <i>2</i>
+        </item>
+    """
+
+    const shader = glsl"""
+        void main()
+        {
+            gl_Position = gl_ProjectionMatrix
+                        * gl_ModelViewMatrix
+                        * gl_Vertex;
+        }
+    """
+
+
+    echo script
+    echo styles
+    echo body
+    echo info
+    echo shader
\ No newline at end of file
diff --git a/tests/template/otests.nim b/tests/template/otests.nim
new file mode 100644
index 000000000..c885e23df
--- /dev/null
+++ b/tests/template/otests.nim
@@ -0,0 +1,219 @@
+# Fields

+const x = 5

+

+

+# Test substring

+static:

+    assert "test".substring(3)   == "t"

+    assert "test".substring(2,1) == "s"

+    assert "test".substring(3,2) == "t"

+    assert "test".substring(1,2) == "es"

+

+

+# Various parsing tests

+when true:

+

+    block: #no_substitution

+        proc actual: string = tmpli html"""

+            <p>Test!</p>

+        """

+        const expected = html"""

+            <p>Test!</p>

+        """

+        doAssert actual() == expected

+

+    block: #basic

+        proc actual: string = tmpli html"""

+            <p>Test $$x</p>

+            $x

+        """

+        const expected = html"""

+            <p>Test $x</p>

+            5

+        """

+        doAssert actual() == expected

+

+    block: #expression

+        proc actual: string = tmpli html"""

+            <p>Test $$(x * 5)</p>

+            $(x * 5)

+        """

+        const expected = html"""

+            <p>Test $(x * 5)</p>

+            25

+        """

+        doAssert actual() == expected

+

+    block: #escape

+        proc actual: string = tmpli js"""

+            [{

+                "hello world"

+            }]

+        """

+        const expected = js"""

+            [{

+                "hello world"

+            }]

+        """

+        doAssert actual() == expected

+

+    block: #forIn

+        proc actual: string = tmpli html"""

+            <p>Test for</p>

+            <ul>

+                $for y in 0..2 {

+                    <li>$y</li>

+                }

+            </ul>

+        """

+        const expected = html"""

+            <p>Test for</p>

+            <ul>

+                <li>0</li>

+                <li>1</li>

+                <li>2</li>

+            </ul>

+        """

+        doAssert actual() == expected

+

+    block: #while

+        proc actual: string = tmpli html"""

+            <p>Test while/stmt</p>

+            <ul>

+                ${ var y = 0 }

+                $while y < 4 {

+                    <li>$y</li>

+                    ${ inc(y) }

+                }

+            </ul>

+        """

+        const expected = html"""

+            <p>Test while/stmt</p>

+            <ul>

+                <li>0</li>

+                <li>1</li>

+                <li>2</li>

+                <li>3</li>

+            </ul>

+        """

+        doAssert actual() == expected

+

+    block: #ifElifElse

+        proc actual: string = tmpli html"""

+            <p>Test if/elif/else</p>

+            $if x == 8 {

+                <div>x is 8!</div>

+            }

+            $elif x == 7 {

+                <div>x is 7!</div>

+            }

+            $else {

+                <div>x is neither!</div>

+            }

+        """

+        const expected = html"""

+            <p>Test if/elif/else</p>

+            <div>x is neither!</div>

+        """

+        doAssert actual() == expected

+

+    block: #multiLineStatements

+        proc actual: string = tmpli html"""

+            <p>Test multiline statements</p>

+            ${

+                var x = 5

+                var y = 7

+            }

+            <span>$x</span><span>$y</span>

+        """

+        const expected = html"""

+            <p>Test multiline statements</p>

+            <span>5</span><span>7</span>

+        """

+        doAssert actual() == expected

+

+    block: #caseOfElse

+        proc actual: string = tmpli html"""

+            <p>Test case</p>

+            $case x

+            $of 5 {

+                <div>x == 5</div>

+            }

+            $of 6 {

+                <div>x == 6</div>

+            }

+            $else {}

+        """

+        const expected = html"""

+            <p>Test case</p>

+            <div>x == 5</div>

+        """

+        doAssert actual() == expected

+

+

+

+when true: #embeddingTest

+    proc no_substitution: string = tmpli html"""

+        <h1>Template test!</h1>

+    """

+

+    # # Single variable substitution

+    proc substitution(who = "nobody"): string = tmpli html"""

+        <div id="greeting">hello $who!</div>

+    """

+

+    # Expression template

+    proc test_expression(nums: openarray[int] = []): string =

+        var i = 2

+        tmpli html"""

+            $(no_substitution())

+            $(substitution("Billy"))

+            <div id="age">Age: $($nums[i] & "!!")</div>

+        """

+

+    proc test_statements(nums: openarray[int] = []): string =

+        tmpli html"""

+            $(test_expression(nums))

+            $if true {

+                <ul>

+                    $for i in nums {

+                        <li>$(i * 2)</li>

+                    }

+                </ul>

+            }

+        """

+

+    var actual = test_statements([0,1,2])

+    const expected = html"""

+        <h1>Template test!</h1>

+        <div id="greeting">hello Billy!</div>

+        <div id="age">Age: 2!!</div>

+        <ul>

+            <li>0</li>

+            <li>2</li>

+            <li>4</li>

+        </ul>

+    """

+    doAssert actual == expected

+

+

+when defined(future):

+    block: #tryCatch

+        proc actual: string = tmpli html"""

+            <p>Test try/catch</p>

+            <div>

+                $try {

+                    <div>Lets try this!</div>

+                }

+                $except {

+                    <div>Uh oh!</div>

+                }

+            </div>

+        """

+        const expected = html"""

+            <p>Test try/catch</p>

+            <div>

+                    <div>Lets try this!</div>

+            </div>

+        """

+        doAssert actual() == expected
\ No newline at end of file
diff --git a/tests/template/t_otemplates.nim b/tests/template/t_otemplates.nim
new file mode 100644
index 000000000..7de728ab2
--- /dev/null
+++ b/tests/template/t_otemplates.nim
@@ -0,0 +1,345 @@
+discard """
+  output: "Success"
+"""
+
+# Ref:

+# http://nimrod-lang.org/macros.html

+# http://nimrod-lang.org/parseutils.html

+

+

+# Imports

+import tables, parseutils, macros, strutils

+import annotate

+export annotate

+

+

+# Fields

+const identChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}

+

+

+# Procedure Declarations

+proc parse_template(node: PNimrodNode, value: string) {.compiletime.}

+

+

+# Procedure Definitions

+proc substring(value: string, index: int, length = -1): string {.compiletime.} =

+    ## Returns a string at most `length` characters long, starting at `index`.

+    return if length < 0:    value.substr(index)

+           elif length == 0: ""

+           else:             value.substr(index, index + length-1)

+

+

+proc parse_thru_eol(value: string, index: int): int {.compiletime.} =

+    ## Reads until and past the end of the current line, unless

+    ## a non-whitespace character is encountered first

+    var remainder: string

+    var read = value.parseUntil(remainder, {0x0A.char}, index)

+    if remainder.skipWhitespace() == read:

+        return read + 1

+

+

+proc trim_after_eol(value: var string) {.compiletime.} =

+    ## Trims any whitespace at end after \n

+    var toTrim = 0

+    for i in countdown(value.len-1, 0):

+        # If \n, return

+        if value[i] in [' ', '\t']: inc(toTrim)

+        else: break

+

+    if toTrim > 0:

+        value = value.substring(0, value.len - toTrim)

+

+

+proc trim_eol(value: var string) {.compiletime.} =

+    ## Removes everything after the last line if it contains nothing but whitespace

+    for i in countdown(value.len - 1, 0):

+        # If \n, trim and return

+        if value[i] == 0x0A.char:

+            value = value.substr(0, i)

+            break

+

+        # This is the first character

+        if i == 0:

+            value = ""

+            break

+

+        # Skip change

+        if not (value[i] in [' ', '\t']): break

+

+

+proc detect_indent(value: string, index: int): int {.compiletime.} =

+    ## Detects how indented the line at `index` is.

+    # Seek to the beginning of the line.

+    var lastChar = index

+    for i in countdown(index, 0):

+        if value[i] == 0x0A.char:

+            # if \n, return the indentation level

+            return lastChar - i

+        elif not (value[i] in [' ', '\t']):

+            # if non-whitespace char, decrement lastChar

+            dec(lastChar)

+

+

+proc parse_thru_string(value: string, i: var int, strType = '"') {.compiletime.} =

+    ## Parses until ending " or ' is reached.

+    inc(i)

+    if i < value.len-1:

+        inc(i, value.skipUntil({'\\', strType}, i))

+

+

+proc parse_to_close(value: string, index: int, open='(', close=')', opened=0): int {.compiletime.} =

+    ## Reads until all opened braces are closed

+    ## ignoring any strings "" or ''

+    var remainder   = value.substring(index)

+    var open_braces = opened

+    result = 0

+

+    while result < remainder.len:

+        var c = remainder[result]

+

+        if   c == open:  inc(open_braces)

+        elif c == close: dec(open_braces)

+        elif c == '"':   remainder.parse_thru_string(result)

+        elif c == '\'':  remainder.parse_thru_string(result, '\'')

+

+        if open_braces == 0: break

+        else: inc(result)

+

+

+iterator parse_stmt_list(value: string, index: var int): string =

+    ## Parses unguided ${..} block

+    var read        = value.parse_to_close(index, open='{', close='}')

+    var expressions = value.substring(index + 1, read - 1).split({ ';', 0x0A.char })

+

+    for expression in expressions:

+        let value = expression.strip

+        if value.len > 0:

+            yield value

+

+    #Increment index & parse thru EOL

+    inc(index, read + 1)

+    inc(index, value.parse_thru_eol(index))

+

+

+iterator parse_compound_statements(value, identifier: string, index: int): string =

+    ## Parses through several statements, i.e. if {} elif {} else {}

+    ## and returns the initialization of each as an empty statement

+    ## i.e. if x == 5 { ... } becomes if x == 5: nil.

+

+    template get_next_ident(expected): stmt =

+        var nextIdent: string

+        discard value.parseWhile(nextIdent, {'$'} + identChars, i)

+

+        var next: string

+        var read: int

+

+        if nextIdent == "case":

+            # We have to handle case a bit differently

+            read = value.parseUntil(next, '$', i)

+            inc(i, read)

+            yield next.strip(leading=false) & "\n"

+

+        else:

+            read = value.parseUntil(next, '{', i)

+

+            if nextIdent in expected:

+                inc(i, read)

+                # Parse until closing }, then skip whitespace afterwards

+                read = value.parse_to_close(i, open='{', close='}')

+                inc(i, read + 1)

+                inc(i, value.skipWhitespace(i))

+                yield next & ": nil\n"

+

+            else: break

+

+

+    var i = index

+    while true:

+        # Check if next statement would be valid, given the identifier

+        if identifier in ["if", "when"]:

+            get_next_ident([identifier, "$elif", "$else"])

+

+        elif identifier == "case":

+            get_next_ident(["case", "$of", "$elif", "$else"])

+

+        elif identifier == "try":

+            get_next_ident(["try", "$except", "$finally"])

+

+

+proc parse_complex_stmt(value, identifier: string, index: var int): PNimrodNode {.compiletime.} =

+    ## Parses if/when/try /elif /else /except /finally statements

+

+    # Build up complex statement string

+    var stmtString = newString(0)

+    var numStatements = 0

+    for statement in value.parse_compound_statements(identifier, index):

+        if statement[0] == '$': stmtString.add(statement.substr(1))

+        else:                   stmtString.add(statement)

+        inc(numStatements)

+

+    # Parse stmt string

+    result = parseExpr(stmtString)

+

+    var resultIndex = 0

+

+    # Fast forward a bit if this is a case statement

+    if identifier == "case":

+        inc(resultIndex)

+

+    while resultIndex < numStatements:

+

+        # Detect indentation

+        let indent = detect_indent(value, index)

+

+        # Parse until an open brace `{`

+        var read = value.skipUntil('{', index)

+        inc(index, read + 1)

+

+        # Parse through EOL

+        inc(index, value.parse_thru_eol(index))

+

+        # Parse through { .. }

+        read = value.parse_to_close(index, open='{', close='}', opened=1)

+

+        # Add parsed sub-expression into body

+        var body       = newStmtList()

+        var stmtString = value.substring(index, read)

+        trim_after_eol(stmtString)

+        stmtString = reindent(stmtString, indent)

+        parse_template(body, stmtString)

+        inc(index, read + 1)

+

+        # Insert body into result

+        var stmtIndex = macros.high(result[resultIndex])

+        result[resultIndex][stmtIndex] = body

+

+        # Parse through EOL again & increment result index

+        inc(index, value.parse_thru_eol(index))

+        inc(resultIndex)

+

+

+proc parse_simple_statement(value: string, index: var int): PNimrodNode {.compiletime.} =

+    ## Parses for/while

+

+    # Detect indentation

+    let indent = detect_indent(value, index)

+

+    # Parse until an open brace `{`

+    var splitValue: string

+    var read = value.parseUntil(splitValue, '{', index)

+    result   = parseExpr(splitValue & ":nil")

+    inc(index, read + 1)

+

+    # Parse through EOL

+    inc(index, value.parse_thru_eol(index))

+

+    # Parse through { .. }

+    read = value.parse_to_close(index, open='{', close='}', opened=1)

+

+    # Add parsed sub-expression into body

+    var body       = newStmtList()

+    var stmtString = value.substring(index, read)

+    trim_after_eol(stmtString)

+    stmtString = reindent(stmtString, indent)

+    parse_template(body, stmtString)

+    inc(index, read + 1)

+

+    # Insert body into result

+    var stmtIndex = macros.high(result)

+    result[stmtIndex] = body

+

+    # Parse through EOL again

+    inc(index, value.parse_thru_eol(index))

+

+

+proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool {.compiletime.} =

+    ## Parses a string until a $ symbol is encountered, if

+    ## two $$'s are encountered in a row, a split will happen

+    ## removing one of the $'s from the resulting output

+    var splitValue: string

+    var read = value.parseUntil(splitValue, '$', index)

+    var insertionPoint = node.len

+

+    inc(index, read + 1)

+    if index < value.len:

+

+        case value[index]

+        of '$':

+            # Check for duplicate `$`, meaning this is an escaped $

+            node.add newCall("add", ident("result"), newStrLitNode("$"))

+            inc(index)

+

+        of '(':

+            # Check for open `(`, which means parse as simple single-line expression.

+            trim_eol(splitValue)

+            read = value.parse_to_close(index) + 1

+            node.add newCall("add", ident("result"),

+                newCall(bindSym"strip", parseExpr("$" & value.substring(index, read)))

+            )

+            inc(index, read)

+

+        of '{':

+            # Check for open `{`, which means open statement list

+            trim_eol(splitValue)

+            for s in value.parse_stmt_list(index):

+                node.add parseExpr(s)

+

+        else:

+            # Otherwise parse while valid `identChars` and make expression w/ $

+            var identifier: string

+            read = value.parseWhile(identifier, identChars, index)

+

+            if identifier in ["for", "while"]:

+                ## for/while means open simple statement

+                trim_eol(splitValue)

+                node.add value.parse_simple_statement(index)

+

+            elif identifier in ["if", "when", "case", "try"]:

+                ## if/when/case/try means complex statement

+                trim_eol(splitValue)

+                node.add value.parse_complex_stmt(identifier, index)

+

+            elif identifier.len > 0:

+                ## Treat as simple variable

+                node.add newCall("add", ident("result"), newCall("$", ident(identifier)))

+                inc(index, read)

+

+        result = true

+

+    # Insert

+    if splitValue.len > 0:

+        node.insert insertionPoint, newCall("add", ident("result"), newStrLitNode(splitValue))

+

+

+proc parse_template(node: PNimrodNode, value: string) =

+    ## Parses through entire template, outputing valid

+    ## Nimrod code into the input `node` AST.

+    var index = 0

+    while index < value.len and

+          parse_until_symbol(node, value, index): nil

+

+

+macro tmpli*(body: expr): stmt =

+    result = newStmtList()

+

+    result.add parseExpr("result = \"\"")

+

+    var value = if body.kind in nnkStrLit..nnkTripleStrLit: body.strVal

+                else: body[1].strVal

+

+    parse_template(result, reindent(value))

+

+

+macro tmpl*(body: expr): stmt =

+    result = newStmtList()

+

+    var value = if body.kind in nnkStrLit..nnkTripleStrLit: body.strVal

+                else: body[1].strVal

+

+    parse_template(result, reindent(value))

+

+

+# Run tests

+when isMainModule:

+    include otests
+    echo "Success"
diff --git a/tests/testament/caasdriver.nim b/tests/testament/caasdriver.nim
index 28f0bae9b..ddfe88273 100644
--- a/tests/testament/caasdriver.nim
+++ b/tests/testament/caasdriver.nim
@@ -25,7 +25,7 @@ const
   silentReplaceText = "--verbosity:0 --hints:off"
 
 var
-  TesterDir = getAppDir()
+  TesterDir = getAppDir() / ".."
   NimrodBin = TesterDir / "../bin/nimrod"
 
 proc replaceVars(session: var TNimrodSession, text: string): string =
@@ -86,6 +86,10 @@ proc doProcCommand(session: var TNimrodSession, command: string): string =
 
 proc doCommand(session: var TNimrodSession, command: string) =
   if session.mode == CaasRun:
+    if not session.nim.running:
+      session.lastOutput = "FAILED TO EXECUTE: " & command & "\n" &
+          "Exit code " & $session.nim.peekExitCode
+      return
     session.lastOutput = doCaasCommand(session,
                                        command & " " & session.filename)
   else:
@@ -102,7 +106,7 @@ proc close(session: var TNimrodSession) {.destructor.} =
   if session.mode == CaasRun:
     session.nim.close
 
-proc doScenario(script: string, output: PStream, mode: TRunMode): bool =
+proc doScenario(script: string, output: PStream, mode: TRunMode, verbose: bool): bool =
   result = true
 
   var f = open(script)
@@ -134,7 +138,7 @@ proc doScenario(script: string, output: PStream, mode: TRunMode): bool =
         continue
       elif line.startsWith(">"):
         s.doCommand(line.substr(1).strip)
-        output.writeln line, "\n", s.lastOutput
+        output.writeln line, "\n", if verbose: s.lastOutput else: ""
       else:
         var expectMatch = true
         var pattern = s.replaceVars(line)
@@ -151,13 +155,14 @@ proc doScenario(script: string, output: PStream, mode: TRunMode): bool =
           output.writeln "FAILURE ", line
           result = false
 
-iterator caasTestsRunner*(filter = ""): tuple[test, output: string,
-                                              status: bool, mode: TRunMode] =
+iterator caasTestsRunner*(filter = "", verbose = false): tuple[test,
+                                              output: string, status: bool,
+                                              mode: TRunMode] =
   for scenario in os.walkFiles(TesterDir / "caas/*.txt"):
     if filter.len > 0 and find(scenario, filter) == -1: continue
     for mode in modes:
       var outStream = newStringStream()
-      let r = doScenario(scenario, outStream, mode)
+      let r = doScenario(scenario, outStream, mode, verbose)
       yield (scenario, outStream.data, r, mode)
 
 when isMainModule:
@@ -175,9 +180,12 @@ when isMainModule:
   if verbose and len(filter) > 0:
     echo "Running only test cases matching filter '$1'" % [filter]
 
-  for test, output, result, mode in caasTestsRunner(filter):
+  for test, output, result, mode in caasTestsRunner(filter, verbose):
     if not result or verbose:
-      echo test, "\n", output, "-> ", $mode, ":", $result, "\n-----"
+      echo "Mode ", $mode, " (", if result: "succeeded)" else: "failed)"
+      echo test
+      echo output
+      echo "---------\n"
     if not result:
       failures += 1
 
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index bb9c90d2a..841eb8159 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -282,26 +282,33 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) =
     echo("[Warning] - Cannot run babel tests: Babel update failed.")
     return
 
-  for name, url in listPackages(filter):
-    var test = makeTest(name, "", cat)
-    echo(url)
-    let
-      installProcess = startProcess(babelExe, "", ["install", "-y", name])
-      installStatus = waitForExitEx(installProcess)
-    installProcess.close
-    if installStatus != quitSuccess:
-      r.addResult(test, "", "", reInstallFailed)
-      continue
+  let packageFileTest = makeTest("PackageFileParsed", "", cat)
+  try:
+    for name, url in listPackages(filter):
+      var test = makeTest(name, "", cat)
+      echo(url)
+      let
+        installProcess = startProcess(babelExe, "", ["install", "-y", name])
+        installStatus = waitForExitEx(installProcess)
+      installProcess.close
+      if installStatus != quitSuccess:
+        r.addResult(test, "", "", reInstallFailed)
+        continue
+
+      let
+        buildPath = getPackageDir(name)[0.. -3]
+      let
+        buildProcess = startProcess(babelExe, buildPath, ["build"])
+        buildStatus = waitForExitEx(buildProcess)
+      buildProcess.close
+      if buildStatus != quitSuccess:
+        r.addResult(test, "", "", reBuildFailed)
+      r.addResult(test, "", "", reSuccess)
+    r.addResult(packageFileTest, "", "", reSuccess)
+  except EJsonParsingError:
+    echo("[Warning] - Cannot run babel tests: Invalid package file.")
+    r.addResult(packageFileTest, "", "", reBuildFailed)
 
-    let
-      buildPath = getPackageDir(name)[0.. -3]
-    let
-      buildProcess = startProcess(babelExe, buildPath, ["build"])
-      buildStatus = waitForExitEx(buildProcess)
-    buildProcess.close
-    if buildStatus != quitSuccess:
-      r.addResult(test, "", "", reBuildFailed)
-    r.addResult(test, "", "", reSuccess)
 
 # ----------------------------------------------------------------------------
 
diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim
index 225ea1891..6e72f4b5e 100644
--- a/tests/testament/specs.nim
+++ b/tests/testament/specs.nim
@@ -46,7 +46,7 @@ type
     msg*: string
     ccodeCheck*: string
     err*: TResultEnum
-    substr*: bool
+    substr*, sortoutput*: bool
     targets*: set[TTarget]
 
 const
@@ -113,6 +113,8 @@ proc parseSpec*(filename: string): TSpec =
       result.action = actionRun
       result.outp = e.value
       result.substr = true
+    of "sortoutput":
+      result.sortoutput = parseCfgBool(e.value)
     of "exitcode": 
       discard parseInt(e.value, result.exitCode)
     of "msg":
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index 757e54889..fc6b4ff95 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -11,7 +11,8 @@
 
 import
   parseutils, strutils, pegs, os, osproc, streams, parsecfg, json,
-  marshal, backend, parseopt, specs, htmlgen, browsers, terminal
+  marshal, backend, parseopt, specs, htmlgen, browsers, terminal,
+  algorithm
 
 const
   resultsFile = "testresults.html"
@@ -48,7 +49,7 @@ type
 
 let
   pegLineError = 
-    peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error'/'Warning') ':' \s* {.*}"
+    peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error') ':' \s* {.*}"
   pegOtherError = peg"'Error:' \s* {.*}"
   pegSuccess = peg"'Hint: operation successful'.*"
   pegOfInterest = pegLineError / pegOtherError
@@ -150,6 +151,11 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) =
     except EIO:
       given.err = reCodeNotFound
 
+proc makeDeterministic(s: string): string =
+  var x = splitLines(s)
+  sort(x, system.cmp)
+  result = join(x, "\n")
+
 proc testSpec(r: var TResults, test: TTest) =
   # major entry point for a single test
   let tname = test.name.addFileExt(".nim")
@@ -191,8 +197,10 @@ proc testSpec(r: var TResults, test: TTest) =
             r.addResult(test, "exitcode: " & $expected.exitCode,
                               "exitcode: " & $exitCode, reExitCodesDiffer)
           else:
-            if strip(buf.string) != strip(expected.outp):
-              if not (expected.substr and expected.outp in buf.string):
+            var bufB = strip(buf.string)
+            if expected.sortoutput: bufB = makeDeterministic(bufB)
+            if bufB != strip(expected.outp):
+              if not (expected.substr and expected.outp in bufB):
                 given.err = reOutputsDiffer
             if given.err == reSuccess:
               codeGenCheck(test, expected.ccodeCheck, given)
@@ -209,7 +217,7 @@ proc testNoSpec(r: var TResults, test: TTest) =
   # does not extract the spec because the file is not supposed to have any
   let tname = test.name.addFileExt(".nim")
   inc(r.total)
-  echo extractFilename(tname)
+  styledEcho "Processing ", fgCyan, extractFilename(tname)
   let given = callCompiler(cmdTemplate, test.name, test.options, test.target)
   r.addResult(test, "", given.msg, given.err)
   if given.err == reSuccess: inc(r.passed)