diff options
Diffstat (limited to 'tests/js')
91 files changed, 4068 insertions, 0 deletions
diff --git a/tests/js/readme.md b/tests/js/readme.md new file mode 100644 index 000000000..7fcc722fa --- /dev/null +++ b/tests/js/readme.md @@ -0,0 +1,5 @@ +## notes +Prefer moving tests to a non-js directory so that they get tested across all backends automatically. +Ideally, tests/js should be reserved to code that only makes sense in js. + +Note also that tests for a js specific module (e.g.: `std/jsbigints`) belong to `tests/stdlib`, (e.g.: `tests/stdlib/tjsbigints.nim`) diff --git a/tests/js/t11166.nim b/tests/js/t11166.nim new file mode 100644 index 000000000..e98ccda10 --- /dev/null +++ b/tests/js/t11166.nim @@ -0,0 +1,20 @@ +discard """ + output: ''' +test1 +test2 +''' +""" + +import jsffi + +type + C = object + props: int + +var c: C + +when compiles(c.props): + echo "test1" + +when not compiles(d.props): + echo "test2" diff --git a/tests/js/t11353.nim b/tests/js/t11353.nim new file mode 100644 index 000000000..c1bc0ad4b --- /dev/null +++ b/tests/js/t11353.nim @@ -0,0 +1,14 @@ +discard """ + output: ''' +{} +{} +''' +""" + +proc foo() = + var bar: set[int16] = {} + echo bar + bar.incl(1) + +foo() +foo() diff --git a/tests/js/t11354.nim b/tests/js/t11354.nim new file mode 100644 index 000000000..8dee90de0 --- /dev/null +++ b/tests/js/t11354.nim @@ -0,0 +1,20 @@ +discard """ + output: ''' +0 +@[@[0, 1]] +''' +""" + +type + TrackySeq[T] = object + s: seq[T] + pos: int + +proc foobar(ls: var TrackySeq[seq[int]], i: int): var seq[int] = + echo ls.pos # removing this, or making the return explicit works + ls.s[i] + +var foo: TrackySeq[seq[int]] +foo.s.add(@[0]) +foo.foobar(0).add(1) +echo foo.s \ No newline at end of file diff --git a/tests/js/t11697.nim b/tests/js/t11697.nim new file mode 100644 index 000000000..967752586 --- /dev/null +++ b/tests/js/t11697.nim @@ -0,0 +1,5 @@ +import tables + +var xs: Table[int, Table[int, int]] + +doAssertRaises(KeyError): reset xs[0] diff --git a/tests/js/t12223.nim b/tests/js/t12223.nim new file mode 100644 index 000000000..c0e75fb44 --- /dev/null +++ b/tests/js/t12223.nim @@ -0,0 +1,20 @@ +discard """ + action: "run" + output: ''' +caught +index out of bounds, the container is empty +''' +""" + +proc fun() = + var z: seq[string] + discard z[4] + +proc main()= + try: + fun() + except Exception as e: + echo "caught" + echo getCurrentExceptionMsg() + +main() \ No newline at end of file diff --git a/tests/js/t12303.nim b/tests/js/t12303.nim new file mode 100644 index 000000000..270d82ced --- /dev/null +++ b/tests/js/t12303.nim @@ -0,0 +1,16 @@ +discard """ + output: "{ b: 2 }" +""" + +import jsconsole, jsffi + +type + A = ref object + b: B + + B = object + b: int + +var a = cast[A](js{}) +a.b = B(b: 2) +console.log a.b diff --git a/tests/js/t12672.nim b/tests/js/t12672.nim new file mode 100644 index 000000000..a658fbcbe --- /dev/null +++ b/tests/js/t12672.nim @@ -0,0 +1,12 @@ +discard """ + output: "" +""" + +proc foo = + var x: seq[seq[int]] + for row in x.mitems: + let i = 1 + echo row + inc row[i-1] + +foo() diff --git a/tests/js/t14153.nim b/tests/js/t14153.nim new file mode 100644 index 000000000..350bbd83b --- /dev/null +++ b/tests/js/t14153.nim @@ -0,0 +1,22 @@ +discard """ + output: ''' +index 5 not in 0 .. 2 +index 5 not in 0 .. 2 +''' +""" + +var x = @[1, 2, 3] + +try: + echo x[5] +except IndexError: + echo getCurrentExceptionMsg() +except: + doAssert false + +try: + x[5] = 8 +except IndexError: + echo getCurrentExceptionMsg() +except: + doAssert false diff --git a/tests/js/t14570.nim b/tests/js/t14570.nim new file mode 100644 index 000000000..100c2651d --- /dev/null +++ b/tests/js/t14570.nim @@ -0,0 +1,11 @@ +discard """ + output: ''' +18 +''' +""" + +type A = range[15 .. 30] + +let a: A = 18 + +echo ord(a) diff --git a/tests/js/t17177.nim b/tests/js/t17177.nim new file mode 100644 index 000000000..fc362cec1 --- /dev/null +++ b/tests/js/t17177.nim @@ -0,0 +1,10 @@ +import std/asyncjs + +proc fn1(n: int): Future[int] {.async.} = return n +proc main2() = + proc fn2(n: int): Future[int] {.async.} = return n +proc main3(a: auto) = + proc fn3(n: int): Future[int] {.async.} = return n +proc main4() {.async.} = + proc fn4(n: int): Future[int] {.async.} = return n + discard diff --git a/tests/js/t20233.nim b/tests/js/t20233.nim new file mode 100644 index 000000000..401d14122 --- /dev/null +++ b/tests/js/t20233.nim @@ -0,0 +1,7 @@ +discard """ + output: "yes" +""" +case 1.0 +of 1.0..2.0, 4.0: echo "yes" +of 3.0: discard +else: echo "no" \ No newline at end of file diff --git a/tests/js/t20235.nim b/tests/js/t20235.nim new file mode 100644 index 000000000..3a69c2bd6 --- /dev/null +++ b/tests/js/t20235.nim @@ -0,0 +1,11 @@ +discard """ + action: "run" + output: "0 4" +""" + +proc main = + var s = "" + s.setLen(4) + echo s[0].ord, " ", s.len + +main() diff --git a/tests/js/t21209.nim b/tests/js/t21209.nim new file mode 100644 index 000000000..4de34f035 --- /dev/null +++ b/tests/js/t21209.nim @@ -0,0 +1,6 @@ +discard """ + action: "compile" + cmd: "nim check --warning[UnusedImport]:off $file" +""" + +import std/times diff --git a/tests/js/t21209.nims b/tests/js/t21209.nims new file mode 100644 index 000000000..318e28f97 --- /dev/null +++ b/tests/js/t21209.nims @@ -0,0 +1 @@ +--b:js \ No newline at end of file diff --git a/tests/js/t21247.nim b/tests/js/t21247.nim new file mode 100644 index 000000000..5b38787b3 --- /dev/null +++ b/tests/js/t21247.nim @@ -0,0 +1,15 @@ +import std/typetraits + +type + QueryParams* = distinct seq[(string, string)] + +converter toBase*(params: var QueryParams): var seq[(string, string)] = + params.distinctBase + +proc foo(): QueryParams = + # Issue was that the implicit converter call didn't say that it took the + # address of the parameter it was converting. This led to the parameter not being + # passed as a fat pointer which toBase expected + result.add(("hello", "world")) + +assert foo().distinctBase() == @[("hello", "world")] diff --git a/tests/js/t21439.nim b/tests/js/t21439.nim new file mode 100644 index 000000000..3caeb090a --- /dev/null +++ b/tests/js/t21439.nim @@ -0,0 +1,11 @@ +proc test(a: openArray[string]): proc = + let a = @a + result = proc = + for i in a: + discard i + + +const a = ["t1", "t2"] + +discard test(a) + diff --git a/tests/js/t6612.nim b/tests/js/t6612.nim new file mode 100644 index 000000000..232711c16 --- /dev/null +++ b/tests/js/t6612.nim @@ -0,0 +1,24 @@ +discard """ + action: "run" +""" + +proc fillWith(sq: var seq[int], n: int, unused: string) = + sq = @[n] + +type + Object = object of RootObj + case hasNums: bool + of true: + numbers: seq[int] + of false: + discard + always: seq[int] + +var obj = Object(hasNums: true) + +obj.always.fillWith(5, "unused") +doAssert obj.always == @[5] + +obj.numbers.fillWith(3, "unused") +doAssert obj.numbers == @[3] +doAssert obj.always == @[5] diff --git a/tests/js/t7109.nim b/tests/js/t7109.nim new file mode 100644 index 000000000..a1a3b718e --- /dev/null +++ b/tests/js/t7109.nim @@ -0,0 +1,8 @@ +iterator iter*(): int {.closure.} = + yield 3 + +var x = iter +doAssert x() == 3 + +let fIt = iterator(): int = yield 70 +doAssert fIt() == 70 diff --git a/tests/js/t7127.nim b/tests/js/t7127.nim new file mode 100644 index 000000000..364aedd4a --- /dev/null +++ b/tests/js/t7127.nim @@ -0,0 +1,2 @@ +doAssertRaises(DivByZeroDefect): discard 1 mod 0 +doAssertRaises(DivByZeroDefect): discard 1 div 0 \ No newline at end of file diff --git a/tests/js/t7224.nim b/tests/js/t7224.nim new file mode 100644 index 000000000..77fef10a7 --- /dev/null +++ b/tests/js/t7224.nim @@ -0,0 +1,28 @@ +discard """ + cmd: "nim $target $options --stackTrace:on --lineTrace:on $file" + outputsub: ''' +t7224.nim(25) at module t7224 +t7224.nim(22) at t7224.aaa +t7224.nim(19) at t7224.bbb +t7224.nim(16) at t7224.ccc +t7224.nim(13) at t7224.ddd +''' +""" + +proc ddd() = + raise newException(IOError, "didn't do stuff") + +proc ccc() = + ddd() + +proc bbb() = + ccc() + +proc aaa() = + bbb() + +try: + aaa() + +except IOError as e: + echo getStackTrace(e) diff --git a/tests/js/t7249.nim b/tests/js/t7249.nim new file mode 100644 index 000000000..52eee2f7c --- /dev/null +++ b/tests/js/t7249.nim @@ -0,0 +1,21 @@ +discard """ + output: ''' +a -> 2 +a <- 2 +''' +""" + +import jsffi + +var a = JsAssoc[cstring, int]{a: 2} + +for z, b in a: + echo z, " -> ", b + +proc f = + var a = JsAssoc[cstring, int]{a: 2} + + for z, b in a: + echo z, " <- ", b + +f() diff --git a/tests/js/t7534.nim b/tests/js/t7534.nim new file mode 100644 index 000000000..64aadb8d6 --- /dev/null +++ b/tests/js/t7534.nim @@ -0,0 +1,7 @@ +proc f(x: int): int = + result = case x + of 1: 2 + elif x == 2: 3 + else: 1 + +doAssert 2 == f(f(f(f(1)))) diff --git a/tests/js/t8231.nim b/tests/js/t8231.nim new file mode 100644 index 000000000..b0625a621 --- /dev/null +++ b/tests/js/t8231.nim @@ -0,0 +1,3 @@ +import strutils + +doAssert formatSize(2462056448, '.', bpIEC, false) == "2.293GiB" \ No newline at end of file diff --git a/tests/js/t8821.nim b/tests/js/t8821.nim new file mode 100644 index 000000000..38c88efa8 --- /dev/null +++ b/tests/js/t8821.nim @@ -0,0 +1,9 @@ + +proc isInt32(i: int): bool = + case i + of 1 .. 70000: + return true + else: + return false + +doAssert isInt32(1) == true \ No newline at end of file diff --git a/tests/js/t8914.nim b/tests/js/t8914.nim new file mode 100644 index 000000000..ff716b42a --- /dev/null +++ b/tests/js/t8914.nim @@ -0,0 +1,12 @@ +discard """ + output: ''' +@[42] +@[24, 42] +''' +""" + +var x = @[42,4242] +x.delete(1) +echo x +x.insert(24) +echo x diff --git a/tests/js/t9410.nim b/tests/js/t9410.nim new file mode 100644 index 000000000..042520dc5 --- /dev/null +++ b/tests/js/t9410.nim @@ -0,0 +1,471 @@ +template tests = + block: + var i = 0 + i = 2 + + var y: ptr int + doAssert y == nil + doAssert isNil(y) + y = i.addr + y[] = 3 + doAssert i == 3 + doAssert i == y[] + + let z = i.addr + z[] = 4 + doAssert i == 4 + doAssert i == y[] and y[] == z[] + + var hmm = (a: (b: z)) + var hmmptr = hmm.a.b.addr + hmmptr[][] = 5 + + doAssert i == 5 + doAssert y == z + doAssert z == hmmptr[] + doAssert 5 == y[] and 5 == z[] and 5 == hmmptr[][] + + block: + var someint = 500 + + let p: ptr int = someint.addr + let tup = (f: p) + let tcopy = tup + var vtcopy = tcopy + p[] = 654 + doAssert p[] == 654 + doAssert tup.f[] == 654 + doAssert tcopy.f[] == 654 + doAssert vtcopy.f[] == 654 + + block: + var someint = 500 + + var p: ptr int = someint.addr + let arr = [p] + let arrc = arr + p[] = 256 + doAssert someint == 256 + doAssert p[] == 256 + doAssert arr[0][] == 256 + doAssert arrc[0][] == 256 + + block: + var someref: ref int + new(someref) + var someref2 = someref + + var tup1 = (f: someref) + tup1.f = someref + let tup2 = tup1 + + someref[] = 543 + + proc passref(r: var ref int): var ref int = r + new(passref(someref)) + + doAssert someref[] == 0 + doAssert tup1.f[] == 543 + doAssert tup2.f[] == 543 + doAssert someref2[] == 543 + + block: + type Whatever = object + i: ref int + + var someref: ref int + new(someref) + someref[] = 10 + + let w = Whatever(i: someref) + var wcopy = w + + someref[] = 20 + + doAssert w.i[] == 20 + doAssert someref[] == 20 + doAssert wcopy.i[] == 20 + doAssert w.i == wcopy.i + #echo w.i[], " ", someref[], " ", wcopy.i[] + + block: + var oneseq: ref seq[ref int] + new(oneseq) + var aref: ref int + new(aref) + aref[] = 123 + let arefs = [aref] + oneseq[] &= arefs[0] + oneseq[] &= aref + aref[] = 222 + new(aref) + doAssert oneseq[0] == oneseq[1] + doAssert oneseq[0][] == 222 + doAssert oneseq[1][] == 222 + doAssert aref[] == 0 + + block: + var seqs: ref seq[ref seq[ref int]] + new(seqs) + seqs[] = newSeq[ref seq[ref int]](1) + new(seqs[0]) + seqs[0][] = newSeq[ref int](0) + + var aref: ref int + new aref + aref[] = 654 + + let arefs = [aref] + doAssert arefs[0] == aref + seqs[0][] &= arefs[0] + seqs[0][] &= aref + seqs[0][1][] = 456 + let seqs2 = seqs + let same = seqs2[0][0] == seqs2[0][1] + doAssert arefs[0] == aref + doAssert aref[] == 456 + doAssert seqs[].len == 1 + doAssert seqs[0][].len == 2 + doAssert seqs[0][0][] == 456 + doAssert seqs[0][1][] == 456 + doAssert same + + block: + type Obj = object + x, y: int + + var objrefs: seq[ref Obj] = @[(ref Obj)(nil), nil, nil] + objrefs[2].new + objrefs[2][] = Obj(x: 123, y: 321) + objrefs[1] = objrefs[2] + doAssert objrefs[0] == nil + doAssert objrefs[1].y == 321 + doAssert objrefs[2].y == 321 + doAssert objrefs[1] == objrefs[2] + + block: + var refs: seq[ref string] = @[(ref string)(nil), nil, nil] + refs[1].new + refs[1][] = "it's a ref!" + refs[0] = refs[1] + refs[2] = refs[1] + new(refs[0]) + doAssert refs[0][] == "" + doAssert refs[1][] == "it's a ref!" + doAssert refs[2][] == "it's a ref!" + doAssert refs[1] == refs[2] + + block: + var retaddr_calls = 0 + proc retaddr(p: var int): var int = + retaddr_calls += 1 + p + + var tfoo_calls = 0 + proc tfoo(x: var int) = + tfoo_calls += 1 + x += 10 + var y = x.addr + y[] += 20 + retaddr(x) += 30 + let z = retaddr(x).addr + z[] += 40 + + var ints = @[1, 2, 3] + tfoo(ints[1]) + doAssert retaddr_calls == 2 + doAssert tfoo_calls == 1 + doAssert ints[1] == 102 + + var tbar_calls = 0 + proc tbar(x: var int): var int = + tbar_calls += 1 + x + + tbar(ints[2]) += 10 + tbar(ints[2]) *= 2 + doAssert tbar_calls == 2 + + var tqux_calls = 0 + proc tqux(x: var int): ptr int = + tqux_calls += 1 + x.addr + + discard tqux(ints[2]) == tqux(ints[2]) + doAssert tqux_calls == 2 + doAssert isNil(tqux(ints[2])) == false + doAssert tqux_calls == 3 + + var tseq_calls = 0 + proc tseq(x: var seq[int]): var seq[int] = + tseq_calls += 1 + x + + tseq(ints) &= 999 + doAssert tseq_calls == 1 + doAssert ints == @[1, 102, 26, 999] + + var rawints = @[555] + rawints &= 666 + doAssert rawints == @[555, 666] + + var resetints_calls = 0 + proc resetInts(): int = + resetints_calls += 1 + ints = @[0, 0, 0] + 1 + + proc incr(x: var int; b: int): var int = + x = x + b + x + + var q = 0 + var qp = q.addr + qp[] += 123 + doAssert q == 123 + # check order of evaluation + doAssert (resetInts() + incr(q, tqux(ints[2])[])) == 124 + + block: # reset + var calls = 0 + proc passsomething(x: var int): var int = + calls += 1 + x + + var + a = 123 + b = 500 + c = a.addr + reset(passsomething(a)) + doAssert calls == 1 + reset(b) + doAssert a == b + reset(c) + doAssert c == nil + + block: # strings + var calls = 0 + proc stringtest(s: var string): var string = + calls += 1 + s + + var somestr: string + + stringtest(somestr) &= 'a' + stringtest(somestr) &= 'b' + doAssert calls == 2 + doAssert somestr == "ab" + stringtest(somestr) &= "woot!" + doAssert somestr == "abwoot!" + doAssert calls == 3 + + doAssert stringtest(somestr).len == 7 + doAssert calls == 4 + doAssert high(stringtest(somestr)) == 6 + doAssert calls == 5 + + var somestr2: string + stringtest(somestr2).setLen(stringtest(somestr).len) + doAssert calls == 7 + doAssert somestr2.len == somestr.len + + var somestr3: string + doAssert (somestr3 & "foo") == "foo" + + block: + var a, b, c, d: string + d = a & b & c + doAssert d == "" + d = stringtest(a) & stringtest(b) & stringtest(c) + doAssert calls == 10 + doAssert d == "" + + block: # seqs + var calls = 0 + proc seqtest(s: var seq[int]): var seq[int] = + calls += 1 + s + + var someseq: seq[int] + + seqtest(someseq) &= 1 + seqtest(someseq) &= 2 + doAssert calls == 2 + doAssert someseq == @[1, 2] + seqtest(someseq) &= @[3, 4, 5] + doAssert someseq == @[1, 2, 3, 4, 5] + doAssert calls == 3 + + doAssert seqtest(someseq).len == 5 + doAssert calls == 4 + doAssert high(seqtest(someseq)) == 4 + doAssert calls == 5 + + # genArrayAddr + doAssert seqtest(someseq)[2] == 3 + doAssert calls == 6 + + seqtest(someseq).setLen(seqtest(someseq).len) + doAssert calls == 8 + + var somenilseq: seq[int] + seqtest(somenilseq).setLen(3) + doAssert calls == 9 + doAssert somenilseq[1] == 0 + + someseq = @[1, 2, 3] + doAssert (seqtest(someseq) & seqtest(someseq)) == @[1, 2, 3, 1, 2, 3] + + + block: # mInc, mDec + var calls = 0 + proc someint(x: var int): var int = + calls += 1 + x + + var x = 10 + + inc(someint(x)) + doAssert x == 11 + doAssert calls == 1 + + dec(someint(x)) + doAssert x == 10 + doAssert calls == 2 + + block: # uints + var calls = 0 + proc passuint(x: var uint32): var uint32 = + calls += 1 + x + + var u: uint32 = 5 + passuint(u) += 1 + doAssert u == 6 + doAssert calls == 1 + + passuint(u) -= 1 + doAssert u == 5 + doAssert calls == 2 + + passuint(u) *= 2 + doAssert u == 10 + doAssert calls == 3 + + block: # objs + type Thing = ref object + x, y: int + + var a, b: Thing + a = Thing() + b = a + + doAssert a == b + + var calls = 0 + proc passobj(o: var Thing): var Thing = + calls += 1 + o + + passobj(b) = Thing(x: 123) + doAssert calls == 1 + doAssert a != b + doAssert b.x == 123 + + var passobjptr_calls = 0 + proc passobjptr(o: var Thing): ptr Thing = + passobjptr_calls += 1 + o.addr + + passobjptr(b)[] = Thing(x: 234) + doAssert passobjptr_calls == 1 + doAssert a != b + doAssert b.x == 234 + passobjptr(b)[].x = 500 + doAssert b.x == 500 + + var pptr = passobjptr(b) + pptr.x += 100 + doAssert b.x == 600 + + proc getuninitptr(): ptr int = + return + + doAssert getuninitptr() == nil + + block: # pointer casting + var obj = (x: 321, y: 543) + var x = 500 + + var objptr = obj.addr + var xptr = x.addr + + var p1, p2: pointer + p1 = cast[pointer](objptr) + p2 = cast[pointer](xptr) + doAssert p1 != p2 + + p1 = cast[pointer](objptr) + p2 = cast[pointer](objptr) + doAssert p1 == p2 + + let objptr2 = cast[type(objptr)](p2) + doAssert objptr == objptr2 + + p1 = cast[pointer](xptr) + p2 = cast[pointer](xptr) + doAssert p1 == p2 + + let xptr2 = cast[type(xptr)](p2) + doAssert xptr == xptr2 + + block: # var types + block t10202: + type Point = object + x: float + y: float + + var points: seq[Point] + + points.add(Point(x:1, y:2)) + + for i, p in points.mpairs: + p.x += 1 + + doAssert points[0].x == 2 + + block: + var ints = @[1, 2, 3] + for i, val in mpairs ints: + val *= 10 + doAssert ints == @[10, 20, 30] + + block: + var seqOfSeqs = @[@[1, 2], @[3, 4]] + for i, val in mpairs seqOfSeqs: + val[0] *= 10 + doAssert seqOfSeqs == @[@[10, 2], @[30, 4]] + + when false: + block: # openArray + # Error: internal error: genAddr: nkStmtListExpr + var calls = 0 + proc getvarint(x: var openArray[int]): var int = + calls += 1 + if true: + x[1] + else: + x[0] + + var arr = [1, 2, 3] + getvarint(arr) += 5 + doAssert calls == 1 + doAssert arr[1] == 7 + +proc tests_in_proc = + tests + +# since pointers are handled differently in global/local contexts +# let's just run all of them twice +tests_in_proc() +tests diff --git a/tests/js/tarrayboundscheck.nim b/tests/js/tarrayboundscheck.nim new file mode 100644 index 000000000..d8bf8de97 --- /dev/null +++ b/tests/js/tarrayboundscheck.nim @@ -0,0 +1,50 @@ +discard """ + output: '''idx out of bounds: -1 +month out of bounds: 0 +Jan +Feb +Mar +Apr +May +Jun +Jul +Aug +Sep +Oct +Nov +Dec +month out of bounds: 13 +idx out of bounds: 14 +''' +""" + +{.push boundChecks:on.} + +# see issue #6532: +# js backend 0.17.3: array bounds check for non zero based arrays is buggy + +proc test_arrayboundscheck() = + var months: array[1..12, string] = + ["Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] + + var indices = [0,1,2,3,4,5,6,7,8,9,10,11,12,13] + + for i in -1 .. 14: + try: + let idx = indices[i] + try: + echo months[idx] + except: + echo "month out of bounds: ", idx + except: + echo "idx out of bounds: ", i + + # #13966 + var negativeIndexed: array[-2..2, int] = [0, 1, 2, 3, 4] + negativeIndexed[-1] = 2 + negativeIndexed[1] = 2 + doAssert negativeIndexed == [0, 2, 2, 2, 4] + +test_arrayboundscheck() +{.pop.} \ No newline at end of file diff --git a/tests/js/tasyncjs.nim b/tests/js/tasyncjs.nim new file mode 100644 index 000000000..f3b273c44 --- /dev/null +++ b/tests/js/tasyncjs.nim @@ -0,0 +1,107 @@ +discard """ + output: ''' +x +e +done +''' +""" + +#[ +xxx move this to tests/stdlib/tasyncjs.nim +]# + +import std/asyncjs + +block: + # demonstrate forward definition for js + proc y(e: int): Future[string] {.async.} + + proc e: int {.discardable.} = + echo "e" + return 2 + + proc x(e: int): Future[void] {.async.} = + var s = await y(e) + if e > 2: + return + echo s + e() + + proc y(e: int): Future[string] {.async.} = + if e > 0: + return await y(0) + else: + return "x" + + discard x(2) + +import std/sugar +from std/strutils import contains + +var witness: seq[string] + +proc fn(n: int): Future[int] {.async.} = + if n >= 7: + raise newException(ValueError, "foobar: " & $n) + if n > 0: + var ret = 1 + await fn(n-1) + witness.add $(n, ret) + return ret + else: + return 10 + +proc asyncFact(n: int): Future[int] {.async.} = + if n > 0: result = n * await asyncFact(n-1) + else: result = 1 + +proc asyncIdentity(n: int): Future[int] {.async.} = + if n > 0: result = 1 + await asyncIdentity(n-1) + else: result = 0 + +proc main() {.async.} = + block: # then + let x = await fn(4) + .then((a: int) => a.float) + .then((a: float) => $a) + doAssert x == "14.0" + doAssert witness == @["(1, 11)", "(2, 12)", "(3, 13)", "(4, 14)"] + + doAssert (await fn(2)) == 12 + + let x2 = await fn(4).then((a: int) => (discard)).then(() => 13) + doAssert x2 == 13 + + let x4 = await asyncFact(3).then(asyncIdentity).then(asyncIdentity).then((a:int) => a * 7).then(asyncIdentity) + doAssert x4 == 3 * 2 * 7 + + block: # bug #17177 + proc asyncIdentityNested(n: int): Future[int] {.async.} = return n + let x5 = await asyncFact(3).then(asyncIdentityNested) + doAssert x5 == 3 * 2 + + when false: # xxx pending bug #17254 + let x6 = await asyncFact(3).then((a:int) {.async.} => a * 11) + doAssert x6 == 3 * 2 * 11 + + block: # catch + var reason: Error + await fn(6).then((a: int) => (witness.add $a)).catch((r: Error) => (reason = r)) + doAssert reason == nil + + await fn(7).then((a: int) => (discard)).catch((r: Error) => (reason = r)) + doAssert reason != nil + doAssert reason.name == "Error" + doAssert "foobar: 7" in $reason.message + echo "done" # justified here to make sure we're running this, since it's inside `async` + +block asyncPragmaInType: + type Handler = proc () {.async.} + proc foo() {.async.} = discard + var x: Handler = foo + +block: # 13341 + proc f {.async.} = + proc g: int = + result = 123 + +discard main() diff --git a/tests/js/tasyncjs_bad.nim b/tests/js/tasyncjs_bad.nim new file mode 100644 index 000000000..b1e5a7bc3 --- /dev/null +++ b/tests/js/tasyncjs_bad.nim @@ -0,0 +1,22 @@ +discard """ + exitCode: 1 + outputsub: "Error: unhandled exception: foobar: 13" +""" + +# note: this needs `--unhandled-rejections=strict`, see D20210217T215950 + +import std/asyncjs +from std/sugar import `=>` + +proc fn(n: int): Future[int] {.async.} = + if n >= 7: raise newException(ValueError, "foobar: " & $n) + else: result = n + +proc main() {.async.} = + let x1 = await fn(6) + doAssert x1 == 6 + await fn(7).catch((a: Error) => (discard)) + let x3 = await fn(13) + doAssert false # shouldn't go here, should fail before + +discard main() diff --git a/tests/js/tasyncjs_pragma.nim b/tests/js/tasyncjs_pragma.nim new file mode 100644 index 000000000..2b6f32e92 --- /dev/null +++ b/tests/js/tasyncjs_pragma.nim @@ -0,0 +1,29 @@ +discard """ + output: ''' +0 +t +''' +""" + +# xxx merge into tasyncjs.nim + +import asyncjs, macros + +macro f*(a: untyped): untyped = + assert a.kind == nnkProcDef + result = nnkProcDef.newTree(a.name, a[1], a[2], a.params, a.pragma, a[5], nnkStmtList.newTree()) + let call = quote: + echo 0 + result.body.add(call) + for child in a.body: + result.body.add(child) + #echo result.body.repr + +proc t* {.async, f.} = + echo "t" + +proc t0* {.async.} = + await t() + +discard t0() + diff --git a/tests/js/tbasics.nim b/tests/js/tbasics.nim new file mode 100644 index 000000000..ef84f8bb5 --- /dev/null +++ b/tests/js/tbasics.nim @@ -0,0 +1,62 @@ +discard """ + output: '''ABCDC +1 +14 +ok +1''' +""" + +type + MyEnum = enum + A,B,C,D +# trick the optimizer with an seq: +var x = @[A,B,C,D] +echo x[0],x[1],x[2],x[3],MyEnum(2) + +# bug #10651 + +var xa: seq[int] +var ya = @[1,2] +xa &= ya +echo xa[0] + +proc test = + var yup: seq[int] + try: + yup.add 14 + echo yup.pop + finally: + discard + +test() + +when true: + var a: seq[int] + + a.setLen(0) + + echo "ok" + +# bug #10697 +proc test2 = + var val = uint16(0) + var i = 0 + if i < 2: + val += uint16(1) + echo int(val) + +test2() + + +var someGlobal = default(array[5, int]) +for x in someGlobal: doAssert(x == 0) + +proc tdefault = + var x = default(int) + doAssert(x == 0) + proc inner(v: openArray[string]) = + doAssert(v.len == 0) + + inner(default(seq[string])) + +tdefault() diff --git a/tests/js/tbigint_backend.nim b/tests/js/tbigint_backend.nim new file mode 100644 index 000000000..8f2f6c4f4 --- /dev/null +++ b/tests/js/tbigint_backend.nim @@ -0,0 +1,57 @@ +import std/private/jsutils + + +type JsBigIntImpl {.importc: "bigint".} = int +type JsBigInt = distinct JsBigIntImpl + +doAssert JsBigInt isnot int +func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} +func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} +func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".} +func `==`*(x, y: JsBigInt): bool {.importjs: "(# === #)".} +func inc*(x: var JsBigInt) {.importjs: "[#][0][0]++".} +func inc2*(x: var JsBigInt) {.importjs: "#++".} +func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".} +func `$`*(this: JsBigInt): string = + $toCstring(this) + +block: + doAssert defined(nimHasJsBigIntBackend) + let z1 = big"10" + let z2 = big"15" + doAssert z1 == big"10" + doAssert z1 == z1 + doAssert z1 != z2 + var s: seq[cstring] + for i in z1 .. z2: + s.add $i + doAssert s == @["10".cstring, "11", "12", "13", "14", "15"] + block: + var a=big"3" + a.inc + doAssert a == big"4" + block: + var z: JsBigInt + doAssert $z == "0" + doAssert z.jsTypeOf == "bigint" # would fail without codegen change + doAssert z != big(1) + doAssert z == big"0" # ditto + + # ditto below + block: + let z: JsBigInt = big"1" + doAssert $z == "1" + doAssert z.jsTypeOf == "bigint" + doAssert z == big"1" + + block: + let z = JsBigInt.default + doAssert $z == "0" + doAssert z.jsTypeOf == "bigint" + doAssert z == big"0" + + block: + var a: seq[JsBigInt] + a.setLen 3 + doAssert a[^1].jsTypeOf == "bigint" + doAssert a[^1] == big"0" diff --git a/tests/js/tbyvar.nim b/tests/js/tbyvar.nim new file mode 100644 index 000000000..93724a2f1 --- /dev/null +++ b/tests/js/tbyvar.nim @@ -0,0 +1,123 @@ +discard """ + output: ''' +foo 12 +bar 12 +2 +foo 12 +bar 12 +2 +12.5 +(nums: @[5.0, 5.0, 10.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) +(nums: @[5.0, 5.0, 50.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) +(nums: @[5.0, 5.0, 45.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) +(nums: @[5.0, 5.0, 9.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) +asd +''' +""" + +# bug #1489 +proc foo(x: int) = echo "foo ", x +proc bar(y: var int) = echo "bar ", y + +var x = 12 +foo(x) +bar(x) + +# bug #1490 +var y = 1 +y *= 2 +echo y + +proc main = + var x = 12 + foo(x) + bar(x) + + var y = 1 + y *= 2 + echo y + +main() + +# Test: pass var seq to var openArray +var s = @[2, 1] +proc foo(a: var openArray[int]) = a[0] = 123 + +proc bar(s: var seq[int], a: int) = + doAssert(a == 5) + foo(s) +s.bar(5) +doAssert(s == @[123, 1]) + +import tables +block: # Test get addr of byvar return value + var t = initTable[string, int]() + t["hi"] = 5 + let a = addr t["hi"] + a[] = 10 + doAssert(t["hi"] == 10) + +block: # Test var arg inside case expression. #5244 + proc foo(a: var string) = + a = case a + of "a": "error" + of "b": "error" + else: a + var a = "ok" + foo(a) + doAssert(a == "ok") + + +proc mainowar = + var x = 9.0 + x += 3.5 + echo x + +mainowar() + + +# bug #5608 + +type Foo = object + nums : seq[float] + +proc newFoo(len : int, default = 0.0) : Foo = + result = Foo() + result.nums = newSeq[float](len) + for i in 0..(len - 1): + result.nums[i] = default + +proc `[]=`(f : var Foo, i : int, v : float) = + f.nums[i] = v + +proc `[]`(f : Foo, i : int) : float = f.nums[i] + +proc `[]`(f : var Foo, i : int) : var float = f.nums[i] + +var f = newFoo(10,5) + +f[2] += 5 +echo f +f[2] *= 5 +echo f +f[2] -= 5 +echo f +f[2] /= 5 +echo f + +# regression for #5608 +import tables + +type + SomeObj = ref object + s: cstring + +var a = initTable[cstring, Table[cstring, SomeObj]]() + +var b = initTable[cstring, SomeObj]() + +b.add(cstring"b", SomeObj(s: cstring"asd")) + +a.add(cstring"a", b) + +echo a[cstring"a"][cstring"b"].s diff --git a/tests/js/tclosures.nim b/tests/js/tclosures.nim new file mode 100644 index 000000000..4f1c28de3 --- /dev/null +++ b/tests/js/tclosures.nim @@ -0,0 +1,95 @@ +discard """ + action: run +""" + +import random, strutils +const consolePrefix = "jsCallbacks" + +asm """ + var callback = [] + function regCallback (fn) { callback.push (fn); } + function runCallbacks () { + var result = "\n" + var n = 0 + for (var fn in callback) { + n += 1 + result += "("+String (n)+")" + result += callback [fn] () + result += "\n" + } + return result + } + function print (text) { console.log (text); } +""" + +proc consoleprint (str:cstring): void {.importc: "print", nodecl.} +proc print* (a: varargs[string, `$`]) = consoleprint "$1: $2" % [consolePrefix, join(a, " ")] + +type CallbackProc {.importc.} = proc () : cstring + +proc regCallback (fn:CallbackProc) {.importc.} +proc runCallbacks ():cstring {.importc.} + +proc `*` (s:string, n:Natural) : string = s.repeat(n) + +proc outer (i:Natural) : (string, int) = + let c = $char(rand(93) + 33) + let n = rand(40) + let s = c * n + proc inner(): cstring = ("[$1]" % $n) & s & " <--" + regCallback(inner) + return (s, n) + +var expected = "\n" +for i in 1 .. 10: + let (s, n) = outer(i) + expected &= ("($1)[$2]" % [$i, $n]) & s & " <--" + expected &= "\n" + +let results = runCallbacks() + +doAssert(expected == $results) + +block issue7048: + block: + proc foo(x: seq[int]): auto = + proc bar: int = x[1] + bar + + var stuff = @[1, 2] + let f = foo(stuff) + stuff[1] = 321 + doAssert f() == 2 + + block: + proc foo(x: tuple[things: string]; y: array[3, int]): auto = + proc very: auto = + proc deeply: auto = + proc nested: (char, int) = (x.things[0], y[1]) + nested + deeply + very() + + var + stuff = (things: "NIM") + stuff2 = [32, 64, 96] + let f = foo(stuff, stuff2) + stuff.things = "VIM" + stuff2[1] *= 10 + doAssert f()() == ('N', 64) + doAssert (stuff.things[0], stuff2[1]) == ('V', 640) + + block: + proc foo(x: ptr string): auto = + proc bar(): int = len(x[]) + bar + + var + s1 = "xyz" + s2 = "stuff" + p = addr s1 + + let f = foo(p) + p = addr s2 + doAssert len(p[]) == 5 + doAssert f() == 3 diff --git a/tests/js/tcodegendeclproc.nim b/tests/js/tcodegendeclproc.nim new file mode 100644 index 000000000..33064bdf1 --- /dev/null +++ b/tests/js/tcodegendeclproc.nim @@ -0,0 +1,11 @@ +discard """ + output: ''' +-1 +8 +''' + ccodecheck: "'console.log(-1); function fac__tcodegendeclproc_u1(n_p0)'" +""" +proc fac(n: int): int {.codegenDecl: "console.log(-1); function $2($3)".} = + return n + +echo fac(8) diff --git a/tests/js/tcodegendeclvar.nim b/tests/js/tcodegendeclvar.nim new file mode 100644 index 000000000..645443ef7 --- /dev/null +++ b/tests/js/tcodegendeclvar.nim @@ -0,0 +1,10 @@ +discard """ + output: ''' +-1 +2 +''' + ccodecheck: "'console.log(-1); var v_' \\d+ ' = [2]'" +""" + +var v {.codegenDecl: "console.log(-1); var $2".} = 2 +echo v diff --git a/tests/js/tconsole.nim b/tests/js/tconsole.nim new file mode 100644 index 000000000..88c71ea18 --- /dev/null +++ b/tests/js/tconsole.nim @@ -0,0 +1,13 @@ +discard """ + output: ''' +Hello, console +1 2 3 +''' +""" + +# This file tests the JavaScript console + +import jsconsole + +console.log("Hello, console") +console.log(1, 2, 3) diff --git a/tests/js/tcopying.nim b/tests/js/tcopying.nim new file mode 100644 index 000000000..306d25090 --- /dev/null +++ b/tests/js/tcopying.nim @@ -0,0 +1,80 @@ +discard """ + output: '''123 +2 9 +2 9 +1 124 +true false +100 300 100 +1 +1 +''' +""" + +type MyArray = array[1, int] + +proc changeArray(a: var MyArray) = + a = [123] + +var a: MyArray +changeArray(a) +echo a[0] + +# bug #4703 +# Test 1 +block: + let ary1 = [1, 2, 3] + var ary2 = ary1 + + ary2[1] = 9 + + echo ary1[1], " ", ary2[1] + +# Test 2 +block: + type TestObj = ref object of RootObj + ary2: array[3, int] + + let ary1 = [1, 2, 3] + var obj = TestObj(ary2: ary1) + + obj.ary2[1] = 9 + + echo ary1[1], " ", obj.ary2[1] + +block: + type TestObj = object + x, y: int + + let obj = TestObj(x: 1, y: 2) + var s = @[obj] + s[0].x += 123 + echo obj.x, " ", s[0].x + +block: + var nums = {1, 2, 3, 4} + let obj = (n: nums) + nums.incl 5 + echo (5 in nums), " ", (5 in obj.n) + +block: + let tup1 = (a: 100) + var tup2 = (t: (t2: tup1)) + var tup3 = tup1 + tup2.t.t2.a = 300 + echo tup1.a, " ", tup2.t.t2.a, " ", tup3.a + +block: + proc foo(arr: array[2, int]) = + var s = @arr + s[0] = 500 + + var nums = [1, 2] + foo(nums) + echo nums[0] + +proc bug9674 = + var b = @[1,2,3] + var a = move(b) + echo a[0] + +bug9674() diff --git a/tests/js/tcsymbol.nim b/tests/js/tcsymbol.nim new file mode 100644 index 000000000..07e52b9b6 --- /dev/null +++ b/tests/js/tcsymbol.nim @@ -0,0 +1,6 @@ +discard """ + matrix: "--cc:gcc; --cc:tcc" +""" + +doAssert not defined(gcc) +doAssert not defined(tcc) \ No newline at end of file diff --git a/tests/js/tdanger.nim b/tests/js/tdanger.nim new file mode 100644 index 000000000..9088859a8 --- /dev/null +++ b/tests/js/tdanger.nim @@ -0,0 +1,17 @@ +discard """ + matrix: ";--d:danger" +""" + +block: + proc foo() = + var name = int64(12) + var x = uint32(name) + var m = x + 12 + + var y = int32(name) + var n = y + 1 + + doAssert m == uint32(n + 11) + + + foo() diff --git a/tests/js/tderef.nim b/tests/js/tderef.nim new file mode 100644 index 000000000..ddb91bd42 --- /dev/null +++ b/tests/js/tderef.nim @@ -0,0 +1,20 @@ +discard """ + output: '''true +''' +""" + +import tables + +type EventStore = Table[string, seq[proc ()]] + +proc newEventStore(): EventStore = + initTable[string, seq[proc ()]]() + +proc register(store: var EventStore, name: string, callback: proc ()) = + if not store.hasKey(name): + store[name] = @[] + store[name].add(callback) + +var store = newEventStore() +store.register("test", proc () = echo "true") +store["test"][0]() diff --git a/tests/js/tdiscard.nim b/tests/js/tdiscard.nim new file mode 100644 index 000000000..9aa6ea1b1 --- /dev/null +++ b/tests/js/tdiscard.nim @@ -0,0 +1,3 @@ +import dom + +discard Node() \ No newline at end of file diff --git a/tests/js/tdollar_float.nim b/tests/js/tdollar_float.nim new file mode 100644 index 000000000..4fd8e3cba --- /dev/null +++ b/tests/js/tdollar_float.nim @@ -0,0 +1,62 @@ +#[ +merge into tests/system/tdollars.nim once https://github.com/nim-lang/Nim/pull/14122 +is merged +]# + +import unittest + +block: # https://github.com/timotheecour/Nim/issues/133 + # simple test + var a: float = 2 + check $a == "2.0" + + # systematic tests + template fun(a2: static float) = + const a: float = a2 # needed pending https://github.com/timotheecour/Nim/issues/132 + var b = a + check $b == $a + + fun 2 + fun 2.0 + fun 2.1 + fun 1_000 + fun 1_000.1 + fun 1_000_000_000.1 + fun 1_000_000_000_000.1 + + # negatives + fun -2.0 + fun -2.1 + + # 0 + fun 0 + fun -0 + fun 0.0 + + block: + var a = -0.0 + check $a in ["-0.0", "0.0"] + + # exponents + block: + var a = 5e20 + check $a in ["5e20", "500000000000000000000.0"] + + fun 3.4e1'f32 + fun 3.4e-1'f32 + fun -3.4e-1'f32 + fun 3.4e-1'f32 + fun 3e-1'f32 + + block: + var a = 3.4e38'f32 + check $a in ["3.4e+38", "3.4e+038"] + # on windows, printf (used in VM) prints as 3.4e+038 + # but js prints as 3.4e+38 + # on osx, both print as 3.4e+38 + # see https://github.com/timotheecour/Nim/issues/138 + + when false: # edge cases + fun -0.0 # see https://github.com/timotheecour/Nim/issues/136 + fun 5e20 + fun 3.4e38'f32 diff --git a/tests/js/temptyseq.nim b/tests/js/temptyseq.nim new file mode 100644 index 000000000..6489cf817 --- /dev/null +++ b/tests/js/temptyseq.nim @@ -0,0 +1,8 @@ +# #12671 + +proc foo = + var x: seq[int] + doAssertRaises(IndexDefect): + inc x[0] + +foo() diff --git a/tests/js/tenumhole.nim b/tests/js/tenumhole.nim new file mode 100644 index 000000000..71a493e8c --- /dev/null +++ b/tests/js/tenumhole.nim @@ -0,0 +1,12 @@ +discard """ + output: "first0second32third64" +""" + +type Holed = enum + hFirst = (0,"first") + hSecond = (32,"second") + hThird = (64,"third") + +var x = @[0,32,64] # This is just to avoid the compiler inlining the value of the enum + +echo Holed(x[0]),ord Holed(x[0]),Holed(x[1]),ord Holed(x[1]),Holed(x[2]),ord Holed(x[2]) diff --git a/tests/js/tenumnegkey.nim b/tests/js/tenumnegkey.nim new file mode 100644 index 000000000..f96c554d4 --- /dev/null +++ b/tests/js/tenumnegkey.nim @@ -0,0 +1,12 @@ +discard """ + output: "first-12second32third64" +""" + +type Holed = enum + hFirst = (-12,"first") + hSecond = (32,"second") + hThird = (64,"third") + +var x = @[-12,32,64] # This is just to avoid the compiler inlining the value of the enum + +echo Holed(x[0]),ord Holed(x[0]),Holed(x[1]),ord Holed(x[1]),Holed(x[2]),ord Holed(x[2]) diff --git a/tests/js/tenumoffset.nim b/tests/js/tenumoffset.nim new file mode 100644 index 000000000..5bdc4c105 --- /dev/null +++ b/tests/js/tenumoffset.nim @@ -0,0 +1,19 @@ +discard """ + output: "my value A1my value Bconc2valueCabc4abc" +""" + +const + strValB = "my value B" + +type + TMyEnum = enum + valueA = (1, "my value A"), + valueB = strValB & "conc", + valueC, + valueD = (4, "abc") + +proc getValue(i:int): TMyEnum = TMyEnum(i) + +# trick the optimizer with a variable: +var x = getValue(4) +echo getValue(1), ord(valueA), getValue(2), ord(valueB), getValue(3), getValue(4), ord(valueD), x diff --git a/tests/js/test1.nim b/tests/js/test1.nim new file mode 100644 index 000000000..7ad3f85f6 --- /dev/null +++ b/tests/js/test1.nim @@ -0,0 +1,52 @@ +discard """ + output: "1261129" +""" + +# This file tests the JavaScript generator + +import strutils + +var + inputElement = "1123" + +proc onButtonClick(inputElement: string) {.exportc.} = + let v = $inputElement + if v.allCharsInSet(WhiteSpace): + echo "only whitespace, hu?" + else: + var x = parseInt(v) + echo x*x + +onButtonClick(inputElement) + +block: + var s: string + s.add("hi") + doAssert(s == "hi") + +block: + var s: string + s.insert("hi", 0) + doAssert(s == "hi") + +block: + var s: string + s.setLen(2) + s[0] = 'h' + s[1] = 'i' + doAssert(s == "hi") + +block: + var s: seq[int] + s.setLen(2) + doAssert(s == @[0, 0]) + +block: + var s: seq[int] + s.insert(2, 0) + doAssert(s == @[2]) + +block: + var s: seq[int] + s.add(2) + doAssert(s == @[2]) diff --git a/tests/js/test2.nim b/tests/js/test2.nim new file mode 100644 index 000000000..fa857ccc5 --- /dev/null +++ b/tests/js/test2.nim @@ -0,0 +1,58 @@ +discard """ + output: '''foo +js 3.14 +7 +1 +-21550 +-21550''' +""" + +# This file tests the JavaScript generator + +doAssert getCurrentException() == nil +doAssert getCurrentExceptionMsg() == "" + +# #335 +proc foo() = + var bar = "foo" + proc baz() = + echo bar + baz() +foo() + +# #376 +when not defined(js): + proc foo(val: float): string = "no js " & $val +else: + proc foo(val: float): string = "js " & $val + +echo foo(3.14) + +# #2495 +type C = concept x + +proc test(x: C, T: typedesc): T = + cast[T](x) + +echo 7.test(int8) + +# #4222 +const someConst = [ "1"] + +proc procThatRefersToConst() # Forward decl +procThatRefersToConst() # Call bar before it is defined + +proc procThatRefersToConst() = + var i = 0 # Use a var index, otherwise nim will constfold foo[0] + echo someConst[i] # JS exception here: foo is still not initialized (undefined) + +# bug #6753 +let x = -1861876800 +const y = 86400 +echo (x - (y - 1)) div y # Now gives `-21550` + +proc foo09() = + let x = -1861876800 + const y = 86400 + echo (x - (y - 1)) div y # Still gives `-21551` +foo09() diff --git a/tests/js/testmagic.nim b/tests/js/testmagic.nim new file mode 100644 index 000000000..8e06f1a9b --- /dev/null +++ b/tests/js/testmagic.nim @@ -0,0 +1,12 @@ +discard """ + output: '''true +123 +''' +""" + +# This file tests some magic + +var foo = cstring("foo") +var bar = cstring("foo") +echo(foo == bar) +echo "01234"[1 .. ^2] diff --git a/tests/js/testobjs.nim b/tests/js/testobjs.nim new file mode 100644 index 000000000..b61d06471 --- /dev/null +++ b/tests/js/testobjs.nim @@ -0,0 +1,73 @@ +discard """ + output: '''{"columns":[{"t":null},{"t":null}]} +{"columns":[{"t":null},{"t":null}]} +''' +""" + +## Tests javascript object generation + +type + Kg = distinct float + Price = int + Item = object of RootObj + weight: Kg + price: Price + desc: cstring + Person = object of RootObj + name: cstring + age: int + item: Item + Test = object + name: cstring + Recurse[T] = object + data: T + next: ref Recurse[T] + +var + test = Test(name: "Jorden") + sword = Item(desc: "pointy", weight: Kg(10.0), + price: Price(50)) + knight = Person(name: "robert", age: 19, item: sword) + recurse4 = (ref Recurse[int])(data: 4, next: nil) + recurse3 = (ref Recurse[int])(data: 3, next: recurse4) + recurse2 = (ref Recurse[int])(data: 2, next: recurse3) + recurse1 = Recurse[int](data: 1, next: recurse2) + + +doAssert test.name == cstring"Jorden" +doAssert knight.age == 19 +doAssert knight.item.price == 50 +doAssert recurse1.next.next.data == 3 + +# bug #6035 +proc toJson*[T](data: T): cstring {.importc: "JSON.stringify".} + +type + Column = object + t: ref Column + + Test2 = object + columns: seq[Column] + +var test1 = Test2(columns: @[Column(t: nil), Column(t: nil)]) +let test2 = test1 + +echo toJSON(test1) +echo toJSON(test2) + +block issue10005: + type + Player = ref object of RootObj + id*: string + nickname*: string + color*: string + + proc newPlayer(nickname: string, color: string): Player = + let pl = Player(color: "#123", nickname: nickname) + return Player( + id: "foo", + nickname: nickname, + color: color, + ) + + doAssert newPlayer("foo", "#1232").nickname == "foo" diff --git a/tests/js/testtojsstr.nim b/tests/js/testtojsstr.nim new file mode 100644 index 000000000..03ac89e20 --- /dev/null +++ b/tests/js/testtojsstr.nim @@ -0,0 +1,8 @@ +discard """ + output = "И\n" +""" + +let s: string = "И\n" +let cs = s.cstring + +echo $s diff --git a/tests/js/tfieldchecks.nim b/tests/js/tfieldchecks.nim new file mode 100644 index 000000000..a0679a349 --- /dev/null +++ b/tests/js/tfieldchecks.nim @@ -0,0 +1,48 @@ +discard """ + output: ''' +foo +C +3.14 +foo +3.14 +3.14 +''' +""" + +type + V = enum + A, B, C + X = object + f0: string + case f1: V + of A: f2: string + of B: discard + of C: f3: float + +var obj = X(f0: "foo", f1: C, f3: 3.14) + +block: + echo obj.f0 + echo obj.f1 + doAssertRaises(FieldDefect): echo obj.f2 + echo obj.f3 + +block: + let a0 = addr(obj.f0) + echo a0[] + # let a1 = addr(obj.f1) + # echo a1[] + doAssertRaises(FieldDefect): + let a2 = addr(obj.f2) + echo a2[] + let a3 = addr(obj.f3) + echo a3[] + +# Prevent double evaluation of LHS +block: + var flag = false + proc wrap(x: X): X = + doAssert flag == false + flag = true + result = x + echo wrap(obj).f3 diff --git a/tests/js/tfloatround.nim b/tests/js/tfloatround.nim new file mode 100644 index 000000000..7bc5430e6 --- /dev/null +++ b/tests/js/tfloatround.nim @@ -0,0 +1,7 @@ +discard """ + output: ''' +3 +''' +""" + +echo int(22 / 7) diff --git a/tests/js/tglobal.nim b/tests/js/tglobal.nim new file mode 100644 index 000000000..38f5eec34 --- /dev/null +++ b/tests/js/tglobal.nim @@ -0,0 +1,30 @@ +block global: + proc getState(): int = + var state0 {.global.}: int + inc state0 + result = state0 + + for i in 0 ..< 3: + doAssert getState() == i + 1 + + for i in 0 ..< 3: + once: + doAssert i == 0 + + +block threadvar: + proc getThreadState0(): int = + var state0 {.threadvar.}: int + inc state0 + result = state0 + + for i in 0 ..< 3: + doAssert getThreadState0() == i + 1 + + proc getThreadState1(): int = + var state1 {.threadvar.}: int + inc state1 + result = state1 + + for i in 0 ..< 3: + doAssert getThreadState1() == i + 1 diff --git a/tests/js/timplicit_nodecl.nim b/tests/js/timplicit_nodecl.nim new file mode 100644 index 000000000..79a921815 --- /dev/null +++ b/tests/js/timplicit_nodecl.nim @@ -0,0 +1,13 @@ +discard """ + output: '''22 +22''' +""" + +# test implicit nodecl +block: + {. emit: "var importMe = 22;" .} + var + a {. importc: "importMe" .}: int + importMe {. importc .}: int + echo a + echo importMe diff --git a/tests/js/tindexdefect.nim b/tests/js/tindexdefect.nim new file mode 100644 index 000000000..37994ec2e --- /dev/null +++ b/tests/js/tindexdefect.nim @@ -0,0 +1,9 @@ +discard """ + outputsub: "unhandled exception: index 10000 not in 0 .. 0 [IndexDefect]" + exitcode: 1 + joinable: false +""" + +var s = ['a'] +let z = s[10000] == 'a' +echo z \ No newline at end of file diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim new file mode 100644 index 000000000..f27ea5546 --- /dev/null +++ b/tests/js/tjsffi.nim @@ -0,0 +1,274 @@ +discard """ +matrix: "--legacy:jsnolambdalifting;" +output: ''' +3 +2 +12 +Event { name: 'click: test' } +Event { name: 'reloaded: test' } +Event { name: 'updates: test' } +''' +""" + +import jsffi, jsconsole + +# Tests for JsObject +block: # Test JsObject []= and [] + let obj = newJsObject() + obj["a"] = 11 + obj["b"] = "test" + obj["c"] = "test".cstring + doAssert obj["a"].to(int) == 11 + doAssert obj["c"].to(cstring) == "test".cstring + +block: # Test JsObject .= and . + let obj = newJsObject() + obj.a = 11 + obj.b = "test" + obj.c = "test".cstring + obj.`$!&` = 42 + obj.`while` = 99 + doAssert obj.a.to(int) == 11 + doAssert obj.b.to(string) == "test" + doAssert obj.c.to(cstring) == "test".cstring + doAssert obj.`$!&`.to(int) == 42 + doAssert obj.`while`.to(int) == 99 + +block: # Test JsObject .() + let obj = newJsObject() + obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z) + doAssert obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6" + +block: # Test JsObject []() + let obj = newJsObject() + obj.a = proc(x, y, z: int, t: string): string = t & $(x + y + z) + let call = obj["a"].to(proc(x, y, z: int, t: string): string) + doAssert call(1, 2, 3, "Result is: ") == "Result is: 6" + +# Test JsObject Iterators +block: # testPairs + let obj = newJsObject() + obj.a = 10 + obj.b = 20 + obj.c = 30 + for k, v in obj.pairs: + case $k + of "a": + doAssert v.to(int) == 10 + of "b": + doAssert v.to(int) == 20 + of "c": + doAssert v.to(int) == 30 + else: + doAssert false +block: # testItems + let obj = newJsObject() + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.items: + doAssert v.to(int) in [10, 20, 30] +block: # testKeys + let obj = newJsObject() + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.keys: + doAssert $v in ["a", "b", "c"] + +block: # Test JsObject equality + {. emit: "var comparison = {a: 22, b: 'test'};" .} + var comparison {. importjs, nodecl .}: JsObject + let obj = newJsObject() + obj.a = 22 + obj.b = "test".cstring + doAssert obj.a == comparison.a and obj.b == comparison.b + +block: # Test JsObject literal + {. emit: "var comparison = {a: 22, b: 'test'};" .} + var comparison {. importjs, nodecl .}: JsObject + let obj = JsObject{ a: 22, b: "test".cstring } + doAssert obj.a == comparison.a and obj.b == comparison.b + +# Tests for JsAssoc +block: # Test JsAssoc []= and [] + let obj = newJsAssoc[int, int]() + obj[1] = 11 + doAssert not compiles(obj["a"] = 11) + doAssert not compiles(obj["a"]) + doAssert not compiles(obj[2] = "test") + doAssert not compiles(obj[3] = "test".cstring) + doAssert obj[1] == 11 + +block: # Test JsAssoc .= and . + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 11 + obj.`$!&` = 42 + doAssert not compiles(obj.b = "test") + doAssert not compiles(obj.c = "test".cstring) + doAssert obj.a == 11 + doAssert obj.`$!&` == 42 + +block: # Test JsAssoc .() + let obj = newJsAssoc[cstring, proc(e: int): int]() + obj.a = proc(e: int): int = e * e + doAssert obj.a(10) == 100 + +block: # Test JsAssoc []() + let obj = newJsAssoc[cstring, proc(e: int): int]() + obj.a = proc(e: int): int = e * e + let call = obj["a"] + doAssert call(10) == 100 + +# Test JsAssoc Iterators +block: # testPairs + let obj = newJsAssoc[cstring, int]() + obj.a = 10 + obj.b = 20 + obj.c = 30 + for k, v in obj.pairs: + case $k + of "a": + doAssert v == 10 + of "b": + doAssert v == 20 + of "c": + doAssert v == 30 + else: + doAssert false +block: # testItems + let obj = newJsAssoc[cstring, int]() + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.items: + doAssert v in [10, 20, 30] +block: # testKeys + let obj = newJsAssoc[cstring, int]() + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.keys: + doAssert v in [cstring"a", cstring"b", cstring"c"] + +block: # Test JsAssoc equality + {. emit: "var comparison = {a: 22, b: 55};" .} + var comparison {. importjs, nodecl .}: JsAssoc[cstring, int] + let obj = newJsAssoc[cstring, int]() + obj.a = 22 + obj.b = 55 + doAssert obj.a == comparison.a and obj.b == comparison.b + +block: # Test JsAssoc literal + {. emit: "var comparison = {a: 22, b: 55};" .} + var comparison {. importjs, nodecl .}: JsAssoc[cstring, int] + let obj = JsAssoc[cstring, int]{ a: 22, b: 55 } + doAssert compiles(JsAssoc[int, int]{ 1: 22, 2: 55 }) + doAssert comparison.a == obj.a and comparison.b == obj.b + doAssert not compiles(JsAssoc[cstring, int]{ a: "test" }) + +# Tests for macros on non-JsRoot objects +block: # Test lit + type TestObject = object + a: int + b: cstring + {. emit: "var comparison = {a: 1};" .} + var comparison {. importjs, nodecl .}: TestObject + let obj = TestObject{ a: 1 } + doAssert obj == comparison + +block: # Test bindMethod + type TestObject = object + a: int + onWhatever: proc(e: int): int {.nimcall.} + proc handleWhatever(this: TestObject, e: int): int = + e + this.a + block: + let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever)) + doAssert obj.onWhatever(1) == 10 + +block: + {.emit: "function jsProc(n) { return n; }" .} + proc jsProc(x: int32): JsObject {.importjs: "jsProc(#)".} + block: + var x = jsProc(1) + var y = jsProc(2) + console.log x + y + console.log ++x + + x += jsProc(10) + console.log x + +block: + {.emit: + """ + function Event(name) { this.name = name; } + function on(eventName, eventHandler) { eventHandler(new Event(eventName + ": test")); } + var jslib = { "on": on, "subscribe": on }; + """ + .} + + type Event = object + name: cstring + + proc on(event: cstring, handler: proc) {.importjs: "on(#,#)".} + var jslib {.importjs: "jslib", nodecl.}: JsObject + + on("click") do (e: Event): + console.log e + + jslib.on("reloaded") do (): + console.log jsarguments[0] + + # this test case is different from the above, because + # `subscribe` is not overloaded in the current scope + jslib.subscribe("updates"): + console.log jsarguments[0] + +block: + doAssert jsUndefined == jsNull + doAssert jsUndefined == nil + doAssert jsNull == nil + doAssert jsUndefined.isNil + doAssert jsNull.isNil + doAssert jsNull.isNull + doAssert jsUndefined.isUndefined + +block: # test ** + var a = toJs(0) + var b = toJs(0) + doAssert to(a ** b, int) == 1 + a = toJs(1) + b = toJs(1) + doAssert to(a ** b, int) == 1 + a = toJs(-1) + b = toJs(-1) + doAssert to(a ** b, int) == -1 + a = toJs(6) + b = toJs(6) + doAssert to(a ** b, int) == 46656 + a = toJs(5.5) + b = toJs(3) + doAssert to(a ** b, float) == 166.375 + a = toJs(5) + b = toJs(3.0) + doAssert to(a ** b, float) == 125.0 + a = toJs(7.0) + b = toJS(6.0) + doAssert to(a ** b, float) == 117649.0 + a = toJs(8) + b = toJS(-2) + doAssert to(a ** b, float) == 0.015625 + + a = toJs(1) + b = toJs(1) + doAssert to(`**`(a + a, b), int) == 2 + + doAssert to(`**`(toJs(1) + toJs(1), toJs(2)), int) == 4 + +block: # issue #21208 + type MyEnum = enum baz + var obj: JsObject + {.emit: "`obj` = {bar: {baz: 123}};".} + discard obj.bar.baz diff --git a/tests/js/tjsffi_old.nim b/tests/js/tjsffi_old.nim new file mode 100644 index 000000000..378003f4e --- /dev/null +++ b/tests/js/tjsffi_old.nim @@ -0,0 +1,340 @@ +discard """ +output: ''' +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +3 +2 +12 +Event { name: 'click: test' } +Event { name: 'reloaded: test' } +Event { name: 'updates: test' } +true +true +true +true +true +true +true +''' +""" + +## same as tjsffi, but this test uses the old names: importc and +## importcpp. This test is for backwards compatibility. + +# xxx instead of maintaining this near-duplicate test file, just have tests +# that check that importc, importcpp, importjs work and remove this file. + +import jsffi, jsconsole + +# Tests for JsObject +# Test JsObject []= and [] +block: + proc test(): bool = + let obj = newJsObject() + var working = true + obj["a"] = 11 + obj["b"] = "test" + obj["c"] = "test".cstring + working = working and obj["a"].to(int) == 11 + working = working and obj["c"].to(cstring) == "test".cstring + working + echo test() + +# Test JsObject .= and . +block: + proc test(): bool = + let obj = newJsObject() + var working = true + obj.a = 11 + obj.b = "test" + obj.c = "test".cstring + obj.`$!&` = 42 + obj.`while` = 99 + working = working and obj.a.to(int) == 11 + working = working and obj.b.to(string) == "test" + working = working and obj.c.to(cstring) == "test".cstring + working = working and obj.`$!&`.to(int) == 42 + working = working and obj.`while`.to(int) == 99 + working + echo test() + +# Test JsObject .() +block: + proc test(): bool = + let obj = newJsObject() + obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z) + obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6" + echo test() + +# Test JsObject []() +block: + proc test(): bool = + let obj = newJsObject() + obj.a = proc(x, y, z: int, t: string): string = t & $(x + y + z) + let call = obj["a"].to(proc(x, y, z: int, t: string): string) + call(1, 2, 3, "Result is: ") == "Result is: 6" + echo test() + +# Test JsObject Iterators +block: + proc testPairs(): bool = + let obj = newJsObject() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for k, v in obj.pairs: + case $k + of "a": + working = working and v.to(int) == 10 + of "b": + working = working and v.to(int) == 20 + of "c": + working = working and v.to(int) == 30 + else: + return false + working + proc testItems(): bool = + let obj = newJsObject() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.items: + working = working and v.to(int) in [10, 20, 30] + working + proc testKeys(): bool = + let obj = newJsObject() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.keys: + working = working and $v in ["a", "b", "c"] + working + proc test(): bool = testPairs() and testItems() and testKeys() + echo test() + +# Test JsObject equality +block: + proc test(): bool = + {. emit: "var comparison = {a: 22, b: 'test'};" .} + var comparison {. importc, nodecl .}: JsObject + let obj = newJsObject() + obj.a = 22 + obj.b = "test".cstring + obj.a == comparison.a and obj.b == comparison.b + echo test() + +# Test JsObject literal +block: + proc test(): bool = + {. emit: "var comparison = {a: 22, b: 'test'};" .} + var comparison {. importc, nodecl .}: JsObject + let obj = JsObject{ a: 22, b: "test".cstring } + obj.a == comparison.a and obj.b == comparison.b + echo test() + +# Tests for JsAssoc +# Test JsAssoc []= and [] +block: + proc test(): bool = + let obj = newJsAssoc[int, int]() + var working = true + obj[1] = 11 + working = working and not compiles(obj["a"] = 11) + working = working and not compiles(obj["a"]) + working = working and not compiles(obj[2] = "test") + working = working and not compiles(obj[3] = "test".cstring) + working = working and obj[1] == 11 + working + echo test() + +# Test JsAssoc .= and . +block: + proc test(): bool = + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 11 + obj.`$!&` = 42 + working = working and not compiles(obj.b = "test") + working = working and not compiles(obj.c = "test".cstring) + working = working and obj.a == 11 + working = working and obj.`$!&` == 42 + working + echo test() + +# Test JsAssoc .() +block: + proc test(): bool = + let obj = newJsAssoc[cstring, proc(e: int): int]() + obj.a = proc(e: int): int = e * e + obj.a(10) == 100 + echo test() + +# Test JsAssoc []() +block: + proc test(): bool = + let obj = newJsAssoc[cstring, proc(e: int): int]() + obj.a = proc(e: int): int = e * e + let call = obj["a"] + call(10) == 100 + echo test() + +# Test JsAssoc Iterators +block: + proc testPairs(): bool = + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for k, v in obj.pairs: + case $k + of "a": + working = working and v == 10 + of "b": + working = working and v == 20 + of "c": + working = working and v == 30 + else: + return false + working + proc testItems(): bool = + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.items: + working = working and v in [10, 20, 30] + working + proc testKeys(): bool = + let obj = newJsAssoc[cstring, int]() + var working = true + obj.a = 10 + obj.b = 20 + obj.c = 30 + for v in obj.keys: + working = working and v in [cstring"a", cstring"b", cstring"c"] + working + proc test(): bool = testPairs() and testItems() and testKeys() + echo test() + +# Test JsAssoc equality +block: + proc test(): bool = + {. emit: "var comparison = {a: 22, b: 55};" .} + var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int] + let obj = newJsAssoc[cstring, int]() + obj.a = 22 + obj.b = 55 + obj.a == comparison.a and obj.b == comparison.b + echo test() + +# Test JsAssoc literal +block: + proc test(): bool = + {. emit: "var comparison = {a: 22, b: 55};" .} + var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int] + let obj = JsAssoc[cstring, int]{ a: 22, b: 55 } + var working = true + working = working and + compiles(JsAssoc[int, int]{ 1: 22, 2: 55 }) + working = working and + comparison.a == obj.a and comparison.b == obj.b + working = working and + not compiles(JsAssoc[cstring, int]{ a: "test" }) + working + echo test() + +# Tests for macros on non-JsRoot objects +# Test lit +block: + type TestObject = object + a: int + b: cstring + proc test(): bool = + {. emit: "var comparison = {a: 1};" .} + var comparison {. importc, nodecl .}: TestObject + let obj = TestObject{ a: 1 } + obj == comparison + echo test() + +# Test bindMethod +block: + type TestObject = object + a: int + onWhatever: proc(e: int): int {.nimcall.} + proc handleWhatever(this: TestObject, e: int): int {.nimcall.} = + e + this.a + proc test(): bool = + let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever)) + obj.onWhatever(1) == 10 + echo test() + +block: + {.emit: "function jsProc(n) { return n; }" .} + proc jsProc(x: int32): JsObject {.importc: "jsProc".} + + proc test() = + var x = jsProc(1) + var y = jsProc(2) + console.log x + y + console.log ++x + + x += jsProc(10) + console.log x + + test() + + +block: + {.emit: + """ + function Event(name) { this.name = name; } + function on(eventName, eventHandler) { eventHandler(new Event(eventName + ": test")); } + var jslib = { "on": on, "subscribe": on }; + """ + .} + + type Event = object + name: cstring + + proc on(event: cstring, handler: proc) {.importc: "on".} + var jslib {.importc: "jslib", nodecl.}: JsObject + + on("click") do (e: Event): + console.log e + + jslib.on("reloaded") do (): + console.log jsarguments[0] + + # this test case is different from the above, because + # `subscribe` is not overloaded in the current scope + jslib.subscribe("updates"): + console.log jsarguments[0] + +block: + + echo jsUndefined == jsNull + echo jsUndefined == nil + echo jsNull == nil + echo jsUndefined.isNil + echo jsNull.isNil + echo jsNull.isNull + echo jsUndefined.isUndefined diff --git a/tests/js/tjshello.nim b/tests/js/tjshello.nim new file mode 100644 index 000000000..8e090b3d2 --- /dev/null +++ b/tests/js/tjshello.nim @@ -0,0 +1,10 @@ +discard """ + cmd: "nim $target $options --stackTrace:off --lineTrace:off $file" + output: "Hello World" + maxcodesize: 1000 + ccodecheck: "!@'function'" +""" + +import jsconsole + +console.log "Hello World" diff --git a/tests/js/tjshello_stacktrace.nim b/tests/js/tjshello_stacktrace.nim new file mode 100644 index 000000000..d5e1c36eb --- /dev/null +++ b/tests/js/tjshello_stacktrace.nim @@ -0,0 +1,9 @@ +discard """ + output: "Hello World" + maxcodesize: 4500 + ccodecheck: "!@'function'" +""" + +import jsconsole + +console.log "Hello World" diff --git a/tests/js/tjsnimscombined.nim b/tests/js/tjsnimscombined.nim new file mode 100644 index 000000000..4d3e6c453 --- /dev/null +++ b/tests/js/tjsnimscombined.nim @@ -0,0 +1 @@ +import std/jsffi diff --git a/tests/js/tjsnimscombined.nims b/tests/js/tjsnimscombined.nims new file mode 100644 index 000000000..01b93d3fa --- /dev/null +++ b/tests/js/tjsnimscombined.nims @@ -0,0 +1 @@ +# test the condition where both `js` and `nimscript` are defined (nimscript receives priority) diff --git a/tests/js/tlent.nim b/tests/js/tlent.nim new file mode 100644 index 000000000..2546e5b1d --- /dev/null +++ b/tests/js/tlent.nim @@ -0,0 +1,33 @@ +discard """ + output: ''' +hmm +100 +hmm +100 +''' +""" + +# #16800 + +type A = object + b: int +var t = A(b: 100) +block: + proc getValues: lent int = + echo "hmm" + result = t.b + echo getValues() +block: + proc getValues: lent int = + echo "hmm" + t.b + echo getValues() + +when false: # still an issue, #16908 + template main = + iterator fn[T](a:T): lent T = yield a + let a = @[10] + for b in fn(a): echo b + + static: main() + main() diff --git a/tests/js/tmangle.nim b/tests/js/tmangle.nim new file mode 100644 index 000000000..caaa15fa1 --- /dev/null +++ b/tests/js/tmangle.nim @@ -0,0 +1,106 @@ +discard """ + output: '''true +true +true +true +true +true +true''' +""" + +# Test not mangled: +block: + type T = object + a: int + b: cstring + proc test(): bool = + let obj = T(a: 11, b: "foo") + {. emit: [result, " = (", obj, ".a == 11);"] .} + {. emit: [result, " = ", result, " && (", obj, ".b == \"foo\");"] .} + echo test() + +# Test indirect (fields in genAddr): +block: + type T = object + a: int + b: cstring + var global = T(a: 11, b: "foo") + proc test(): bool = + var obj = T(a: 11, b: "foo") + {. emit: [result, " = (", obj.addr[], ".a == 11);"] .} + {. emit: [result, " = ", result, " && (", obj.addr[], ".b == \"foo\");"] .} + {. emit: [result, " = ", result, " && (", global, ".a == 11);"] .} + {. emit: [result, " = ", result, " && (", global, ".b == \"foo\");"] .} + echo test() + +# Test addr of field: +block: + type T = object + a: int + b: cstring + proc test(): bool = + var obj = T(a: 11, b: "foo") + result = obj.a.addr[] == 11 + result = result and obj.b.addr[] == "foo".cstring + echo test() + +# Test reserved words: +block: + type T = ref object + `if`: int + `for`: int + `==`: cstring + `&&`: cstring + proc test(): bool = + var + obj1 = T(`if`: 11, `for`: 22, `==`: "foo", `&&`: "bar") + obj2: T + new obj2 # Test behaviour for createRecordVarAux. + result = obj1.`if` == 11 + result = result and obj1.addr[].`for` == 22 + result = result and obj1.`==` == "foo".cstring + result = result and obj1.`&&`.addr[] == "bar".cstring + result = result and obj2.`if` == 0 + result = result and obj2.`for` == 0 + result = result and obj2.`==`.isNil + result = result and obj2.`&&`.isNil + echo test() + +# Test codegen for fields with uppercase letters: +block: + type MyObj = object + mField: int + proc test(): bool = + var a: MyObj + var b = a + result = b.mField == 0 + echo test() + +# Test tuples +block: + type T = tuple + a: int + b: int + proc test(): bool = + var a: T = (a: 1, b: 1) + result = a.a == 1 + result = result and a.b == 1 + echo test() + +# Test importc / exportc fields: +block: + type T = object + a: int + b {. importc: "notB" .}: cstring + type U = object + a: int + b {. exportc: "notB" .}: cstring + proc test(): bool = + var + obj1 = T(a: 11, b: "foo") + obj2 = U(a: 11, b: "foo") + {. emit: [result, " = (", obj1, ".a == 11);"] .} + {. emit: [result, " = ", result, " && (", obj1, ".notB == \"foo\");"] .} + {. emit: [result, " = (", obj2, ".a == 11);"] .} + {. emit: [result, " = ", result, " && (", obj2, ".notB == \"foo\");"] .} + echo test() diff --git a/tests/js/tmodify_cstring.nim b/tests/js/tmodify_cstring.nim new file mode 100644 index 000000000..82f8ccb23 --- /dev/null +++ b/tests/js/tmodify_cstring.nim @@ -0,0 +1,6 @@ +discard """ + errormsg: "cstring doesn't support `[]=` operator" +""" + +var x = cstring"abcd" +x[0] = 'x' diff --git a/tests/js/tnativeexc.nim b/tests/js/tnativeexc.nim new file mode 100644 index 000000000..8b2b43e8f --- /dev/null +++ b/tests/js/tnativeexc.nim @@ -0,0 +1,31 @@ +discard """ + action: "run" +""" + +import jsffi + +# Can catch JS exceptions +try: + asm """throw new Error('a new error');""" +except JsError as e: + doAssert e.message == "a new error" +except: + doAssert false + +# Can distinguish different exceptions +try: + asm """JSON.parse(';;');""" +except JsEvalError: + doAssert false +except JsSyntaxError as se: + doAssert se.message == "Unexpected token ';', \";;\" is not valid JSON" +except JsError as e: + doAssert false + +# Can catch parent exception +try: + asm """throw new SyntaxError();""" +except JsError as e: + discard +except: + doAssert false diff --git a/tests/js/tneginthash.nim b/tests/js/tneginthash.nim new file mode 100644 index 000000000..c082405c9 --- /dev/null +++ b/tests/js/tneginthash.nim @@ -0,0 +1,21 @@ +# issue #19929 + +import std/[tables, hashes] + +type Foo = object + a: int + +proc hash(f: Foo): Hash = + var h: Hash = 0 + h = h !& hash(f.a) + result = !$h + +proc transpose[T, S](data: array[T, S]): Table[S, T] = + for i, x in data: + result[x] = i + +const xs = [Foo(a: 5), Foo(a: -5)] +const x = transpose(xs) + +doAssert x[Foo(a: -5)] == 1 +doAssert x[Foo(a: 5)] == 0 diff --git a/tests/js/tnilstrs.nim b/tests/js/tnilstrs.nim new file mode 100644 index 000000000..6c1e4e401 --- /dev/null +++ b/tests/js/tnilstrs.nim @@ -0,0 +1,25 @@ +block: + var x: string + var y = "foo" + + echo x + doAssert x == "" + doAssert "" == x + + add(x, y) + y[0] = 'm' + doAssert y == "moo" and x == "foo" + +block: + var x = "foo".cstring + var y: string + add(y, x) + doAssert y == "foo" + +block: + type Foo = object + a: string + var foo = Foo(a: "foo") + var y = move foo.a + doAssert foo.a.len == 0 + doAssert y == "foo" diff --git a/tests/js/tobjfieldbyvar.nim b/tests/js/tobjfieldbyvar.nim new file mode 100644 index 000000000..91a3c1315 --- /dev/null +++ b/tests/js/tobjfieldbyvar.nim @@ -0,0 +1,20 @@ +discard """ + output: '''5 +''' +""" + +# bug #2798 + +type Inner = object + value: int + +type Outer = object + i: Inner + +proc test(i: var Inner) = + i.value += 5 + +var o: Outer +test(o.i) + +echo o.i.value diff --git a/tests/js/tos.nim b/tests/js/tos.nim new file mode 100644 index 000000000..40fb52bcf --- /dev/null +++ b/tests/js/tos.nim @@ -0,0 +1,21 @@ +# xxx consider merging this in tests/stdlib/tos.nim for increased coverage (with selecting disabling) + +static: doAssert defined(nodejs) + +import os + +block: + doAssert "./foo//./bar/".normalizedPath == "foo/bar" + doAssert relativePath(".//foo/bar", "foo") == "bar" + doAssert "/".isAbsolute + doAssert not "".isAbsolute + doAssert not ".".isAbsolute + doAssert not "foo".isAbsolute + doAssert relativePath("", "bar") == "" + doAssert normalizedPath(".///foo//./") == "foo" + + when nimvm: discard + else: + let cwd = getCurrentDir() + doAssert cwd.isAbsolute + doAssert relativePath(getCurrentDir() / "foo", "bar") == ".." / "foo" diff --git a/tests/js/trefbyvar.nim b/tests/js/trefbyvar.nim new file mode 100644 index 000000000..5b168044e --- /dev/null +++ b/tests/js/trefbyvar.nim @@ -0,0 +1,69 @@ +discard """ + output: '''0 +5 +0 +5 +@[1, 2] +~''' +""" + +# bug #2476 + +type A = ref object + m: int + +proc f(a: var A) = + var b: A + b.new() + b.m = 5 + a = b + +var t: A +t.new() + +echo t.m +t.f() +echo t.m + +proc main = + # now test the same for locals + var t: A + t.new() + + echo t.m + t.f() + echo t.m + +main() + +# bug #5974 +type + View* = object + data: ref seq[int] + +let a = View(data: new(seq[int])) +a.data[] = @[1, 2] + +echo a.data[] + +# bug #5379 +var input = newSeq[ref string]() +input.add(nil) +input.add(new string) +input[1][] = "~" +echo input[1][] + +# bug #5517 +type + TypeA1 = object of RootObj + a_impl: int + b_impl: string + c_impl: pointer + +proc initTypeA1(a: int; b: string; c: pointer = nil): TypeA1 = + result.a_impl = a + result.b_impl = b + result.c_impl = c + +let x = initTypeA1(1, "a") +doAssert($x == "(a_impl: 1, b_impl: \"a\", c_impl: ...)") diff --git a/tests/js/trepr.nim b/tests/js/trepr.nim new file mode 100644 index 000000000..a562ad63b --- /dev/null +++ b/tests/js/trepr.nim @@ -0,0 +1,413 @@ +# xxx consider merging with `tests/stdlib/trepr.nim` to increase overall test coverage + +block ints: + let + na: int8 = -120'i8 + nb: int16 = -32700'i16 + nc: int32 = -2147483000'i32 + nd: int64 = -9223372036854775000'i64 + ne: int = -1234567 + pa: int8 = 120'i8 + pb: int16 = 32700'i16 + pc: int32 = 2147483000'i32 + pd: int64 = 9223372036854775000'i64 + pe: int = 1234567 + + doAssert(repr(na) == "-120") + doAssert(repr(nb) == "-32700") + doAssert(repr(nc) == "-2147483000") + doAssert(repr(nd) == "-9223372036854775000") + doAssert(repr(ne) == "-1234567") + doAssert(repr(pa) == "120") + doAssert(repr(pb) == "32700") + doAssert(repr(pc) == "2147483000") + doAssert(repr(pd) == "9223372036854775000") + doAssert(repr(pe) == "1234567") + +block uints: + let + a: uint8 = 254'u8 + b: uint16 = 65300'u16 + c: uint32 = 4294967290'u32 + # d: uint64 = 18446744073709551610'u64 -> unknown node type + e: uint = 1234567 + + doAssert(repr(a) == "254") + doAssert(repr(b) == "65300") + doAssert(repr(c) == "4294967290") + # doAssert(repr(d) == "18446744073709551610") + doAssert(repr(e) == "1234567") + +block floats: + let + a: float32 = 3.4e38'f32 + b: float64 = 1.7976931348623157e308'f64 + c: float = 1234.567e89 + + when defined js: + doAssert(repr(a) == "3.4e+38") # in C: 3.399999952144364e+038 + doAssert(repr(b) == "1.7976931348623157e+308") # in C: 1.797693134862316e+308 + doAssert(repr(c) == "1.234567e+92") # in C: 1.234567e+092 + +block bools: + let + a: bool = true + b: bool = false + + doAssert(repr(a) == "true") + doAssert(repr(b) == "false") + +block enums: + type + AnEnum = enum + aeA + aeB + aeC + HoledEnum = enum + heA = -12 + heB = 15 + heC = 123 + + doAssert(repr(aeA) == "aeA") + doAssert(repr(aeB) == "aeB") + doAssert(repr(aeC) == "aeC") + doAssert(repr(heA) == "heA") + doAssert(repr(heB) == "heB") + doAssert(repr(heC) == "heC") + +block emums_and_unicode: #6741 + type K = enum Kanji = "漢字" + let kanji = Kanji + doAssert(kanji == Kanji, "Enum values are not equal") + doAssert($kanji == $Kanji, "Enum string values are not equal") + +block chars: + let + a = 'a' + b = 'z' + one = '1' + nl = '\x0A' + + doAssert(repr(a) == "'a'") + doAssert(repr(b) == "'z'") + doAssert(repr(one) == "'1'") + doAssert(repr(nl) == "'\\10'") + +block strings: + let + a: string = "12345" + b: string = "hello,repr" + c: string = "hi\nthere" + when defined js: # C prepends the pointer, JS does not. + doAssert(repr(a) == "\"12345\"") + doAssert(repr(b) == "\"hello,repr\"") + doAssert(repr(c) == "\"hi\\10there\"") + +block sets: + let + a: set[int16] = {1'i16, 2'i16, 3'i16} + b: set[char] = {'A', 'k'} + + doAssert(repr(a) == "{1, 2, 3}") + doAssert(repr(b) == "{'A', 'k'}") + +block ranges: + let + a: range[0..12] = 6 + b: range[-12..0] = -6 + doAssert(repr(a) == "6") + doAssert(repr(b) == "-6") + +block tuples: + type + ATuple = tuple + a: int + b: float + c: string + d: OtherTuple + OtherTuple = tuple + a: bool + b: int8 + + let + ot: OtherTuple = (a: true, b: 120'i8) + t: ATuple = (a: 42, b: 12.34, c: "tuple", d: ot) + when defined js: + doAssert(repr(ot) == """ +[Field0 = true, +Field1 = 120]""") + doAssert(repr(t) == """ +[Field0 = 42, +Field1 = 12.34, +Field2 = "tuple", +Field3 = [Field0 = true, +Field1 = 120]]""") + +block objects: + type + AnObj = object + a: int + b: float + c: OtherObj + OtherObj = object + a: bool + b: int8 + let + oo: OtherObj = OtherObj(a: true, b: 120'i8) + o: AnObj = AnObj(a: 42, b: 12.34, c: oo) + + doAssert(repr(oo) == """ +[a = true, +b = 120]""") + doAssert(repr(o) == """ +[a = 42, +b = 12.34, +c = [a = true, +b = 120]]""") + +block arrays: + type + AObj = object + x: int + y: array[3,float] + let + a = [0.0, 1, 2] + b = [a, a, a] + o = AObj(x: 42, y: a) + c = [o, o, o] + d = ["hi", "array", "!"] + + doAssert(repr(a) == "[0.0, 1.0, 2.0]") + doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]") + doAssert(repr(c) == """ +[[x = 42, +y = [0.0, 1.0, 2.0]], [x = 42, +y = [0.0, 1.0, 2.0]], [x = 42, +y = [0.0, 1.0, 2.0]]]""") + doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]") + +block seqs: + type + AObj = object + x: int + y: seq[float] + let + a = @[0.0, 1, 2] + b = @[a, a, a] + o = AObj(x: 42, y: a) + c = @[o, o, o] + d = @["hi", "array", "!"] + + doAssert(repr(a) == "@[0.0, 1.0, 2.0]") + doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]") + doAssert(repr(c) == """ +@[[x = 42, +y = @[0.0, 1.0, 2.0]], [x = 42, +y = @[0.0, 1.0, 2.0]], [x = 42, +y = @[0.0, 1.0, 2.0]]]""") + doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]") + +block ptrs: + type + AObj = object + x: ptr array[2, AObj] + y: int + var + a = [12.0, 13.0, 14.0] + b = addr a[0] + c = addr a[2] + d = AObj() + + doAssert(repr(a) == "[12.0, 13.0, 14.0]") + doAssert(repr(b) == "ref 0 --> 12.0") + doAssert(repr(c) == "ref 2 --> 14.0") + doAssert(repr(d) == """ +[x = nil, +y = 0]""") + +block ptrs: + type + AObj = object + x: ref array[2, AObj] + y: int + var + a = AObj() + + new(a.x) + + doAssert(repr(a) == """ +[x = ref 0 --> [[x = nil, +y = 0], [x = nil, +y = 0]], +y = 0]""") + +block procs: + proc test(): int = + echo "hello" + var + ptest = test + nilproc: proc(): int + + doAssert(repr(test) == "0") + doAssert(repr(ptest) == "0") + doAssert(repr(nilproc) == "nil") + +block bunch: + type + AnEnum = enum + eA, eB, eC + B = object + a: string + b: seq[char] + A = object + a: uint32 + b: int + c: float + d: char + e: AnEnum + f: string + g: set[char] + h: set[int16] + i: array[3,string] + j: seq[string] + k: range[-12..12] + l: B + m: ref B + n: ptr B + o: tuple[x: B, y: string] + p: proc(b: B): ref B + q: cstring + + proc refB(b:B):ref B = + new result + result[] = b + + var + aa = default(A) + bb: B = B(a: "inner", b: @['o', 'b', 'j']) + cc: A = A(a: 12, b: 1, c: 1.2, d: '\0', e: eC, + f: "hello", g: {'A'}, h: {2'i16}, + i: ["hello", "world", "array"], + j: @["hello", "world", "seq"], k: -1, + l: bb, m: refB(bb), n: addr bb, + o: (bb, "tuple!"), p: refB, q: "cstringtest" ) + + doAssert(repr(aa) == """ +[a = 0, +b = 0, +c = 0.0, +d = '\0', +e = eA, +f = "", +g = {}, +h = {}, +i = ["", "", ""], +j = @[], +k = -12, +l = [a = "", +b = @[]], +m = nil, +n = nil, +o = [Field0 = [a = "", +b = @[]], +Field1 = ""], +p = nil, +q = nil]""") + doAssert(repr(cc) == """ +[a = 12, +b = 1, +c = 1.2, +d = '\0', +e = eC, +f = "hello", +g = {'A'}, +h = {2}, +i = ["hello", "world", "array"], +j = @["hello", "world", "seq"], +k = -1, +l = [a = "inner", +b = @['o', 'b', 'j']], +m = ref 0 --> [a = "inner", +b = @['o', 'b', 'j']], +n = ref 0 --> [a = "inner", +b = @['o', 'b', 'j']], +o = [Field0 = [a = "inner", +b = @['o', 'b', 'j']], +Field1 = "tuple!"], +p = 0, +q = "cstringtest"]""") + +block another: + type + Size1 = enum + s1a, s1b + Size2 = enum + s2c=0, s2d=20000 + Size3 = enum + s3e=0, s3f=2000000000 + + doAssert(repr([s1a, s1b]) == "[s1a, s1b]") + doAssert(repr([s2c, s2d]) == "[s2c, s2d]") + doAssert(repr([s3e, s3f]) == "[s3e, s3f]") + +block another2: + + type + AnEnum = enum + en1, en2, en3, en4, en5, en6 + + Point {.final.} = object + x, y, z: int + s: array[0..1, string] + e: AnEnum + + var + p: Point + q: ref Point + s: seq[ref Point] + + p.x = 0 + p.y = 13 + p.z = 45 + p.s[0] = "abc" + p.s[1] = "xyz" + p.e = en6 + + new(q) + q[] = p + + s = @[q, q, q, q] + + doAssert(repr(p) == """ +[x = 0, +y = 13, +z = 45, +s = ["abc", "xyz"], +e = en6]""") + doAssert(repr(q) == """ +ref 0 --> [x = 0, +y = 13, +z = 45, +s = ["abc", "xyz"], +e = en6]""") + doAssert(repr(s) == """ +@[ref 0 --> [x = 0, +y = 13, +z = 45, +s = ["abc", "xyz"], +e = en6], ref 1 --> [x = 0, +y = 13, +z = 45, +s = ["abc", "xyz"], +e = en6], ref 2 --> [x = 0, +y = 13, +z = 45, +s = ["abc", "xyz"], +e = en6], ref 3 --> [x = 0, +y = 13, +z = 45, +s = ["abc", "xyz"], +e = en6]]""") + doAssert(repr(en4) == "en4") + + doAssert(repr({'a'..'p'}) == "{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'}") diff --git a/tests/js/treprinifexpr.nim b/tests/js/treprinifexpr.nim new file mode 100644 index 000000000..09ded18b9 --- /dev/null +++ b/tests/js/treprinifexpr.nim @@ -0,0 +1,18 @@ +type + Enum = enum A + +let + enumVal = A + tmp = if true: $enumVal else: $enumVal + +let + intVal = 12 + tmp2 = if true: repr(intVal) else: $enumVal + +let + strVal = "123" + tmp3 = if true: repr(strVal) else: $strVal + +let + floatVal = 12.4 + tmp4 = if true: repr(floatVal) else: $floatVal \ No newline at end of file diff --git a/tests/js/tseqops.nim b/tests/js/tseqops.nim new file mode 100644 index 000000000..8cfb50886 --- /dev/null +++ b/tests/js/tseqops.nim @@ -0,0 +1,48 @@ +# bug #4139 + +type + TestO = object + x, y: int + +proc onLoad() = + var test: seq[TestO] = @[] + var foo = TestO(x: 0, y: 0) + test.add(foo) + foo.x = 5 + doAssert $test[0] == "(x: 0, y: 0)" + doAssert $foo == "(x: 5, y: 0)" + +onLoad() + +# 'setLen' bug (part of bug #5933) +type MyObj = object + x: cstring + y: int + +proc foo(x: var seq[MyObj]) = + let L = x.len + x.setLen L + 1 + x[L] = x[1] + +var s = @[MyObj(x: "2", y: 4), MyObj(x: "4", y: 5)] +foo(s) +doAssert $s == """@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)]""" + +# bug #5933 +import sequtils + +type + Test = object + a: cstring + b: int + +var test = @[Test(a: "1", b: 1), Test(a: "2", b: 2)] + +test.insert(@[Test(a: "3", b: 3)], 0) + +doAssert $test == """@[(a: "3", b: 3), (a: "1", b: 1), (a: "2", b: 2)]""" + +proc hello(): array[5, int] = discard +var x = @(hello()) +x.add(2) +doAssert x == @[0, 0, 0, 0, 0, 2] diff --git a/tests/js/tsourcemap.nim b/tests/js/tsourcemap.nim new file mode 100644 index 000000000..d358e4a57 --- /dev/null +++ b/tests/js/tsourcemap.nim @@ -0,0 +1,96 @@ +discard """ + action: "run" + targets: "js" + cmd: "nim js -r -d:nodejs $options --sourceMap:on $file" +""" +import std/[os, json, strutils, sequtils, algorithm, assertions, paths, compilesettings] + +# Implements a very basic sourcemap parser and then runs it on itself. +# Allows to check for basic problems such as bad counts and lines missing (e.g. issue #21052) + +type + SourceMap = object + version: int + sources: seq[string] + names: seq[string] + mappings: string + file: string + + Line = object + line, column: int + file: string + +const + flag = 1 shl 5 + signBit = 0b1 + fourBits = 0b1111 + fiveBits = 0b11111 + mask = (1 shl 5) - 1 + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +var b64Table: seq[int] = 0.repeat(max(alphabet.mapIt(it.ord)) + 1) +for i, b in alphabet.pairs: + b64Table[b.ord] = i + +# From https://github.com/juancarlospaco/nodejs/blob/main/src/nodejs/jsfs.nim +proc importFs*() {.importjs: "var fs = require(\"fs\");".} +proc readFileSync*(path: cstring): cstring {.importjs: "(fs.$1(#).toString())".} +importFS() +# Read in needed files +let + jsFileName = string(querySetting(outDir).Path / "tsourcemap.js".Path) + mapFileName = jsFileName & ".map" + + data = parseJson($mapFileName.cstring.readFileSync()).to(SourceMap) + jsFile = $readFileSync(jsFileName.cstring) + +proc decodeVLQ(inp: string): seq[int] = + var + shift, value: int + for v in inp.mapIt(b64Table[it.ord]): + value += (v and mask) shl shift + if (v and flag) > 0: + shift += 5 + continue + result &= (value shr 1) * (if (value and 1) > 0: -1 else: 1) + shift = 0 + value = 0 + + +# Keep track of state +var + line = 0 + source = 0 + name = 0 + column = 0 + jsLine = 1 + lines: seq[Line] + +for gline in data.mappings.split(';'): + jsLine += 1 + var jsColumn = 0 + for item in gline.strip().split(','): + let value = item.decodeVLQ() + doAssert value.len in [0, 1, 4, 5] + if value.len == 0: + continue + jsColumn += value[0] + if value.len >= 4: + source += value[1] + line += value[2] + column += value[3] + lines &= Line(line: line, column: column, file: data.sources[source]) + +let jsLines = jsFile.splitLines().len +# There needs to be a mapping for every line in the JS +# If there isn't then the JS lines wont match up with Nim lines. +# Except we don't care about the final line since that doesn't need to line up +doAssert data.mappings.count(';') == jsLines - 1 + +# Check we can find this file somewhere in the source map +var foundSelf = false +for line in lines: + if "tsourcemap.nim" in line.file: + foundSelf = true + doAssert line.line in 0..<jsLines, "Lines is out of bounds for file" +doAssert foundSelf, "Couldn't find tsourcemap.nim in source map" diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim new file mode 100644 index 000000000..db851ba28 --- /dev/null +++ b/tests/js/tstdlib_imports.nim @@ -0,0 +1,80 @@ +discard """ + action: compile +""" + +{.warning[UnusedImport]: off.} + +when defined(nimPreviewSlimSystem): + import std/[ + syncio, assertions, formatfloat, objectdollar, widestrs + ] + +import std/[ + # Core: + bitops, typetraits, lenientops, macros, volatile, typeinfo, + # fails due to FFI: rlocks + # fails due to cstring cast/copyMem: endians + # works but uses FFI: cpuinfo, locks + + # Algorithms: + algorithm, enumutils, sequtils, setutils, + + # Collections: + critbits, deques, heapqueue, intsets, lists, options, sets, + tables, packedsets, + + # Strings: + cstrutils, editdistance, wordwrap, parseutils, ropes, + pegs, strformat, strmisc, strscans, strtabs, + strutils, unicode, unidecode, + # fails due to FFI: encodings + + # Time handling: + monotimes, times, + + # Generic operator system services: + os, streams, + # fails intentionally: dynlib, marshal, memfiles + # fails due to FFI: osproc, terminal + # fails due to osproc import: distros + + # Math libraries: + complex, math, random, rationals, stats, sums, sysrand, + # works but uses FFI: fenv + + # Internet protocols: + cookies, httpcore, mimetypes, uri, + # fails due to FFI: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver, + # asyncnet, cgi, httpclient, nativesockets, net, selectors + # works but no need to test: asyncstreams, asyncfutures + + # Threading: + # fails due to FFI: threadpool + + # Parsers: + htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, + parseopt, jsonutils, + + # XML processing: + xmltree, xmlparser, + + # Generators: + htmlgen, + + # Hashing: + base64, hashes, + # fails due to cstring cast/endians import: oids + # fails due to copyMem/endians import: sha1 + + # Miscellaneous: + colors, logging, sugar, unittest, varints, enumerate, with, + # fails due to FFI: browsers, coro + # works but uses FFI: segfaults + + # Modules for JS backend: + asyncjs, dom, jsconsole, jscore, jsffi, jsbigints, + + # Unlisted in lib.html: + decls, compilesettings, wrapnils, exitprocs, effecttraits, + genasts, importutils, isolation, jsfetch, jsformdata, jsheaders +] diff --git a/tests/js/tstdlib_various.nim b/tests/js/tstdlib_various.nim new file mode 100644 index 000000000..1e584f735 --- /dev/null +++ b/tests/js/tstdlib_various.nim @@ -0,0 +1,174 @@ +discard """ +output: ''' +abc +def +definition +prefix +xyz +def +definition +Hi Andreas! How do you feel, Rumpf? + +@[0, 2, 1] +@[1, 0, 2] +@[1, 2, 0] +@[2, 0, 1] +@[2, 1, 0] +@[2, 0, 1] +@[1, 2, 0] +@[1, 0, 2] +@[0, 2, 1] +@[0, 1, 2] +[5] +[4, 5] +[3, 4, 5] +[2, 3, 4, 5] +[2, 3, 4, 5, 6] +[1, 2, 3, 4, 5, 6] +''' +""" + +import + critbits, sets, strutils, tables, random, algorithm, ropes, + lists, htmlgen, xmltree, strtabs + + +block tcritbits: + var r: CritBitTree[void] + r.incl "abc" + r.incl "xyz" + r.incl "def" + r.incl "definition" + r.incl "prefix" + doAssert r.contains"def" + #r.del "def" + + for w in r.items: + echo w + for w in r.itemsWithPrefix("de"): + echo w + + + +block testequivalence: + doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset") + doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset") + doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset") + doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset") + doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset") + doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset") + doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==") + doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==") + doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==") + + + +block tformat: + echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"]) + + + +block tnilecho: + var x = @["1", "", "3"] + doAssert $x == """@["1", "", "3"]""" + + + +block torderedtable: + var t = initOrderedTable[int,string]() + + # this tests issue #5917 + var data = newSeq[int]() + for i in 0..<1000: + var x = rand(1000) + if x notin t: data.add(x) + t[x] = "meh" + + # this checks that keys are re-inserted + # in order when table is enlarged. + var i = 0 + for k, v in t: + doAssert(k == data[i]) + doAssert(v == "meh") + inc(i) + + + +block tpermutations: + var v = @[0, 1, 2] + while v.nextPermutation(): + echo v + while v.prevPermutation(): + echo v + + +block tropes: + var + r1 = rope("") + r2 = rope("123") + doAssert r1.len == 0 + doAssert r2.len == 3 + doAssert $r1 == "" + doAssert $r2 == "123" + + r1.add("123") + r2.add("456") + doAssert r1.len == 3 + doAssert r2.len == 6 + doAssert $r1 == "123" + doAssert $r2 == "123456" + doAssert $r1[1] == "2" + doAssert $r2[2] == "3" + + +block tsinglylinkedring: + var r = initSinglyLinkedRing[int]() + r.prepend(5) + echo r + r.prepend(4) + echo r + r.prepend(3) + echo r + r.prepend(2) + echo r + r.append(6) + echo r + r.prepend(1) + echo r + +block tsplit: + var s = "" + for w in split("|abc|xy|z", {'|'}): + s.add("#") + s.add(w) + + doAssert s == "##abc#xy#z" + +block tsplit2: + var s = "" + for w in split("|abc|xy|z", {'|'}): + s.add("#") + s.add(w) + + doAssert "true".split("") == @["true"] + +block txmlgen: + var nim = "Nim" + doAssert h1(a(href="http://force7.de/nim", nim)) == + "<h1><a href=\"http://force7.de/nim\">Nim</a></h1>" + +block txmltree: + var x = <>a(href="nim.de", newText("www.nim-test.de")) + + doAssert($x == "<a href=\"nim.de\">www.nim-test.de</a>") + doAssert(newText("foo").innerText == "foo") + doAssert(newEntity("bar").innerText == "bar") + doAssert(newComment("baz").innerText == "") + + let y = newXmlTree("x", [ + newText("foo"), + newXmlTree("y", [ + newText("bar") + ]) + ]) + doAssert(y.innerText == "foobar") diff --git a/tests/js/tstreams.nim b/tests/js/tstreams.nim new file mode 100644 index 000000000..43c26e01a --- /dev/null +++ b/tests/js/tstreams.nim @@ -0,0 +1,22 @@ +discard """ + output: ''' +I +AM +GROOT +''' +""" + +import streams + +var s = newStringStream("I\nAM\nGROOT") +doAssert s.peekStr(1) == "I" +doAssert s.peekChar() == 'I' +for line in s.lines: + echo line +s.close + +var s2 = newStringStream("abc") +doAssert s2.readAll == "abc" +s2.write("def") +doAssert s2.data == "abcdef" +s2.close diff --git a/tests/js/tstring_assignment.nim b/tests/js/tstring_assignment.nim new file mode 100644 index 000000000..97ffa748f --- /dev/null +++ b/tests/js/tstring_assignment.nim @@ -0,0 +1,21 @@ +discard """ + output: '''true +asdfasekjkler''' +""" + +# bug #4471 +when true: + let s1 = "123" + var s2 = s1 + s2.setLen(0) + # fails - s1.len == 0 + echo s1.len == 3 + +# bug #4470 +proc main(s: cstring): string = + result = newString(0) + for i in 0..<s.len: + if s[i] >= 'a' and s[i] <= 'z': + result.add s[i] + +echo main("asdfasekjkleräöü") diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim new file mode 100644 index 000000000..16df04149 --- /dev/null +++ b/tests/js/tstringitems.nim @@ -0,0 +1,95 @@ +discard """ + output: '''Hello +Hello +c +d +e''' +""" + +block: # bug #2581 + const someVars = [ "Hello" ] + var someVars2 = [ "Hello" ] + + proc getSomeVar: string = + for i in someVars: + if i == "Hello": + result = i + break + + proc getSomeVar2: string = + for i in someVars2: + if i == "Hello": + result = i + break + + echo getSomeVar() + echo getSomeVar2() + +block: # Test compile-time binary data generation, invalid unicode + proc signatureMaker(): string {. compiletime .} = + const signatureBytes = [137, 80, 78, 71, 13, 10, 26, 10] + result = "" + for c in signatureBytes: result.add chr(c) + + const cSig = signatureMaker() + + var rSig = newString(8) + rSig[0] = chr(137) + rSig[1] = chr(80) + rSig[2] = chr(78) + rSig[3] = chr(71) + rSig[4] = chr(13) + rSig[5] = chr(10) + rSig[6] = chr(26) + rSig[7] = chr(10) + + doAssert(rSig == cSig) + +block: # Test unicode strings + const constStr = "Привет!" + var jsStr : cstring + {.emit: """`jsStr` = "Привет!";""".} + + doAssert($jsStr == constStr) + var runtimeStr = "При" + runtimeStr &= "вет!" + + doAssert(runtimeStr == constStr) + +block: # Conversions from/to cstring + proc stringSaysHelloInRussian(s: cstring): bool = + {.emit: """`result` = (`s` === "Привет!");""".} + + doAssert(stringSaysHelloInRussian("Привет!")) + + const constStr = "Привет!" + doAssert(stringSaysHelloInRussian(constStr)) + + var rtStr = "Привет!" + doAssert(stringSaysHelloInRussian(rtStr)) + +block: # String case of + const constStr = "Привет!" + var s = "Привет!" + + case s + of constStr: discard + else: doAssert(false) + + case s + of "Привет!": discard + else: doAssert(false) + +block: # String cmp + var a, b: string + doAssert(cmp(a, b) == 0) + doAssert(cmp("foo", "foo") == 0) + doAssert(cmp("foobar", "foo") == 3) + doAssert(cmp("foo", "foobar") == -3) + doAssert(cmp("fooz", "foog") == 19) + doAssert(cmp("foog", "fooz") == -19) + +proc main(x: openArray[char]) = + for c in x: echo c + +main(toOpenArray(['a', 'b', 'c', 'd', 'e'], 2, 4)) diff --git a/tests/js/ttempgen.nim b/tests/js/ttempgen.nim new file mode 100644 index 000000000..badc66c1b --- /dev/null +++ b/tests/js/ttempgen.nim @@ -0,0 +1,79 @@ +discard """ + output: ''' +foo +''' +""" + +block: # #12672 + var a = @[1] + let i = 1 + inc a[i-1] + + var b: seq[int] + doAssertRaises(IndexDefect): inc b[0] + doAssertRaises(IndexDefect): inc b[i-1] + + var x: seq[seq[int]] + doAssertRaises(IndexDefect): # not TypeError + inc x[0][i-1] + +block: # #14087 + type Obj = object + str: string + + var s = @[Obj(str: "abc"), Obj(str: "def")] + s[1].str.add("ghi") + s[s.len - 1].str.add("jkl") + s[^1].str.add("mno") + s[s.high].str.add("pqr") + + let slen = s.len + s[slen - 1].str.add("stu") + + let shigh = s.high + s[shigh].str.add("vwx") + + proc foo(): int = + echo "foo" + shigh + s[foo()].str.add("yz") + doAssert s[1].str == "defghijklmnopqrstuvwxyz" + +block: # #14117 + type + A = object + case kind: bool + of true: + sons: seq[int] + else: discard + + var a = A(kind: true) + doAssert a.sons.len == 0 + a.sons.add(1) + doAssert a.sons.len == 1 + +import tables + +block: # #13966 + var t: Table[int8, array[int8, seq[tuple[]]]] + + t[0] = default(array[int8, seq[tuple[]]]) + t[0][0].add () + +block: # #11783 + proc fun(): string = + discard + + var ret: string + ret.add fun() + doAssert ret == "" + +block: # #12256 + var x: bool + + doAssert x == false + + reset x + + doAssert x == false + doAssert x != true diff --git a/tests/js/tthismangle.nim b/tests/js/tthismangle.nim new file mode 100644 index 000000000..880abcc83 --- /dev/null +++ b/tests/js/tthismangle.nim @@ -0,0 +1,23 @@ +proc moo1(this: int) = + doAssert this == 42 + +proc moo2(x: int) = + var this = x + doAssert this == 42 + +proc moo3() = + for this in [1,1,1]: + doAssert this == 1 + +proc moo4() = + type + X = object + this: int + + var q = X(this: 42) + doAssert q.this == 42 + +moo1(42) +moo2(42) +moo3() +moo4() diff --git a/tests/js/ttryexceptnewsyntax.nim b/tests/js/ttryexceptnewsyntax.nim new file mode 100644 index 000000000..2573c3727 --- /dev/null +++ b/tests/js/ttryexceptnewsyntax.nim @@ -0,0 +1,13 @@ +discard """ + output: '''hello''' +""" + +type + MyException = ref Exception + +#bug #5986 + +try: + raise MyException(msg: "hello") +except MyException as e: + echo e.msg diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim new file mode 100644 index 000000000..4807cb103 --- /dev/null +++ b/tests/js/ttypedarray.nim @@ -0,0 +1,26 @@ +discard """ + matrix: "--jsbigint64:off -d:nimStringHash2; --jsbigint64:on" +""" + +import std/private/jsutils + +proc main()= + template fn(a): untyped = jsConstructorName(a) + doAssert fn(array[2, int8].default) == "Int8Array" + doAssert fn(array[2, uint8].default) == "Uint8Array" + doAssert fn(array[2, byte].default) == "Uint8Array" + doAssert fn(array[2, char].default) == "Uint8Array" + whenJsNoBigInt64: discard + do: + doAssert fn(array[2, uint64].default) == "BigUint64Array" + doAssert fn([1'u8]) == "Uint8Array" + doAssert fn([1'u16]) == "Uint16Array" + doAssert fn([byte(1)]) == "Uint8Array" + doAssert fn([1.0'f32]) == "Float32Array" + doAssert fn(array[2, float32].default) == "Float32Array" + doAssert fn(array[2, float].default) == "Float64Array" + doAssert fn(array[2, float64].default) == "Float64Array" + doAssert fn([1.0]) == "Float64Array" + doAssert fn([1.0'f64]) == "Float64Array" + +main() diff --git a/tests/js/tunion.nim b/tests/js/tunion.nim new file mode 100644 index 000000000..e185495ad --- /dev/null +++ b/tests/js/tunion.nim @@ -0,0 +1,7 @@ +discard """ + errormsg: "`{.union.}` is not implemented for js backend." +""" + +type Foo {.union.} = object + as_bytes: array[8, int8] + data: int64 diff --git a/tests/js/tunittest_error.nim b/tests/js/tunittest_error.nim new file mode 100644 index 000000000..781e34338 --- /dev/null +++ b/tests/js/tunittest_error.nim @@ -0,0 +1,24 @@ +discard """ + exitcode: 1 + outputsub: "[FAILED] with exception" +""" + +# see also: `tests/stdlib/tunittest_error.nim` + +import unittest + +proc ddd() = + raise newException(IOError, "didn't do stuff") + +proc ccc() = + ddd() + +proc bbb() = + ccc() + +proc aaa() = + bbb() + +test "with exception": + check 3 == 3 + aaa() diff --git a/tests/js/tunittest_error2.nim b/tests/js/tunittest_error2.nim new file mode 100644 index 000000000..9c5af7529 --- /dev/null +++ b/tests/js/tunittest_error2.nim @@ -0,0 +1,16 @@ +discard """ + exitcode: 1 + outputsub: ''' +[<foreign exception>] +[FAILED] Bad test + ''' + matrix: "-d:nodejs" + targets: "js" + joinable: false +""" + +# bug #16978 +import unittest +test "Bad test": + var x: cstring = nil + let y = x[0] diff --git a/tests/js/tvarargs.nim b/tests/js/tvarargs.nim new file mode 100644 index 000000000..8d57af58d --- /dev/null +++ b/tests/js/tvarargs.nim @@ -0,0 +1,15 @@ +discard """ + output: "Hello, world" +""" + +# bug #3584 + +type + ConsoleObj {.importc.} = object of RootObj + log*: proc() {.nimcall varargs.} + Console = ref ConsoleObj + +var console* {.importc.}: Console + +when true: + console.log "Hello, world" diff --git a/tests/js/twritestacktrace.nim b/tests/js/twritestacktrace.nim new file mode 100644 index 000000000..2fe2b1987 --- /dev/null +++ b/tests/js/twritestacktrace.nim @@ -0,0 +1,12 @@ +discard """ + cmd: "nim js --panics:on $file" + output: '''Traceback (most recent call last) +twritestacktrace.nim(12) at module twritestacktrace +twritestacktrace.nim(10) at twritestacktrace.hello +''' +""" + +proc hello() = + writeStackTrace() + +hello() |