diff options
Diffstat (limited to 'tests')
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) |