Merge branch 'devel' into araq
This commit is contained in:
commit
1eaeccc15d
616 changed files with 73547 additions and 36764 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
discard """
|
||||
output: '''nil
|
||||
nil
|
||||
nil'''
|
||||
output: '''
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
type Bar = object
|
||||
|
|
|
|||
20
tests/closure/t1641.nim
Normal file
20
tests/closure/t1641.nim
Normal file
|
|
@ -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()
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
discard """
|
||||
output: '''10
|
||||
10
|
||||
nil
|
||||
|
||||
1'''
|
||||
msg: '''
|
||||
K=string V=int
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
143
tests/destructor/tcustomseqs.nim
Normal file
143
tests/destructor/tcustomseqs.nim
Normal file
|
|
@ -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
|
||||
99
tests/destructor/tcustomstrings.nim
Normal file
99
tests/destructor/tcustomstrings.nim
Normal file
|
|
@ -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
|
||||
104
tests/destructor/topttree.nim
Normal file
104
tests/destructor/topttree.nim
Normal file
|
|
@ -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
|
||||
12
tests/effects/tgcsafe2.nim
Normal file
12
tests/effects/tgcsafe2.nim
Normal file
|
|
@ -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")
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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':
|
||||
|
|
|
|||
16
tests/float/tfloatnan.nim
Normal file
16
tests/float/tfloatnan.nim
Normal file
|
|
@ -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)"
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
discard """
|
||||
errormsg: "unguarded access: counter"
|
||||
line: 14
|
||||
"""
|
||||
|
||||
import threadpool, locks
|
||||
|
||||
var counterLock: Lock
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
discard """
|
||||
disabled: "windows"
|
||||
"""
|
||||
|
||||
import sfml, os
|
||||
var window = newRenderWindow(videoMode(800, 600), "SFML works!")
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
3
tests/package_level_objects/definefoo.nim
Normal file
3
tests/package_level_objects/definefoo.nim
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
type
|
||||
Foo* {.package.} = object
|
||||
x, y: int
|
||||
0
tests/package_level_objects/mypackage.nimble
Normal file
0
tests/package_level_objects/mypackage.nimble
Normal file
16
tests/package_level_objects/tusefoo.nim
Normal file
16
tests/package_level_objects/tusefoo.nim
Normal file
|
|
@ -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
|
||||
19
tests/package_level_objects/tusefoo2.nim
Normal file
19
tests/package_level_objects/tusefoo2.nim
Normal file
|
|
@ -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
|
||||
75
tests/pragmas/treorder.nim
Normal file
75
tests/pragmas/treorder.nim
Normal file
|
|
@ -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 = ""
|
||||
18
tests/range/tn8vsint16.nim
Normal file
18
tests/range/tn8vsint16.nim
Normal file
|
|
@ -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)
|
||||
|
||||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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!"
|
||||
|
|
|
|||
18
tests/system/tsystem_misc.nim
Normal file
18
tests/system/tsystem_misc.nim
Normal file
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
import cgi, backend, strutils, json, os
|
||||
|
||||
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>
|
||||
import "testamenthtml.templ"
|
||||
|
||||
var tabLinks = new Array();
|
||||
var contentDivs = new Array();
|
||||
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)
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
outfile.generateHtmlTabListItem(
|
||||
firstTabActiveClass,
|
||||
commitId,
|
||||
machineId,
|
||||
branch,
|
||||
hash,
|
||||
machineName
|
||||
)
|
||||
|
||||
function showTab() {
|
||||
var selectedId = getHash(this.getAttribute('href'));
|
||||
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"
|
||||
|
||||
// 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;
|
||||
}
|
||||
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()
|
||||
|
||||
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>
|
||||
type
|
||||
AllTests = object
|
||||
data: JSonNode
|
||||
totalCount, successCount, ignoredCount, failedCount: int
|
||||
successPercentage, ignoredPercentage, failedPercentage: BiggestFloat
|
||||
|
||||
</head>
|
||||
<body onload="init()">"""
|
||||
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
|
||||
|
||||
HtmlEnd = "</body></html>"
|
||||
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 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 generateTestResultsPanelGroupPartial(outfile: File, allResults: JsonNode, onlyFailing = false) =
|
||||
for testresultRow in allResults:
|
||||
generateTestResultPanelPartial(outfile, testresultRow, onlyFailing)
|
||||
|
||||
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)
|
||||
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")
|
||||
|
||||
var outfile = open(filename, fmWrite)
|
||||
outfile.write(HtmlBegin)
|
||||
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()
|
||||
|
||||
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])
|
||||
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()
|
||||
|
||||
# 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.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)
|
||||
|
||||
let machine = $backend.getMachine(db)
|
||||
let data = db.getRow(sql(selRow), lastCommit, machine)
|
||||
outfile.generateHtmlBegin()
|
||||
|
||||
outfile.writeLine("""{"total": $#, "passed": $#, "skipped": $#""" % data)
|
||||
generateTestRunsHtmlPartial(outfile, allTestResults(), onlyFailing)
|
||||
|
||||
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)
|
||||
outfile.generateHtmlEnd()
|
||||
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
|
|
|
|||
318
tests/testament/testamenthtml.templ
Normal file
318
tests/testament/testamenthtml.templ
Normal file
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
8
tests/types/tillegaltyperecursion2.nim
Normal file
8
tests/types/tillegaltyperecursion2.nim
Normal file
|
|
@ -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]
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue