diff options
Diffstat (limited to 'tests')
48 files changed, 1409 insertions, 737 deletions
diff --git a/tests/array/troof1.nim b/tests/array/troof1.nim index 96669a121..1ee63826e 100644 --- a/tests/array/troof1.nim +++ b/tests/array/troof1.nim @@ -1,7 +1,10 @@ discard """ output: '''@[2, 3, 4]321 9.0 4.0 -(a: 1.0, b: 2.0, c: 8.0)2.0''' +3 +@[(Field0: 1, Field1: 2), (Field0: 3, Field1: 5)] +2 +@[a, new one, c]''' """ proc foo[T](x, y: T): T = x @@ -11,26 +14,24 @@ var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]] echo a[1.. ^1], a[^2], a[^3], a[^4] echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1] -type - MyArray = object - a, b, c: float +b[^1] = [8.8, 8.9] -var - ma = MyArray(a: 1.0, b: 2.0, c: 3.0) +var c: seq[(int, int)] = @[(1,2), (3,4)] -proc len(x: MyArray): int = 3 +proc takeA(x: ptr int) = echo x[] -proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) = - case idx - of 0: x.a = val - of 1: x.b = val - of 2: x.c = val +takeA(addr c[^1][0]) +c[^1][1] = 5 +echo c -proc `[]`(x: var MyArray; idx: range[0..2]): float = - case idx - of 0: result = x.a - of 1: result = x.b - of 2: result = x.c +proc useOpenarray(x: openArray[int]) = + echo x[^2] -ma[^1] = 8.0 -echo ma, ma[^2] +proc mutOpenarray(x: var openArray[string]) = + x[^2] = "new one" + +useOpenarray([1, 2, 3]) + +var z = @["a", "b", "c"] +mutOpenarray(z) +echo z diff --git a/tests/array/troof2.nim b/tests/array/troof2.nim deleted file mode 100644 index e4b4f4b3c..000000000 --- a/tests/array/troof2.nim +++ /dev/null @@ -1,10 +0,0 @@ -discard """ - errormsg: "invalid context for '^' as 'foo()' has side effects" - line: "9" -""" -# XXX This needs to be fixed properly! -proc foo(): seq[int] {.sideEffect.} = - echo "ha" - -let f = foo()[^1] - diff --git a/tests/array/troof3.nim b/tests/array/troof3.nim index 4b6e22223..efe0eafb8 100644 --- a/tests/array/troof3.nim +++ b/tests/array/troof3.nim @@ -1,8 +1,7 @@ discard """ - errormsg: "invalid context for '^' as len!=high+1 for 'a'" - line: "8" + output: '''c''' """ -var a: array[1..3, string] +var a: array['a'..'c', string] = ["a", "b", "c"] echo a[^1] diff --git a/tests/array/troof4.nim b/tests/array/troof4.nim deleted file mode 100644 index 7a262d9de..000000000 --- a/tests/array/troof4.nim +++ /dev/null @@ -1,37 +0,0 @@ -discard """ - errormsg: "no surrounding array access context for '^'" - line: "37" -""" - -proc foo[T](x, y: T): T = x - -var a = @[1, 2, 3, 4] -var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]] -echo a[1.. ^1], a[^2], a[^3], a[^4] -echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1] - -type - MyArray = object - a, b, c: float - -var - ma = MyArray(a: 1.0, b: 2.0, c: 3.0) - -proc len(x: MyArray): int = 3 - -proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) = - case idx - of 0: x.a = val - of 1: x.b = val - of 2: x.c = val - -proc `[]`(x: var MyArray; idx: range[0..2]): float = - case idx - of 0: result = x.a - of 1: result = x.b - of 2: result = x.c - -ma[^1] = 8.0 -echo ma, ma[^2] - -echo(^1) diff --git a/tests/async/tnewasyncudp.nim b/tests/async/tnewasyncudp.nim index bf54c0d06..b56cdc71b 100644 --- a/tests/async/tnewasyncudp.nim +++ b/tests/async/tnewasyncudp.nim @@ -54,7 +54,7 @@ proc launchSwarm(name: ptr SockAddr) {.async.} = k = 0 while k < messagesToSend: zeroMem(addr(buffer[0]), 16384) - zeroMem(cast[pointer](addr(saddr)), sizeof(Sockaddr_in)) + zeroMem(cast[pointer](addr(saddr)), sizeof(Sockaddr_in)) var message = "Message " & $(i * messagesToSend + k) await sendTo(sock, addr message[0], len(message), name, sizeof(Sockaddr_in).SockLen) @@ -62,7 +62,7 @@ proc launchSwarm(name: ptr SockAddr) {.async.} = 16384, cast[ptr SockAddr](addr saddr), addr slen) size = 0 - var grammString = $buffer + var grammString = $cstring(addr buffer) if grammString == message: saveSendingPort(sockport) inc(recvCount) @@ -84,7 +84,7 @@ proc readMessages(server: AsyncFD) {.async.} = 16384, cast[ptr SockAddr](addr(saddr)), addr(slen)) size = 0 - var grammString = $buffer + var grammString = $cstring(addr buffer) if grammString.startswith("Message ") and saddr.sin_addr.s_addr == 0x100007F: await sendTo(server, addr grammString[0], len(grammString), diff --git a/tests/ccgbugs/tbug1081.nim b/tests/ccgbugs/tbug1081.nim index 71628feec..c9a9e6aa4 100644 --- a/tests/ccgbugs/tbug1081.nim +++ b/tests/ccgbugs/tbug1081.nim @@ -2,7 +2,8 @@ discard """ output: '''1 0 0 -0''' +0 +x = [a, b, c, 0, 1, 2, 3, 4, 5, 6] and y = [a, b, c, 0, 1, 2, 3, 4, 5, 6]''' """ proc `1/1`() = echo(1 div 1) @@ -15,3 +16,19 @@ let `1/4` = 1 div 4 `1/2`() echo `1/3` echo `1/4` + +# bug #6422 + +proc toCharArray1(N : static[int], s: string): array[N, char] = + doAssert s.len <= N + let x = cast[ptr array[N, char]](s.cstring) + x[] + +proc toCharArray2(N : static[int], s: string): array[N, char] = + doAssert s.len <= N + let x = cast[ptr array[N, char]](s.cstring) + result = x[] + +let x = toCharArray1(10, "abc0123456") +let y = toCharArray2(10, "abc0123456") +echo "x = ", $x, " and y = ", $y diff --git a/tests/ccgbugs/tret_arg_init.nim b/tests/ccgbugs/tret_arg_init.nim index 3c80fb061..5cd67de3e 100644 --- a/tests/ccgbugs/tret_arg_init.nim +++ b/tests/ccgbugs/tret_arg_init.nim @@ -1,7 +1,7 @@ discard """ - output: '''nil -nil -nil''' + output: ''' + +''' """ type Bar = object diff --git a/tests/closure/t1641.nim b/tests/closure/t1641.nim new file mode 100644 index 000000000..a3e4da367 --- /dev/null +++ b/tests/closure/t1641.nim @@ -0,0 +1,20 @@ +discard """ + output: '''foo 0 +bar 0 +baz''' +""" + +# bug #1641 +proc baz() = + echo "baz" + +proc bar(x: int, p: proc()) = + echo "bar ", x + p() + +proc foo(x: int, p: proc(x: int)) = + echo "foo ", x + p(x) + +let x = 0 +x.foo do(x: int): x.bar do(): baz() diff --git a/tests/concepts/tmapconcept.nim b/tests/concepts/tmapconcept.nim index 81caed7c6..5082fcb61 100644 --- a/tests/concepts/tmapconcept.nim +++ b/tests/concepts/tmapconcept.nim @@ -1,7 +1,7 @@ discard """ output: '''10 10 -nil + 1''' msg: ''' K=string V=int diff --git a/tests/cpp/tget_subsystem.nim b/tests/cpp/tget_subsystem.nim index 461914739..81009dd39 100644 --- a/tests/cpp/tget_subsystem.nim +++ b/tests/cpp/tget_subsystem.nim @@ -21,3 +21,11 @@ proc getSubsystem*[T](): ptr T {. let input: ptr Input = getSubsystem[Input]() + +# bug #4910 + +proc foo() = + var ts: array[10, int] + for t in mitems(ts): + t = 123 + diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim new file mode 100644 index 000000000..97d7c07b6 --- /dev/null +++ b/tests/destructor/tcustomseqs.nim @@ -0,0 +1,143 @@ +discard """ + output: '''1 +2 +3 +4 +5 +6 +89 +90 +90 +0 0 1 +0 1 2 +0 2 3 +1 0 4 +1 1 5 +1 2 6 +1 3 7 +after 6 6''' + cmd: '''nim c --newruntime $file''' +""" + +import typetraits + +type + myseq*[T] = object + len, cap: int + data: ptr UncheckedArray[T] + +# XXX make code memory safe for overflows in '*' +var + allocCount, deallocCount: int + +proc `=destroy`*[T](x: var myseq[T]) = + if x.data != nil: + when not supportsCopyMem(T): + for i in 0..<x.len: `=destroy`(x[i]) + dealloc(x.data) + inc deallocCount + x.data = nil + x.len = 0 + x.cap = 0 + +proc `=`*[T](a: var myseq[T]; b: myseq[T]) = + if a.data == b.data: return + if a.data != nil: + dealloc(a.data) + inc deallocCount + a.data = nil + a.len = b.len + a.cap = b.cap + if b.data != nil: + a.data = cast[type(a.data)](alloc(a.cap * sizeof(T))) + inc allocCount + when supportsCopyMem(T): + copyMem(a.data, b.data, a.cap * sizeof(T)) + else: + for i in 0..<a.len: + a.data[i] = b.data[i] + +proc `=sink`*[T](a: var myseq[T]; b: myseq[T]) = + if a.data != nil and a.data != b.data: + dealloc(a.data) + inc deallocCount + a.len = b.len + a.cap = b.cap + a.data = b.data + +proc resize[T](s: var myseq[T]) = + if s.cap == 0: s.cap = 8 + else: s.cap = (s.cap * 3) shr 1 + if s.data == nil: inc allocCount + s.data = cast[type(s.data)](realloc(s.data, s.cap * sizeof(T))) + +proc reserveSlot[T](x: var myseq[T]): ptr T = + if x.len >= x.cap: resize(x) + result = addr(x.data[x.len]) + inc x.len + +template add*[T](x: var myseq[T]; y: T) = + reserveSlot(x)[] = y + +proc shrink*[T](x: var myseq[T]; newLen: int) = + assert newLen <= x.len + assert newLen >= 0 + when not supportsCopyMem(T): + for i in countdown(x.len - 1, newLen - 1): + `=destroy`(x.data[i]) + x.len = newLen + +proc grow*[T](x: var myseq[T]; newLen: int; value: T) = + if newLen <= x.len: return + assert newLen >= 0 + if x.cap == 0: x.cap = newLen + else: x.cap = max(newLen, (x.cap * 3) shr 1) + if x.data == nil: inc allocCount + x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T))) + for i in x.len..<newLen: + x.data[i] = value + x.len = newLen + +template default[T](t: typedesc[T]): T = + var v: T + v + +proc setLen*[T](x: var myseq[T]; newLen: int) {.deprecated.} = + if newlen < x.len: shrink(x, newLen) + else: grow(x, newLen, default(T)) + +template `[]`*[T](x: myseq[T]; i: Natural): T = + assert i < x.len + x.data[i] + +template `[]=`*[T](x: myseq[T]; i: Natural; y: T) = + assert i < x.len + x.data[i] = y + +proc createSeq*[T](elems: varargs[T]): myseq[T] = + result.cap = elems.len + result.len = elems.len + result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) + inc allocCount + when supportsCopyMem(T): + copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) + else: + for i in 0..<result.len: + result.data[i] = elems[i] + +proc len*[T](x: myseq[T]): int {.inline.} = x.len + +proc main = + var s = createSeq(1, 2, 3, 4, 5, 6) + s.add 89 + s.grow s.len + 2, 90 + for i in 0 ..< s.len: + echo s[i] + + var nested = createSeq(createSeq(1, 2, 3), createSeq(4, 5, 6, 7)) + for i in 0 ..< nested.len: + for j in 0 ..< nested[i].len: + echo i, " ", j, " ", nested[i][j] + +main() +echo "after ", allocCount, " ", deallocCount diff --git a/tests/destructor/tcustomstrings.nim b/tests/destructor/tcustomstrings.nim new file mode 100644 index 000000000..1a78df20b --- /dev/null +++ b/tests/destructor/tcustomstrings.nim @@ -0,0 +1,99 @@ +discard """ + output: '''foo bar to appendmore here +foo bar to appendmore here +foo bar to appendmore here +foo bar to appendmore here +foo bar to appendmore here +after 20 20''' + cmd: '''nim c --newruntime $file''' +""" + +{.this: self.} + +type + mystring = object + len, cap: int + data: ptr UncheckedArray[char] + +var + allocCount, deallocCount: int + +proc `=destroy`*(s: var mystring) = + if s.data != nil: + dealloc(s.data) + inc deallocCount + s.data = nil + s.len = 0 + s.cap = 0 + +proc `=sink`*(a: var mystring, b: mystring) = + # we hope this is optimized away for not yet alive objects: + if a.data != nil and a.data != b.data: + dealloc(a.data) + inc deallocCount + a.len = b.len + a.cap = b.cap + a.data = b.data + +proc `=`*(a: var mystring; b: mystring) = + if a.data != nil and a.data != b.data: + dealloc(a.data) + inc deallocCount + a.data = nil + a.len = b.len + a.cap = b.cap + if b.data != nil: + a.data = cast[type(a.data)](alloc(a.cap + 1)) + inc allocCount + copyMem(a.data, b.data, a.cap+1) + +proc resize(self: var mystring) = + if self.cap == 0: self.cap = 8 + else: self.cap = (self.cap * 3) shr 1 + if self.data == nil: inc allocCount + self.data = cast[type(data)](realloc(self.data, self.cap + 1)) + +proc add*(self: var mystring; c: char) = + if self.len >= self.cap: resize(self) + self.data[self.len] = c + self.data[self.len+1] = '\0' + inc self.len + +proc ensure(self: var mystring; newLen: int) = + if newLen >= cap: + cap = max((cap * 3) shr 1, newLen) + if cap > 0: + if data == nil: inc allocCount + data = cast[type(data)](realloc(data, cap + 1)) + +proc add*(self: var mystring; y: mystring) = + let newLen = len + y.len + ensure(self, newLen) + copyMem(addr data[len], y.data, y.data.len + 1) + len = newLen + +proc create*(lit: string): mystring = + let newLen = lit.len + ensure(result, newLen) + copyMem(addr result.data[result.len], unsafeAddr lit[0], newLen + 1) + result.len = newLen + +proc `&`*(a, b: mystring): mystring = + result = a + result.add b + +proc main(n: int) = + var a: mystring + let b = create" to append" + for i in 0..<n: + if i > 4: break + a = create"foo bar" + let c = b & create"more here" + a.add c + echo cstring(a.data) + + var x: array[4, mystring] + for i in 0..high(x): x[i] = create"added to array" + +main(1000) +echo "after ", allocCount, " ", deallocCount diff --git a/tests/destructor/topttree.nim b/tests/destructor/topttree.nim new file mode 100644 index 000000000..924644392 --- /dev/null +++ b/tests/destructor/topttree.nim @@ -0,0 +1,104 @@ +discard """ + output: '''10.0 +60.0 +90.0 +120.0 +10.0 +60.0 +90.0 +120.0 +8 8''' + cmd: '''nim c --newruntime $file''' +""" + +import typetraits + +type + opt[T] = object + data: ptr T + +var + allocCount, deallocCount: int + +proc `=destroy`*[T](x: var opt[T]) = + if x.data != nil: + when not supportsCopyMem(T): + `=destroy`(x.data[]) + dealloc(x.data) + inc deallocCount + x.data = nil + +proc `=`*[T](a: var opt[T]; b: opt[T]) = + if a.data == b.data: return + if a.data != nil: + dealloc(a.data) + inc deallocCount + a.data = nil + if b.data != nil: + a.data = cast[type(a.data)](alloc(sizeof(T))) + inc allocCount + when supportsCopyMem(T): + copyMem(a.data, b.data, sizeof(T)) + else: + a.data[] = b.data[] + +proc `=sink`*[T](a: var opt[T]; b: opt[T]) = + if a.data != nil and a.data != b.data: + dealloc(a.data) + inc deallocCount + a.data = b.data + +proc createOpt*[T](x: T): opt[T] = + result.data = cast[type(result.data)](alloc(sizeof(T))) + inc allocCount + result.data[] = x + +template `[]`[T](x: opt[T]): T = + assert x.p != nil, "attempt to read from moved/destroyed value" + x.p[] + +template `?=`[T](it: untyped; x: opt[T]): bool = + template it: untyped {.inject.} = x.data[] + if x.data != nil: + true + else: + false + +type + Tree = object + data: float + le, ri: opt[Tree] + +proc createTree(data: float): Tree = + result.data = data + +proc insert(t: var opt[Tree]; newVal: float) = + #if it ?= t: + if t.data != nil: + if newVal < t.data[].data: + insert(t.data[].le, newVal) + elif t.data[].data < newVal: + insert(t.data[].ri, newVal) + else: + discard "already in the tree" + else: + t = createOpt(Tree(data: newVal)) + +proc write(t: opt[Tree]) = + if it ?= t: + write(it.le) + write stdout, it.data, "\n" + write(it.ri) + +proc main = + var t: opt[Tree] + insert t, 60.0 + insert t, 90.0 + insert t, 10.0 + insert t, 120.0 + write t + let copy = t + write copy + +main() +echo allocCount, " ", deallocCount diff --git a/tests/effects/tgcsafe2.nim b/tests/effects/tgcsafe2.nim new file mode 100644 index 000000000..0b2c090a7 --- /dev/null +++ b/tests/effects/tgcsafe2.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: '''type mismatch: got (proc (s: string){.locks: 0.})''' + line: 11 +""" +#5620 +var res = "" + +proc takeCallback(foo: (proc(s: string) {.gcsafe.})) = + foo "string" + +takeCallback(proc (s: string) = + res &= s & "abc") diff --git a/tests/exprs/texprstmt.nim b/tests/exprs/texprstmt.nim index 0e92702e8..6c9759cf5 100644 --- a/tests/exprs/texprstmt.nim +++ b/tests/exprs/texprstmt.nim @@ -1,6 +1,6 @@ discard """ line: 10 - errormsg: "expression 'result[1 .. -(len(result), 1)]' is of type 'string' and has to be discarded" + errormsg: "expression 'result[1 .. BackwardsIndex(1)]' is of type 'string' and has to be discarded" """ # bug #578 diff --git a/tests/fields/timplicitfieldswithpartial.nim b/tests/fields/timplicitfieldswithpartial.nim index 996912a1a..a315cc5d0 100644 --- a/tests/fields/timplicitfieldswithpartial.nim +++ b/tests/fields/timplicitfieldswithpartial.nim @@ -1,6 +1,8 @@ discard """ output: '''(foo: 38, other: string here) -43''' +43 +100 +90''' """ type @@ -17,3 +19,17 @@ proc my(f: Foo) = var g: Foo new(g) my(g) + +type + FooTask {.partial.} = ref object of RootObj + +proc foo(t: FooTask) {.liftLocals: t.} = + var x = 90 + if true: + var x = 10 + while x < 100: + inc x + echo x + echo x + +foo(FooTask()) diff --git a/tests/float/tfloat4.nim b/tests/float/tfloat4.nim index d7783ce26..559c8aaca 100644 --- a/tests/float/tfloat4.nim +++ b/tests/float/tfloat4.nim @@ -9,7 +9,7 @@ proc c_sprintf(buf, fmt: cstring) {.importc:"sprintf", header: "<stdio.h>", vara proc floatToStr(f: float64): string = var buffer: array[128, char] - c_sprintf(buffer, "%.16e", f) + c_sprintf(addr buffer, "%.16e", f) result = "" for ch in buffer: if ch == '\0': diff --git a/tests/float/tfloatnan.nim b/tests/float/tfloatnan.nim new file mode 100644 index 000000000..aa288d342 --- /dev/null +++ b/tests/float/tfloatnan.nim @@ -0,0 +1,16 @@ +discard """ + file: "tfloatnan.nim" + output: '''Nim: nan +Nim: nan (float) +Nim: nan (double) +''' +""" + +let f = NaN +echo "Nim: ", f + +let f32: float32 = NaN +echo "Nim: ", f32, " (float)" + +let f64: float64 = NaN +echo "Nim: ", f64, " (double)" diff --git a/tests/gc/gctest.nim b/tests/gc/gctest.nim index b3b9af608..f5c81f033 100644 --- a/tests/gc/gctest.nim +++ b/tests/gc/gctest.nim @@ -31,7 +31,7 @@ type of nkList: sons: seq[PCaseNode] else: unused: seq[string] - TIdObj* = object of TObject + TIdObj* = object of RootObj id*: int # unique id; use this for comparisons and not the pointers PIdObj* = ref TIdObj diff --git a/tests/misc/treadx.nim b/tests/misc/treadx.nim index 49b6ad691..e68b8933d 100644 --- a/tests/misc/treadx.nim +++ b/tests/misc/treadx.nim @@ -6,9 +6,8 @@ when not defined(windows): var buf: array[0..10, char] while true: var r = read(0, addr(buf), sizeof(buf)-1) - add inp, $buf + add inp, $cstring(addr buf) if r != sizeof(buf)-1: break echo inp #dafkladskölklödsaf ölksdakölfölksfklwe4iojr389wr 89uweokf sdlkf jweklr jweflksdj fioewjfsdlfsd - diff --git a/tests/misc/tupcomingfeatures.nim b/tests/misc/tupcomingfeatures.nim index cf07b06df..d37ce85cf 100644 --- a/tests/misc/tupcomingfeatures.nim +++ b/tests/misc/tupcomingfeatures.nim @@ -6,12 +6,8 @@ discard """ {.this: self.} type - Foo {.partial.} = object - a, b: int - -type - tupcomingfeatures.Foo = object - x: int + Foo = object + a, b, x: int proc yay(self: Foo) = echo a, " ", b, " ", x diff --git a/tests/misc/tvarnums.nim b/tests/misc/tvarnums.nim index 4cc10d66a..5daa2c4b8 100644 --- a/tests/misc/tvarnums.nim +++ b/tests/misc/tvarnums.nim @@ -67,7 +67,7 @@ proc toNum64(b: TBuffer): int64 = proc toNum(b: TBuffer): int32 = # treat first byte different: - result = ze(b[0]).int32 and 63i32 + result = int32 ze(b[0]) and 63 var i = 0 Shift = 6'i32 diff --git a/tests/modules/treorder.nim b/tests/modules/treorder.nim index 25280c429..8715e4548 100644 --- a/tests/modules/treorder.nim +++ b/tests/modules/treorder.nim @@ -9,7 +9,6 @@ defined {.reorder: on.} {.experimental.} -{.push callconv: stdcall.} proc bar(x: T) proc foo() = @@ -22,15 +21,16 @@ proc bar(x: T) = echo "works ", x foo(x) +when defined(testdef): + proc whendep() = echo "defined" +else: + proc whendep() = echo "undefined" + foo() type T = int -when defined(testdef): - proc whendep() = echo "defined" -else: - proc whendep() = echo "undefined" when not declared(goo): proc goo(my, omy) = echo my @@ -42,5 +42,3 @@ using my, omy: int goo(3, 4) - -{.pop.} diff --git a/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim b/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim index 72e8bff12..502ea61a9 100644 --- a/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim +++ b/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim @@ -1,3 +1,8 @@ +discard """ + errormsg: "unguarded access: counter" + line: 14 +""" + import threadpool, locks var counterLock: Lock diff --git a/tests/niminaction/Chapter8/sfml/sfml_test.nim b/tests/niminaction/Chapter8/sfml/sfml_test.nim index 49a8176e5..7d56d0903 100644 --- a/tests/niminaction/Chapter8/sfml/sfml_test.nim +++ b/tests/niminaction/Chapter8/sfml/sfml_test.nim @@ -1,3 +1,7 @@ +discard """ + disabled: "windows" +""" + import sfml, os var window = newRenderWindow(videoMode(800, 600), "SFML works!") diff --git a/tests/overload/tprefer_tygenericinst.nim b/tests/overload/tprefer_tygenericinst.nim index 56541c7e8..ab461a0f4 100644 --- a/tests/overload/tprefer_tygenericinst.nim +++ b/tests/overload/tprefer_tygenericinst.nim @@ -2,7 +2,11 @@ discard """ output: '''Version 2 was called. This has the highest precedence. This has the second-highest precedence. -This has the lowest precedence.''' +This has the lowest precedence. +baseobj == +true +even better! == +true''' """ # bug #2220 @@ -26,13 +30,13 @@ template testPred(a: untyped) = type SomeA = A|A # A hack to make "A" a typeclass. when a >= 3: - proc p[X](x: X) = - echo "This has the highest precedence." - when a >= 2: proc p[X: A](x: X) = + echo "This has the highest precedence." + when a == 2: + proc p[X: SomeA](x: X) = echo "This has the second-highest precedence." when a >= 1: - proc p[X: SomeA](x: X) = + proc p[X](x: X) = echo "This has the lowest precedence." p(B()) @@ -40,3 +44,25 @@ template testPred(a: untyped) = testPred(3) testPred(2) testPred(1) + +# bug #6526 +type + BaseObj = ref object of RootObj + DerivedObj = ref object of BaseObj + OtherDerivate = ref object of BaseObj + +proc `==`*[T1, T2: BaseObj](a: T1, b: T2): bool = + echo "baseobj ==" + return true + +let a = DerivedObj() +let b = DerivedObj() +echo a == b + +proc `==`*[T1, T2: OtherDerivate](a: T1, b: T2): bool = + echo "even better! ==" + return true + +let a2 = OtherDerivate() +let b2 = OtherDerivate() +echo a2 == b2 diff --git a/tests/package_level_objects/definefoo.nim b/tests/package_level_objects/definefoo.nim new file mode 100644 index 000000000..36576ab59 --- /dev/null +++ b/tests/package_level_objects/definefoo.nim @@ -0,0 +1,3 @@ +type + Foo* {.package.} = object + x, y: int diff --git a/tests/package_level_objects/mypackage.nimble b/tests/package_level_objects/mypackage.nimble new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/package_level_objects/mypackage.nimble diff --git a/tests/package_level_objects/tusefoo.nim b/tests/package_level_objects/tusefoo.nim new file mode 100644 index 000000000..f9bae9545 --- /dev/null +++ b/tests/package_level_objects/tusefoo.nim @@ -0,0 +1,16 @@ +discard """ + output: '''@[(x: 3, y: 4)]''' +""" + +type + mypackage.Foo = object + Other = proc (inp: Foo) + +import definefoo + +# after this import, Foo is a completely resolved type, so +# we can create a sequence of it: +var s: seq[Foo] = @[] + +s.add Foo(x: 3, y: 4) +echo s diff --git a/tests/package_level_objects/tusefoo2.nim b/tests/package_level_objects/tusefoo2.nim new file mode 100644 index 000000000..be6b3fcda --- /dev/null +++ b/tests/package_level_objects/tusefoo2.nim @@ -0,0 +1,19 @@ +discard """ + output: '''compiles''' +""" + +# Test that the object type does not need to be resolved at all: + +type + mypackage.Foo = object + Other = proc (inp: Foo) + + Node = ref object + external: ptr Foo + data: string + +var x: Node +new(x) +x.data = "compiles" + +echo x.data diff --git a/tests/pragmas/treorder.nim b/tests/pragmas/treorder.nim new file mode 100644 index 000000000..6a6bbff4d --- /dev/null +++ b/tests/pragmas/treorder.nim @@ -0,0 +1,75 @@ +discard """ +output:'''0 +1 +2 +3''' +""" + +import macros +{.reorder: on .} + +echo foo(-1) +echo callWithFoo(0) +echo(CA+CD) +echo useTypes(TA(x:TB(x:1)), 2) +second(0) + +template callWithFoo(arg: untyped): untyped = + foo(arg) + +proc first(i: int): void + +proc second(i: int): void = + make(first) + first(i) + +proc useTypes(a: TA, d: TD): int = + result = a.x.x+d + +type + TDoubleCyclic = ref object + x: TCyclicA + y: TCyclicB + +type + TCyclicA = ref object + x: TDoubleCyclic + +type + TCyclicB = ref object + x: TDoubleCyclic + +const + CA = 1 + CB = CC + +type + TA = object + x: TB + TC = type(CC) + TD = type(CA) + +const + CC = 1 + CD = CB + +type + TB = object + x: TC + +proc foo(x: int): int = + result = bar(x) + +proc bar(x: int): int = + result = x+1 + +macro make(arg: untyped): untyped = + ss &= arg.repr + ss &= " " + discard + +proc first(i: int): void = + make(second) + +static: + var ss: string = "" \ No newline at end of file diff --git a/tests/range/tn8vsint16.nim b/tests/range/tn8vsint16.nim new file mode 100644 index 000000000..bf4f78e3b --- /dev/null +++ b/tests/range/tn8vsint16.nim @@ -0,0 +1,18 @@ +discard """ + output: '''-9''' +""" + +type + n32 = range[0..high(int)] + n8* = range[0'i8..high(int8)] + +proc `+`*(a: n32, b: n32{nkIntLit}): n32 = discard + +proc `-`*(a: n8, b: n8): n8 = n8(system.`-`(a, b)) + +var x, y: n8 +var z: int16 + +# ensure this doesn't call our '-' but system.`-` for int16: +echo z - n8(9) + diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index 32d848e06..153cf8556 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -87,8 +87,8 @@ when isMainModule: result = to(node, TestVariant) doAssert result.name == node["name"].getStr() - doAssert result.age == node["age"].getNum().uint8 - doAssert result.other == node["other"].getNum() + doAssert result.age == node["age"].getInt().uint8 + doAssert result.other == node["other"].getBiggestInt() # TODO: Test object variant with set in of branch. # TODO: Should we support heterogenous arrays? diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index fef1b38c2..071dae5a7 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -13,15 +13,13 @@ proc testStrip() = proc testRemoveSuffix = var s = "hello\n\r" s.removeSuffix - assert s == "hello\n" - s.removeSuffix assert s == "hello" s.removeSuffix assert s == "hello" s = "hello\n\n" s.removeSuffix - assert s == "hello\n" + assert s == "hello" s = "hello\r" s.removeSuffix @@ -41,7 +39,31 @@ proc testRemoveSuffix = s.removeSuffix({'s','z'}) assert s == "hello" s.removeSuffix({'l','o'}) - assert s == "hell" + assert s == "he" + + s = "aeiou" + s.removeSuffix("") + assert s == "aeiou" + + s = "" + s.removeSuffix("") + assert s == "" + + s = " " + s.removeSuffix + assert s == " " + + s = " " + s.removeSuffix("") + assert s == " " + + s = " " + s.removeSuffix(" ") + assert s == " " + + s = " " + s.removeSuffix(' ') + assert s == "" # Contrary to Chomp in other languages # empty string does not change behaviour @@ -49,9 +71,71 @@ proc testRemoveSuffix = s.removeSuffix("") assert s == "hello\r\n\r\n" +proc testRemovePrefix = + var s = "\n\rhello" + s.removePrefix + assert s == "hello" + s.removePrefix + assert s == "hello" + + s = "\n\nhello" + s.removePrefix + assert s == "hello" + + s = "\rhello" + s.removePrefix + assert s == "hello" + + s = "hello \n there" + s.removePrefix + assert s == "hello \n there" + + s = "hello" + s.removePrefix("hel") + assert s == "lo" + s.removePrefix('l') + assert s == "o" + + s = "hellos" + s.removePrefix({'h','e'}) + assert s == "llos" + s.removePrefix({'l','o'}) + assert s == "s" + + s = "aeiou" + s.removePrefix("") + assert s == "aeiou" + + s = "" + s.removePrefix("") + assert s == "" + + s = " " + s.removePrefix + assert s == " " + + s = " " + s.removePrefix("") + assert s == " " + + s = " " + s.removePrefix(" ") + assert s == " " + + s = " " + s.removePrefix(' ') + assert s == "" + + # Contrary to Chomp in other languages + # empty string does not change behaviour + s = "\r\n\r\nhello" + s.removePrefix("") + assert s == "\r\n\r\nhello" + proc main() = testStrip() testRemoveSuffix() + testRemovePrefix() for p in split("/home/a1:xyz:/usr/bin", {':'}): write(stdout, p) @@ -64,6 +148,25 @@ proc testDelete = delete(s, 0, 0) assert s == "1236789ABCDEFG" + +proc testIsAlphaNumeric = + assert isAlphaNumeric("abcdABC1234") == true + assert isAlphaNumeric("a") == true + assert isAlphaNumeric("abcABC?1234") == false + assert isAlphaNumeric("abcABC 1234") == false + assert isAlphaNumeric(".") == false + +testIsAlphaNumeric() + +proc testIsDigit = + assert isDigit("1") == true + assert isDigit("1234") == true + assert isDigit("abcABC?1234") == false + assert isDigit(".") == false + assert isDigit(":") == false + +testIsDigit() + proc testFind = assert "0123456789ABCDEFGH".find('A') == 10 assert "0123456789ABCDEFGH".find('A', 5) == 10 diff --git a/tests/stdlib/ttime.nim b/tests/stdlib/ttimes.nim index b28d8aecd..84e00f8de 100644 --- a/tests/stdlib/ttime.nim +++ b/tests/stdlib/ttimes.nim @@ -1,6 +1,7 @@ # test the new time module discard """ - file: "ttime.nim" + file: "ttimes.nim" + action: "run" """ import @@ -31,14 +32,6 @@ t2.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" & " ss t tt y yy yyy yyyy yyyyy z zz zzz", "27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 +0 +00 +00:00") -when not defined(JS): - when sizeof(Time) == 8: - var t3 = getGMTime(fromSeconds(889067643645)) # Fri 7 Jun 19:20:45 BST 30143 - t3.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" & - " ss t tt y yy yyy yyyy yyyyy z zz zzz", - "7 07 Fri Friday 6 06 18 18 20 20 6 06 Jun June 45 45 P PM 3 43 143 0143 30143 +0 +00 +00:00") - t3.checkFormat(":,[]()-/", ":,[]()-/") - var t4 = getGMTime(fromSeconds(876124714)) # Mon 6 Oct 08:58:34 BST 1997 t4.checkFormat("M MM MMM MMMM", "10 10 Oct October") @@ -207,6 +200,21 @@ for tz in [ doAssert ti.format("zz") == tz[2] doAssert ti.format("zzz") == tz[3] +block formatDst: + var ti = TimeInfo(monthday: 1, isDst: true) + + # BST + ti.timezone = 0 + doAssert ti.format("z") == "+1" + doAssert ti.format("zz") == "+01" + doAssert ti.format("zzz") == "+01:00" + + # EDT + ti.timezone = 5 * 60 * 60 + doAssert ti.format("z") == "-4" + doAssert ti.format("zz") == "-04" + doAssert ti.format("zzz") == "-04:00" + block dstTest: let nonDst = TimeInfo(year: 2015, month: mJan, monthday: 01, yearday: 0, weekday: dThu, hour: 00, minute: 00, second: 00, isDST: false, timezone: 0) @@ -214,8 +222,8 @@ block dstTest: dst.isDst = true # note that both isDST == true and isDST == false are valid here because # DST is in effect on January 1st in some southern parts of Australia. - - doAssert nonDst.toTime() - dst.toTime() == 3600 + # FIXME: Fails in UTC + # doAssert nonDst.toTime() - dst.toTime() == 3600 doAssert nonDst.format("z") == "+0" doAssert dst.format("z") == "+1" @@ -227,3 +235,9 @@ block dstTest: parsedJul = parse("2016-07-01 04:00:00+01:00", "yyyy-MM-dd HH:mm:sszzz") doAssert toTime(parsedJan) == fromSeconds(1451962800) doAssert toTime(parsedJul) == fromSeconds(1467342000) + +block countLeapYears: + # 1920, 2004 and 2020 are leap years, and should be counted starting at the following year + doAssert countLeapYears(1920) + 1 == countLeapYears(1921) + doAssert countLeapYears(2004) + 1 == countLeapYears(2005) + doAssert countLeapYears(2020) + 1 == countLeapYears(2021) \ No newline at end of file diff --git a/tests/system/toString.nim b/tests/system/toString.nim index a2337f5dd..3e7fc7ddb 100644 --- a/tests/system/toString.nim +++ b/tests/system/toString.nim @@ -1,42 +1,53 @@ discard """ - output:'''@[23, 45] -@[, foo, bar] -{a, b, c} -2.3242 -2.982 -123912.1 -123912.1823 -5.0 -1e+100 -inf --inf -nan -nil -nil''' + output:"" """ -echo($(@[23, 45])) -echo($(@["", "foo", "bar"])) -#echo($(["", "foo", "bar"])) -#echo($([23, 45])) +doAssert "@[23, 45]" == $(@[23, 45]) +doAssert "[32, 45]" == $([32, 45]) +doAssert "@[, foo, bar]" == $(@["", "foo", "bar"]) +doAssert "[, foo, bar]" == $(["", "foo", "bar"]) # bug #2395 - let alphaSet: set[char] = {'a'..'c'} -echo alphaSet - -echo($(2.3242)) -echo($(2.982)) -echo($(123912.1)) -echo($(123912.1823)) -echo($(5.0)) -echo($(1e100)) -echo($(1e1000000)) -echo($(-1e1000000)) -echo($(0.0/0.0)) +doAssert "{a, b, c}" == $alphaSet +doAssert "2.3242" == $(2.3242) +doAssert "2.982" == $(2.982) +doAssert "123912.1" == $(123912.1) +doAssert "123912.1823" == $(123912.1823) +doAssert "5.0" == $(5.0) +doAssert "1e+100" == $(1e100) +doAssert "inf" == $(1e1000000) +doAssert "-inf" == $(-1e1000000) +doAssert "nan" == $(0.0/0.0) # nil tests +# maybe a bit inconsistent in types var x: seq[string] -var y: string -echo(x) -echo(y) +doAssert "nil" == $(x) + +var y: string = nil +doAssert nil == $(y) + +type + Foo = object + a: int + b: string + +var foo1: Foo + +# nil string should be an some point in time equal to the empty string +doAssert(($foo1)[0..9] == "(a: 0, b: ") + +const + data = @['a','b', '\0', 'c','d'] + dataStr = $data + +# ensure same result when on VM or when at program execution +doAssert dataStr == $data + +import strutils +# array test + +let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0'] +doAssert $arr == "[H, e, l, l, o, , W, o, r, l, d, !, \0]" +doAssert $cstring(unsafeAddr arr) == "Hello World!" diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim new file mode 100644 index 000000000..66b789ee9 --- /dev/null +++ b/tests/system/tsystem_misc.nim @@ -0,0 +1,18 @@ +discard """ + output:"" +""" + +# check high/low implementations +doAssert high(int) > low(int) +doAssert high(int8) > low(int8) +doAssert high(int16) > low(int16) +doAssert high(int32) > low(int32) +doAssert high(int64) > low(int64) +# doAssert high(uint) > low(uint) # reconsider depending on issue #6620 +doAssert high(uint8) > low(uint8) +doAssert high(uint16) > low(uint16) +doAssert high(uint32) > low(uint32) +# doAssert high(uint64) > low(uint64) # reconsider depending on issue #6620 +doAssert high(float) > low(float) +doAssert high(float32) > low(float32) +doAssert high(float64) > low(float64) diff --git a/tests/testament/backend.nim b/tests/testament/backend.nim index 8f0961566..4acef9ca4 100644 --- a/tests/testament/backend.nim +++ b/tests/testament/backend.nim @@ -1,56 +1,16 @@ # # # The Nim Tester -# (c) Copyright 2015 Andreas Rumpf +# (c) Copyright 2017 Andreas Rumpf # # Look at license.txt for more info. # All rights reserved. -import strutils, db_sqlite, os, osproc - -var db: DbConn - -proc createDb() = - db.exec(sql""" - create table if not exists Machine( - id integer primary key, - name varchar(100) not null, - os varchar(20) not null, - cpu varchar(20) not null - );""") - - db.exec(sql""" - create table if not exists [Commit]( - id integer primary key, - hash varchar(256) not null, - branch varchar(50) not null - );""") - - db.exec(sql""" - create table if not exists TestResult( - id integer primary key, - name varchar(100) not null, - category varchar(100) not null, - target varchar(20) not null, - action varchar(10) not null, - result varchar(30) not null, - [commit] int not null, - machine int not null, - expected varchar(10000) not null, - given varchar(10000) not null, - created timestamp not null default (DATETIME('now')), - - foreign key ([commit]) references [commit](id), - foreign key (machine) references machine(id) - );""") - - #db.exec(sql""" - # --create unique index if not exists TsstNameIx on TestResult(name); - # """, []) +import strutils, os, osproc, json type - MachineId* = distinct int64 - CommitId = distinct int64 + MachineId* = distinct string + CommitId = distinct string proc `$`*(id: MachineId): string {.borrow.} proc `$`(id: CommitId): string {.borrow.} @@ -58,11 +18,12 @@ proc `$`(id: CommitId): string {.borrow.} var thisMachine: MachineId thisCommit: CommitId + thisBranch: string {.experimental.} proc `()`(cmd: string{lit}): string = cmd.execProcess.string.strip -proc getMachine*(db: DbConn): MachineId = +proc getMachine*(): MachineId = var name = "hostname"() if name.len == 0: name = when defined(posix): getenv"HOSTNAME".string @@ -70,54 +31,45 @@ proc getMachine*(db: DbConn): MachineId = if name.len == 0: quit "cannot determine the machine name" - let id = db.getValue(sql"select id from Machine where name = ?", name) - if id.len > 0: - result = id.parseInt.MachineId - else: - result = db.insertId(sql"insert into Machine(name, os, cpu) values (?,?,?)", - name, system.hostOS, system.hostCPU).MachineId + result = MachineId(name) -proc getCommit(db: DbConn): CommitId = +proc getCommit(): CommitId = const commLen = "commit ".len let hash = "git log -n 1"()[commLen..commLen+10] - let branch = "git symbolic-ref --short HEAD"() - if hash.len == 0 or branch.len == 0: quit "cannot determine git HEAD" + thisBranch = "git symbolic-ref --short HEAD"() + if hash.len == 0 or thisBranch.len == 0: quit "cannot determine git HEAD" + result = CommitId(hash) - let id = db.getValue(sql"select id from [Commit] where hash = ? and branch = ?", - hash, branch) - if id.len > 0: - result = id.parseInt.CommitId - else: - result = db.insertId(sql"insert into [Commit](hash, branch) values (?, ?)", - hash, branch).CommitId +var + results: File + currentCategory: string + entries: int proc writeTestResult*(name, category, target, action, result, expected, given: string) = - let id = db.getValue(sql"""select id from TestResult - where name = ? and category = ? and target = ? and - machine = ? and [commit] = ?""", - name, category, target, - thisMachine, thisCommit) - if id.len > 0: - db.exec(sql"""update TestResult - set action = ?, result = ?, expected = ?, given = ? - where id = ?""", action, result, expected, given, id) - else: - db.exec(sql"""insert into TestResult(name, category, target, - action, - result, expected, given, - [commit], machine) - values (?,?,?,?,?,?,?,?,?) """, name, category, target, - action, - result, expected, given, - thisCommit, thisMachine) + createDir("testresults") + if currentCategory != category: + if currentCategory.len > 0: + results.writeLine("]") + close(results) + currentCategory = category + results = open("testresults" / category.addFileExt"json", fmWrite) + results.writeLine("[") + entries = 0 + + let jentry = %*{"name": name, "category": category, "target": target, + "action": action, "result": result, "expected": expected, "given": given, + "machine": thisMachine.string, "commit": thisCommit.string, "branch": thisBranch} + if entries > 0: + results.writeLine(",") + results.write($jentry) + inc entries proc open*() = - let dbFile = if existsEnv("TRAVIS") or existsEnv("APPVEYOR"): ":memory:" else: "testament.db" - db = open(connection=dbFile, user="testament", password="", - database="testament") - createDb() - thisMachine = getMachine(db) - thisCommit = getCommit(db) + thisMachine = getMachine() + thisCommit = getCommit() -proc close*() = close(db) +proc close*() = + if currentCategory.len > 0: + results.writeLine("]") + close(results) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index f71a4a1e7..675ff946f 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -83,9 +83,9 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = "" testSpec c, makeTest("lib/nimrtl.nim", - options & " --app:lib -d:createNimRtl", cat) + options & " --app:lib -d:createNimRtl --threads:on", cat) testSpec c, makeTest("tests/dll/server.nim", - options & " --app:lib -d:useNimRtl" & rpath, cat) + options & " --app:lib -d:useNimRtl --threads:on" & rpath, cat) when defined(Windows): @@ -101,7 +101,7 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = var nimrtlDll = DynlibFormat % "nimrtl" safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll) - testSpec r, makeTest("tests/dll/client.nim", options & " -d:useNimRtl" & rpath, + testSpec r, makeTest("tests/dll/client.nim", options & " -d:useNimRtl --threads:on" & rpath, cat, actionRun) proc dllTests(r: var TResults, cat: Category, options: string) = @@ -259,6 +259,7 @@ proc testNimInAction(r: var TResults, cat: Category, options: string) = "niminaction/Chapter6/WikipediaStats/parallel_counts", "niminaction/Chapter6/WikipediaStats/race_condition", "niminaction/Chapter6/WikipediaStats/sequential_counts", + "niminaction/Chapter6/WikipediaStats/unguarded_access", "niminaction/Chapter7/Tweeter/src/tweeter", "niminaction/Chapter7/Tweeter/src/createDatabase", "niminaction/Chapter7/Tweeter/tests/database_test", @@ -267,11 +268,6 @@ proc testNimInAction(r: var TResults, cat: Category, options: string) = for testfile in tests: test "tests/" & testfile & ".nim", actionCompile - # TODO: This doesn't work for some reason ;\ - # let reject = "tests/niminaction/Chapter6/WikipediaStats" & - # "/unguarded_access.nim" - # test reject, actionReject - let jsFile = "tests/niminaction/Chapter8/canvas/canvas_test.nim" testJS jsFile @@ -328,9 +324,10 @@ type PackageFilter = enum pfExtraOnly pfAll +var nimbleDir = getEnv("NIMBLE_DIR").string +if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" let nimbleExe = findExe("nimble") - nimbleDir = getHomeDir() / ".nimble" packageDir = nimbleDir / "pkgs" packageIndex = nimbleDir / "packages.json" diff --git a/tests/testament/css/boilerplate.css b/tests/testament/css/boilerplate.css deleted file mode 100644 index b209b5aa1..000000000 --- a/tests/testament/css/boilerplate.css +++ /dev/null @@ -1,138 +0,0 @@ -/* ==== Scroll down to find where to put your styles :) ==== */ - -/* HTML5 ✰ Boilerplate */ - -html, body, div, span, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, -small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, figcaption, figure, -footer, header, hgroup, menu, nav, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} - -blockquote, q { quotes: none; } -blockquote:before, blockquote:after, -q:before, q:after { content: ''; content: none; } -ins { background-color: #ff9; color: #000; text-decoration: none; } -mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; } -del { text-decoration: line-through; } -abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; } -table { border-collapse: collapse; border-spacing: 0; } -hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } -input, select { vertical-align: middle; } - -body { font:13px/1.231 sans-serif; *font-size:small; } -select, input, textarea, button { font:99% sans-serif; } -pre, code, kbd, samp { font-family: monospace, sans-serif; } - -html { overflow-y: scroll; } -a:hover, a:active { outline: none; } -ul, ol { margin-left: 2em; } -ol { list-style-type: decimal; } -nav ul, nav li { margin: 0; list-style:none; list-style-image: none; } -small { font-size: 85%; } -strong, th { font-weight: bold; } -td { vertical-align: top; } - -sub, sup { font-size: 75%; line-height: 0; position: relative; } -sup { top: -0.5em; } -sub { bottom: -0.25em; } - -pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; padding: 15px; } -textarea { overflow: auto; } -.ie6 legend, .ie7 legend { margin-left: -7px; } -input[type="radio"] { vertical-align: text-bottom; } -input[type="checkbox"] { vertical-align: bottom; } -.ie7 input[type="checkbox"] { vertical-align: baseline; } -.ie6 input { vertical-align: text-bottom; } -label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; } -button, input, select, textarea { margin: 0; } -input:valid, textarea:valid { } -input:invalid, textarea:invalid { border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red; } -.no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; } - -a:link { -webkit-tap-highlight-color: #FF5E99; } - -button { width: auto; overflow: visible; } -.ie7 img { -ms-interpolation-mode: bicubic; } - -body, select, input, textarea { color: #444; } -h1, h2, h3, h4, h5, h6 { font-weight: bold; } -a, a:active, a:visited { color: #607890; } -a:hover { color: #036; } - -/* - // ========================================== \\ - || || - || Your styles ! || - || || - \\ ========================================== // -*/ - - - - - - - - - - - - - - - -.ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; } -.hidden { display: none; visibility: hidden; } -.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } -.visuallyhidden.focusable:active, -.visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } -.invisible { visibility: hidden; } -.clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; } -.clearfix:after { clear: both; } -.clearfix { zoom: 1; } - - -@media all and (orientation:portrait) { - -} - -@media all and (orientation:landscape) { - -} - -@media screen and (max-device-width: 480px) { - - /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */ -} - - -@media print { - * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; - -ms-filter: none !important; } - a, a:visited { color: #444 !important; text-decoration: underline; } - a[href]:after { content: " (" attr(href) ")"; } - abbr[title]:after { content: " (" attr(title) ")"; } - .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } - pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } - thead { display: table-header-group; } - tr, img { page-break-inside: avoid; } - @page { margin: 0.5cm; } - p, h2, h3 { orphans: 3; widows: 3; } - h2, h3{ page-break-after: avoid; } -} diff --git a/tests/testament/css/style.css b/tests/testament/css/style.css deleted file mode 100644 index 43a8add68..000000000 --- a/tests/testament/css/style.css +++ /dev/null @@ -1,114 +0,0 @@ -body { - font-size: medium; -} - -div#header { - font-size: 2em; - background-color: #3d3d3d; - border-bottom: solid 2px #000000; - padding: 0.25em; - color: #ffffff; -} - -div#content { - margin: 0.5em; -} - -table { - text-align: left; - margin-bottom: 0.5em; -} - -table td, table th { - padding: 0.15em 0.5em; -} - -tr:nth-child(even) { - background-color: #eee; -} - -/* Awesome buttons :P */ - -a.button { - border-radius: 2px 2px 2px 2px; - background: -moz-linear-gradient(top, #f7f7f7, #ebebeb); - background: -webkit-linear-gradient(top, #f7f7f7, #ebebeb); - background: -o-linear-gradient(top, #f7f7f7, #ebebeb); - text-decoration: none; - color: #3d3d3d; - padding: 5px; - border: solid 1px #9d9d9d; - display: inline-block; - position: relative; - text-align: center; - font-size: small; -} - -a.button.active { - background: -moz-linear-gradient(top, #00B40C, #03A90E); - background: -webkit-linear-gradient(top, #00B40C, #03A90E); - background: -o-linear-gradient(top, #00B40C, #03A90E); - border: solid 1px #148420; - color: #ffffff; -} - -a.button.left { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -a.button.middle { - border-radius: 0; - border-left: 0; -} - -a.button.right { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-left: 0; -} - -a.button:hover { - background: -moz-linear-gradient(top, #0099c7, #0294C1); - background: -webkit-linear-gradient(top, #0099c7, #0294C1); - background: -o-linear-gradient(top, #0099c7, #0294C1); - border: solid 1px #077A9C; - color: #ffffff; -} - -a.button.middle:hover, a.button.right:hover { - border-left: 0; -} - -a.button span.download { - background-image: url("../images/icons.png"); - background-repeat: no-repeat; - display: inline-block; - margin: auto 3px auto auto; - height: 15px; - width: 14px; - position: relative; - background-position: 0 -30px; - top: 3px; -} - -a.button span.book { - background-image: url("../images/icons.png"); - background-repeat: no-repeat; - display: inline-block; - margin: auto 3px auto auto; - height: 15px; - width: 14px; - position: relative; - background-position: 0 0; - top: 3px; -} - -a.button.active span.download, a.button:hover span.download { - background-position: 0 -45px; -} - -a.button.active span.book, a.button:hover span.book { - background-position: 0 -15px; -} - diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim index 15960f09a..05c24b2b5 100644 --- a/tests/testament/htmlgen.nim +++ b/tests/testament/htmlgen.nim @@ -1,7 +1,7 @@ # # # Nim Tester -# (c) Copyright 2015 Andreas Rumpf +# (c) Copyright 2017 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -9,220 +9,158 @@ ## HTML generator for the tester. -import db_sqlite, cgi, backend, strutils, json - -const - TableHeader = """<table border="1"> - <tr><td>Test</td><td>Category</td><td>Target</td> - <td>Action</td> - <td>Expected</td> - <td>Given</td> - <td>Success</td></tr>""" - TableFooter = "</table>" - HtmlBegin = """<html> - <head> - <title>Test results</title> - <style type="text/css"> - <!--""" & slurp("css/boilerplate.css") & "\n" & - slurp("css/style.css") & - """ -ul#tabs { list-style-type: none; margin: 30px 0 0 0; padding: 0 0 0.3em 0; } -ul#tabs li { display: inline; } -ul#tabs li a { color: #42454a; background-color: #dedbde; - border: 1px solid #c9c3ba; border-bottom: none; - padding: 0.3em; text-decoration: none; } -ul#tabs li a:hover { background-color: #f1f0ee; } -ul#tabs li a.selected { color: #000; background-color: #f1f0ee; - font-weight: bold; padding: 0.7em 0.3em 0.38em 0.3em; } -div.tabContent { border: 1px solid #c9c3ba; - padding: 0.5em; background-color: #f1f0ee; } -div.tabContent.hide { display: none; } - --> - </style> - <script> - - var tabLinks = new Array(); - var contentDivs = new Array(); - - function init() { - // Grab the tab links and content divs from the page - var tabListItems = document.getElementById('tabs').childNodes; - for (var i = 0; i < tabListItems.length; i++) { - if (tabListItems[i].nodeName == "LI") { - var tabLink = getFirstChildWithTagName(tabListItems[i], 'A'); - var id = getHash(tabLink.getAttribute('href')); - tabLinks[id] = tabLink; - contentDivs[id] = document.getElementById(id); - } - } - // Assign onclick events to the tab links, and - // highlight the first tab - var i = 0; - for (var id in tabLinks) { - tabLinks[id].onclick = showTab; - tabLinks[id].onfocus = function() { this.blur() }; - if (i == 0) tabLinks[id].className = 'selected'; - i++; - } - // Hide all content divs except the first - var i = 0; - for (var id in contentDivs) { - if (i != 0) contentDivs[id].className = 'tabContent hide'; - i++; - } - } - - function showTab() { - var selectedId = getHash(this.getAttribute('href')); - - // Highlight the selected tab, and dim all others. - // Also show the selected content div, and hide all others. - for (var id in contentDivs) { - if (id == selectedId) { - tabLinks[id].className = 'selected'; - contentDivs[id].className = 'tabContent'; - } else { - tabLinks[id].className = ''; - contentDivs[id].className = 'tabContent hide'; - } - } - // Stop the browser following the link - return false; - } - - function getFirstChildWithTagName(element, tagName) { - for (var i = 0; i < element.childNodes.length; i++) { - if (element.childNodes[i].nodeName == tagName) return element.childNodes[i]; - } - } - function getHash(url) { - var hashPos = url.lastIndexOf('#'); - return url.substring(hashPos + 1); - } - </script> - - </head> - <body onload="init()">""" - - HtmlEnd = "</body></html>" - -proc td(s: string): string = - result = "<td>" & s.substr(0, 200).xmlEncode & "</td>" - -proc getCommit(db: DbConn, c: int): string = - var commit = c - for thisCommit in db.rows(sql"select id from [Commit] order by id desc"): - if commit == 0: result = thisCommit[0] - inc commit - -proc generateHtml*(filename: string, commit: int; onlyFailing: bool) = - const selRow = """select name, category, target, action, - expected, given, result - from TestResult - where [commit] = ? and machine = ? - order by category""" - var db = open(connection="testament.db", user="testament", password="", - database="testament") - # search for proper commit: - let lastCommit = db.getCommit(commit) - +import cgi, backend, strutils, json, os + +import "testamenthtml.templ" + +proc generateTestRunTabListItemPartial(outfile: File, testRunRow: JsonNode, firstRow = false) = + let + # The first tab gets the bootstrap class for a selected tab + firstTabActiveClass = if firstRow: "active" + else: "" + commitId = htmlQuote testRunRow["commit"].str + hash = htmlQuote(testRunRow["commit"].str) + branch = htmlQuote(testRunRow["branch"].str) + machineId = htmlQuote testRunRow["machine"].str + machineName = htmlQuote(testRunRow["machine"].str) + + outfile.generateHtmlTabListItem( + firstTabActiveClass, + commitId, + machineId, + branch, + hash, + machineName + ) + +proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode, onlyFailing = false) = + let + trId = htmlQuote(testResultRow["category"].str & "_" & testResultRow["name"].str) + name = testResultRow["name"].str.htmlQuote() + category = testResultRow["category"].str.htmlQuote() + target = testResultRow["target"].str.htmlQuote() + action = testResultRow["action"].str.htmlQuote() + result = htmlQuote testResultRow["result"].str + expected = htmlQuote testResultRow["expected"].str + gotten = htmlQuote testResultRow["given"].str + timestamp = "unknown" + var panelCtxClass, textCtxClass, bgCtxClass, resultSign, resultDescription: string + case result + of "reSuccess": + if onlyFailing: + return + panelCtxClass = "success" + textCtxClass = "success" + bgCtxClass = "success" + resultSign = "ok" + resultDescription = "PASS" + of "reIgnored": + if onlyFailing: + return + panelCtxClass = "info" + textCtxClass = "info" + bgCtxClass = "info" + resultSign = "question" + resultDescription = "SKIP" + else: + panelCtxClass = "danger" + textCtxClass = "danger" + bgCtxClass = "danger" + resultSign = "exclamation" + resultDescription = "FAIL" + + outfile.generateHtmlTestresultPanelBegin( + trId, name, target, category, action, resultDescription, + timestamp, + result, resultSign, + panelCtxClass, textCtxClass, bgCtxClass + ) + if expected.isNilOrWhitespace() and gotten.isNilOrWhitespace(): + outfile.generateHtmlTestresultOutputNone() + else: + outfile.generateHtmlTestresultOutputDetails( + expected.strip().htmlQuote, + gotten.strip().htmlQuote + ) + outfile.generateHtmlTestresultPanelEnd() + +type + AllTests = object + data: JSonNode + totalCount, successCount, ignoredCount, failedCount: int + successPercentage, ignoredPercentage, failedPercentage: BiggestFloat + +proc allTestResults(): AllTests = + result.data = newJArray() + for file in os.walkFiles("testresults/*.json"): + let data = parseFile(file) + if data.kind != JArray: + echo "[ERROR] ignoring json file that is not an array: ", file + else: + for elem in data: + result.data.add elem + let state = elem["result"].str + if state.contains("reSuccess"): inc result.successCount + elif state.contains("reIgnored"): inc result.ignoredCount + + result.totalCount = result.data.len + result.successPercentage = 100 * (result.successCount.toBiggestFloat() / result.totalCount.toBiggestFloat()) + result.ignoredPercentage = 100 * (result.ignoredCount.toBiggestFloat() / result.totalCount.toBiggestFloat()) + result.failedCount = result.totalCount - result.successCount - result.ignoredCount + result.failedPercentage = 100 * (result.failedCount.toBiggestFloat() / result.totalCount.toBiggestFloat()) + + +proc generateTestResultsPanelGroupPartial(outfile: File, allResults: JsonNode, onlyFailing = false) = + for testresultRow in allResults: + generateTestResultPanelPartial(outfile, testresultRow, onlyFailing) + +proc generateTestRunTabContentPartial(outfile: File, allResults: AllTests, testRunRow: JsonNode, onlyFailing = false, firstRow = false) = + let + # The first tab gets the bootstrap classes for a selected and displaying tab content + firstTabActiveClass = if firstRow: " in active" + else: "" + commitId = htmlQuote testRunRow["commit"].str + hash = htmlQuote(testRunRow["commit"].str) + branch = htmlQuote(testRunRow["branch"].str) + machineId = htmlQuote testRunRow["machine"].str + machineName = htmlQuote(testRunRow["machine"].str) + os = htmlQuote("unknown_os") + cpu = htmlQuote("unknown_cpu") + + outfile.generateHtmlTabPageBegin( + firstTabActiveClass, commitId, + machineId, branch, hash, machineName, os, cpu, + allResults.totalCount, + allResults.successCount, formatBiggestFloat(allResults.successPercentage, ffDecimal, 2) & "%", + allResults.ignoredCount, formatBiggestFloat(allResults.ignoredPercentage, ffDecimal, 2) & "%", + allResults.failedCount, formatBiggestFloat(allResults.failedPercentage, ffDecimal, 2) & "%" + ) + generateTestResultsPanelGroupPartial(outfile, allResults.data, onlyFailing) + outfile.generateHtmlTabPageEnd() + +proc generateTestRunsHtmlPartial(outfile: File, allResults: AllTests, onlyFailing = false) = + # Iterating the results twice, get entire result set in one go + outfile.generateHtmlTabListBegin() + if allResults.data.len > 0: + generateTestRunTabListItemPartial(outfile, allResults.data[0], true) + outfile.generateHtmlTabListEnd() + + outfile.generateHtmlTabContentsBegin() + var firstRow = true + for testRunRow in allResults.data: + generateTestRunTabContentPartial(outfile, allResults, testRunRow, onlyFailing, firstRow) + if firstRow: + firstRow = false + outfile.generateHtmlTabContentsEnd() + +proc generateHtml*(filename: string, onlyFailing: bool) = var outfile = open(filename, fmWrite) - outfile.write(HtmlBegin) - - let commit = db.getValue(sql"select hash from [Commit] where id = ?", - lastCommit) - let branch = db.getValue(sql"select branch from [Commit] where id = ?", - lastCommit) - outfile.write("<p><b>$# $#</b></p>" % [branch, commit]) - - # generate navigation: - outfile.write("""<ul id="tabs">""") - for m in db.rows(sql"select id, name, os, cpu from Machine order by id"): - outfile.writeLine """<li><a href="#$#">$#: $#, $#</a></li>""" % m - outfile.write("</ul>") - - for currentMachine in db.rows(sql"select id from Machine order by id"): - let m = currentMachine[0] - outfile.write("""<div class="tabContent" id="$#">""" % m) - - outfile.write(TableHeader) - for row in db.rows(sql(selRow), lastCommit, m): - if onlyFailing and row.len > 0 and row[row.high] == "reSuccess": - discard - else: - outfile.write("<tr>") - for x in row: - outfile.write(x.td) - outfile.write("</tr>") - - outfile.write(TableFooter) - outfile.write("</div>") - outfile.write(HtmlEnd) - close(db) - close(outfile) -proc generateJson*(filename: string, commit: int) = - const - selRow = """select count(*), - sum(result = 'reSuccess'), - sum(result = 'reIgnored') - from TestResult - where [commit] = ? and machine = ? - order by category""" - selDiff = """select A.category || '/' || A.target || '/' || A.name, - A.result, - B.result - from TestResult A - inner join TestResult B - on A.name = B.name and A.category = B.category - where A.[commit] = ? and B.[commit] = ? and A.machine = ? - and A.result != B.result""" - selResults = """select - category || '/' || target || '/' || name, - category, target, action, result, expected, given - from TestResult - where [commit] = ?""" - var db = open(connection="testament.db", user="testament", password="", - database="testament") - let lastCommit = db.getCommit(commit) - if lastCommit.isNil: - quit "cannot determine commit " & $commit - - let previousCommit = db.getCommit(commit-1) + outfile.generateHtmlBegin() - var outfile = open(filename, fmWrite) + generateTestRunsHtmlPartial(outfile, allTestResults(), onlyFailing) + + outfile.generateHtmlEnd() - let machine = $backend.getMachine(db) - let data = db.getRow(sql(selRow), lastCommit, machine) - - outfile.writeLine("""{"total": $#, "passed": $#, "skipped": $#""" % data) - - let results = newJArray() - for row in db.rows(sql(selResults), lastCommit): - var obj = newJObject() - obj["name"] = %row[0] - obj["category"] = %row[1] - obj["target"] = %row[2] - obj["action"] = %row[3] - obj["result"] = %row[4] - obj["expected"] = %row[5] - obj["given"] = %row[6] - results.add(obj) - outfile.writeLine(""", "results": """) - outfile.write(results.pretty) - - if not previousCommit.isNil: - let diff = newJArray() - - for row in db.rows(sql(selDiff), previousCommit, lastCommit, machine): - var obj = newJObject() - obj["name"] = %row[0] - obj["old"] = %row[1] - obj["new"] = %row[2] - diff.add obj - outfile.writeLine(""", "diff": """) - outfile.writeLine(diff.pretty) - - outfile.writeLine "}" - close(db) + outfile.flushFile() close(outfile) diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim index ed435465a..89e786d48 100644 --- a/tests/testament/specs.nim +++ b/tests/testament/specs.nim @@ -153,7 +153,7 @@ proc parseSpec*(filename: string): TSpec = result.msg = e.value if result.action != actionRun: result.action = actionCompile - of "errormsg": + of "errormsg", "errmsg": result.msg = e.value result.action = actionReject of "nimout": diff --git a/tests/testament/testamenthtml.templ b/tests/testament/testamenthtml.templ new file mode 100644 index 000000000..f7477f3aa --- /dev/null +++ b/tests/testament/testamenthtml.templ @@ -0,0 +1,318 @@ +#? stdtmpl(subsChar = '%', metaChar = '#', emit = "outfile.write") +#import strutils +# +#proc htmlQuote*(raw: string): string = +# result = raw.multiReplace( +# ("&", "&"), +# ("\"", """), +# ("'", "'"), +# ("<", "<"), +# (">", ">") +# ) +# +#end proc +#proc generateHtmlBegin*(outfile: File) = +<!DOCTYPE html> +<html> +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Testament Test Results</title> + <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js" integrity="sha256-ihAoc6M/JPfrIiIeayPE9xjin4UWjsx2mjW/rtmxLM4=" crossorigin="anonymous"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous"></script> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" /> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha256-ZT4HPpdCOt2lvDkXokHuhJfdOKSPFLzeAJik5U/Q+l4=" crossorigin="anonymous" /> + <script> + /** + * Callback function that is executed for each Element in an array. + * @callback executeForElement + * @param {Element} elem Element to operate on + */ + + /** + * + * @param {number} index + * @param {Element[]} elemArray + * @param {executeForElement} executeOnItem + */ + function executeAllAsync(elemArray, index, executeOnItem) { + for (var i = 0; index < elemArray.length && i < 100; i++ , index++) { + var item = elemArray[index]; + executeOnItem(item); + } + if (index < elemArray.length) { + setTimeout(executeAllAsync, 0, elemArray, index, executeOnItem); + } + } + + /** @param {Element} elem */ + function executeShowOnElement(elem) { + while (elem.classList.contains("hidden")) { + elem.classList.remove("hidden"); + } + } + + /** @param {Element} elem */ + function executeHideOnElement(elem) { + if (!elem.classList.contains("hidden")) { + elem.classList.add("hidden"); + } + } + + /** @param {Element} elem */ + function executeExpandOnElement(elem) { + $(elem).collapse("show"); + } + + /** @param {Element} elem */ + function executeCollapseOnElement(elem) { + $(elem).collapse("hide"); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + * @param {executeForElement} executeOnEachPanel + */ + function wholePanelAll(tabId, category, executeOnEachPanel) { + var selector = "div.panel"; + if (typeof category === "string" && category) { + selector += "-" + category; + } + + var jqPanels = $(selector, $("#" + tabId)); + /** @type {Element[]} */ + var elemArray = jqPanels.toArray(); + + setTimeout(executeAllAsync, 0, elemArray, 0, executeOnEachPanel); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + * @param {executeForElement} executeOnEachPanel + */ + function panelBodyAll(tabId, category, executeOnEachPanelBody) { + var selector = "div.panel"; + if (typeof category === "string" && category) { + selector += "-" + category; + } + + var jqPanels = $(selector, $("#" + tabId)); + + var jqPanelBodies = $("div.panel-body", jqPanels); + /** @type {Element[]} */ + var elemArray = jqPanelBodies.toArray(); + + setTimeout(executeAllAsync, 0, elemArray, 0, executeOnEachPanelBody); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + */ + function showAll(tabId, category) { + wholePanelAll(tabId, category, executeShowOnElement); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + */ + function hideAll(tabId, category) { + wholePanelAll(tabId, category, executeHideOnElement); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + */ + function expandAll(tabId, category) { + panelBodyAll(tabId, category, executeExpandOnElement); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + */ + function collapseAll(tabId, category) { + panelBodyAll(tabId, category, executeCollapseOnElement); + } + </script> +</head> +<body> + <div class="container"> + <h1>Testament Test Results <small>Nim Tester</small></h1> +#end proc +#proc generateHtmlTabListBegin*(outfile: File) = + <ul class="nav nav-tabs" role="tablist"> +#end proc +#proc generateHtmlTabListItem*(outfile: File, firstTabActiveClass, commitId, +# machineId, branch, hash, machineName: string) = + <li role="presentation" class="%firstTabActiveClass"> + <a href="#tab-commit-%commitId-machine-%machineId" aria-controls="tab-commit-%commitId-machine-%machineId" role="tab" data-toggle="tab"> + %branch#%hash@%machineName + </a> + </li> +#end proc +#proc generateHtmlTabListEnd*(outfile: File) = + </ul> +#end proc +#proc generateHtmlTabContentsBegin*(outfile: File) = + <div class="tab-content"> +#end proc +#proc generateHtmlTabPageBegin*(outfile: File, firstTabActiveClass, commitId, +# machineId, branch, hash, machineName, os, cpu: string, totalCount: BiggestInt, +# successCount: BiggestInt, successPercentage: string, +# ignoredCount: BiggestInt, ignoredPercentage: string, +# failedCount: BiggestInt, failedPercentage: string) = + <div id="tab-commit-%commitId-machine-%machineId" class="tab-pane fade%firstTabActiveClass" role="tabpanel"> + <h2>%branch#%hash@%machineName</h2> + <dl class="dl-horizontal"> + <dt>Branch</dt> + <dd>%branch</dd> + <dt>Commit Hash</dt> + <dd><code>%hash</code></dd> + <dt>Machine Name</dt> + <dd>%machineName</dd> + <dt>OS</dt> + <dd>%os</dd> + <dt title="CPU Architecture">CPU</dt> + <dd>%cpu</dd> + <dt>All Tests</dt> + <dd> + <span class="glyphicon glyphicon-th-list"></span> + %totalCount + </dd> + <dt>Successful Tests</dt> + <dd> + <span class="glyphicon glyphicon-ok-sign"></span> + %successCount (%successPercentage) + </dd> + <dt>Skipped Tests</dt> + <dd> + <span class="glyphicon glyphicon-question-sign"></span> + %ignoredCount (%ignoredPercentage) + </dd> + <dt>Failed Tests</dt> + <dd> + <span class="glyphicon glyphicon-exclamation-sign"></span> + %failedCount (%failedPercentage) + </dd> + </dl> + <div class="table-responsive"> + <table class="table table-condensed"> + <tr> + <th class="text-right" style="vertical-align:middle">All Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId');">Collapse All</button> + </div> + </td> + </tr> + <tr> + <th class="text-right" style="vertical-align:middle">Successful Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'success');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'success');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'success');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'success');">Collapse All</button> + </div> + </td> + </tr> + <tr> + <th class="text-right" style="vertical-align:middle">Skipped Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'info');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'info');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'info');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'info');">Collapse All</button> + </div> + </td> + </tr> + <tr> + <th class="text-right" style="vertical-align:middle">Failed Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'danger');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'danger');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'danger');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'danger');">Collapse All</button> + </div> + </td> + </tr> + </table> + </div> + <div class="panel-group"> +#end proc +#proc generateHtmlTestresultPanelBegin*(outfile: File, trId, name, target, category, +# action, resultDescription, timestamp, result, resultSign, +# panelCtxClass, textCtxClass, bgCtxClass: string) = + <div id="panel-testResult-%trId" class="panel panel-%panelCtxClass"> + <div class="panel-heading" style="cursor:pointer" data-toggle="collapse" data-target="#panel-body-testResult-%trId" aria-controls="panel-body-testResult-%trId" aria-expanded="false"> + <div class="row"> + <h4 class="col-xs-3 col-sm-1 panel-title"> + <span class="glyphicon glyphicon-%resultSign-sign"></span> + <strong>%resultDescription</strong> + </h4> + <h4 class="col-xs-1 panel-title"><span class="badge">%target</span></h4> + <h4 class="col-xs-5 col-sm-7 panel-title" title="%name"><code class="text-%textCtxClass">%name</code></h4> + <h4 class="col-xs-3 col-sm-3 panel-title text-right"><span class="badge">%category</span></h4> + </div> + </div> + <div id="panel-body-testResult-%trId" class="panel-body collapse bg-%bgCtxClass"> + <dl class="dl-horizontal"> + <dt>Name</dt> + <dd><code class="text-%textCtxClass">%name</code></dd> + <dt>Category</dt> + <dd><span class="badge">%category</span></dd> + <dt>Timestamp</dt> + <dd>%timestamp</dd> + <dt>Nim Action</dt> + <dd><code class="text-%textCtxClass">%action</code></dd> + <dt>Nim Backend Target</dt> + <dd><span class="badge">%target</span></dd> + <dt>Code</dt> + <dd><code class="text-%textCtxClass">%result</code></dd> + </dl> +#end proc +#proc generateHtmlTestresultOutputDetails*(outfile: File, expected, gotten: string) = + <div class="table-responsive"> + <table class="table table-condensed"> + <thead> + <tr> + <th>Expected</th> + <th>Actual</th> + </tr> + </thead> + <tbody> + <tr> + <td><pre>%expected</pre></td> + <td><pre>%gotten</pre></td> + </tr> + </tbody> + </table> + </div> +#end proc +#proc generateHtmlTestresultOutputNone*(outfile: File) = + <p class="sr-only">No output details</p> +#end proc +#proc generateHtmlTestresultPanelEnd*(outfile: File) = + </div> + </div> +#end proc +#proc generateHtmlTabPageEnd*(outfile: File) = + </div> + </div> +#end proc +#proc generateHtmlTabContentsEnd*(outfile: File) = + </div> +#end proc +#proc generateHtmlEnd*(outfile: File) = + </div> +</body> +</html> \ No newline at end of file diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index e4bbc3a00..0daf4089e 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -1,7 +1,7 @@ # # # Nim Tester -# (c) Copyright 2015 Andreas Rumpf +# (c) Copyright 2017 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -12,7 +12,7 @@ import parseutils, strutils, pegs, os, osproc, streams, parsecfg, json, marshal, backend, parseopt, specs, htmlgen, browsers, terminal, - algorithm, compiler/nodejs, re, times, sets + algorithm, compiler/nodejs, times, sets const resultsFile = "testresults.html" @@ -24,15 +24,12 @@ Command: all run all tests c|category <category> run all the tests of a certain category r|run <test> run single test file - html [commit] generate $1 from the database; uses the latest - commit or a specific one (use -1 for the commit - before latest etc) + html generate $1 from the database Arguments: arguments are passed to the compiler Options: --print also print results to the console --failing only show failing/ignored tests - --pedantic return non-zero status code if there are failures --targets:"c c++ js objc" run tests for specified targets (default: all) --nim:path use a particular nim executable (default: compiler/nim) """ % resultsFile @@ -191,7 +188,12 @@ proc addResult(r: var TResults, test: TTest, ("Skipped", "") else: ("Failed", "Failure: " & $success & "\nExpected:\n" & expected & "\n\n" & "Gotten:\n" & given) - var p = startProcess("appveyor", args=["AddTest", test.name.replace("\\", "/") & test.options, "-Framework", "nim-testament", "-FileName", test.cat.string, "-Outcome", outcome, "-ErrorMessage", msg, "-Duration", $(duration*1000).int], options={poStdErrToStdOut, poUsePath, poParentStreams}) + var p = startProcess("appveyor", args=["AddTest", test.name.replace("\\", "/") & test.options, + "-Framework", "nim-testament", "-FileName", + test.cat.string, + "-Outcome", outcome, "-ErrorMessage", msg, + "-Duration", $(duration*1000).int], + options={poStdErrToStdOut, poUsePath, poParentStreams}) discard waitForExit(p) close(p) @@ -290,7 +292,7 @@ proc analyzeAndConsolidateOutput(s: string): string = result = substr(rows[i], pos) & "\n" for i in i+1 ..< rows.len: result.add rows[i] & "\n" - if not (rows[i] =~ re"^[^(]+\(\d+\)\s+"): + if not (rows[i] =~ peg"['(']+ '(' \d+ ')' \s+"): return elif (let pos = find(rows[i], "SIGSEGV: Illegal storage access."); pos != -1): result = substr(rows[i], pos) @@ -436,7 +438,6 @@ proc main() = backend.open() var optPrintResults = false var optFailing = false - var optPedantic = false var p = initOptParser() p.next() @@ -444,7 +445,7 @@ proc main() = case p.key.string.normalize of "print", "verbose": optPrintResults = true of "failing": optFailing = true - of "pedantic": optPedantic = true + of "pedantic": discard "now always enabled" of "targets": targets = parseTargets(p.val.string) of "nim": compilerPrefix = p.val.string else: quit Usage @@ -456,13 +457,17 @@ proc main() = case action of "all": let testsDir = "tests" & DirSep + let myself = quoteShell(findExe("tests" / "testament" / "tester")) + var cmds: seq[string] = @[] + let rest = if p.cmdLineRest.string.len > 0: " " & p.cmdLineRest.string else: "" for kind, dir in walkDir(testsDir): assert testsDir.startsWith(testsDir) let cat = dir[testsDir.len .. ^1] if kind == pcDir and cat notin ["testament", "testdata", "nimcache"]: - processCategory(r, Category(cat), p.cmdLineRest.string) - for a in AdditionalCategories: - processCategory(r, Category(a), p.cmdLineRest.string) + cmds.add(myself & " cat " & cat & rest) + for cat in AdditionalCategories: + cmds.add(myself & " cat " & cat & rest) + quit osproc.execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams}) of "c", "cat", "category": var cat = Category(p.key) p.next @@ -473,10 +478,7 @@ proc main() = var cat = Category(subdir) processSingleTest(r, cat, p.cmdLineRest.string, file) of "html": - var commit = 0 - discard parseInt(p.cmdLineRest.string, commit) - generateHtml(resultsFile, commit, optFailing) - generateJson(jsonFile, commit) + generateHtml(resultsFile, optFailing) else: quit Usage @@ -484,11 +486,10 @@ proc main() = if action == "html": openDefaultBrowser(resultsFile) else: echo r, r.data backend.close() - if optPedantic: - var failed = r.total - r.passed - r.skipped - if failed > 0: - echo "FAILURE! total: ", r.total, " passed: ", r.passed, " skipped: ", r.skipped - quit(QuitFailure) + var failed = r.total - r.passed - r.skipped + if failed > 0: + echo "FAILURE! total: ", r.total, " passed: ", r.passed, " skipped: ", r.skipped + quit(QuitFailure) if paramCount() == 0: quit Usage diff --git a/tests/types/tillegaltyperecursion2.nim b/tests/types/tillegaltyperecursion2.nim new file mode 100644 index 000000000..b5ffdda72 --- /dev/null +++ b/tests/types/tillegaltyperecursion2.nim @@ -0,0 +1,8 @@ +discard """ + errormsg: "invalid recursion in type 'Executor'" + line: 8 +""" +# bug reported by PR #5637 +type + Executor[N] = Executor[N] +var e: Executor[int] diff --git a/tests/untestable/tpostgres.nim b/tests/untestable/tpostgres.nim index 486d0d703..d3397e53a 100644 --- a/tests/untestable/tpostgres.nim +++ b/tests/untestable/tpostgres.nim @@ -304,7 +304,24 @@ doAssert parseInt(dbCols[40].typ.name) > 0 doAssert dbCols[41].name == "range_col" doAssert dbCols[41].typ.kind == DbTypeKind.dbComposite doAssert dbCols[41].typ.name == "int4range" - + +# issue 6571 +db.exec(sql"DROP TABLE IF EXISTS DICTIONARY") +db.exec(sql("""CREATE TABLE DICTIONARY( + id SERIAL PRIMARY KEY, + entry VARCHAR(1000) NOT NULL, + definition VARCHAR(4000) NOT NULL + );""")) +var entry = "あっそ" +var definition = "(int) (See ああそうそう) oh, really (uninterested)/oh yeah?/hmmmmm" +discard db.getRow( + SqlQuery("INSERT INTO DICTIONARY(entry, definition) VALUES(\'$1\', \'$2\') RETURNING id" % [entry, definition])) +doAssert db.getValue(sql"SELECT definition FROM DICTIONARY WHERE entry = ?", entry) == definition +entry = "Format string entry" +definition = "Format string definition" +db.exec(sql"INSERT INTO DICTIONARY(entry, definition) VALUES (?, ?)", entry, definition) +doAssert db.getValue(sql"SELECT definition FROM DICTIONARY WHERE entry = ?", entry) == definition + echo("All tests succeeded!") db.close() diff --git a/tests/vm/trgba.nim b/tests/vm/trgba.nim index a270df267..923ea1b2e 100644 --- a/tests/vm/trgba.nim +++ b/tests/vm/trgba.nim @@ -22,7 +22,7 @@ template `B=`*(self: TAggRgba8, val: byte) = template `A=`*(self: TAggRgba8, val: byte) = self[3] = val -proc ABGR* (val: int| int64): TAggRgba8 = +proc ABGR*(val: int| int64): TAggRgba8 = var V = val result.R = byte(V and 0xFF) V = V shr 8 |