diff options
Diffstat (limited to 'tests/misc')
108 files changed, 5106 insertions, 0 deletions
diff --git a/tests/misc/99bottles.nim b/tests/misc/99bottles.nim new file mode 100644 index 000000000..14904ac0f --- /dev/null +++ b/tests/misc/99bottles.nim @@ -0,0 +1 @@ +# Test if the compiler detects invalid module names diff --git a/tests/misc/m15316.nim b/tests/misc/m15316.nim new file mode 100644 index 000000000..188d06946 --- /dev/null +++ b/tests/misc/m15316.nim @@ -0,0 +1 @@ +proc foo = (if) diff --git a/tests/misc/m15955.nim b/tests/misc/m15955.nim new file mode 100644 index 000000000..22da345db --- /dev/null +++ b/tests/misc/m15955.nim @@ -0,0 +1,4 @@ +proc add*(a, b: int): int {.cdecl, exportc.} = + a + b +proc sub*(a, b: int): int {.cdecl, exportc.} = + a - b \ No newline at end of file diff --git a/tests/misc/m15955_main.nim b/tests/misc/m15955_main.nim new file mode 100644 index 000000000..a71af8121 --- /dev/null +++ b/tests/misc/m15955_main.nim @@ -0,0 +1,11 @@ +import stdtest/specialpaths +import std/os + +const buildLib = buildDir / "libD20220923T19380" + +{.passL: buildLib.} +proc add*(a, b: int):int {.cdecl, importc.} +proc sub*(a, b: int):int {.cdecl, importc.} + +echo add(10, 5) +echo sub(10, 5) diff --git a/tests/misc/m20149.nim b/tests/misc/m20149.nim new file mode 100644 index 000000000..942262a6e --- /dev/null +++ b/tests/misc/m20149.nim @@ -0,0 +1,2 @@ +let x = 12 +echo x diff --git a/tests/misc/m20456.nims b/tests/misc/m20456.nims new file mode 100644 index 000000000..8a9313129 --- /dev/null +++ b/tests/misc/m20456.nims @@ -0,0 +1 @@ +echo 123 \ No newline at end of file diff --git a/tests/misc/mbackend.nim b/tests/misc/mbackend.nim new file mode 100644 index 000000000..b6578a212 --- /dev/null +++ b/tests/misc/mbackend.nim @@ -0,0 +1,30 @@ +#[ +We can't merge this test inside a `when defined(cpp)` because some bug that was +fixed would not trigger in that case. +]# + +import std/compilesettings + +static: + ## bugfix 1: this used to CT error with: Error: unhandled exception: mimportcpp.nim(6, 18) `defined(cpp)` + doAssert defined(cpp) + doAssert querySetting(backend) == "cpp" + + ## checks that `--backend:c` has no side effect (ie, can be overridden by subsequent commands) + doAssert not defined(c) + doAssert not defined(js) + doAssert not defined(js) + +type + std_exception {.importcpp: "std::exception", header: "<exception>".} = object +proc what(s: std_exception): cstring {.importcpp: "((char *)#.what())".} + +var isThrown = false +try: + ## bugfix 2: this used to CT error with: Error: only a 'ref object' can be raised + raise std_exception() +except std_exception as ex: + doAssert ex.what().len > 0 + isThrown = true + +doAssert isThrown diff --git a/tests/misc/mbetterrun.nim b/tests/misc/mbetterrun.nim new file mode 100644 index 000000000..d4f427af0 --- /dev/null +++ b/tests/misc/mbetterrun.nim @@ -0,0 +1,3 @@ +const mbetterrunVal {.strdefine.} = "" +static: echo "compiling: " & mbetterrunVal +echo "running: " & mbetterrunVal diff --git a/tests/misc/mfield_defect.nim b/tests/misc/mfield_defect.nim new file mode 100644 index 000000000..53bfba40e --- /dev/null +++ b/tests/misc/mfield_defect.nim @@ -0,0 +1,30 @@ +#[ +ran from trunner +]# + + + + + + +# line 10 +type Kind = enum k0, k1, k2, k3, k4 + +type Foo = object + case kind: Kind + of k0: f0: int + of k1: f1: int + of k2: f2: int + of k3: f3: int + of k4: f4: int + +proc main()= + var foo = Foo(kind: k3, f3: 3) + let s1 = foo.f3 + doAssert s1 == 3 + let s2 = foo.f2 + +when defined case1: + static: main() +when defined case2: + main() diff --git a/tests/misc/mimportc.nim b/tests/misc/mimportc.nim new file mode 100644 index 000000000..602c6372d --- /dev/null +++ b/tests/misc/mimportc.nim @@ -0,0 +1,26 @@ +#[ +this test will grow with more importc+importcpp tests; see driver in trunner.nim +]# + +{.emit:""" +struct A { + static int fun0(int a){ + return a; + } + static int& fun1(int& a){ + return a; + } +}; +""".} + +proc fun0*(a: cint): int {.importcpp:"A::$1(@)".} +proc fun1*(a: var cint): var int {.importcpp:"A::$1(@)".} = + ## some comment; this test is for #14314 + runnableExamples: discard + +proc main()= + var a = 10.cint + doAssert fun0(a) == a + doAssert fun1(a).addr == a.addr + echo "witness" +main() diff --git a/tests/misc/minit.nim b/tests/misc/minit.nim new file mode 100644 index 000000000..513f46af5 --- /dev/null +++ b/tests/misc/minit.nim @@ -0,0 +1,2 @@ +# Test the new initialization for modules +write(stdout, "Hello from module! ") diff --git a/tests/misc/mjsondoc.nim b/tests/misc/mjsondoc.nim new file mode 100644 index 000000000..016c8522d --- /dev/null +++ b/tests/misc/mjsondoc.nim @@ -0,0 +1,14 @@ +proc doSomething*(x, y: int): int = + ## do something + x + y + +const + a* = 1 ## echo 1234 + b* = "test" + +type + MyEnum* = enum + foo, bar + +proc foo2*[T: int, M: string, U](x: T, y: U, z: M) = + echo 1 diff --git a/tests/misc/modulea.nim b/tests/misc/modulea.nim new file mode 100644 index 000000000..a9e6b364e --- /dev/null +++ b/tests/misc/modulea.nim @@ -0,0 +1,2 @@ +type modulea* = object + a: int diff --git a/tests/misc/msizeof5.nim b/tests/misc/msizeof5.nim new file mode 100644 index 000000000..63573a705 --- /dev/null +++ b/tests/misc/msizeof5.nim @@ -0,0 +1,131 @@ +## tests for -d:checkAbi used by addAbiCheck via NIM_STATIC_ASSERT + +{.emit:"""/*TYPESECTION*/ +struct Foo1{ + int a; +}; +struct Foo2{ + int a; +}; +enum Foo3{k1, k2}; +typedef enum Foo3 Foo3b; +typedef enum Foo4{k3, k4} Foo4; + +typedef int Foo5[3]; + +typedef struct Foo6{ + int a1; + bool a2; + double a3; + struct Foo6* a4; +} Foo6; +""".} + +template ensureCgen(T: typedesc) = + ## ensures cgen + var a {.volatile.}: T + +block: + type Foo1Alias{.importc: "struct Foo1", size: sizeof(cint).} = object + a: cint + ensureCgen Foo1Alias + +block: + type Foo3Alias{.importc: "enum Foo3", size: sizeof(cint).} = enum + k1, k2 + ensureCgen Foo3Alias + +block: + type Foo3bAlias{.importc: "Foo3b", size: sizeof(cint).} = enum + k1, k2 + ensureCgen Foo3bAlias + +block: + type Foo3b{.importc, size: sizeof(cint).} = enum + k1, k2 + ensureCgen Foo3b + static: + doAssert Foo3b.sizeof == cint.sizeof + +block: + type Foo4{.importc, size: sizeof(cint).} = enum + k3, k4 + # adding entries should not yield duplicate ABI checks, as enforced by + # `typeABICache`. + # Currently the test doesn't check for this but you can inspect the cgen'd file + ensureCgen Foo4 + ensureCgen Foo4 + ensureCgen Foo4 + +block: + type Foo5{.importc.} = array[3, cint] + ensureCgen Foo5 + +block: + type Foo5{.importc.} = array[3, cint] + ensureCgen Foo5 + +block: # CT sizeof + type Foo6GT = object # grountruth + a1: cint + a2: bool + a3: cfloat + a4: ptr Foo6GT + + type Foo6{.importc, completeStruct.} = object + a1: cint + a2: bool + a3: cfloat + a4: ptr Foo6 + + static: doAssert compiles(static(Foo6.sizeof)) + static: doAssert Foo6.sizeof == Foo6GT.sizeof + static: doAssert (Foo6, int, array[2, Foo6]).sizeof == + (Foo6GT, int, array[2, Foo6GT]).sizeof + +block: + type GoodImportcType {.importc: "signed char", nodecl.} = char + # "good" in sense the sizeof will match + ensureCgen GoodImportcType + +block: + type Foo6{.importc.} = object + a1: cint + doAssert compiles(Foo6.sizeof) + static: doAssert not compiles(static(Foo6.sizeof)) + +when defined caseBad: + # Each case below should give a static cgen assert fail message + + block: + type BadImportcType {.importc: "unsigned char", nodecl.} = uint64 + # "sizeof" check will fail + ensureCgen BadImportcType + + block: + type Foo2AliasBad{.importc: "struct Foo2", size: 1.} = object + a: cint + ensureCgen Foo2AliasBad + + block: + type Foo5{.importc.} = array[4, cint] + ensureCgen Foo5 + + block: + type Foo5{.importc.} = array[3, bool] + ensureCgen Foo5 + + block: + type Foo6{.importc:"struct Foo6", completeStruct.} = object + a1: cint + # a2: bool # missing this should trigger assert fail + a3: cfloat + a4: ptr Foo6 + ensureCgen Foo6 + + when false: + block: + # pre-existing BUG: this should give a CT error in semcheck because `size` + # disagrees with `array[3, cint]` + type Foo5{.importc, size: 1.} = array[3, cint] + ensureCgen Foo5 diff --git a/tests/misc/msizeof5.nim.cfg b/tests/misc/msizeof5.nim.cfg new file mode 100644 index 000000000..dc0712a8c --- /dev/null +++ b/tests/misc/msizeof5.nim.cfg @@ -0,0 +1,5 @@ +# Do not limit number of error messages from backend compiler. +gcc.options.always %= "${gcc.options.always} -fmax-errors=100" +clang.options.always %= "${clang.options.always} -ferror-limit=100" +gcc.cpp.options.always %= "${gcc.cpp.options.always} -fmax-errors=100" +clang.cpp.options.always %= "${clang.cpp.options.always} -ferror-limit=100" diff --git a/tests/misc/mtlsemulation.h b/tests/misc/mtlsemulation.h new file mode 100644 index 000000000..992977acd --- /dev/null +++ b/tests/misc/mtlsemulation.h @@ -0,0 +1,37 @@ +#include <stdio.h> + +struct Foo1 { + /* + uncommenting would give: + error: initializer for thread-local variable must be a constant expression + N_LIB_PRIVATE NIM_THREADVAR Foo1 g1__9brEZhPEldbVrNpdRGmWESA; + */ + // Foo1() noexcept { } + + /* + uncommenting would give: + error: type of thread-local variable has non-trivial destruction + */ + // ~Foo1() { } + int x; +}; + +struct Foo2 { + Foo2() noexcept { } + ~Foo2() { } + int x; +}; + +static int ctorCalls = 0; +static int dtorCalls = 0; + +struct Foo3 { + Foo3() noexcept { + ctorCalls = ctorCalls + 1; + x = 10; + } + ~Foo3() { + dtorCalls = dtorCalls + 1; + } + int x; +}; diff --git a/tests/misc/mvarious.nim b/tests/misc/mvarious.nim new file mode 100644 index 000000000..8efe7c92f --- /dev/null +++ b/tests/misc/mvarious.nim @@ -0,0 +1,6 @@ +# Test a submodule + +#type +# TStringArr = array[0.. *] of string + +proc exportme* = discard diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim new file mode 100644 index 000000000..4f149cbf6 --- /dev/null +++ b/tests/misc/parsecomb.nim @@ -0,0 +1,109 @@ +discard """ + matrix: "--mm:arc; --mm:refc" +""" + +type Input[T] = object + toks: seq[T] + index: int + +type + ResultKind* = enum rkSuccess, rkFailure + Result*[T, O] = object + case kind*: ResultKind + of rkSuccess: + output*: O + input: Input[T] + of rkFailure: + nil + +type + Parser*[T, O] = proc (input: Input[T]): Result[T, O] + +proc unit*[T, O](v: O): Parser[T, O] = + result = proc (inp: Input[T]): Result[T, O] = + Result[T, O](kind: rkSuccess, output: v, input: inp) + +proc fail*[T, O](): Parser[T, O] = + result = proc (inp: Input[T]): Result[T, O] = + Result(kind: rkFailure) + +method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] = + # hmmm .. + type tmp = proc (input: Input[T]): Result[T, O] + # XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C. + tmp(self)(inp) + +proc run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] = + self.runInput(Input[T](toks: toks, index: 0)) + +proc chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] = + result = proc (inp: Input[T]): Result[T, O2] = + let r = self.runInput(inp) + case r.kind: + of rkSuccess: + nextp(r.output).runInput(r.input) + of rkFailure: + Result[T, O2](kind: rkFailure) + +method skip[T](self: Input[T], n: int): Input[T] {.base.} = + Input[T](toks: self.toks, index: self.index + n) + +proc pskip*[T](n: int): Parser[T, tuple[]] = + result = proc (inp: Input[T]): Result[T, tuple[]] = + if inp.index + n <= inp.toks.len: + Result[T, tuple[]](kind: rkSuccess, output: (), input: inp.skip(n)) + else: + Result[T, tuple[]](kind: rkFailure) + +proc tok*[T](t: T): Parser[T, T] = + result = proc (inp: Input[T]): Result[T, T] = + if inp.index < inp.toks.len and inp.toks[inp.index] == t: + pskip[T](1).then(unit[T, T](t)).runInput(inp) + else: + Result[T, T](kind: rkFailure) + +proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] = + result = proc (inp: Input[T]): Result[T, O] = + let r = first.runInput(inp) + case r.kind + of rkSuccess: + r + else: + second.runInput(inp) + +# end of primitives (definitions involving Parser(..)) + +proc map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] = + self.chain(proc (v: O1): Parser[T, O2] = + unit[T, O2](p(v))) + +proc then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] = + self.chain(proc (v: O1): Parser[T, O2] = + next) + +proc `*`*[T, O1, O2](first: Parser[T, O1], second: Parser[T, O2]): Parser[T, (O1, O2)] = + first.chain(proc (v1: O1): Parser[T, (O1, O2)] = + second.map(proc (v2: O2): (O1, O2) = + (v1, v2))) + +proc repeat0*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] = + var nothing = unit[T, seq[O]](@[]) + inner.chain(proc(v: O): Parser[T, seq[O]] = + repeat0(inner).map(proc(vs: seq[O]): seq[O] = + @[v] & vs)) + nothing + +proc repeat1*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] = + inner.chain(proc(v: O): Parser[T, seq[O]] = + repeat0(inner).map(proc(vs: seq[O]): seq[O] = + @[v] & vs)) + +proc leftRec*[T, O, A](inner: Parser[T, O], after: Parser[T, A], fold: proc(i: O, a: A): O): Parser[T, O] = + (inner*repeat0(after)).map(proc(ias: (O, seq[A])): O = + var (i, asx) = ias + for a in asx: + i = fold(i, a) + i) + +proc lazy*[T, O](inner: proc(): Parser[T, O]): Parser[T, O] = + unit[T, tuple[]](()).chain(proc(v: tuple[]): Parser[T, O] = + inner()) diff --git a/tests/misc/t11634.nim b/tests/misc/t11634.nim new file mode 100644 index 000000000..390af40f4 --- /dev/null +++ b/tests/misc/t11634.nim @@ -0,0 +1,17 @@ +discard """ + action: reject +""" + +type Foo = ref object + val: int + +proc divmod(a, b: Foo): (Foo, Foo) = + ( + Foo(val: a.val div b.val), + Foo(val: a.val mod b.val) + ) + +block: + let a {.compileTime.} = Foo(val: 2) + let b {.compileTime.} = Foo(val: 3) + let (c11634 {.compileTime.}, d11634 {.compileTime.}) = divmod(a, b) diff --git a/tests/misc/t12480.nim b/tests/misc/t12480.nim new file mode 100644 index 000000000..992533ef6 --- /dev/null +++ b/tests/misc/t12480.nim @@ -0,0 +1,5 @@ +discard """ + errormsg: "'return' not allowed here" +""" + +return \ No newline at end of file diff --git a/tests/misc/t12869.nim b/tests/misc/t12869.nim new file mode 100644 index 000000000..054e28a03 --- /dev/null +++ b/tests/misc/t12869.nim @@ -0,0 +1,14 @@ +discard """ + errormsg: "type mismatch: got <openArray[int], proc (x: GenericParam, y: GenericParam): auto, SortOrder>" + line: 12 +""" + +import sugar +from algorithm import sorted, SortOrder + +let a = 5 + +proc sorted*[T](a: openArray[T], key: proc(v: T): int, order = SortOrder.Ascending): seq[T] = + sorted(a, (x, y) => key(x) < key(y), order) + +echo sorted(@[9, 1, 8, 2, 6, 4, 5, 0], (x) => (a - x).abs) diff --git a/tests/misc/t14667.nim b/tests/misc/t14667.nim new file mode 100644 index 000000000..3034e2841 --- /dev/null +++ b/tests/misc/t14667.nim @@ -0,0 +1,12 @@ +discard """ + matrix: "--cc:vcc" + disabled: "linux" + disabled: "bsd" + disabled: "osx" + disabled: "unix" + disabled: "posix" +""" + +type A = tuple +discard () +discard default(A) diff --git a/tests/misc/t15351.nim b/tests/misc/t15351.nim new file mode 100644 index 000000000..c31e604a2 --- /dev/null +++ b/tests/misc/t15351.nim @@ -0,0 +1,5 @@ +discard """ + action: "compile" +""" +var + ## TODO: broken diff --git a/tests/misc/t15955.nim b/tests/misc/t15955.nim new file mode 100644 index 000000000..7441e5398 --- /dev/null +++ b/tests/misc/t15955.nim @@ -0,0 +1,22 @@ +discard """ +joinable: false +""" + +import stdtest/specialpaths +import std/[osproc, strformat, os] + +const + nim = getCurrentCompilerExe() + buildLib = buildDir / "libD20220923T19380" + currentDir = splitFile(currentSourcePath).dir + file = currentDir / "m15955.nim" + main = currentDir / "m15955_main.nim" + + +proc runCmd(cmd: string) = + let (msg, code) = execCmdEx(cmd) + doAssert code == 0, msg + + +runCmd fmt"{nim} c -o:{buildLib} --nomain --nimMainPrefix:libA -f --app:staticlib {file}" +runCmd fmt"{nim} c -r {main}" diff --git a/tests/misc/t16244.nim b/tests/misc/t16244.nim new file mode 100644 index 000000000..5e8128736 --- /dev/null +++ b/tests/misc/t16244.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "type mismatch: got <int, float64>" + line: 9 +""" + +proc g(): auto = 1 +proc h(): auto = 1.0 + +var a = g() + h() diff --git a/tests/misc/t16264.nim b/tests/misc/t16264.nim new file mode 100644 index 000000000..afe319e6c --- /dev/null +++ b/tests/misc/t16264.nim @@ -0,0 +1,2 @@ +import times +doAssert low(Time) == fromUnix(0) \ No newline at end of file diff --git a/tests/misc/t16541.nim b/tests/misc/t16541.nim new file mode 100644 index 000000000..452327e8f --- /dev/null +++ b/tests/misc/t16541.nim @@ -0,0 +1,12 @@ +discard """ + action: "reject" + +""" + +import strutils, sugar, nre + +proc my_replace*(s: string, r: Regex, by: string | (proc (match: string): string)): string = + nre.replace(s, r, by) + +discard my_replace("abcde", re"[bcd]", match => match.to_upper) == "aBCDe" +discard my_replace("abcde", re"[bcd]", (match: string) => match.to_upper) == "aBCDe" diff --git a/tests/misc/t17286.nim b/tests/misc/t17286.nim new file mode 100644 index 000000000..3a54e624e --- /dev/null +++ b/tests/misc/t17286.nim @@ -0,0 +1,16 @@ +discard """ + cmd: "nim check -b:js $file" + action: "compile" +""" + +# bug #17286 + +import std/compilesettings + +static: + doAssert querySetting(backend) == "js" + doAssert defined(js) + doAssert not defined(c) + +import random +randomize() \ No newline at end of file diff --git a/tests/misc/t18077.nim b/tests/misc/t18077.nim new file mode 100644 index 000000000..6cd05d575 --- /dev/null +++ b/tests/misc/t18077.nim @@ -0,0 +1,21 @@ +discard """ + cmd: '''nim doc -d:nimTestsT18077b:4 --doccmd:"-d:nimTestsT18077 -d:nimTestsT18077b:3 --hints:off" $file''' + action: compile +""" + +# bug #18077 + +const nimTestsT18077b {.intdefine.} = 1 + +static: + when defined(nimdoc): + doAssert nimTestsT18077b == 4 + doAssert not defined(nimTestsT18077) + else: + doAssert defined(nimTestsT18077) + doAssert nimTestsT18077b == 3 + +runnableExamples: + const nimTestsT18077b {.intdefine.} = 2 + doAssert nimTestsT18077b == 3 + doAssert defined(nimTestsT18077) diff --git a/tests/misc/t18079.nim b/tests/misc/t18079.nim new file mode 100644 index 000000000..ae64bbff9 --- /dev/null +++ b/tests/misc/t18079.nim @@ -0,0 +1,15 @@ +discard """ + matrix: "--mm:orc" +""" + +type + Foo = object + y: int + + Bar = object + x: Foo + +proc baz(state: var Bar):int = + state.x.y = 2 + state.x.y +doAssert baz((ref Bar)(x: (new Foo)[])[]) == 2 diff --git a/tests/misc/t19046.nim b/tests/misc/t19046.nim new file mode 100644 index 000000000..b3bfec7ae --- /dev/null +++ b/tests/misc/t19046.nim @@ -0,0 +1,19 @@ +discard """ + targets: "c cpp" + matrix: "--threads:on" + disabled: "win" + disabled: "osx" + action: compile +""" + +# bug #19046 + +import std/os + +var t: Thread[void] + +proc test = discard +proc main = + createThread(t, test) + pinToCpu(t, 1) +main() \ No newline at end of file diff --git a/tests/misc/t20253.nim b/tests/misc/t20253.nim new file mode 100644 index 000000000..d47c36c55 --- /dev/null +++ b/tests/misc/t20253.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "'result' requires explicit initialization" + line: 10 +""" + +type Meow {.requiresInit.} = object + init: bool + +proc initMeow(): Meow = + discard diff --git a/tests/misc/t20289.nim b/tests/misc/t20289.nim new file mode 100644 index 000000000..5a0a269f0 --- /dev/null +++ b/tests/misc/t20289.nim @@ -0,0 +1,15 @@ +discard """ + action: reject +""" + +type E[T] = object + v: T + +template j[T](R: type E[T], x: untyped): R = R(v: x) +template d[T](O: type E, v: T): E[T] = E[T].j(v) + +proc w[T](): E[T] = + template r(k: int): auto = default(T) + E.d r + +discard w[int]() diff --git a/tests/misc/t20456_2.nim b/tests/misc/t20456_2.nim new file mode 100644 index 000000000..37e52c452 --- /dev/null +++ b/tests/misc/t20456_2.nim @@ -0,0 +1,14 @@ +discard """ + joinable: false +""" + +import std/[osproc, os, strformat] +from stdtest/specialpaths import testsDir + +when defined(nimPreviewSlimSystem): + import std/assertions + +const + nim = getCurrentCompilerExe() + file = testsDir / "misc" / "m20456.nims" +doAssert execCmd(fmt"{nim} check {file}") == 0 diff --git a/tests/misc/t20883.nim b/tests/misc/t20883.nim new file mode 100644 index 000000000..92e7929f4 --- /dev/null +++ b/tests/misc/t20883.nim @@ -0,0 +1,13 @@ +discard """ + action: reject +nimout: ''' +t20883.nim(13, 4) template/generic instantiation of `foo` from here +t20883.nim(9, 11) Error: cannot instantiate: 'U' +''' +""" + +proc foo*[U](x: U = U(1e-6)) = + echo x + +foo[float]() +foo() diff --git a/tests/misc/t21109.nim b/tests/misc/t21109.nim new file mode 100644 index 000000000..0f7980896 --- /dev/null +++ b/tests/misc/t21109.nim @@ -0,0 +1,13 @@ +discard """ + action: reject + errormsg: "type expected" + file: "iterators.nim" +""" + + +template b(j: untyped) = j +template m() = discard + +b: + for t, f in @[]: + m() diff --git a/tests/misc/t21443.nim b/tests/misc/t21443.nim new file mode 100644 index 000000000..70413c5b3 --- /dev/null +++ b/tests/misc/t21443.nim @@ -0,0 +1,6 @@ +import std/envvars + +# bug #19292 +putEnv("NimPutEnvTest", "test") +# bug #21122 +doAssert getEnv("NimPutEnvTest") == "test" diff --git a/tests/misc/t23240.nim b/tests/misc/t23240.nim new file mode 100644 index 000000000..d5edcefe8 --- /dev/null +++ b/tests/misc/t23240.nim @@ -0,0 +1,6 @@ +discard """ + cmd: "nim c foo/bar.nim" + action: "reject" + errormsg: "cannot open 'foo/'" + file: "" +""" diff --git a/tests/misc/t3482.nim b/tests/misc/t3482.nim new file mode 100644 index 000000000..33b3b8f40 --- /dev/null +++ b/tests/misc/t3482.nim @@ -0,0 +1,15 @@ +discard """ + action: reject + nimout: "t3482.nim(13, 8) Error: undeclared identifier: 'output'" +""" +# bug #3482 (correct behavior since 1.4.0, cgen error in 1.2.0) +template foo*(body: typed) = + if true: + body + +proc test = + foo: + var output = "" + echo output.len + +test() diff --git a/tests/misc/t3907.nim b/tests/misc/t3907.nim new file mode 100644 index 000000000..45fc75e81 --- /dev/null +++ b/tests/misc/t3907.nim @@ -0,0 +1,10 @@ +import std/assertions + +let a = 0 +let b = if false: -1 else: a +doAssert b == 0 + +let c: range[0..high(int)] = 0 +let d = if false: -1 else: c + +doAssert d == 0 diff --git a/tests/misc/t5540.nim b/tests/misc/t5540.nim new file mode 100644 index 000000000..6a19e70e1 --- /dev/null +++ b/tests/misc/t5540.nim @@ -0,0 +1,45 @@ +# bug #5540; works in 1.2.0 +# fails in 1.0 (Error: cannot generate VM code for) +# fails in 0.18.0 (Error: type mismatch: got <type T>) + +block: + type + Fruit = object + Yellow = object + a: int + template getColor(x: typedesc[Fruit]): typedesc = Yellow + type + Banana[T] = object + b: T + a: getColor(Fruit) + Apple[T] = object + a: T + b: getColor(T) + block: + var x: Banana[int] + doAssert x.b == 0 + doAssert x.a is Yellow + block: + var x: Apple[Fruit] + doAssert x.b is Yellow + +block: + type + Fruit = object + Yellow = object + a: int + + template getColor(x: typedesc[Fruit]): typedesc = Yellow + + type + Banana[T] = object + b: T + a: getColor(Fruit) + + Apple[T] = object + a: T + b: getColor(T) + + var x: Banana[int] + x.b = 13 + x.a.a = 17 diff --git a/tests/misc/t6549.nim b/tests/misc/t6549.nim new file mode 100644 index 000000000..1d7393318 --- /dev/null +++ b/tests/misc/t6549.nim @@ -0,0 +1,4 @@ + +const l = $(range[low(uint64) .. high(uint64)]) +const r = "range 0..18446744073709551615(uint64)" +doAssert l == r diff --git a/tests/misc/t8404.nim b/tests/misc/t8404.nim new file mode 100644 index 000000000..87991071c --- /dev/null +++ b/tests/misc/t8404.nim @@ -0,0 +1,33 @@ +discard """ + targets: "c cpp js" +""" +template main() = + block: # bug #8404 + # can conv + template float2int(T) = + var a = -1.0 + let b = T(a) + doAssert b < 0 + let c = b + 1 + doAssert c is T + doAssert c == 0 + + float2int(int8) + float2int(int16) + float2int(int32) + float2int(int64) + + block: + # can handle middle conv + # `/` can trigger int to float + template float2int(T) = + let n = T(1 / 256) + doAssert n == 0 + + float2int(int8) + float2int(int16) + float2int(int32) + # float2int(int64) +main() +static: + main() diff --git a/tests/misc/t8545.nim b/tests/misc/t8545.nim new file mode 100644 index 000000000..48b886cb8 --- /dev/null +++ b/tests/misc/t8545.nim @@ -0,0 +1,24 @@ +discard """ + # just tests that this doesn't crash the compiler + errormsg: "cannot instantiate: 'a:type'" +""" + +# bug #8545 + +template bar(a: static[bool]): untyped = int + +proc main() = + proc foo1(a: static[bool]): auto = 1 + doAssert foo1(true) == 1 + + proc foo2(a: static[bool]): bar(a) = 1 + doAssert foo2(true) == 1 + + proc foo3(a: static[bool]): bar(cast[static[bool]](a)) = 1 + doAssert foo3(true) == 1 + + proc foo4(a: static[bool]): bar(static(a)) = 1 + doAssert foo4(true) == 1 + +static: main() +main() diff --git a/tests/misc/t9039.nim b/tests/misc/t9039.nim new file mode 100644 index 000000000..3271cd34e --- /dev/null +++ b/tests/misc/t9039.nim @@ -0,0 +1,24 @@ +discard """ + action: reject + nimout: ''' +t9039.nim(22, 22) Error: type mismatch: got <array[0..2, int], int, array[0..1, int]> +but expression 'nesting + 1' is of type: int +''' +""" + +# bug #9039; this used to hang in 0.19.0 + + + + + +# line 15 +func default(T: typedesc[array]): T = discard +doAssert default(array[3, int]) == [0, 0, 0] +func shapeBad*[T: not char](s: openArray[T], rank: static[int], nesting = 0, parent_shape = default(array[rank, int])): array[rank, int] = + result = parent_shape + result[nesting] = s.len + when (T is seq|array): + result = shapeBad(s[0], nesting + 1, result) +let a1 = [1, 2, 3].shapeBad(rank = 1) +let a2 = [[1, 2, 3], [4, 5, 6]].shapeBad(rank = 2) diff --git a/tests/misc/t9091.nim b/tests/misc/t9091.nim new file mode 100644 index 000000000..6e7a98ca5 --- /dev/null +++ b/tests/misc/t9091.nim @@ -0,0 +1,33 @@ +# bug #9091 + +import streams + +block: + type Mine = ref object + a: int + + proc write(io: Stream, t: Mine) = + io.write("sure") + + let str = newStringStream() + let mi = new Mine + + str.write(mi) + str.setPosition 0 + doAssert str.readAll == "sure" + +block: + type + AObj = object + x: int + + proc foo(a: int): string = "" + + proc test(args: varargs[string, foo]) = + doAssert false + + proc test(a: AObj) = + discard + + let x = AObj() + test(x) diff --git a/tests/misc/t9710.nim b/tests/misc/t9710.nim new file mode 100644 index 000000000..c65cb7bf4 --- /dev/null +++ b/tests/misc/t9710.nim @@ -0,0 +1,6 @@ +discard """ + matrix: "--debugger:native" +""" +# bug #9710 +for i in 1 || 200: + discard i diff --git a/tests/misc/t99bott.nim b/tests/misc/t99bott.nim new file mode 100644 index 000000000..f60023818 --- /dev/null +++ b/tests/misc/t99bott.nim @@ -0,0 +1,32 @@ +discard """ + errormsg: "cannot evaluate at compile time: bn" + file: "t99bott.nim" + line: 26 +""" + +## 99 Bottles of Beer +## http://www.99-bottles-of-beer.net/ +## Nim version + +## Author: Philippe Lhoste <PhiLho(a)GMX.net> http://Phi.Lho.free.fr +# 2012-11-25 +# Loosely based on my old Lua version... Updated to current official lyrics. + +proc GetBottleNumber(n: int): string = + var bs: string + if n == 0: + bs = "No more bottles" + elif n == 1: + bs = "1 bottle" + else: + bs = $n & " bottles" + return bs & " of beer" + +for bn in countdown(99, 1): + const cur = GetBottleNumber(bn) + echo(cur, " on the wall, ", cur, ".") + echo("Take one down and pass it around, ", GetBottleNumber(bn-1), + " on the wall.\n") + +echo "No more bottles of beer on the wall, no more bottles of beer." +echo "Go to the store and buy some more, 99 bottles of beer on the wall." diff --git a/tests/misc/tack.nim b/tests/misc/tack.nim new file mode 100644 index 000000000..458395ef6 --- /dev/null +++ b/tests/misc/tack.nim @@ -0,0 +1,19 @@ +discard """ + output: "125" +""" +# the Ackermann function + +proc ack(x, y: int): int = + if x != 0: + if y != 0: + return ack(x-1, ack(x, y-1)) + return ack(x-1, 1) + else: + return y + 1 +# if x == 0: return y + 1 +# elif y == 0: return ack(x-1, 1) +# else: return ack(x-1, ack(x, y-1)) + +# echo(ack(0, 0)) +write(stdout, ack(3, 4)) #OUT 125 +write stdout, "\n" diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim new file mode 100644 index 000000000..64f95c7e3 --- /dev/null +++ b/tests/misc/taddr.nim @@ -0,0 +1,295 @@ +discard """ + targets: "c cpp js" + matrix: "; -d:release" +""" + +type T = object + x: int + s: string + +var obj: T +var fieldAddr = addr(obj.x) +var objAddr = addr(obj) + +# Integer tests +var field = fieldAddr[] +doAssert field == 0 + +var objDeref = objAddr[] +doAssert objDeref.x == 0 + +# Change value +obj.x = 42 + +doAssert field == 0 +doAssert objDeref.x == 0 + +field = fieldAddr[] +objDeref = objAddr[] + +doAssert field == 42 +doAssert objDeref.x == 42 + +# String tests +obj.s = "lorem ipsum dolor sit amet" +when defined(gcArc) or defined(gcOrc): + prepareMutation(obj.s) + + +var indexAddr = addr(obj.s[2]) + +doAssert indexAddr[] == 'r' + +indexAddr[] = 'd' + +doAssert indexAddr[] == 'd' + +doAssert obj.s == "lodem ipsum dolor sit amet" + +# Bug #2148 +var x: array[2, int] +var y = addr x[1] + +y[] = 12 +doAssert(x[1] == 12) + +type + Foo = object + bar: int + +var foo: array[2, Foo] +var z = addr foo[1] + +z[].bar = 12345 +doAssert(foo[1].bar == 12345) + +var t : tuple[a, b: int] +var pt = addr t[1] +pt[] = 123 +doAssert(t.b == 123) + +#block: # Test "untyped" pointer. +proc testPtr(p: pointer, a: int) = + doAssert(a == 5) + (cast[ptr int](p))[] = 124 +var i = 123 +testPtr(addr i, 5) +doAssert(i == 124) + +var someGlobal = 5 +proc getSomeGlobalPtr(): ptr int = addr someGlobal +let someGlobalPtr = getSomeGlobalPtr() +doAssert(someGlobalPtr[] == 5) +someGlobalPtr[] = 10 +doAssert(someGlobal == 10) + +block: + # bug #14576 + # lots of these used to give: Error: internal error: genAddr: 2 + proc byLent[T](a: T): lent T = a + proc byPtr[T](a: T): ptr T = a.addr + + block: + let a = (10,11) + let (x,y) = byLent(a) + doAssert (x,y) == a + + block: # (with -d:release) bug #14578 + let a = 10 + doAssert byLent(a) == 10 + let a2 = byLent(a) + doAssert a2 == 10 + + block: + let a = [11,12] + doAssert byLent(a) == [11,12] # bug #15958 + let a2 = (11,) + doAssert byLent(a2) == (11,) + + block: + proc byLent2[T](a: seq[T]): lent T = a[1] + var a = @[20,21,22] + doAssert byLent2(a) == 21 + + block: # sanity checks + proc bar[T](a: var T): var T = a + var a = (10, 11) + let (k,v) = bar(a) + doAssert (k, v) == a + doAssert k == 10 + bar(a)[0]+=100 + doAssert a == (110, 11) + var a2 = 12 + doAssert bar(a2) == a2 + bar(a2).inc + doAssert a2 == 13 + + block: # pending bug #15959 + when false: + proc byLent2[T](a: T): lent type(a[0]) = a[0] + +proc test14420() = # bug #14420 + # s/proc/template/ would hit bug #16005 + block: + type Foo = object + x: float + + proc fn(a: var Foo): var float = + ## WAS: discard <- turn this into a comment (or a `discard`) and error disappears + # result = a.x # this works + a.x # WAS: Error: limited VM support for 'addr' + + proc fn2(a: var Foo): var float = + result = a.x # this works + a.x # WAS: Error: limited VM support for 'addr' + + var a = Foo() + discard fn(a) + discard fn2(a) + + block: + proc byLent2[T](a: T): lent T = + runnableExamples: discard + a + proc byLent3[T](a: T): lent T = + runnableExamples: discard + result = a + var a = 10 + let x3 = byLent3(a) # works + let x2 = byLent2(a) # WAS: Error: internal error: genAddr: nkStmtListExpr + + block: + type MyOption[T] = object + case has: bool + of true: + value: T + of false: + discard + func some[T](val: T): MyOption[T] = + result = MyOption[T](has: true, value: val) + func get[T](opt: MyOption[T]): lent T = + doAssert opt.has + # result = opt.value # this was ok + opt.value # this had the bug + let x = some(10) + doAssert x.get() == 10 + +template test14339() = # bug #14339 + block: + type + Node = ref object + val: int + proc bar(c: Node): var int = + var n = c # was: Error: limited VM support for 'addr' + c.val + var a = Node() + discard a.bar() + block: + type + Node = ref object + val: int + proc bar(c: Node): var int = + var n = c + doAssert n.val == n[].val + n.val + var a = Node(val: 3) + a.bar() = 5 + when nimvm: + doAssert a.val == 5 + else: + when not defined(js): # pending bug #16003 + doAssert a.val == 5 + +template testStatic15464() = # bug #15464 + proc access(s: var seq[char], i: int): var char = s[i] + proc access(s: var string, i: int): var char = s[i] + static: + var s = @['a', 'b', 'c'] + access(s, 2) = 'C' + doAssert access(s, 2) == 'C' + static: + var s = "abc" + access(s, 2) = 'C' + doAssert access(s, 2) == 'C' + +proc test15464() = # bug #15464 (v2) + proc access(s: var seq[char], i: int): var char = s[i] + proc access(s: var string, i: int): var char = s[i] + block: + var s = @['a', 'b', 'c'] + access(s, 2) = 'C' + doAssert access(s, 2) == 'C' + block: + var s = "abc" + access(s, 2) = 'C' + doAssert access(s, 2) == 'C' + +block: # bug #15939 + block: + const foo = "foo" + proc proc1(s: var string) = + if s[^1] notin {'a'..'z'}: + s = "" + proc proc2(f: string): string = + result = f + proc1(result) + const bar = proc2(foo) + doAssert bar == "foo" + +template prepareMutationForOrc(x: string) = + when defined(gcArc) or defined(gcOrc): + when nimvm: + discard + else: + prepareMutation(x) + +proc test15939() = # bug #15939 (v2) + template fn(a) = + when typeof(a) is string: + prepareMutationForOrc(a) + let pa = a[0].addr + doAssert pa != nil + doAssert pa[] == 'a' + pa[] = 'x' + doAssert pa[] == 'x' + doAssert a == "xbc" + when not defined js: # otherwise overflows + let pa2 = cast[ptr char](cast[int](pa) + 1) + doAssert pa2[] == 'b' + pa2[] = 'B' + doAssert a == "xBc" + + # mystring[ind].addr + var a = "abc" + fn(a) + + # mycstring[ind].addr + template cstringTest = + var a2 = "abc" + prepareMutationForOrc(a2) + var b2 = a2.cstring + fn(b2) + when nimvm: cstringTest() + else: # can't take address of cstring element in js + when not defined(js): cstringTest() + +block: # bug #23499 + template volatileStore[T](dest: ptr T, val: T) = + dest[] = val + + proc foo = + var ctr = 0 + volatileStore(addr ctr, 0) + + foo() + +template main = + # xxx wrap all other tests here like that so they're also tested in VM + test14420() + test14339() + test15464() + test15939() + +testStatic15464() +static: main() +main() diff --git a/tests/misc/tapp_lib_staticlib.nim b/tests/misc/tapp_lib_staticlib.nim new file mode 100644 index 000000000..92c9acbc3 --- /dev/null +++ b/tests/misc/tapp_lib_staticlib.nim @@ -0,0 +1,27 @@ +discard """ +joinable: false +""" + +# bug #16949 + +when defined case1: + proc foo(): int {.exportc.} = 10 +elif defined case2: + proc foo(): int {.exportc, dynlib.} = 10 +elif defined caseMain: + proc foo(): int {.importc.} + doAssert foo() == 10 +else: + import stdtest/specialpaths + import std/[os, strformat, strutils, compilesettings] + proc runCmd(cmd: string) = + doAssert execShellCmd(cmd) == 0, $cmd + const + file = currentSourcePath + nim = getCurrentCompilerExe() + mode = querySetting(backend) + proc test(lib, options: string) = + runCmd fmt"{nim} {mode} -o:{lib} --nomain {options} -f {file}" + # runCmd fmt"{nim} r -b:{mode} --passl:{lib} -d:caseMain -f {file}" # pending https://github.com/nim-lang/Nim/pull/16945 + test(buildDir / "libD20210205T172314.a", "--app:staticlib -d:nimLinkerWeakSymbols -d:case1") + test(buildDir / DynlibFormat % "D20210205T172720", "--app:lib -d:case2") diff --git a/tests/misc/tbug1217bracketquotes.nim b/tests/misc/tbug1217bracketquotes.nim new file mode 100644 index 000000000..90e67d45b --- /dev/null +++ b/tests/misc/tbug1217bracketquotes.nim @@ -0,0 +1,14 @@ +discard """ + output: "13{(.{}}{*4&*$**()&*@1235" +""" + +type + Test = enum + `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@` + +let `.}` = 1 +let `(}` = 2 +let `[` = 3 +let `]` = 5 + +echo `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`, `.}`, `(}`, `[`, `]` diff --git a/tests/misc/tbug511622.nim b/tests/misc/tbug511622.nim new file mode 100644 index 000000000..1af6380ed --- /dev/null +++ b/tests/misc/tbug511622.nim @@ -0,0 +1,12 @@ +discard """ + output: "3" +""" +import math + +proc FibonacciA(n: int): int64 = + var fn = float64(n) + var p: float64 = (1.0 + sqrt(5.0)) / 2.0 + var q: float64 = 1.0 / p + return int64((pow(p, fn) + pow(q, fn)) / sqrt(5.0)) + +echo FibonacciA(4) #OUT 3 diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim new file mode 100644 index 000000000..73196e76c --- /dev/null +++ b/tests/misc/tcast.nim @@ -0,0 +1,108 @@ +discard """ + output: ''' +Hello World +Hello World +Hello World''' + joinable: false +""" +type MyProc = proc() {.cdecl.} +type MyProc2 = proc() {.nimcall.} +type MyProc3 = proc() #{.closure.} is implicit + +proc testProc() {.exportc:"foo".} = echo "Hello World" + +template reject(x) = doAssert(not compiles(x)) + +proc callPointer(p: pointer) = + # can cast to proc(){.cdecl.} + let ffunc0 = cast[MyProc](p) + # can cast to proc(){.nimcall.} + let ffunc1 = cast[MyProc2](p) + # cannot cast to proc(){.closure.} + reject: cast[MyProc3](p) + + ffunc0() + ffunc1() + + # bug #5901 + proc foo() {.importc.} + (cast[proc(a: int) {.cdecl.}](foo))(5) + +callPointer(cast[pointer](testProc)) + +reject: discard cast[enum](0) +proc a = echo "hi" + +reject: discard cast[ptr](a) + +# bug #15623 +block: + if false: + let x = cast[ptr int](nil) + echo x[] + +block: + if false: + var x: ref int = nil + echo cast[ptr int](x)[] + +block: + doAssert cast[int](cast[ptr int](nil)) == 0 + +block: + var x: ref int = nil + doAssert cast[int](cast[ptr int](x)) == 0 + +block: # cast of nil + block: + static: + let a = cast[pointer](nil) + doAssert a.repr == "nil" + + block: + static: + doAssert cast[ptr int](nil).repr == "nil" + + block: + const str = cast[ptr int](nil) + static: + doAssert str.repr == "nil" + + block: + static: + doAssert cast[ptr int](nil).repr == "nil" + + block: + static: + doAssert cast[RootRef](nil).repr == "nil" + + when false: # xxx bug #15730, not fixed yet + block: + static: + doAssert cast[cstring](nil).repr == "nil" + +template main() = + # xxx move all under here to get tested in VM + block: # cast of enum + type Koo = enum k1, k2 + type Goo = enum g1, g2 + type Boo = enum b1 = -1, b2, b3, b4 + type Coo = enum c1 = -1i8, c2, c3, c4 + when nimvm: + # xxx: Error: VM does not support 'cast' from tyEnum to tyEnum + discard + else: + doAssert cast[Koo](k2) == k2 + doAssert cast[Goo](k2) == g2 + doAssert cast[Goo](k2.ord) == g2 + + doAssert b3.ord == 1 + doAssert cast[Koo](b3) == k2 + doAssert cast[Boo](k2) == b3 + + doAssert c3.ord == 1 + doAssert cast[Koo](c3) == k2 + doAssert cast[Coo](k2) == c3 + +static: main() +main() diff --git a/tests/misc/tcharinc.nim b/tests/misc/tcharinc.nim new file mode 100644 index 000000000..1b5d19c18 --- /dev/null +++ b/tests/misc/tcharinc.nim @@ -0,0 +1,10 @@ +discard """ + output: "1" +""" + +var c = '\0' +while true: + if c == '\xFF': break + inc c + +echo "1" diff --git a/tests/misc/tcmdline.nim b/tests/misc/tcmdline.nim new file mode 100644 index 000000000..71e1301ca --- /dev/null +++ b/tests/misc/tcmdline.nim @@ -0,0 +1,18 @@ +discard """ +outputsub: "Number of parameters: 0" +joinable: false +""" +# Test the command line + +import + os, strutils + +var + i: int + params = paramCount() +i = 0 +writeLine(stdout, "This exe: " & getAppFilename()) +writeLine(stdout, "Number of parameters: " & $params) +while i <= params: + writeLine(stdout, paramStr(i)) + i = i + 1 diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim new file mode 100644 index 000000000..90fae868b --- /dev/null +++ b/tests/misc/tconv.nim @@ -0,0 +1,143 @@ +discard """ + matrix: "--warningAsError:EnumConv --warningAsError:CStringConv" +""" + +from std/enumutils import items # missing from the example code +from std/sequtils import toSeq + +template reject(x) = + static: doAssert(not compiles(x)) +template accept(x) = + static: doAssert(compiles(x)) + +reject: + const x = int8(300) + +reject: + const x = int64(NaN) + +type + R = range[0..10] + +reject: + const x = R(11) + +reject: + const x = R(11.0) + +reject: + const x = R(NaN) + +reject: + const x = R(Inf) + +type + FloatRange = range[0'f..10'f] + +reject: + const x = FloatRange(-1'f) + +reject: + const x = FloatRange(-1) + +reject: + const x = FloatRange(NaN) + +block: + const x = float32(NaN) + +type E = enum a, b, c + +reject: + const e = E(4) + +block: # issue 3766 + + type R = range[0..2] + + reject: + type + T[n: static[R]] = object + V = T[3.R] + + reject: + proc r(x: static[R]) = + echo x + r 3.R + + +block: # https://github.com/nim-lang/RFCs/issues/294 + type Koo = enum k1, k2 + type Goo = enum g1, g2 + + accept: Koo(k2) + accept: k2.Koo + accept: k2.int.Goo + + reject: Goo(k2) + reject: k2.Goo + reject: k2.string + + {.push warningAsError[EnumConv]:off.} + discard Goo(k2) + accept: Goo(k2) + accept: k2.Goo + reject: k2.string + {.pop.} + + reject: Goo(k2) + reject: k2.Goo + + type KooRange = range[k2..k2] + accept: KooRange(k2) + accept: k2.KooRange + let k2ranged: KooRange = k2 + accept: Koo(k2ranged) + accept: k2ranged.Koo + +reject: + # bug #18550 + proc f(c: char): cstring = + var x = newString(109*1024*1024) + x[0] = c + x + +{.push warning[AnyEnumConv]:on, warningAsError[AnyEnumConv]:on.} + +reject: + type + Foo = enum + one + three + + var va = 2 + var vb = va.Foo + +{.pop.} + +{.push warningAsError[HoleEnumConv]:on.} + +reject: + # bug #12815 + type + Hole = enum + one = 1 + three = 3 + + var va = 2 + var vb = va.Hole + +block: # bug #22844 + type + A = enum + a0 = 2 + a1 = 4 + a2 + B[T] = enum + b0 = 2 + b1 = 4 + + doAssert A.toSeq == [a0, a1, a2] + doAssert B[float].toSeq == [B[float].b0, B[float].b1] + +{.pop.} diff --git a/tests/misc/tcsharpusingstatement.nim b/tests/misc/tcsharpusingstatement.nim new file mode 100644 index 000000000..1ce553895 --- /dev/null +++ b/tests/misc/tcsharpusingstatement.nim @@ -0,0 +1,76 @@ +discard """ + output: "Using test.Closing test." +""" + +import + macros + +# This macro mimics the using statement from C# +# +# It's kept only as a test for the macro system +# Nim's destructors offer a mechanism for automatic +# disposal of resources. +# +macro autoClose(args: varargs[untyped]): untyped = + let e = callsite() + if e.len != 3: + error "Using statement: unexpected number of arguments. Got " & + $e.len & ", expected: 1 or more variable assignments and a block" + + var args = e + var body = e[2] + + var + variables : seq[NimNode] + closingCalls : seq[NimNode] + + newSeq(variables, 0) + newSeq(closingCalls, 0) + + for i in countup(1, args.len-2): + if args[i].kind == nnkExprEqExpr: + var varName = args[i][0] + var varValue = args[i][1] + + var varAssignment = newNimNode(nnkIdentDefs) + varAssignment.add(varName) + varAssignment.add(newNimNode(nnkEmpty)) # empty means no type + varAssignment.add(varValue) + variables.add(varAssignment) + + closingCalls.add(newCall(newIdentNode("close"), varName)) + else: + error "Using statement: Unexpected expression. Got " & + $args[i].kind & " instead of assignment." + + var varSection = newNimNode(nnkVarSection) + varSection.add(variables) + + var finallyBlock = newNimNode(nnkStmtList) + finallyBlock.add(closingCalls) + + result = quote do: + block: + `varSection` + try: + `body` + finally: + `finallyBlock` + +type + TResource* = object + field*: string + +proc openResource(param: string): TResource = + result.field = param + +proc close(r: var TResource) = + write(stdout, "Closing " & r.field & ".") + +proc use(r: var TResource) = + write(stdout, "Using " & r.field & ".") + +autoClose(r = openResource("test")): + use r + +write stdout, "\n" diff --git a/tests/misc/tdangerisrelease.nim b/tests/misc/tdangerisrelease.nim new file mode 100644 index 000000000..e1854dca5 --- /dev/null +++ b/tests/misc/tdangerisrelease.nim @@ -0,0 +1,14 @@ +discard """ + cmd: "nim c $options -r $file" + matrix: "-d:danger; -d:release" + output: ''' +a +b +c +''' +""" + +echo "a" +when defined(release): + echo "b" +echo "c" diff --git a/tests/misc/tdefine.nim b/tests/misc/tdefine.nim new file mode 100644 index 000000000..f3fa4711f --- /dev/null +++ b/tests/misc/tdefine.nim @@ -0,0 +1,77 @@ +discard """ +joinable: false +cmd: "nim c $options -d:booldef -d:booldef2=false -d:intdef=2 -d:strdef=foobar -d:namespaced.define=false -d:double.namespaced.define -r $file" +matrix: "; -d:useGenericDefine" +""" + +when defined(useGenericDefine): + {.pragma: booldefine2, define.} + {.pragma: intdefine2, define.} + {.pragma: strdefine2, define.} +else: + + {.pragma: booldefine2, booldefine.} + {.pragma: intdefine2, intdefine.} + {.pragma: strdefine2, strdefine.} + +const booldef {.booldefine2.} = false +const booldef2 {.booldefine2.} = true +const intdef {.intdefine2.} = 0 +const strdef {.strdefine2.} = "" + +doAssert defined(booldef) +doAssert defined(booldef2) +doAssert defined(intdef) +doAssert defined(strdef) +doAssert booldef +doAssert not booldef2 +doAssert intdef == 2 +doAssert strdef == "foobar" + +when defined(useGenericDefine): + block: + const uintdef {.define: "intdef".}: uint = 17 + doAssert intdef == int(uintdef) + const cstrdef {.define: "strdef".}: cstring = "not strdef" + doAssert $cstrdef == strdef + type FooBar = enum foo, bar, foobar + const enumdef {.define: "strdef".} = foo + doAssert $enumdef == strdef + doAssert enumdef == foobar + +# Intentionally not defined from command line +const booldef3 {.booldefine2.} = true +const intdef2 {.intdefine2.} = 1 +const strdef2 {.strdefine2.} = "abc" +type T = object + when booldef3: + field1: int + when intdef2 == 1: + field2: int + when strdef2 == "abc": + field3: int + +doAssert not defined(booldef3) +doAssert not defined(intdef2) +doAssert not defined(strdef2) +discard T(field1: 1, field2: 2, field3: 3) + +doAssert defined(namespaced.define) +const `namespaced.define` {.booldefine2.} = true +doAssert not `namespaced.define` +when defined(useGenericDefine): + const aliasToNamespacedDefine {.define: "namespaced.define".} = not `namespaced.define` +else: + const aliasToNamespacedDefine {.booldefine: "namespaced.define".} = not `namespaced.define` +doAssert aliasToNamespacedDefine == `namespaced.define` + +doAssert defined(double.namespaced.define) +const `double.namespaced.define` {.booldefine2.} = false +doAssert `double.namespaced.define` +when defined(useGenericDefine): + const aliasToDoubleNamespacedDefine {.define: "double.namespaced.define".} = not `double.namespaced.define` +else: + const aliasToDoubleNamespacedDefine {.booldefine: "double.namespaced.define".} = not `double.namespaced.define` +doAssert aliasToDoubleNamespacedDefine == `double.namespaced.define` + +doAssert not defined(namespaced.butnotdefined) diff --git a/tests/misc/tdllvar.nim b/tests/misc/tdllvar.nim new file mode 100644 index 000000000..68029ddf4 --- /dev/null +++ b/tests/misc/tdllvar.nim @@ -0,0 +1,18 @@ +discard """ +disabled: true +""" + +import os + +proc getDllName: string = + result = "mylib.dll" + if fileExists(result): return + result = "mylib2.dll" + if fileExists(result): return + quit("could not load dynamic library") + +proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().} +proc myImport2(s: int) {.cdecl, importc, dynlib: getDllName().} + +myImport("test2") +myImport2(12) diff --git a/tests/misc/teventemitter.nim b/tests/misc/teventemitter.nim new file mode 100644 index 000000000..7da1a2522 --- /dev/null +++ b/tests/misc/teventemitter.nim @@ -0,0 +1,32 @@ +discard """ + output: "pie" +""" + +import tables, lists + +type + EventArgs = object of RootObj + EventEmitter = object of RootObj + events*: Table[string, DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]] + +proc emit*(emitter: EventEmitter, event: string, args: EventArgs) = + for fn in nodes(emitter.events[event]): + fn.value(args) #call function with args. + +proc on*(emitter: var EventEmitter, event: string, + fn: proc(e: EventArgs) {.nimcall.}) = + if not hasKey(emitter.events, event): + var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}] + add(emitter.events, event, list) #if not, add it. + append(emitter.events[event], fn) + +proc initEmitter(emitter: var EventEmitter) = + emitter.events = initTable[string, + DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]]() + +var + ee: EventEmitter + args: EventArgs +initEmitter(ee) +ee.on("print", proc(e: EventArgs) = echo("pie")) +ee.emit("print", args) diff --git a/tests/misc/tfib.nim b/tests/misc/tfib.nim new file mode 100644 index 000000000..34fe0dcf9 --- /dev/null +++ b/tests/misc/tfib.nim @@ -0,0 +1,11 @@ + +iterator fibonacci(): int = + var a = 0 + var b = 1 + while true: + yield a + var c = b + b = a + a = a + c + + diff --git a/tests/misc/tfilter.nim b/tests/misc/tfilter.nim new file mode 100644 index 000000000..5846d0efb --- /dev/null +++ b/tests/misc/tfilter.nim @@ -0,0 +1,41 @@ +discard """ + output: "02468101214161820\n15" +""" + +proc filter[T](list: seq[T], f: proc (item: T): bool {.closure.}): seq[T] = + result = @[] + for i in items(list): + if f(i): + result.add(i) + +let nums = @[0, 1, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] + +when true: + let nums2 = filter(nums, + (proc (item: int): bool = + result = (item mod 2) == 0) + ) + +proc outer = + # lets use a proper closure this time: + var modulo = 2 + let nums2 = filter(nums, + (proc (item: int): bool = result = (item mod modulo) == 0) + ) + + for n in nums2: stdout.write(n) + stdout.write("\n") + +outer() + +import math +proc compose[T](f1, f2: proc (x: T): T {.closure.}): proc (x: T): T {.closure.} = + result = (proc (x: T): T = + result = f1(f2(x))) + + +proc add5(x: int): int = result = x + 5 + +var test = compose(add5, add5) +echo test(5) + diff --git a/tests/misc/thallo.nim b/tests/misc/thallo.nim new file mode 100644 index 000000000..8dac56023 --- /dev/null +++ b/tests/misc/thallo.nim @@ -0,0 +1,87 @@ +discard """ +action: compile +""" + +# noted this seems to be an old test file designed for manual testing. + +import + os, strutils, macros + +type + TMyEnum = enum + meA, meB, meC, meD + +when true: + {.hint: "this is the main file".} + +proc fac[T](x: T): T = + # test recursive generic procs + if x <= 1: return 1 + else: return x.`*`(fac(x-1)) + +macro macrotest(n: varargs[untyped]): untyped = + let n = callsite() + expectKind(n, nnkCall) + expectMinLen(n, 2) + result = newNimNode(nnkStmtList, n) + for i in 2..n.len-1: + result.add(newCall("write", n[1], n[i])) + result.add(newCall("writeLine", n[1], newStrLitNode(""))) + +macro debug(n: untyped): untyped = + let n = callsite() + result = newNimNode(nnkStmtList, n) + for i in 1..n.len-1: + result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i]))) + result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": "))) + result.add(newCall("writeLine", newIdentNode("stdout"), n[i])) + +macrotest(stdout, "finally", 4, 5, "variable", "argument lists") +macrotest(stdout) + +#GC_disable() + +echo("This was compiled by Nim version " & system.NimVersion) +writeLine(stdout, "Hello", " World", "!") + +echo(["a", "b", "c", "d"].len) +for x in items(["What's", "your", "name", "?", ]): + echo(x) +var `name` = readLine(stdin) +echo("Hi " & thallo.name & "!\n") +debug(name) + +var testseq: seq[string] = @[ + "a", "b", "c", "d", "e" +] +echo(repr(testseq)) + +var dummy = "hello" +echo(substr(dummy, 2, 3)) + +echo($meC) + +# test tuples: +for x, y in items([(1, 2), (3, 4), (6, 1), (5, 2)]): + echo x + echo y + +proc simpleConst(): int = return 34 + +# test constant evaluation: +const + constEval3 = simpleConst() + constEval = "abc".contains('b') + constEval2 = fac(7) + +echo(constEval3) +echo(constEval) +echo(constEval2) +echo(1.`+`(2)) + +for i in 2..6: + for j in countdown(i+4, 2): + echo(fac(i * j)) + +when true: + {.hint: "this is the main file".} diff --git a/tests/misc/theaproots.nim b/tests/misc/theaproots.nim new file mode 100644 index 000000000..2dd345254 --- /dev/null +++ b/tests/misc/theaproots.nim @@ -0,0 +1,75 @@ +discard """ +action: compile +""" + +type + Bar = object + x: int + + Foo = object + rheap: ref Bar + rmaybe: ref Bar + rstack: ref Bar + list: seq[ref Bar] + listarr: array[0..5, ref Bar] + nestedtup: Tup + inner: TInner + inref: ref TInner + + TInner = object + inref: ref Bar + + Tup = tuple + tupbar: ref Bar + inner: TInner + +proc acc(x: var Foo): var ref Bar = + result = x.rheap + +proc test(maybeFoo: var Foo, + maybeSeq: var seq[ref Bar], + bars: var openArray[ref Bar], + maybeTup: var Tup) = + var bb: ref Bar + maybeFoo.rmaybe = bb + maybeFoo.list[3] = bb + maybeFoo.listarr[3] = bb + acc(maybeFoo) = bb + + var localFoo: Foo + localFoo.rstack = bb + localFoo.list[3] = bb + localFoo.listarr[3] = bb + acc(localFoo) = bb + + var heapFoo: ref Foo + heapFoo.rheap = bb + heapFoo.list[3] = bb + heapFoo.listarr[3] = bb + acc(heapFoo[]) = bb + + heapFoo.nestedtup.tupbar = bb + heapFoo.nestedtup.inner.inref = bb + heapFoo.inner.inref = bb + heapFoo.inref.inref = bb + + var locseq: seq[ref Bar] + locseq[3] = bb + + var locarr: array[0..4, ref Bar] + locarr[3] = bb + + maybeSeq[3] = bb + + bars[3] = bb + + maybeTup[0] = bb + +var + ff: ref Foo + tt: Tup + gseq: seq[ref Bar] + +new(ff) + +test(ff[], gseq, gseq, tt) diff --git a/tests/misc/tinit.nim b/tests/misc/tinit.nim new file mode 100644 index 000000000..207cb17e8 --- /dev/null +++ b/tests/misc/tinit.nim @@ -0,0 +1,9 @@ +discard """ + output: "Hello from module! Hello from main module!" +""" +# Test the new init section in modules + +import minit + +write(stdout, "Hello from main module!\n") +#OUT Hello from module! Hello from main module! diff --git a/tests/misc/tinout.nim b/tests/misc/tinout.nim new file mode 100644 index 000000000..bae0fb185 --- /dev/null +++ b/tests/misc/tinout.nim @@ -0,0 +1,14 @@ +discard """ + errormsg: "type mismatch: got <int literal(3)>" + file: "tinout.nim" + line: 12 +""" +# Test in out checking for parameters + +proc abc(x: var int) = + x = 0 + +proc b() = + abc(3) #ERROR + +b() diff --git a/tests/misc/tinvalidnewseq.nim b/tests/misc/tinvalidnewseq.nim new file mode 100644 index 000000000..7a95db020 --- /dev/null +++ b/tests/misc/tinvalidnewseq.nim @@ -0,0 +1,24 @@ +discard """ + errormsg: "type mismatch: got <array[0..6, string], int literal(7)>" + file: "tinvalidnewseq.nim" + line: 15 +""" +import re, strutils + +type + TURL = tuple[protocol, subdomain, domain, port: string, path: seq[string]] + +proc parseURL(url: string): TURL = + #([a-zA-Z]+://)?(\w+?\.)?(\w+)(\.\w+)(:[0-9]+)?(/.+)? + var pattern: string = r"([a-zA-Z]+://)?(\w+?\.)?(\w+)(\.\w+)(:[0-9]+)?(/.+)?" + var m: array[0..6, string] #Array with the matches + newSeq(m, 7) #ERROR + discard re.match(url, re(pattern), m) + + result = (protocol: m[1], subdomain: m[2], domain: m[3] & m[4], + port: m[5], path: m[6].split('/')) + +var r: TUrl + +r = parseUrl(r"http://google.com/search?var=bleahdhsad") +echo(r.domain) diff --git a/tests/misc/tissue710.nim b/tests/misc/tissue710.nim new file mode 100644 index 000000000..ec125b840 --- /dev/null +++ b/tests/misc/tissue710.nim @@ -0,0 +1,10 @@ +discard """ + errorMsg: "attempting to call routine: '||'" + file: "tissue710.nim" + line: 8 +""" +var sum = 0 +for x in 3..1000: + if (x mod 3 == 0) || (x mod 5 == 0): + sum += x +echo(sum) diff --git a/tests/misc/tjoinable.nim b/tests/misc/tjoinable.nim new file mode 100644 index 000000000..f23fca0d4 --- /dev/null +++ b/tests/misc/tjoinable.nim @@ -0,0 +1,3 @@ +# checks that megatest allows duplicate names, see also `tests/testament/tjoinable.nim` +doAssert defined(testing) +doAssert defined(nimMegatest) diff --git a/tests/misc/tlastmod.nim b/tests/misc/tlastmod.nim new file mode 100644 index 000000000..1cc1d4bd9 --- /dev/null +++ b/tests/misc/tlastmod.nim @@ -0,0 +1,25 @@ +discard """ +outputsub: "is newer than" +""" +# test the new LastModificationTime() proc + +let + file1 = "tests/testdata/data.csv" + file2 = "tests/testdata/doc1.xml" + +import + os, times, strutils + +proc main() = + var + a, b: Time + a = getLastModificationTime(file1) + b = getLastModificationTime(file2) + writeLine(stdout, $a) + writeLine(stdout, $b) + if a < b: + write(stdout, "$2 is newer than $1\n" % [file1, file2]) + else: + write(stdout, "$1 is newer than $2\n" % [file1, file2]) + +main() diff --git a/tests/misc/tloops.nim b/tests/misc/tloops.nim new file mode 100644 index 000000000..61e0baf10 --- /dev/null +++ b/tests/misc/tloops.nim @@ -0,0 +1,93 @@ +discard """ +output: ''' +Hello!(x: 1, y: 2, z: 3) +(x: 1.0, y: 2.0) +''' +""" + +# Test nested loops and some other things + +proc andTest() = + var a = 0 == 5 and 6 == 6 + +proc incx(x: var int) = # is built-in proc + x = x + 1 + +proc decx(x: var int) = + x = x - 1 + +proc First(y: var int) = + var x: int + i_ncx(x) + if x == 10: + y = 0 + else: + if x == 0: + incx(x) + else: + x=11 + +proc TestLoops() = + var i, j: int + while i >= 0: + if i mod 3 == 0: + break + i = i + 1 + while j == 13: + j = 13 + break + break + + while true: + break + + +proc Foo(n: int): int = + var + a, old: int + b, c: bool + F_irst(a) + if a == 10: + a = 30 + elif a == 11: + a = 22 + elif a == 12: + a = 23 + elif b: + old = 12 + else: + a = 40 + + # + b = false or 2 == 0 and 3 == 9 + a = 0 + 3 * 5 + 6 + 7 + +8 # 36 + while b: + a = a + 3 + a = a + 5 + write(stdout, "Hello!") + + +# We should come till here :-) +discard Foo(345) + +# test the new type symbol lookup feature: + +type + MyType[T] = tuple[ + x, y, z: T] + MyType2 = tuple[x, y: float] + +proc main[T]() = + var myType: MyType[T] + var b: MyType[T] + b = (1, 2, 3) + myType = b + echo myType + + var myType2: MyType2 + var c: MyType2 + c = (1.0, 2.0) + myType2 = c + echo myType2 + +main[int]() diff --git a/tests/misc/tmemoization.nim b/tests/misc/tmemoization.nim new file mode 100644 index 000000000..c65692608 --- /dev/null +++ b/tests/misc/tmemoization.nim @@ -0,0 +1,17 @@ +discard """ + nimout: "test 1\ntest 2\ntest 3" + output: "TEST 1\nTEST 2\nTEST 3" +""" + +import strutils + +proc foo(s: static[string]): string = + static: echo s + + const R = s.toUpperAscii + return R + +echo foo("test 1") +echo foo("test 2") +echo foo("test " & $3) + diff --git a/tests/misc/tmissingnilcheck.nim b/tests/misc/tmissingnilcheck.nim new file mode 100644 index 000000000..461fb18f4 --- /dev/null +++ b/tests/misc/tmissingnilcheck.nim @@ -0,0 +1,20 @@ +discard """ + disabled: true +""" + +type + PFutureBase = ref object + callback: proc () {.closure.} + +proc newConnection = + iterator newConnectionIter(): PFutureBase {.closure.} = + discard + var newConnectionIterVar = newConnectionIter + var first = newConnectionIterVar() + + proc cb {.closure.} = + discard + + first.callback = cb + +newConnection() diff --git a/tests/misc/tmodulea.nim b/tests/misc/tmodulea.nim new file mode 100644 index 000000000..5aeb1824b --- /dev/null +++ b/tests/misc/tmodulea.nim @@ -0,0 +1,3 @@ +from modulea import modulea + +#bug #6731 diff --git a/tests/misc/tnoforward.nim b/tests/misc/tnoforward.nim new file mode 100644 index 000000000..b6a71897a --- /dev/null +++ b/tests/misc/tnoforward.nim @@ -0,0 +1,15 @@ +discard """ + output: "10" +""" + +# {. noforward: on .} +{.experimental: "codeReordering".} + +proc foo(x: int) = + bar x + +proc bar(x: int) = + echo x + +foo(10) + diff --git a/tests/misc/tnolen.nim b/tests/misc/tnolen.nim new file mode 100644 index 000000000..e0e8025d4 --- /dev/null +++ b/tests/misc/tnolen.nim @@ -0,0 +1,8 @@ +discard """ + errormsg: "type mismatch: got <int literal(3)>" + line: 8 +""" + +# please finally disallow Len(3) + +echo len(3) diff --git a/tests/misc/tparedef.nim b/tests/misc/tparedef.nim new file mode 100644 index 000000000..83c2651ff --- /dev/null +++ b/tests/misc/tparedef.nim @@ -0,0 +1,4 @@ +# This test is now superfluous: + +proc a(a: int) = + return diff --git a/tests/misc/tparsecombnum.nim b/tests/misc/tparsecombnum.nim new file mode 100644 index 000000000..6fe539813 --- /dev/null +++ b/tests/misc/tparsecombnum.nim @@ -0,0 +1,55 @@ +import parsecomb + +discard """ + output: "-289096" +""" + +type Num = int + +# forward stuff +var exp3: Parser[string, Num] +var exp = lazy(proc(): Parser[string, Num] = exp3) + +var digit = (proc(): Parser[string, Num] = + result = tok("0").then(unit[string, Num](Num(0))) + for n in 1..9: + result = result + tok($n).then(unit[string, Num](Num(n))) +)() + +var num = repeat1(digit).map(proc(ds: seq[Num]): Num = + result = 0 + for d in ds: + result = result*10 + d) + +type Op = proc(a, b: Num): Num + +var plusOp = tok("+").then(unit[string, Op](proc(a, b: Num): Num = a + b)) +var minusOp = tok("-").then(unit[string, Op](proc(a, b: Num): Num = a - b)) +var timesOp = tok("*").then(unit[string, Op](proc(a, b: Num): Num = a*b)) +var divideOp = tok("/").then(unit[string, Op](proc(a, b: Num): Num = a div b)) + +var paren = (tok("(") * exp * tok(")")).map(proc(ler: ((string, Num), string)): Num = + var (le, r) = ler + var (l, e) = le + e) + +proc foldOp(a: Num, ob: (Op, Num)): Num = + var (o, b) = ob + o(a, b) + +var exp0 = paren + num +var exp1 = exp0.leftRec((timesOp + divideOp)*exp0, foldOp) +var exp2 = exp1.leftRec((plusOp + minusOp)*exp1, foldOp) +exp3 = exp2 + +proc strsplit(s: string): seq[string] = + result = @[] + for i in 0 .. s.len - 1: + result.add($s[i]) + +var r = exp.run("523-(1243+411/744*1642/1323)*233".strsplit) +case r.kind: +of rkSuccess: + echo r.output +of rkFailure: + echo "failed" diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim new file mode 100644 index 000000000..47be05bac --- /dev/null +++ b/tests/misc/tparseopt.nim @@ -0,0 +1,156 @@ +discard """ + output: ''' +parseopt +first round +kind: cmdLongOption key:val -- left: +second round +kind: cmdLongOption key:val -- left: +kind: cmdLongOption key:val -- debug:3 +kind: cmdShortOption key:val -- l:4 +kind: cmdShortOption key:val -- r:2 +cmdLongOption foo +cmdLongOption path +parseoptNoVal +kind: cmdLongOption key:val -- left: +kind: cmdLongOption key:val -- debug:3 +kind: cmdShortOption key:val -- l: +kind: cmdShortOption key:val -- r:2 +kind: cmdLongOption key:val -- debug:2 +kind: cmdLongOption key:val -- debug:1 +kind: cmdShortOption key:val -- r:1 +kind: cmdShortOption key:val -- r:0 +kind: cmdShortOption key:val -- l: +kind: cmdShortOption key:val -- r:4 +kind: cmdLongOption key:val -- debug: +cmdShortOption key: v value: '' +cmdArgument key: ABC value: '' +cmdShortOption key: v value: 'ABC' +cmdShortOption key: v value: '' +cmdArgument key: ABC value: '' +cmdShortOption key: v value: '' +cmdArgument key: ABC value: '' +cmdShortOption key: j value: '4' +cmdArgument key: ok value: '' +''' +joinable: false +""" + +when defined(testament_tparseopt): + import os + proc main() = + let args = commandLineParams() + echo args + for i, ai in args: + echo "arg ", i, " ai.len:", ai.len, " :{", ai, "}" + main() +else: + from parseopt import nil + + block: + echo "parseopt" + for kind, key, val in parseopt.getopt(): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + + # pass custom cmdline arguments + echo "first round" + var argv = "--left --debug:3 -l=4 -r:2" + var p = parseopt.initOptParser(argv) + for kind, key, val in parseopt.getopt(p): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + break + # reset getopt iterator and check arguments are returned correctly. + echo "second round" + for kind, key, val in parseopt.getopt(p): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + + # bug #9619 + var x = parseopt.initOptParser(@["--foo:", "--path"], + allowWhitespaceAfterColon = false) + for kind, key, val in parseopt.getopt(x): + echo kind, " ", key + + block: + echo "parseoptNoVal" + # test NoVal mode with custom cmdline arguments + var argv = "--left --debug:3 -l -r:2 --debug 2 --debug=1 -r1 -r=0 -lr4 --debug:" + var p = parseopt.initOptParser(argv, + shortNoVal = {'l'}, longNoVal = @["left"]) + for kind, key, val in parseopt.getopt(p): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + + import osproc, os, strutils + from stdtest/specialpaths import buildDir + import stdtest/unittest_light + + block: # fix #9951 + template runTest(parseoptCustom) = + var p = parseoptCustom.initOptParser(@["echo \"quoted\""]) + let expected = when defined(windows): + """"echo \"quoted\""""" + else: + """'echo "quoted"'""" + assertEquals parseoptCustom.cmdLineRest(p), expected + + doAssert "a5'b" == "a5\'b" + + let args = @["a1b", "a2 b", "", "a4\"b", "a5'b", r"a6\b", "a7\'b"] + var p2 = parseoptCustom.initOptParser(args) + let expected2 = when defined(windows): + """a1b "a2 b" "" a4\"b a5'b a6\b a7'b""" + else: + """a1b 'a2 b' '' 'a4"b' 'a5'"'"'b' 'a6\b' 'a7'"'"'b'""" + doAssert "a5'b" == "a5\'b" + assertEquals parseoptCustom.cmdLineRest(p2), expected2 + runTest(parseopt) + + block: # fix #9842 + let exe = buildDir / "D20190112T145450".addFileExt(ExeExt) + defer: + when not defined(windows): + # workaround #10359 ; innocuous to skip since we're saving under `buildDir` + removeFile exe + let args = @["a1b", "a2 b", "", "a4\"b", "a5'b", r"a6\b", "a7\'b"] + let cmd = "$# c -r --verbosity:0 -o:$# -d:testament_tparseopt $# $#" % + [getCurrentCompilerExe(), exe, currentSourcePath(), + args.quoteShellCommand] + var ret = execCmdEx(cmd, options = {}) + if ret.exitCode != 0: + # before bug fix, running cmd would show: + # sh: -c: line 0: unexpected EOF while looking for matching `"'\n + echo "exitCode: ", ret.exitCode, " cmd:", cmd + doAssert false + stripLineEnd(ret.output) + assertEquals ret.output, + """ +@["a1b", "a2 b", "", "a4\"b", "a5\'b", "a6\\b", "a7\'b"] +arg 0 ai.len:3 :{a1b} +arg 1 ai.len:4 :{a2 b} +arg 2 ai.len:0 :{} +arg 3 ai.len:4 :{a4"b} +arg 4 ai.len:4 :{a5'b} +arg 5 ai.len:4 :{a6\b} +arg 6 ai.len:4 :{a7'b}""" + + + + block: + let args = @["-v", "ABC"] + var p = parseopt.initOptParser(args, shortnoVal = {'n'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(p): + echo kind," key: ", key, " value: '", val, "'" + + var r = parseopt.initOptParser(@["-v ABC"], shortnoVal = {'n'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(r): + echo kind," key: ", key, " value: '", val, "'" + + var s = parseopt.initOptParser("-v ABC", shortnoVal = {'v'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(s): + echo kind," key: ", key, " value: '", val, "'" + + var m = parseopt.initOptParser("-v ABC", shortnoVal = {'n'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(m): + echo kind," key: ", key, " value: '", val, "'" + + var n = parseopt.initOptParser("-j4 ok", shortnoVal = {'n'}, longnoVal = @["novalue"]) + for kind, key, val in parseopt.getopt(n): + echo kind," key: ", key, " value: '", val, "'" diff --git a/tests/misc/tpos.nim b/tests/misc/tpos.nim new file mode 100644 index 000000000..f7607d643 --- /dev/null +++ b/tests/misc/tpos.nim @@ -0,0 +1,33 @@ +discard """ + output: "6" +""" +# test this particular function + +proc mypos(sub, s: string, start: int = 0): int = + var + i, j, M, N: int + M = sub.len + N = s.len + i = start + j = 0 + if i >= N: + result = -1 + else: + while true: + if s[i] == sub[j]: + inc(i) + inc(j) + else: + i = i - j + 1 + j = 0 + if (j >= M) or (i >= N): break + if j >= M: + result = i - M + else: + result = -1 + +var sub = "hello" +var s = "world hello" +write(stdout, mypos(sub, s)) +write stdout, "\n" +#OUT 6 diff --git a/tests/misc/tprep.nim b/tests/misc/tprep.nim new file mode 100644 index 000000000..45f25b790 --- /dev/null +++ b/tests/misc/tprep.nim @@ -0,0 +1,38 @@ +discard """ +nimout: ''' +tprep.nim(25, 9) Hint: Case 2 [User] +tprep.nim(27, 11) Hint: Case 2.3 [User] +''' +outputsub: "" +""" + +# Test the features that used to belong to the preprocessor + +import + times + +#{.warning: "This is only a test warning!".} + +const + case2 = true + case3 = true + +when defined(case1): + {.hint: "Case 1".} + when case3: + {.hint: "Case 1.3".} +elif case2: + {.hint: "Case 2".} + when case3: + {.hint: "Case 2.3".} +elif case3: + {.hint: "Case 3".} +else: + {.hint: "unknown case".} + +var + s: string +write(stdout, "compiled at " & system.CompileDate & + " " & CompileTime & "\n") +echo getDateStr() +echo getClockStr() diff --git a/tests/misc/tquicksort.nim b/tests/misc/tquicksort.nim new file mode 100644 index 000000000..017c73fbc --- /dev/null +++ b/tests/misc/tquicksort.nim @@ -0,0 +1,23 @@ +proc QuickSort(list: seq[int]): seq[int] = + if len(list) == 0: + return @[] + var pivot = list[0] + var left: seq[int] = @[] + var right: seq[int] = @[] + for i in low(list)..high(list): + if list[i] < pivot: + left.add(list[i]) + elif list[i] > pivot: + right.add(list[i]) + result = QuickSort(left) & + pivot & + QuickSort(right) + +proc echoSeq(a: seq[int]) = + for i in low(a)..high(a): + echo(a[i]) + +let list = QuickSort(@[89,23,15,23,56,123,356,12,7,1,6,2,9,4,3]) +let expected = @[1, 2, 3, 4, 6, 7, 9, 12, 15, 23, 56, 89, 123, 356] + +doAssert list == expected diff --git a/tests/misc/tradix.nim b/tests/misc/tradix.nim new file mode 100644 index 000000000..f4fb56849 --- /dev/null +++ b/tests/misc/tradix.nim @@ -0,0 +1,254 @@ +discard """ +output: ''' +start tradix.nim +false +false +false +false +false +false +false +false +false +false +128 +1 +2 +3 +4 +255 +17 +45 +19000 +4294967288 +''' +""" + +# implements and tests an efficient radix tree + +## another method to store an efficient array of pointers: +## We use a radix tree with node compression. +## There are two node kinds: + +echo "start tradix.nim" + +const BitsPerUnit = 8*sizeof(int) + +type + TRadixNodeKind = enum rnLinear, rnFull, rnLeafBits, rnLeafLinear + PRadixNode = ptr TRadixNode + TRadixNode {.pure, inheritable.} = object + kind: TRadixNodeKind + TRadixNodeLinear = object of TRadixNode + len: uint8 + keys: array[0..31, uint8] + vals: array[0..31, PRadixNode] + + TRadixNodeFull = object of TRadixNode + b: array[0..255, PRadixNode] + TRadixNodeLeafBits = object of TRadixNode + b: array[0..7, int] + TRadixNodeLeafLinear = object of TRadixNode + len: uint8 + keys: array[0..31, uint8] + +var + root: PRadixNode + +proc searchInner(r: PRadixNode, a: int): PRadixNode = + case r.kind + of rnLinear: + var x = cast[ptr TRadixNodeLinear](r) + for i in 0..int(x.len)-1: + if int(x.keys[i]) == a: return x.vals[i] + of rnFull: + var x = cast[ptr TRadixNodeFull](r) + return x.b[a] + else: assert(false) + +proc testBit(w, i: int): bool {.inline.} = + result = (w and (1 shl (i %% BitsPerUnit))) != 0 + +proc setBit(w: var int, i: int) {.inline.} = + w = w or (1 shl (i %% BitsPerUnit)) + +proc resetBit(w: var int, i: int) {.inline.} = + w = w and not (1 shl (i %% BitsPerUnit)) + +proc testOrSetBit(w: var int, i: int): bool {.inline.} = + var x = (1 shl (i %% BitsPerUnit)) + if (w and x) != 0: return true + w = w or x + +proc searchLeaf(r: PRadixNode, a: int): bool = + case r.kind + of rnLeafBits: + var x = cast[ptr TRadixNodeLeafBits](r) + return testBit(x.b[a /% BitsPerUnit], a) + of rnLeafLinear: + var x = cast[ptr TRadixNodeLeafLinear](r) + for i in 0..int(x.len)-1: + if int(x.keys[i]) == a: return true + else: assert(false) + +proc exclLeaf(r: PRadixNode, a: int) = + case r.kind + of rnLeafBits: + var x = cast[ptr TRadixNodeLeafBits](r) + resetBit(x.b[a /% BitsPerUnit], a) + of rnLeafLinear: + var x = cast[ptr TRadixNodeLeafLinear](r) + var L = int(x.len) + for i in 0..L-1: + if int(x.keys[i]) == a: + x.keys[i] = x.keys[L-1] + dec(x.len) + return + else: assert(false) + +proc contains*(r: PRadixNode, a: ByteAddress): bool = + if r == nil: return false + var x = searchInner(r, a shr 24 and 0xff) + if x == nil: return false + x = searchInner(x, a shr 16 and 0xff) + if x == nil: return false + x = searchInner(x, a shr 8 and 0xff) + if x == nil: return false + return searchLeaf(x, a and 0xff) + +proc excl*(r: PRadixNode, a: ByteAddress): bool = + if r == nil: return false + var x = searchInner(r, a shr 24 and 0xff) + if x == nil: return false + x = searchInner(x, a shr 16 and 0xff) + if x == nil: return false + x = searchInner(x, a shr 8 and 0xff) + if x == nil: return false + exclLeaf(x, a and 0xff) + +proc addLeaf(r: var PRadixNode, a: int): bool = + if r == nil: + # a linear node: + var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear))) + x.kind = rnLeafLinear + x.len = 1'u8 + x.keys[0] = uint8(a) + r = x + return false # not already in set + case r.kind + of rnLeafBits: + var x = cast[ptr TRadixNodeLeafBits](r) + return testOrSetBit(x.b[a /% BitsPerUnit], a) + of rnLeafLinear: + var x = cast[ptr TRadixNodeLeafLinear](r) + var L = int(x.len) + for i in 0..L-1: + if int(x.keys[i]) == a: return true + if L <= high(x.keys): + x.keys[L] = uint8(a) + inc(x.len) + else: + # transform into a full node: + var y = cast[ptr TRadixNodeLeafBits](alloc0(sizeof(TRadixNodeLeafBits))) + y.kind = rnLeafBits + for i in 0..int(x.len)-1: + var u = int(x.keys[i]) + setBit(y.b[u /% BitsPerUnit], u) + setBit(y.b[a /% BitsPerUnit], a) + dealloc(r) + r = y + else: assert(false) + +proc addInner(r: var PRadixNode, a: int, d: int): bool = + if d == 0: + return addLeaf(r, a and 0xff) + var k = a shr d and 0xff + if r == nil: + # a linear node: + var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear))) + x.kind = rnLinear + x.len = 1'u8 + x.keys[0] = uint8(k) + r = x + return addInner(x.vals[0], a, d-8) + case r.kind + of rnLinear: + var x = cast[ptr TRadixNodeLinear](r) + var L = int(x.len) + for i in 0..L-1: + if int(x.keys[i]) == k: # already exists + return addInner(x.vals[i], a, d-8) + if L <= high(x.keys): + x.keys[L] = uint8(k) + inc(x.len) + return addInner(x.vals[L], a, d-8) + else: + # transform into a full node: + var y = cast[ptr TRadixNodeFull](alloc0(sizeof(TRadixNodeFull))) + y.kind = rnFull + for i in 0..L-1: y.b[int(x.keys[i])] = x.vals[i] + dealloc(r) + r = y + return addInner(y.b[k], a, d-8) + of rnFull: + var x = cast[ptr TRadixNodeFull](r) + return addInner(x.b[k], a, d-8) + else: assert(false) + +proc incl*(r: var PRadixNode, a: ByteAddress) {.inline.} = + discard addInner(r, a, 24) + +proc testOrIncl*(r: var PRadixNode, a: ByteAddress): bool {.inline.} = + return addInner(r, a, 24) + +iterator innerElements(r: PRadixNode): tuple[prefix: int, n: PRadixNode] = + if r != nil: + case r.kind + of rnFull: + var r = cast[ptr TRadixNodeFull](r) + for i in 0..high(r.b): + if r.b[i] != nil: + yield (i, r.b[i]) + of rnLinear: + var r = cast[ptr TRadixNodeLinear](r) + for i in 0..int(r.len)-1: + yield (int(r.keys[i]), r.vals[i]) + else: assert(false) + +iterator leafElements(r: PRadixNode): int = + if r != nil: + case r.kind + of rnLeafBits: + var r = cast[ptr TRadixNodeLeafBits](r) + # iterate over any bit: + for i in 0..high(r.b): + if r.b[i] != 0: # test all bits for zero + for j in 0..BitsPerUnit-1: + if testBit(r.b[i], j): + yield i*BitsPerUnit+j + of rnLeafLinear: + var r = cast[ptr TRadixNodeLeafLinear](r) + for i in 0..int(r.len)-1: + yield int(r.keys[i]) + else: assert(false) + +iterator elements*(r: PRadixNode): ByteAddress {.inline.} = + for p1, n1 in innerElements(r): + for p2, n2 in innerElements(n1): + for p3, n3 in innerElements(n2): + for p4 in leafElements(n3): + yield p1 shl 24 or p2 shl 16 or p3 shl 8 or p4 + +proc main() = + const + numbers = [128, 1, 2, 3, 4, 255, 17, -8, 45, 19_000] + var + r: PRadixNode = nil + for x in items(numbers): + echo testOrIncl(r, x) + for x in elements(r): + # ByteAddress being defined as a signed integer cases trouble + # exactly here + echo(cast[uint](x)) + +main() diff --git a/tests/misc/trfc405.nim b/tests/misc/trfc405.nim new file mode 100644 index 000000000..0828879ee --- /dev/null +++ b/tests/misc/trfc405.nim @@ -0,0 +1,112 @@ + +{.experimental: "flexibleOptionalParams".} + +# https://github.com/nim-lang/RFCs/issues/405 + +template main = + template fn1(a = 1, b = 2, body): auto = (a, b, astToStr(body)) + let a1 = fn1(10, 20): + foo + doAssert a1 == (10, 20, "\nfoo") + + template fn2(a = 1, b = 2, body): auto = (a, b, astToStr(body)) + let a2 = fn2(a = 10): foo + doAssert a2 == (10, 2, "\nfoo") + let a2b = fn2(b = 20): foo + doAssert a2b == (1, 20, "\nfoo") + + template fn3(x: int, a = 1, b = 2, body): auto = (a, b, astToStr(body)) + let a3 = fn3(3, 10, 20): foo + doAssert a3 == (10, 20, "\nfoo") + let a3b = fn3(3, a = 10): foo + doAssert a3b == (10, 2, "\nfoo") + + template fn4(x: int, y: int, body): auto = (x, y, astToStr(body)) + let a4 = fn4(1, 2): foo + doAssert a4 == (1, 2, "\nfoo") + + template fn5(x = 1, y = 2, body: untyped = 3): auto = (x, y, astToStr(body)) + doAssert compiles(fn5(1, 2, foo)) + doAssert not compiles(fn5(1, foo)) + + block: + # with an overload + var witness = 0 + template fn6() = discard + template fn6(procname: string, body: untyped): untyped = witness.inc + fn6("abc"): discard + assert witness == 1 + + block: + # with overloads + var witness = 0 + template fn6() = discard + template fn6(a: int) = discard + template fn6(procname: string, body: untyped): untyped = witness.inc + fn6("abc"): discard + assert witness == 1 + + template fn6(b = 1.5, body: untyped): untyped = witness.inc + fn6(1.3): discard + assert witness == 2 + + block: + var witness = 0 + template fn6(a: int) = discard + template fn6(a: string) = discard + template fn6(ignore: string, b = 1.5, body: untyped): untyped = witness.inc + fn6(""): + foobar1 + foobar2 + doAssert witness == 1 + fn6(""): discard + doAssert witness == 2 + + block: # multi block args + template fn8(a = 1, b = 2, body1: untyped, body2: untyped): auto = (a, b, astToStr(body1), astToStr(body2)) + let a1 = fn8(): + foobar1 + foobar2 + do: + foobar3 + foobar4 + doAssert a1 == (1, 2, "\nfoobar1\nfoobar2", "\nfoobar3\nfoobar4") + + let a2 = fn8(b = 20): + foobar1 + foobar2 + do: + foobar3 + foobar4 + doAssert a2 == (1, 20, "\nfoobar1\nfoobar2", "\nfoobar3\nfoobar4") + + block: # issue #19015 + template hi(a: untyped, b: varargs[untyped]): untyped = + a + + var worked = false + hi: + worked = true + doAssert worked + worked = false + hi(doAssert(not worked)): + doesntCompile + hi(doAssert(not worked), doesntCompile, againDoesntCompile): + definitelyDoesntCompile + + template hi2(a: bool, b: untyped, c: varargs[untyped]): untyped = + b + doAssert a + + hi2 worked: + worked = true + doAssert worked + hi2 worked, doAssert(worked): + doesntCompile + hi2 worked, doAssert(worked), doesntCompile, againDoesntCompile: + definitelyDoesntCompile + hi2 worked, doAssert(worked), againDoesntCompile: + definitelyDoesntCompile + +static: main() +main() diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim new file mode 100644 index 000000000..6e5487d1b --- /dev/null +++ b/tests/misc/trunner.nim @@ -0,0 +1,444 @@ +discard """ + targets: "c cpp" + joinable: false +""" + +## tests that don't quite fit the mold and are easier to handle via `execCmdEx` +## A few others could be added to here to simplify code. +## Note: this test is a bit slow but tests a lot of things; please don't disable. +## Note: if needed, we could use `matrix: "-d:case1; -d:case2"` to split this +## into several independent tests while retaining the common test helpers. + +import std/[strformat,os,osproc,unittest,compilesettings] +from std/sequtils import toSeq,mapIt +from std/algorithm import sorted +import stdtest/[specialpaths, unittest_light] +from std/private/globs import nativeToUnixPath +from strutils import startsWith, strip, removePrefix +from std/sugar import dup +import "$lib/../compiler/nimpaths" + +proc isDots(a: string): bool = + ## test for `hintProcessing` dots + a.startsWith(".") and a.strip(chars = {'.'}) == "" + +const + nim = getCurrentCompilerExe() + mode = querySetting(backend) + nimcache = buildDir / "nimcacheTrunner" + # instead of `querySetting(nimcacheDir)`, avoids stomping on other parallel tests + +proc runNimCmd(file, options = "", rtarg = ""): auto = + let fileabs = testsDir / file.unixToNativePath + # doAssert fileabs.fileExists, fileabs # disabled because this allows passing `nim r --eval:code fakefile` + let cmd = fmt"{nim} {mode} --hint:all:off {options} {fileabs} {rtarg}" + result = execCmdEx(cmd) + when false: # for debugging + echo cmd + echo result[0] & "\n" & $result[1] + +proc runNimCmdChk(file, options = "", rtarg = "", status = 0): string = + let (ret, status2) = runNimCmd(file, options, rtarg = rtarg) + doAssert status2 == status, $(file, options, status, status2) & "\n" & ret + ret + +proc genShellCmd(filename: string): string = + let filename = filename.quoteShell + when defined(windows): "cmd /c " & filename # or "cmd /c " ? + else: "sh " & filename + +when defined(nimTrunnerFfi): + block: # mevalffi + when defined(openbsd): + #[ + openbsd defines `#define stderr (&__sF[2])` which makes it cumbersome + for dlopen'ing inside `importcSymbol`. Instead of adding special rules + inside `importcSymbol` to handle this, we disable just the part that's + not working and will provide a more general, clean fix in future PR. + ]# + var opt = "-d:nimEvalffiStderrWorkaround" + let prefix = "" + else: + var opt = "" + let prefix = """ +hello world stderr +hi stderr +""" + let output = runNimCmdChk("vm/mevalffi.nim", fmt"{opt} --warnings:off --experimental:compiletimeFFI") + doAssert output == fmt""" +{prefix}foo +foo:100 +foo:101 +foo:102:103 +foo:102:103:104 +foo:0.03:asdf:103:105 +ret=[s1:foobar s2:foobar age:25 pi:3.14] +""", output + +elif not defined(nimTestsTrunnerDebugging): + # don't run twice the same test with `nimTrunnerFfi` + # use `-d:nimTestsTrunnerDebugging` for debugging convenience when you want to just run 1 test + import std/strutils + import std/json + template check2(msg) = doAssert msg in output, output + + block: # tests with various options `nim doc --project --index --docroot` + # regression tests for issues and PRS: #14376 #13223 #6583 ##13647 + let file = testsDir / "nimdoc/sub/mmain.nim" + let mainFname = "mmain.html" + let htmldocsDirCustom = nimcache / "htmldocsCustom" + let docroot = testsDir / "nimdoc" + let options = [ + 0: "--project", + 1: "--project --docroot", + 2: "", + 3: fmt"--outDir:{htmldocsDirCustom}", + 4: fmt"--docroot:{docroot}", + 5: "--project --useNimcache", + 6: "--index:off", + ] + + for i in 0..<options.len: + let htmldocsDir = case i + of 3: htmldocsDirCustom + of 5: nimcache / htmldocsDirname + else: file.parentDir / htmldocsDirname + + var cmd = fmt"{nim} doc --index:on --filenames:abs --hint:successX:on --nimcache:{nimcache} {options[i]} {file}" + removeDir(htmldocsDir) + let (outp, exitCode) = execCmdEx(cmd) + check exitCode == 0 + let ret = toSeq(walkDirRec(htmldocsDir, relative=true)).mapIt(it.nativeToUnixPath).sorted.join("\n") + let context = $(i, ret, cmd) + case i + of 0,5: + let htmlFile = htmldocsDir/mainFname + check htmlFile in outp # sanity check for `hintSuccessX` + assertEquals ret, fmt""" +{dotdotMangle}/imp.html +{dotdotMangle}/imp.idx +{docHackJsFname} +imp.html +imp.idx +imp2.html +imp2.idx +{mainFname} +mmain.idx +{nimdocOutCss} +{theindexFname}""", context + of 1: assertEquals ret, fmt""" +{docHackJsFname} +{nimdocOutCss} +tests/nimdoc/imp.html +tests/nimdoc/imp.idx +tests/nimdoc/sub/imp.html +tests/nimdoc/sub/imp.idx +tests/nimdoc/sub/imp2.html +tests/nimdoc/sub/imp2.idx +tests/nimdoc/sub/{mainFname} +tests/nimdoc/sub/mmain.idx +{theindexFname}""" + of 2, 3: assertEquals ret, fmt""" +{docHackJsFname} +{mainFname} +mmain.idx +{nimdocOutCss}""", context + of 4: assertEquals ret, fmt""" +{docHackJsFname} +{nimdocOutCss} +sub/{mainFname} +sub/mmain.idx""", context + of 6: assertEquals ret, fmt""" +{mainFname} +{nimdocOutCss}""", context + else: doAssert false + + block: # mstatic_assert + let (output, exitCode) = runNimCmd("ccgbugs/mstatic_assert.nim", "-d:caseBad") + check2 "sizeof(bool) == 2" + check exitCode != 0 + + block: # ABI checks + let file = "misc/msizeof5.nim" + block: + discard runNimCmdChk(file, "-d:checkAbi") + block: + let (output, exitCode) = runNimCmd(file, "-d:checkAbi -d:caseBad") + # on platforms that support _StaticAssert natively, errors will show full context, e.g.: + # error: static_assert failed due to requirement 'sizeof(unsigned char) == 8' + # "backend & Nim disagree on size for: BadImportcType{int64} [declared in mabi_check.nim(1, 6)]" + check2 "sizeof(unsigned char) == 8" + check2 "sizeof(struct Foo2) == 1" + check2 "sizeof(Foo5) == 16" + check2 "sizeof(Foo5) == 3" + check2 "sizeof(struct Foo6) == " + check exitCode != 0 + + import streams + block: # stdin input + let nimcmd = fmt"""{nim} r --hints:off - -firstparam "-second param" """ + let expected = """@["-firstparam", "-second param"]""" + block: + let p = startProcess(nimcmd, options = {poEvalCommand}) + p.inputStream.write("import os; echo commandLineParams()") + p.inputStream.close + var output = p.outputStream.readAll + let error = p.errorStream.readAll + doAssert p.waitForExit == 0 + doAssert error.len == 0, $error + output.stripLineEnd + check output == expected + p.errorStream.close + p.outputStream.close + + block: + when defined posix: + # xxx on windows, `poEvalCommand` should imply `/cmd`, (which should + # make this work), but currently doesn't + let cmd = fmt"""echo "import os; echo commandLineParams()" | {nimcmd}""" + var (output, exitCode) = execCmdEx(cmd) + output.stripLineEnd + check output == expected + doAssert exitCode == 0 + + block: # nim doc --backend:$backend --doccmd:$cmd + # test for https://github.com/nim-lang/Nim/issues/13129 + # test for https://github.com/nim-lang/Nim/issues/13891 + let file = testsDir / "nimdoc/m13129.nim" + for backend in fmt"{mode} js".split: + # pending #14343 this fails on windows: --doccmd:"-d:m13129Foo2 --hints:off" + let cmd = fmt"""{nim} doc -b:{backend} --nimcache:{nimcache} -d:m13129Foo1 "--doccmd:-d:m13129Foo2 --hints:off" --usenimcache --hints:off {file}""" + check execCmdEx(cmd) == (&"ok1:{backend}\nok2: backend: {backend}\n", 0) + # checks that --usenimcache works with `nim doc` + check fileExists(nimcache / "htmldocs/m13129.html") + + block: # mak sure --backend works with `nim r` + let cmd = fmt"{nim} r --backend:{mode} --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("ok3\n", 0) + + block: # nim jsondoc # bug #20132 + let file = testsDir / "misc/mjsondoc.nim" + let output = "nimcache_tjsondoc.json" + defer: removeFile(output) + let (msg, exitCode) = execCmdEx(fmt"{nim} jsondoc -o:{output} {file}") + doAssert exitCode == 0, msg + + let data = parseJson(readFile(output))["entries"] + doAssert data.len == 5 + let doSomething = data[0] + doAssert doSomething["name"].getStr == "doSomething" + doAssert doSomething["type"].getStr == "skProc" + doAssert doSomething["line"].getInt == 1 + doAssert doSomething["col"].getInt == 0 + doAssert doSomething["code"].getStr == "proc doSomething(x, y: int): int {.raises: [], tags: [], forbids: [].}" + let foo2 = data[4] + doAssert $foo2["signature"] == """{"arguments":[{"name":"x","type":"T"},{"name":"y","type":"U"},{"name":"z","type":"M"}],"genericParams":[{"name":"T","types":"int"},{"name":"M","types":"string"},{"name":"U"}]}""" + + block: # nim jsondoc # bug #11953 + let file = testsDir / "misc/mjsondoc.nim" + let destDir = testsDir / "misc/htmldocs" + removeDir(destDir) + defer: removeDir(destDir) + let (msg, exitCode) = execCmdEx(fmt"{nim} jsondoc {file}") + doAssert exitCode == 0, msg + + let data = parseJson(readFile(destDir / "mjsondoc.json"))["entries"] + doAssert data.len == 5 + let doSomething = data[0] + doAssert doSomething["name"].getStr == "doSomething" + doAssert doSomething["type"].getStr == "skProc" + doAssert doSomething["line"].getInt == 1 + doAssert doSomething["col"].getInt == 0 + doAssert doSomething["code"].getStr == "proc doSomething(x, y: int): int {.raises: [], tags: [], forbids: [].}" + + block: # further issues with `--backend` + let file = testsDir / "misc/mbackend.nim" + var cmd = fmt"{nim} doc -b:cpp --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("", 0) + cmd = fmt"{nim} check -b:c -b:cpp --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("", 0) + # issue https://github.com/timotheecour/Nim/issues/175 + cmd = fmt"{nim} c -b:js -b:cpp --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("", 0) + + block: # some importc tests + # issue #14314 + let file = testsDir / "misc/mimportc.nim" + let cmd = fmt"{nim} r -b:cpp --hints:off --nimcache:{nimcache} --warningAsError:ProveInit {file}" + check execCmdEx(cmd) == ("witness\n", 0) + + block: # bug #20149 + let file = testsDir / "misc/m20149.nim" + let cmd = fmt"{nim} r --hints:off --nimcache:{nimcache} --hintAsError:XDeclaredButNotUsed {file}" + check execCmdEx(cmd) == ("12\n", 0) + + block: # bug #15316 + when not defined(windows): + # This never worked reliably on Windows. Needs further investigation but it is hard to reproduce. + # Looks like a mild stack corruption when bailing out of nested exception handling. + let file = testsDir / "misc/m15316.nim" + let cmd = fmt"{nim} check --hints:off --nimcache:{nimcache} {file}" + check execCmdEx(cmd) == ("m15316.nim(1, 15) Error: expression expected, but found \')\'\nm15316.nim(2, 1) Error: expected: \':\', but got: \'[EOF]\'\nm15316.nim(2, 1) Error: expression expected, but found \'[EOF]\'\nm15316.nim(2, 1) " & + "Error: expected: \')\', but got: \'[EOF]\'\nError: illformed AST: \n", 1) + + + block: # config.nims, nim.cfg, hintConf, bug #16557 + let cmd = fmt"{nim} r --hint:all:off --hint:conf tests/newconfig/bar/mfoo.nim" + let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) + doAssert exitCode == 0 + let dir = getCurrentDir() + let files = """ +tests/config.nims +tests/newconfig/bar/nim.cfg +tests/newconfig/bar/config.nims +tests/newconfig/bar/mfoo.nim.cfg +tests/newconfig/bar/mfoo.nims""".splitLines + var expected = "" + for a in files: + let b = dir / a + expected.add &"Hint: used config file '{b}' [Conf]\n" + doAssert outp.endsWith expected, outp & "\n" & expected + + block: # bug #8219 + let file = "tests/newconfig/mconfigcheck.nims" + let cmd = fmt"{nim} check --hints:off {file}" + check execCmdEx(cmd) == ("", 0) + + block: # mfoo2.customext + let filename = testsDir / "newconfig/foo2/mfoo2.customext" + let cmd = fmt"{nim} e --hint:conf {filename}" + let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) + doAssert exitCode == 0 + var expected = &"Hint: used config file '{filename}' [Conf]\n" + doAssert outp.endsWith "123" & "\n" & expected + + + block: # nim --eval + let opt = "--hints:off" + check fmt"""{nim} {opt} --eval:"echo defined(nimscript)"""".execCmdEx == ("true\n", 0) + check fmt"""{nim} r {opt} --eval:"echo defined(c)"""".execCmdEx == ("true\n", 0) + check fmt"""{nim} r -b:js {opt} --eval:"echo defined(js)"""".execCmdEx == ("true\n", 0) + + block: # `hintProcessing` dots should not interfere with `static: echo` + friends + let cmd = fmt"""{nim} r --hint:all:off --hint:processing -f --eval:"static: echo 1+1"""" + let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) + template check3(cond) = doAssert cond, $(outp,) + doAssert exitCode == 0 + let lines = outp.splitLines + check3 lines.len == 3 + when not defined(windows): # xxx: on windows, dots not properly handled, gives: `....2\n\n` + check3 lines[0].isDots + check3 lines[1] == "2" + check3 lines[2] == "" + else: + check3 "2" in outp + + block: # nim secret + let opt = "--hint:all:off --hint:processing" + template check3(cond) = doAssert cond, $(outp,) + for extra in ["", "--stdout"]: + let cmd = fmt"""{nim} secret {opt} {extra}""" + # xxx minor bug: `nim --hint:QuitCalled:off secret` ignores the hint cmdline flag + template run(input2): untyped = + execCmdEx(cmd, options = {poStdErrToStdOut}, input = input2) + block: + let (outp, exitCode) = run """echo 1+2; import strutils; echo strip(" ab "); quit()""" + let lines = outp.splitLines + when not defined(windows): + check3 lines.len == 5 + check3 lines[0].isDots + # check3 lines[1].isDots # todo nim secret might use parsing pipeline + check3 lines[2].dup(removePrefix(">>> ")) == "3" # prompt depends on `nimUseLinenoise` + check3 lines[3] == "ab" + check3 lines[4] == "" + else: + check3 "3" in outp + check3 "ab" in outp + doAssert exitCode == 0 + block: + let (outp, exitCode) = run "echo 1+2; quit(2)" + check3 "3" in outp + doAssert exitCode == 2 + + block: # nimBetterRun + let file = "misc/mbetterrun.nim" + const nimcache2 = buildDir / "D20210423T185116" + removeDir nimcache2 + # related to `-d:nimBetterRun` + let opt = fmt"-r --usenimcache --nimcache:{nimcache2}" + var ret = "" + for a in @["v1", "v2", "v1", "v3"]: + ret.add runNimCmdChk(file, fmt"{opt} -d:mbetterrunVal:{a}") + ret.add runNimCmdChk(file, fmt"{opt} -d:mbetterrunVal:v2", rtarg = "arg1 arg2") + # rt arguments should not cause a recompilation + doAssert ret == """ +compiling: v1 +running: v1 +compiling: v2 +running: v2 +running: v1 +compiling: v3 +running: v3 +running: v2 +""", ret + + block: # nim dump + let cmd = fmt"{nim} dump --dump.format:json -d:D20210428T161003 --hints:off ." + let (ret, status) = execCmdEx(cmd) + doAssert status == 0 + let j = ret.parseJson + # sanity checks + doAssert "D20210428T161003" in j["defined_symbols"].to(seq[string]) + doAssert j["version"].to(string) == NimVersion + doAssert j["nimExe"].to(string) == getCurrentCompilerExe() + + block: # genscript + const nimcache2 = buildDir / "D20210524T212851" + removeDir(nimcache2) + let input = "tgenscript_fakefile" # no need for a real file, --eval is good enough + let output = runNimCmdChk(input, fmt"""--genscript --nimcache:{nimcache2.quoteShell} --eval:"echo(12345)" """) + doAssert output.len == 0, output + let ext = when defined(windows): ".bat" else: ".sh" + let filename = fmt"compile_{input}{ext}" # synchronize with `generateScript` + doAssert fileExists(nimcache2/filename), nimcache2/filename + let (outp, status) = execCmdEx(genShellCmd(filename), options = {poStdErrToStdOut}, workingDir = nimcache2) + doAssert status == 0, outp + let (outp2, status2) = execCmdEx(nimcache2 / input, options = {poStdErrToStdOut}) + doAssert outp2 == "12345\n", outp2 + doAssert status2 == 0 + + block: # UnusedImport + proc fn(opt: string, expected: string) = + let output = runNimCmdChk("msgs/mused3.nim", fmt"--warning:all:off --warning:UnusedImport --hint:DuplicateModuleImport {opt}") + doAssert output == expected, opt & "\noutput:\n" & output & "expected:\n" & expected + fn("-d:case1"): """ +mused3.nim(13, 8) Warning: imported and not used: 'mused3b' [UnusedImport] +""" + fn("-d:case2"): "" + fn("-d:case3"): "" + fn("-d:case4"): "" + fn("-d:case5"): "" + fn("-d:case6"): "" + fn("-d:case7"): "" + fn("-d:case8"): "" + fn("-d:case9"): "" + fn("-d:case10"): "" + when false: + fn("-d:case11"): """ + Warning: imported and not used: 'm2' [UnusedImport] + """ + fn("-d:case12"): """ +mused3.nim(75, 10) Hint: duplicate import of 'mused3a'; previous import here: mused3.nim(74, 10) [DuplicateModuleImport] +""" + + block: # FieldDefect + proc fn(opt: string, expected: string) = + let output = runNimCmdChk("misc/mfield_defect.nim", fmt"-r --warning:all:off --declaredlocs {opt}", status = 1) + doAssert expected in output, opt & "\noutput:\n" & output & "expected:\n" & expected + fn("-d:case1"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" + fn("-d:case2 --gc:refc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" + fn("-d:case1 -b:js"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" + fn("-d:case2 -b:js"): """field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" + fn("-d:case2 --gc:arc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" +else: + discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled diff --git a/tests/misc/trunner_special.nim b/tests/misc/trunner_special.nim new file mode 100644 index 000000000..e08b419b0 --- /dev/null +++ b/tests/misc/trunner_special.nim @@ -0,0 +1,37 @@ +discard """ + targets: "c cpp" + joinable: false + disabled: osx +""" + +#[ +Runs tests that require special treatment, e.g. because they rely on 3rd party code +or require external networking. + +xxx test all tests/untestable/* here, possibly with adjustments to make running times reasonable +]# + +import std/[strformat,os,unittest,compilesettings] +import stdtest/specialpaths + + +from stdtest/testutils import disableSSLTesting + + +const + nim = getCurrentCompilerExe() + mode = querySetting(backend) + +proc runCmd(cmd: string) = + let ret = execShellCmd(cmd) + check ret == 0 # allows more than 1 failure + +proc main = + let options = fmt"-b:{mode} --hints:off" + block: # SSL nimDisableCertificateValidation integration tests + runCmd fmt"{nim} r {options} -d:nimDisableCertificateValidation -d:ssl {testsDir}/untestable/thttpclient_ssl_disabled.nim" + block: # SSL certificate check integration tests + runCmd fmt"{nim} r {options} -d:ssl --threads:on --mm:refc {testsDir}/untestable/thttpclient_ssl_remotenetwork.nim" + +when not disableSSLTesting(): + main() diff --git a/tests/misc/tsamename.nim b/tests/misc/tsamename.nim new file mode 100644 index 000000000..b2d17a506 --- /dev/null +++ b/tests/misc/tsamename.nim @@ -0,0 +1,15 @@ +# bug #9891 + +import "."/tsamename2 + +# this works +callFun(fooBar2) + +when true: + # Error: attempting to call routine: 'processPattern' + callFun(fooBar) + +when true: + # BUG: Error: internal error: expr(skModule); unknown symbol + proc processPattern() = discard + callFun(fooBar) diff --git a/tests/misc/tsamename2.nim b/tests/misc/tsamename2.nim new file mode 100644 index 000000000..d2272f557 --- /dev/null +++ b/tests/misc/tsamename2.nim @@ -0,0 +1,4 @@ +proc fooBar*()=discard +proc fooBar2*()=discard +proc callFun*[Fun](processPattern: Fun) = + processPattern() diff --git a/tests/misc/tsemfold.nim b/tests/misc/tsemfold.nim new file mode 100644 index 000000000..2ce8d9560 --- /dev/null +++ b/tests/misc/tsemfold.nim @@ -0,0 +1,27 @@ +discard """ + action: run +""" + +doAssertRaises(OverflowDefect): discard low(int8) - 1'i8 +doAssertRaises(OverflowDefect): discard high(int8) + 1'i8 +doAssertRaises(OverflowDefect): discard abs(low(int8)) +doAssertRaises(DivByZeroDefect): discard 1 mod 0 +doAssertRaises(DivByZeroDefect): discard 1 div 0 +doAssertRaises(OverflowDefect): discard low(int8) div -1'i8 + +doAssertRaises(OverflowDefect): discard -low(int64) +doAssertRaises(OverflowDefect): discard low(int64) - 1'i64 +doAssertRaises(OverflowDefect): discard high(int64) + 1'i64 + +type E = enum eA, eB +doAssertRaises(OverflowDefect): discard eA.pred +doAssertRaises(OverflowDefect): discard eB.succ + +doAssertRaises(OverflowDefect): discard low(int8) * -1 +doAssertRaises(OverflowDefect): discard low(int64) * -1 +doAssertRaises(OverflowDefect): discard high(int8) * 2 +doAssertRaises(OverflowDefect): discard high(int64) * 2 + +doAssert abs(-1) == 1 +doAssert 2 div 2 == 1 +doAssert 2 * 3 == 6 diff --git a/tests/misc/tshadow_magic_type.nim b/tests/misc/tshadow_magic_type.nim new file mode 100644 index 000000000..8b2d26133 --- /dev/null +++ b/tests/misc/tshadow_magic_type.nim @@ -0,0 +1,29 @@ +discard """ +output: ''' +mylist +''' +""" + + +type + TListItemType* = enum + RedisNil, RedisString + + TListItem* = object + case kind*: TListItemType + of RedisString: + str*: string + else: nil + TRedisList* = seq[TListItem] + +# Caused by this. +proc seq*() = + discard + +proc lrange*(key: string): TRedisList = + var foo = TListItem(kind: RedisString, str: key) + result = @[foo] + +var p = lrange("mylist") +for i in items(p): + echo(i.str) diff --git a/tests/misc/tsimplesort.nim b/tests/misc/tsimplesort.nim new file mode 100644 index 000000000..395db55e6 --- /dev/null +++ b/tests/misc/tsimplesort.nim @@ -0,0 +1,306 @@ +discard """ + output: '''true''' +""" + +import hashes, math + +{.pragma: myShallow.} + +type + TSlotEnum = enum seEmpty, seFilled, seDeleted + TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] + TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] + TTable*[A, B] {.final, myShallow.} = object + data: TKeyValuePairSeq[A, B] + counter: int + +proc len*[A, B](t: TTable[A, B]): int = + ## returns the number of keys in `t`. + result = t.counter + +iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] = + ## iterates over any (key, value) pair in the table `t`. + for h in 0..high(t.data): + if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) + +iterator keys*[A, B](t: TTable[A, B]): A = + ## iterates over any key in the table `t`. + for h in 0..high(t.data): + if t.data[h].slot == seFilled: yield t.data[h].key + +iterator values*[A, B](t: TTable[A, B]): B = + ## iterates over any value in the table `t`. + for h in 0..high(t.data): + if t.data[h].slot == seFilled: yield t.data[h].val + +const + growthFactor = 2 + +proc mustRehash(length, counter: int): bool {.inline.} = + assert(length > counter) + result = (length * 2 < counter * 3) or (length - counter < 4) + +proc nextTry(h, maxHash: Hash): Hash {.inline.} = + result = ((5 * h) + 1) and maxHash + +template rawGetImpl() = + var h: Hash = hash(key) and high(t.data) # start with real hash value + while t.data[h].slot != seEmpty: + if t.data[h].key == key and t.data[h].slot == seFilled: + return h + h = nextTry(h, high(t.data)) + result = -1 + +template rawInsertImpl() = + var h: Hash = hash(key) and high(data) + while data[h].slot == seFilled: + h = nextTry(h, high(data)) + data[h].key = key + data[h].val = val + data[h].slot = seFilled + +proc rawGet[A, B](t: TTable[A, B], key: A): int = + rawGetImpl() + +proc `[]`*[A, B](t: TTable[A, B], key: A): B = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, + ## default empty value for the type `B` is returned + ## and no exception is raised. One can check with ``hasKey`` whether the key + ## exists. + var index = rawGet(t, key) + if index >= 0: result = t.data[index].val + +proc hasKey*[A, B](t: TTable[A, B], key: A): bool = + ## returns true iff `key` is in the table `t`. + result = rawGet(t, key) >= 0 + +proc rawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B], + key: A, val: B) = + rawInsertImpl() + +proc enlarge[A, B](t: var TTable[A, B]) = + var n: TKeyValuePairSeq[A, B] + newSeq(n, len(t.data) * growthFactor) + for i in countup(0, high(t.data)): + if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val) + swap(t.data, n) + +template putImpl() = + var index = rawGet(t, key) + if index >= 0: + t.data[index].val = val + else: + if mustRehash(len(t.data), t.counter): enlarge(t) + rawInsert(t, t.data, key, val) + inc(t.counter) + +proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) = + ## puts a (key, value)-pair into `t`. + putImpl() + +proc del*[A, B](t: var TTable[A, B], key: A) = + ## deletes `key` from hash table `t`. + var index = rawGet(t, key) + if index >= 0: + t.data[index].slot = seDeleted + dec(t.counter) + +proc initTable*[A, B](initialSize=64): TTable[A, B] = + ## creates a new hash table that is empty. `initialSize` needs to be + ## a power of two. + assert isPowerOfTwo(initialSize) + result.counter = 0 + newSeq(result.data, initialSize) + +proc toTable*[A, B](pairs: openArray[tuple[key: A, + val: B]]): TTable[A, B] = + ## creates a new hash table that contains the given `pairs`. + result = initTable[A, B](nextPowerOfTwo(pairs.len+10)) + for key, val in items(pairs): result[key] = val + +template dollarImpl(): typed = + if t.len == 0: + result = "{:}" + else: + result = "{" + for key, val in pairs(t): + if result.len > 1: result.add(", ") + result.add($key) + result.add(": ") + result.add($val) + result.add("}") + +proc `$`*[A, B](t: TTable[A, B]): string = + ## The `$` operator for hash tables. + dollarImpl() + +# ------------------------------ count tables ------------------------------- + +type + TCountTable*[A] {.final, myShallow.} = object ## table that counts the number of each key + data: seq[tuple[key: A, val: int]] + counter: int + +proc len*[A](t: TCountTable[A]): int = + ## returns the number of keys in `t`. + result = t.counter + +iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] = + ## iterates over any (key, value) pair in the table `t`. + for h in 0..high(t.data): + if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val) + +iterator keys*[A](t: TCountTable[A]): A = + ## iterates over any key in the table `t`. + for h in 0..high(t.data): + if t.data[h].val != 0: yield t.data[h].key + +iterator values*[A](t: TCountTable[A]): int = + ## iterates over any value in the table `t`. + for h in 0..high(t.data): + if t.data[h].val != 0: yield t.data[h].val + +proc RawGet[A](t: TCountTable[A], key: A): int = + var h: Hash = hash(key) and high(t.data) # start with real hash value + while t.data[h].val != 0: + if t.data[h].key == key: return h + h = nextTry(h, high(t.data)) + result = -1 + +proc `[]`*[A](t: TCountTable[A], key: A): int = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, + ## 0 is returned. One can check with ``hasKey`` whether the key + ## exists. + var index = RawGet(t, key) + if index >= 0: result = t.data[index].val + +proc hasKey*[A](t: TCountTable[A], key: A): bool = + ## returns true iff `key` is in the table `t`. + result = rawGet(t, key) >= 0 + +proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]], + key: A, val: int) = + var h: Hash = hash(key) and high(data) + while data[h].val != 0: h = nextTry(h, high(data)) + data[h].key = key + data[h].val = val + +proc enlarge[A](t: var TCountTable[A]) = + var n: seq[tuple[key: A, val: int]] + newSeq(n, len(t.data) * growthFactor) + for i in countup(0, high(t.data)): + if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val) + swap(t.data, n) + +proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) = + ## puts a (key, value)-pair into `t`. `val` has to be positive. + assert val > 0 + putImpl() + +proc initCountTable*[A](initialSize=64): TCountTable[A] = + ## creates a new count table that is empty. `initialSize` needs to be + ## a power of two. + assert isPowerOfTwo(initialSize) + result.counter = 0 + newSeq(result.data, initialSize) + +proc toCountTable*[A](keys: openArray[A]): TCountTable[A] = + ## creates a new count table with every key in `keys` having a count of 1. + result = initCountTable[A](nextPowerOfTwo(keys.len+10)) + for key in items(keys): result[key] = 1 + +proc `$`*[A](t: TCountTable[A]): string = + ## The `$` operator for count tables. + dollarImpl() + +proc inc*[A](t: var TCountTable[A], key: A, val = 1) = + ## increments `t[key]` by `val`. + var index = RawGet(t, key) + if index >= 0: + inc(t.data[index].val, val) + else: + if mustRehash(len(t.data), t.counter): enlarge(t) + rawInsert(t, t.data, key, val) + inc(t.counter) + +proc smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] = + ## returns the largest (key,val)-pair. Efficiency: O(n) + assert t.len > 0 + var minIdx = 0 + for h in 1..high(t.data): + if t.data[h].val > 0 and t.data[minIdx].val > t.data[h].val: minIdx = h + result.key = t.data[minIdx].key + result.val = t.data[minIdx].val + +proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] = + ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n) + assert t.len > 0 + var maxIdx = 0 + for h in 1..high(t.data): + if t.data[maxIdx].val < t.data[h].val: maxIdx = h + result.key = t.data[maxIdx].key + result.val = t.data[maxIdx].val + +proc sort*[A](t: var TCountTable[A]) = + ## sorts the count table so that the entry with the highest counter comes + ## first. This is destructive! You must not modify `t` afterwards! + ## You can use the iterators `pairs`, `keys`, and `values` to iterate over + ## `t` in the sorted order. + + # we use shellsort here; fast enough and simple + var h = 1 + while true: + h = 3 * h + 1 + if h >= high(t.data): break + while true: + h = h div 3 + for i in countup(h, high(t.data)): + var j = i + while t.data[j-h].val <= t.data[j].val: + var xyz = t.data[j] + t.data[j] = t.data[j-h] + t.data[j-h] = xyz + j = j-h + if j < h: break + if h == 1: break + + +const + data = { + "34": 123456, "12": 789, + "90": 343, "0": 34404, + "1": 344004, "2": 344774, + "3": 342244, "4": 3412344, + "5": 341232144, "6": 34214544, + "7": 3434544, "8": 344544, + "9": 34435644, "---00": 346677844, + "10": 34484, "11": 34474, "19": 34464, + "20": 34454, "30": 34141244, "40": 344114, + "50": 344490, "60": 344491, "70": 344492, + "80": 344497} + +proc countTableTest1 = + var s = initTable[string, int](64) + for key, val in items(data): s[key] = val + var w: tuple[key: string, val: int] #type(otherCountTable.data[0]) + + var t = initCountTable[string]() + for k, v in items(data): t.inc(k) + for k in t.keys: assert t[k] == 1 + t.inc("90", 3) + t.inc("12", 2) + t.inc("34", 1) + assert t.largest()[0] == "90" + t.sort() + + var i = 0 + for k, v in t.pairs: + case i + of 0: assert k == "90" and v == 4 + of 1: assert k == "12" and v == 3 + of 2: assert k == "34" and v == 2 + else: break + inc i + +countTableTest1() +echo true diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim new file mode 100644 index 000000000..ce5334664 --- /dev/null +++ b/tests/misc/tsizeof.nim @@ -0,0 +1,742 @@ +discard """ + targets: "c cpp" + output: ''' +body executed +body executed +OK +macros api OK +''' +""" + +# This is for Azure. The keyword ``alignof`` only exists in ``c++11`` +# and newer. On Azure gcc does not default to c++11 yet. +when defined(cpp) and not defined(windows): + {.passC: "-std=c++11".} + +# Object offsets are different for inheritance objects when compiling +# to c++. + +type + TMyEnum = enum + tmOne, tmTwo, tmThree, tmFour + + TMyArray1 = array[3, uint8] + TMyArray2 = array[1..3, int32] + TMyArray3 = array[TMyEnum, float64] + +var failed = false + +const + mysize1 = sizeof(TMyArray1) + mysize2 = sizeof(TMyArray2) + mysize3 = sizeof(TMyArray3) + +doAssert mysize1 == 3 +doAssert mysize2 == 12 +doAssert mysize3 == 32 + +import macros, typetraits + +macro testSizeAlignOf(args: varargs[untyped]): untyped = + result = newStmtList() + for arg in args: + result.add quote do: + let + c_size = c_sizeof(`arg`) + nim_size = sizeof(`arg`) + c_align = c_alignof(type(`arg`)) + nim_align = alignof(`arg`) + + if nim_size != c_size or nim_align != c_align: + var msg = strAlign(`arg`.type.name & ": ") + if nim_size != c_size: + msg.add " size(got, expected): " & $nim_size & " != " & $c_size + if nim_align != c_align: + msg.add " align(get, expected): " & $nim_align & " != " & $c_align + echo msg + failed = true + + +macro testOffsetOf(a, b: untyped): untyped = + let typeName = newLit(a.repr) + let member = newLit(b.repr) + result = quote do: + let + c_offset = c_offsetof(`a`,`b`) + nim_offset = offsetof(`a`,`b`) + if c_offset != nim_offset: + echo `typeName`, ".", `member`, " offsetError, C: ", c_offset, " nim: ", nim_offset + failed = true + +proc strAlign(arg: string): string = + const minLen = 22 + result = arg + for i in 0 ..< minLen - arg.len: + result &= ' ' + +macro c_offsetof(fieldAccess: typed): int32 = + ## Bullet proof implementation that works on actual offsetof operator + ## in the c backend. Assuming of course this implementation is + ## correct. + let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0] + else: fieldAccess + let a = s[0].getTypeInst + let b = s[1] + result = quote do: + var res: int32 + {.emit: [res, " = offsetof(", `a`, ", ", `b`, ");"] .} + res + +template c_offsetof(t: typedesc, a: untyped): int32 = + var x: ptr t + c_offsetof(x[].a) + +macro c_sizeof(a: typed): int32 = + ## Bullet proof implementation that works using the sizeof operator + ## in the c backend. Assuming of course this implementation is + ## correct. + result = quote do: + var res: int32 + {.emit: [res, " = sizeof(", `a`, ");"] .} + res + +macro c_alignof(arg: untyped): untyped = + ## Bullet proof implementation that works on actual alignment + ## behavior measured at runtime. + let typeSym = genSym(nskType, "AlignTestType"&arg.repr) + result = quote do: + type + `typeSym` = object + causeAlign: byte + member: `arg` + c_offsetof(`typeSym`, member) + +macro testAlign(arg:untyped):untyped = + let prefix = newLit(arg.lineinfo & " alignof " & arg.repr & " ") + result = quote do: + let cAlign = c_alignof(`arg`) + let nimAlign = alignof(`arg`) + if cAlign != nimAlign: + echo `prefix`, cAlign, " != ", nimAlign + failed = true + +macro testSize(arg:untyped):untyped = + let prefix = newLit(arg.lineinfo & " sizeof " & arg.repr & " ") + result = quote do: + let cSize = c_sizeof(`arg`) + let nimSize = sizeof(`arg`) + if cSize != nimSize: + echo `prefix`, cSize, " != ", nimSize + failed = true + +type + MyEnum {.pure.} = enum + ValueA + ValueB + ValueC + + OtherEnum {.pure, size: 8.} = enum + ValueA + ValueB + + Enum1 {.pure, size: 1.} = enum + ValueA + ValueB + + Enum2 {.pure, size: 2.} = enum + ValueA + ValueB + + Enum4 {.pure, size: 4.} = enum + ValueA + ValueB + + Enum8 {.pure, size: 8.} = enum + ValueA + ValueB + + # Must have more than 32 elements so that set[MyEnum33] will become compile to an int64. + MyEnum33 {.pure.} = enum + Value1, Value2, Value3, Value4, Value5, Value6, + Value7, Value8, Value9, Value10, Value11, Value12, + Value13, Value14, Value15, Value16, Value17, Value18, + Value19, Value20, Value21, Value22, Value23, Value24, + Value25, Value26, Value27, Value28, Value29, Value30, + Value31, Value32, Value33 + +proc transformObjectconfigPacked(arg: NimNode): NimNode = + let debug = arg.kind == nnkPragmaExpr + + if arg.eqIdent("objectconfig"): + result = ident"packed" + else: + result = copyNimNode(arg) + for child in arg: + result.add transformObjectconfigPacked(child) + +proc removeObjectconfig(arg: NimNode): NimNode = + if arg.kind == nnkPragmaExpr and arg[1][0].eqIdent "objectconfig": + result = arg[0] + else: + result = copyNimNode(arg) + for child in arg: + result.add removeObjectconfig(child) + +macro testinstance(body: untyped): untyped = + let bodyPure = removeObjectconfig(body) + let bodyPacked = transformObjectconfigPacked(body) + + result = quote do: + proc pureblock(): void = + const usePacked {.inject.} = false + `bodyPure` + + pureblock() + + proc packedblock(): void = + const usePacked {.inject.} = true + `bodyPacked` + + packedblock() + +proc testPrimitiveTypes(): void = + testAlign(pointer) + testAlign(int) + testAlign(uint) + testAlign(int8) + testAlign(int16) + testAlign(int32) + testAlign(int64) + testAlign(uint8) + testAlign(uint16) + testAlign(uint32) + testAlign(uint64) + testAlign(float) + testAlign(float32) + testAlign(float64) + + testAlign(MyEnum) + testAlign(OtherEnum) + testAlign(Enum1) + testAlign(Enum2) + testAlign(Enum4) + testAlign(Enum8) + +testPrimitiveTypes() + +testinstance: + type + + EnumObjectA {.objectconfig.} = object + a : Enum1 + b : Enum2 + c : Enum4 + d : Enum8 + + EnumObjectB {.objectconfig.} = object + a : Enum8 + b : Enum4 + c : Enum2 + d : Enum1 + + TrivialType {.objectconfig.} = object + x,y,z: int8 + + SimpleAlignment {.objectconfig.} = object + # behaves differently on 32bit Windows and 32bit Linux + a,b: int8 + c: int64 + + AlignAtEnd {.objectconfig.} = object + a: int64 + b,c: int8 + + SimpleBranch {.objectconfig.} = object + case kind: MyEnum + of MyEnum.ValueA: + a: int16 + of MyEnum.ValueB: + b: int32 + of MyEnum.ValueC: + c: int64 + + PaddingBeforeBranchA {.objectconfig.} = object + cause: int8 + case kind: MyEnum + of MyEnum.ValueA: + a: int16 + of MyEnum.ValueB: + b: int32 + of MyEnum.ValueC: + c: int64 + + PaddingBeforeBranchB {.objectconfig.} = object + cause: int8 + case kind: MyEnum + of MyEnum.ValueA: + a: int8 + of MyEnum.ValueB: + b: int16 + of MyEnum.ValueC: + c: int32 + + PaddingAfterBranch {.objectconfig.} = object + case kind: MyEnum + of MyEnum.ValueA: + a: int8 + of MyEnum.ValueB: + b: int16 + of MyEnum.ValueC: + c: int32 + cause: int64 + + RecursiveStuff {.objectconfig.} = object + case kind: MyEnum # packedOffset: 0 + of MyEnum.ValueA: # packedOffset: + a: int16 # packedOffset: 1 + of MyEnum.ValueB: # packedOffset: + b: int32 # packedOffset: 1 + of MyEnum.ValueC: # packedOffset: + case kind2: MyEnum # packedOffset: 1 + of MyEnum.ValueA: # packedOffset: + ca1: int8 + ca2: int32 + of MyEnum.ValueB: # packedOffset: + cb: int32 # packedOffset: 2 + of MyEnum.ValueC: # packedOffset: + cc: int64 # packedOffset: 2 + d1: int8 + d2: int64 + + Foobar {.objectconfig.} = object + case kind: OtherEnum + of OtherEnum.ValueA: + a: uint8 + of OtherEnum.ValueB: + b: int8 + c: int8 + + PaddingOfSetEnum33 {.objectconfig.} = object + cause: int8 + theSet: set[MyEnum33] + + Bazing {.objectconfig.} = object of RootObj + a: int64 + # TODO test on 32 bit system + # only there the object header is smaller than the first member + + InheritanceA {.objectconfig.} = object of RootObj + a: char + + InheritanceB {.objectconfig.} = object of InheritanceA + b: char + + InheritanceC {.objectconfig.} = object of InheritanceB + c: char + + # from issue 4763 + GenericObject[T] {.objectconfig.} = object + a: int32 + b: T + + # this type mixes `packed` with `align`. + MyCustomAlignPackedObject {.objectconfig.} = object + a: char + b {.align: 32.}: int32 # align overrides `packed` for this field. + c: char + d: int32 # unaligned + + Kind = enum + K1, K2 + + AnotherEnum = enum + X1, X2, X3 + + MyObject = object + s: string + case k: Kind + of K1: nil + of K2: + x: float + y: int32 + z: AnotherEnum + + Stack[N: static int, T: object] = object + pad: array[128 - sizeof(array[N, ptr T]) - sizeof(int) - sizeof(pointer), byte] + stack: array[N, ptr T] + len*: int + rawMem: ptr array[N, T] + + Stack2[T: object] = object + pad: array[128 - sizeof(array[sizeof(T), ptr T]), byte] + + + const trivialSize = sizeof(TrivialType) # needs to be able to evaluate at compile time + + proc main(): void = + var t : TrivialType + var a : SimpleAlignment + var b : AlignAtEnd + var c : SimpleBranch + var d : PaddingBeforeBranchA + var e : PaddingBeforeBranchB + var f : PaddingAfterBranch + var g : RecursiveStuff + var ro : RootObj + var go : GenericObject[int64] + var po : PaddingOfSetEnum33 + var capo: MyCustomAlignPackedObject + var issue15516: MyObject + var issue12636_1: Stack[5, MyObject] + var issue12636_2: Stack2[MyObject] + + var + e1: Enum1 + e2: Enum2 + e4: Enum4 + e8: Enum8 + var + eoa: EnumObjectA + eob: EnumObjectB + + testAlign(SimpleAlignment) + + # sanity check to ensure both branches are actually executed + when usePacked: + doAssert sizeof(SimpleAlignment) == 10 + else: + doAssert sizeof(SimpleAlignment) > 10 + + testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo, issue15516, issue12636_1, issue12636_2) + + type + WithBitsize {.objectconfig.} = object + bitfieldA {.bitsize: 16.}: uint32 + bitfieldB {.bitsize: 16.}: uint32 + + var wbs: WithBitsize + testSize(wbs) + + testOffsetOf(TrivialType, x) + testOffsetOf(TrivialType, y) + testOffsetOf(TrivialType, z) + + testOffsetOf(SimpleAlignment, a) + testOffsetOf(SimpleAlignment, b) + testOffsetOf(SimpleAlignment, c) + + testOffsetOf(AlignAtEnd, a) + testOffsetOf(AlignAtEnd, b) + testOffsetOf(AlignAtEnd, c) + + testOffsetOf(SimpleBranch, a) + testOffsetOf(SimpleBranch, b) + testOffsetOf(SimpleBranch, c) + + testOffsetOf(PaddingBeforeBranchA, cause) + testOffsetOf(PaddingBeforeBranchA, a) + testOffsetOf(PaddingBeforeBranchB, cause) + testOffsetOf(PaddingBeforeBranchB, a) + + testOffsetOf(PaddingAfterBranch, a) + testOffsetOf(PaddingAfterBranch, cause) + + testOffsetOf(Foobar, c) + + testOffsetOf(PaddingOfSetEnum33, cause) + testOffsetOf(PaddingOfSetEnum33, theSet) + + testOffsetOf(Bazing, a) + testOffsetOf(InheritanceA, a) + testOffsetOf(InheritanceB, b) + testOffsetOf(InheritanceC, c) + + testOffsetOf(EnumObjectA, a) + testOffsetOf(EnumObjectA, b) + testOffsetOf(EnumObjectA, c) + testOffsetOf(EnumObjectA, d) + testOffsetOf(EnumObjectB, a) + testOffsetOf(EnumObjectB, b) + testOffsetOf(EnumObjectB, c) + testOffsetOf(EnumObjectB, d) + + testOffsetOf(RecursiveStuff, kind) + testOffsetOf(RecursiveStuff, a) + testOffsetOf(RecursiveStuff, b) + testOffsetOf(RecursiveStuff, kind2) + testOffsetOf(RecursiveStuff, ca1) + testOffsetOf(RecursiveStuff, ca2) + testOffsetOf(RecursiveStuff, cb) + testOffsetOf(RecursiveStuff, cc) + testOffsetOf(RecursiveStuff, d1) + testOffsetOf(RecursiveStuff, d2) + + testOffsetOf(MyCustomAlignPackedObject, a) + testOffsetOf(MyCustomAlignPackedObject, b) + testOffsetOf(MyCustomAlignPackedObject, c) + testOffsetOf(MyCustomAlignPackedObject, d) + + echo "body executed" # sanity check to ensure this logic isn't skipped entirely + + + main() + +{.emit: """/*TYPESECTION*/ +typedef struct{ + float a; float b; +} Foo; +""".} + +type + Foo {.importc.} = object + + Bar = object + b: byte + foo: Foo + +assert sizeof(Bar) == 12 + +# bug #10082 +type + A = int8 # change to int16 and get sizeof(C)==6 + B = int16 + C {.packed.} = object + d {.bitsize: 1.}: A + e {.bitsize: 7.}: A + f {.bitsize: 16.}: B + +assert sizeof(C) == 3 + + +type + MixedBitsize {.packed.} = object + a: uint32 + b {.bitsize: 8.}: uint8 + c {.bitsize: 1.}: uint8 + d {.bitsize: 7.}: uint8 + e {.bitsize: 16.}: uint16 + f: uint32 + +doAssert sizeof(MixedBitsize) == 12 + + +type + MyUnionType {.union.} = object + a: int32 + b: float32 + + MyCustomAlignUnion {.union.} = object + c: char + a {.align: 32.}: int + + MyCustomAlignObject = object + c: char + a {.align: 32.}: int + +doAssert sizeof(MyUnionType) == 4 +doAssert sizeof(MyCustomAlignUnion) == 32 +doAssert alignof(MyCustomAlignUnion) == 32 +doAssert sizeof(MyCustomAlignObject) == 64 +doAssert alignof(MyCustomAlignObject) == 32 + + + + + + +########################################## +# bug #9794 +########################################## + +type + imported_double {.importc: "double".} = object + + Pod = object + v* : imported_double + seed*: int32 + + Pod2 = tuple[v: imported_double, seed: int32] + +proc foobar() = + testAlign(Pod) + testSize(Pod) + testAlign(Pod2) + testSize(Pod2) + doAssert sizeof(Pod) == sizeof(Pod2) + doAssert alignof(Pod) == alignof(Pod2) +foobar() + +if failed: + quit("FAIL") +else: + echo "OK" + +########################################## +# sizeof macros API +########################################## + +import macros + +type + Vec2f = object + x,y: float32 + + Vec4f = object + x,y,z,w: float32 + + # this type is constructed to have no platform depended alignment. + ParticleDataA = object + pos, vel: Vec2f + birthday: float32 + padding: float32 + moreStuff: Vec4f + +const expected = [ + # name size align offset + ("pos", 8, 4, 0), + ("vel", 8, 4, 8), + ("birthday", 4, 4, 16), + ("padding", 4, 4, 20), + ("moreStuff", 16, 4, 24) +] + +macro typeProcessing(arg: typed): untyped = + let recList = arg.getTypeImpl[2] + recList.expectKind nnkRecList + for i, identDefs in recList: + identDefs.expectKind nnkIdentDefs + identDefs.expectLen 3 + let sym = identDefs[0] + sym.expectKind nnkSym + doAssert expected[i][0] == sym.strVal + doAssert expected[i][1] == getSize(sym) + doAssert expected[i][2] == getAlign(sym) + doAssert expected[i][3] == getOffset(sym) + + result = newCall(bindSym"echo", newLit("macros api OK")) + +proc main() = + var mylocal: ParticleDataA + typeProcessing(mylocal) + +main() + +# issue #11320 use UncheckedArray + +type + Payload = object + something: int8 + vals: UncheckedArray[int32] + +proc payloadCheck() = + doAssert offsetOf(Payload, vals) == 4 + doAssert sizeof(Payload) == 4 + +payloadCheck() + +# offsetof tuple types + +type + MyTupleType = tuple + a: float64 + b: float64 + c: float64 + + MyOtherTupleType = tuple + a: float64 + b: imported_double + c: float64 + + MyCaseObject = object + val1: imported_double + case kind: bool + of true: + val2,val3: float32 + else: + val4,val5: int32 + +doAssert offsetof(MyTupleType, a) == 0 +doAssert offsetof(MyTupleType, b) == 8 +doAssert offsetof(MyTupleType, c) == 16 + +doAssert offsetof(MyOtherTupleType, a) == 0 +doAssert offsetof(MyOtherTupleType, b) == 8 + +# The following expression can only work if the offsetof expression is +# properly forwarded for the C code generator. +doAssert offsetof(MyOtherTupleType, c) == 16 +doAssert offsetof(Bar, foo) == 4 +doAssert offsetof(MyCaseObject, val1) == 0 +doAssert offsetof(MyCaseObject, kind) == 8 +doAssert offsetof(MyCaseObject, val2) == 12 +doAssert offsetof(MyCaseObject, val3) == 16 +doAssert offsetof(MyCaseObject, val4) == 12 +doAssert offsetof(MyCaseObject, val5) == 16 + +template reject(e) = + static: assert(not compiles(e)) + +reject: + const off1 = offsetof(MyOtherTupleType, c) + +reject: + const off2 = offsetof(MyOtherTupleType, b) + +reject: + const off3 = offsetof(MyCaseObject, kind) + + +type + MyPackedCaseObject {.packed.} = object + val1: imported_double + case kind: bool + of true: + val2,val3: float32 + else: + val4,val5: int32 + +# packed case object + +doAssert offsetof(MyPackedCaseObject, val1) == 0 +doAssert offsetof(MyPackedCaseObject, val2) == 9 +doAssert offsetof(MyPackedCaseObject, val3) == 13 +doAssert offsetof(MyPackedCaseObject, val4) == 9 +doAssert offsetof(MyPackedCaseObject, val5) == 13 + +reject: + const off5 = offsetof(MyPackedCaseObject, val2) + +reject: + const off6 = offsetof(MyPackedCaseObject, val3) + +reject: + const off7 = offsetof(MyPackedCaseObject, val4) + +reject: + const off8 = offsetof(MyPackedCaseObject, val5) + + +type + O0 = object + T0 = tuple[] + +doAssert sizeof(O0) == 1 +doAssert sizeof(T0) == 1 + + +type + # this thing may not have padding bytes at the end + PackedUnion* {.union, packed.} = object + a*: array[11, byte] + b*: int64 + +doAssert sizeof(PackedUnion) == 11 +doAssert alignof(PackedUnion) == 1 + +# bug #22553 +type + ChunkObj = object + data: UncheckedArray[byte] + +doAssert sizeof(ChunkObj) == 1 +doAssert offsetOf(ChunkObj, data) == 1 diff --git a/tests/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim new file mode 100644 index 000000000..da28de508 --- /dev/null +++ b/tests/misc/tsizeof2.nim @@ -0,0 +1,17 @@ +discard """ +errormsg: "'sizeof' requires '.importc' types to be '.completeStruct'" +line: 9 +""" + +type + MyStruct {.importc: "MyStruct".} = object + +const i = sizeof(MyStruct) + +echo i + +# bug #9868 +proc foo(a: SomeInteger): array[sizeof(a), byte] = + discard + +discard foo(1) diff --git a/tests/misc/tsizeof3.nim b/tests/misc/tsizeof3.nim new file mode 100644 index 000000000..f0ba8c4d0 --- /dev/null +++ b/tests/misc/tsizeof3.nim @@ -0,0 +1,58 @@ +discard """ +output: ''' +@[48, 57] +''' +""" +# bug #7238 + +type ByteArrayBE*[N: static[int]] = array[N, byte] + ## A byte array that stores bytes in big-endian order + +proc toByteArrayBE*[T: SomeInteger](num: T): ByteArrayBE[sizeof(T)]= + ## Convert an integer (in native host endianness) to a big-endian byte array + ## Notice the result type + const N = T.sizeof + for i in 0 ..< N: + result[i] = byte((num shr ((N-1-i) * 8)) and high(int8)) + +let a = 12345.toByteArrayBE +echo a[^2 .. ^1] # to make it work on both 32-bit and 64-bit + +#--------------------------------------------------------------------- + +type + Payload = object + something: int + vals: UncheckedArray[int] + +static: + doAssert(compiles(offsetOf(Payload, vals))) + + +type + GoodboySave* {.bycopy.} = object + saveCount: uint8 + savePoint: uint16 + shards: uint32 + friendCount: uint8 + friendCards: set[0..255] + locationsKnown: set[0..127] + locationsUnlocked: set[0..127] + pickupsObtained: set[0..127] + pickupsUsed: set[0..127] + pickupCount: uint8 + +block: # bug #20914 + block: + proc csizeof[T](a: T): int {.importc:"sizeof", nodecl.} + + var s: GoodboySave + doAssert sizeof(s) == 108 + doAssert csizeof(s) == static(sizeof(s)) + + block: + proc calignof[T](a: T): int {.importc:"alignof", header: "<stdalign.h>".} + + var s: set[0..256] + doAssert alignof(s) == 1 + doAssert calignof(s) == static(alignof(s)) diff --git a/tests/misc/tsizeof4.nim b/tests/misc/tsizeof4.nim new file mode 100644 index 000000000..94c08ba39 --- /dev/null +++ b/tests/misc/tsizeof4.nim @@ -0,0 +1,20 @@ +discard """ +disabled: "arm64" +""" + +# bug #11792 +type + m256d {.importc: "__m256d", header: "immintrin.h".} = object + + MyKind = enum + k1, k2, k3 + + MyTypeObj = object + kind: MyKind + x: int + amount: UncheckedArray[m256d] + + +# The sizeof(MyTypeObj) is not equal to (sizeof(int) + sizeof(MyKind)) due to +# alignment requirement of m256d, make sure Nim understands that +doAssert(sizeof(MyTypeObj) > sizeof(int) + sizeof(MyKind)) diff --git a/tests/misc/tsortdev.nim b/tests/misc/tsortdev.nim new file mode 100644 index 000000000..6a290577b --- /dev/null +++ b/tests/misc/tsortdev.nim @@ -0,0 +1,58 @@ +discard """ + output: "done tsortdev" +""" + +import algorithm, strutils + +proc cmpPlatforms(a, b: string): int = + if a == b: return 0 + var dashes = a.split('-') + var dashes2 = b.split('-') + if dashes[0] == dashes2[0]: + if dashes[1] == dashes2[1]: return system.cmp(a,b) + case dashes[1] + of "x86": + return 1 + of "x86_64": + if dashes2[1] == "x86": return -1 + else: return 1 + of "ppc64": + if dashes2[1] == "x86" or dashes2[1] == "x86_64": return -1 + else: return 1 + else: + return system.cmp(dashes[1], dashes2[1]) + else: + case dashes[0] + of "linux": + return 1 + of "windows": + if dashes2[0] == "linux": return -1 + else: return 1 + of "macosx": + if dashes2[0] == "linux" or dashes2[0] == "windows": return -1 + else: return 1 + else: + if dashes2[0] == "linux" or dashes2[0] == "windows" or + dashes2[0] == "macosx": return -1 + else: + return system.cmp(a, b) + +proc sorted[T](a: openArray[T]): bool = + result = true + for i in 0 ..< a.high: + if cmpPlatforms(a[i], a[i+1]) > 0: + echo "Out of order: ", a[i], " ", a[i+1] + result = false + +proc main() = + var testData = @["netbsd-x86_64", "windows-x86", "linux-x86_64", "linux-x86", + "linux-ppc64", "macosx-x86-1058", "macosx-x86-1068"] + + sort(testData, cmpPlatforms) + + doAssert sorted(testData) + +for i in 0..1_000: + main() + +echo "done tsortdev" diff --git a/tests/misc/tstrace.nim b/tests/misc/tstrace.nim new file mode 100644 index 000000000..00af0af69 --- /dev/null +++ b/tests/misc/tstrace.nim @@ -0,0 +1,36 @@ +discard """ +exitcode: 1 +output: ''' +Traceback (most recent call last) +tstrace.nim(36) tstrace +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(28) recTest +tstrace.nim(31) recTest +SIGSEGV: Illegal storage access. (Attempt to read from nil?) +''' +""" + +# Test the new stacktraces (great for debugging!) + +{.push stack_trace: on.} + +proc recTest(i: int) = + # enter + if i < 10: + recTest(i+1) + else: # should printStackTrace() + var p: ptr int = nil + p[] = 12 + # leave + +{.pop.} + +recTest(0) diff --git a/tests/misc/tstrange.nim b/tests/misc/tstrange.nim new file mode 100644 index 000000000..f8c063240 --- /dev/null +++ b/tests/misc/tstrange.nim @@ -0,0 +1,28 @@ +discard """ +output: ''' +hallo40 +1 +2 +''' +""" +# test for extremely strange bug + +proc ack(x: int, y: int): int = + if x != 0: + if y != 5: + return y + return x + return x+y + +proc gen[T](a: T) = + write(stdout, a) + + +gen("hallo") +write(stdout, ack(5, 4)) +#OUT hallo4 + +# bug #1442 +let h=3 +for x in 0 ..< h.int: + echo x diff --git a/tests/misc/tstrdesc.nim b/tests/misc/tstrdesc.nim new file mode 100644 index 000000000..1479fcda8 --- /dev/null +++ b/tests/misc/tstrdesc.nim @@ -0,0 +1,14 @@ +var + x: array[0..2, int] + +x = [0, 1, 2] + +type + TStringDesc {.final.} = object + len, space: int # len and space without counting the terminating zero + data: array[0..0, char] # for the '\0' character + +var + emptyString {.exportc: "emptyString".}: TStringDesc + + diff --git a/tests/misc/tstrdist.nim b/tests/misc/tstrdist.nim new file mode 100644 index 000000000..53ace2fae --- /dev/null +++ b/tests/misc/tstrdist.nim @@ -0,0 +1,26 @@ +# compute the edit distance between two strings + +proc editDistance(a, b: string): int = + var + c: seq[int] + n = a.len + m = b.len + newSeq(c, (n+1)*(m+1)) + for i in 0..n: + c[i*n] = i # [i,0] + for j in 0..m: + c[j] = j # [0,j] + + for i in 1..n: + for j in 1..m: + var x = c[(i-1)*n + j]+1 + var y = c[i*n + j-1]+1 + var z: int + if a[i-1] == b[j-1]: + z = c[(i-1)*n + j-1] + else: + z = c[(i-1)*n + j-1]+1 + c[(i-1)*n + (j-1)] = min(x,min(y,z)) + return c[n*m] + +doAssert editDistance("abc", "abd") == 3 diff --git a/tests/misc/ttlsemulation.nim b/tests/misc/ttlsemulation.nim new file mode 100644 index 000000000..767a9bd4e --- /dev/null +++ b/tests/misc/ttlsemulation.nim @@ -0,0 +1,76 @@ +discard """ + disabled: i386 + matrix: "-d:nimTtlsemulationCase1 --threads --tlsEmulation:on; -d:nimTtlsemulationCase2 --threads --tlsEmulation:off; -d:nimTtlsemulationCase3 --threads" + targets: "c cpp" +""" + +#[ +tests for: `.cppNonPod`, `--tlsEmulation` +]# + +import std/sugar + +block: + # makes sure the logic in config/nim.cfg or testament doesn't interfere with `--tlsEmulation` so we test the right thing. + when defined(nimTtlsemulationCase1): + doAssert compileOption("tlsEmulation") + elif defined(nimTtlsemulationCase2): + doAssert not compileOption("tlsEmulation") + elif defined(nimTtlsemulationCase3): + when defined(osx): + doAssert not compileOption("tlsEmulation") + else: + doAssert false + +block: + proc main1(): int = + var g0 {.threadvar.}: int + g0.inc + g0 + let s = collect: + for i in 0..<3: main1() + doAssert s == @[1,2,3] + +when defined(cpp): # bug #16752 + when defined(windows) and defined(nimTtlsemulationCase2): + discard # xxx this failed with exitCode 1 + else: + type Foo1 {.importcpp: "Foo1", header: "mtlsemulation.h".} = object + x: cint + type Foo2 {.cppNonPod, importcpp: "Foo2", header: "mtlsemulation.h".} = object + x: cint + + var ctorCalls {.importcpp.}: cint + var dtorCalls {.importcpp.}: cint + type Foo3 {.cppNonPod, importcpp: "Foo3", header: "mtlsemulation.h".} = object + x: cint + + proc sub(i: int) = + var g1 {.threadvar.}: Foo1 + var g2 {.threadvar.}: Foo2 + var g3 {.threadvar.}: Foo3 + discard g1 + discard g2 + + # echo (g3.x, ctorCalls, dtorCalls) + when compileOption("tlsEmulation"): + # xxx bug + discard + else: + doAssert g3.x.int == 10 + i + doAssert ctorCalls == 2 + doAssert dtorCalls == 1 + g3.x.inc + + proc main() = + doAssert ctorCalls == 0 + doAssert dtorCalls == 0 + block: + var f3: Foo3 + doAssert f3.x == 10 + doAssert ctorCalls == 1 + doAssert dtorCalls == 1 + + for i in 0..<3: + sub(i) + main() diff --git a/tests/misc/tvarious.nim b/tests/misc/tvarious.nim new file mode 100644 index 000000000..191107a87 --- /dev/null +++ b/tests/misc/tvarious.nim @@ -0,0 +1,72 @@ +discard """ +action: compile +""" + +# Test various aspects + +# bug #572 +var a=12345678901'u64 + +var x = (x: 42, y: (a: 8, z: 10)) +echo x.y + +import + mvarious + +type + PA = ref TA + PB = ref TB + + TB = object + a: PA + + TA = object + b: TB + x: int + +proc getPA(): PA = + var + b: bool + b = not false + return nil + +# bug #501 +proc f(): int = 54 + +var + global: int + +var + s: string + i: int + r: TA + +r.b.a.x = 0 +global = global + 1 +exportme() +write(stdout, "Hallo wie heißt du? ") +write(stdout, getPA().x) +s = readLine(stdin) +i = 0 +while i < s.len: + if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n") + i = i + 1 + +write(stdout, "Du heißt " & s) + +# bug #544 + +# yay, fails again +type Bar [T; I:range] = array[I, T] +proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] = + when len(a) != 3: + # Error: constant expression expected + {.fatal:"Dimensions have to be 3".} + #... +block: + var a, b: Bar[int, range[0..2]] + discard foo(a, b) + +# bug #1788 + +echo "hello" & char(ord(' ')) & "world" diff --git a/tests/misc/tvarious1.nim b/tests/misc/tvarious1.nim new file mode 100644 index 000000000..9c912ee8e --- /dev/null +++ b/tests/misc/tvarious1.nim @@ -0,0 +1,58 @@ +discard """ +output: ''' +1 +0 +Whopie +12 +1.7''' +""" + +echo len([1_000_000]) #OUT 1 + +type + TArray = array[0..3, int] + TVector = distinct array[0..3, int] +proc `[]`(v: TVector; idx: int): int = TArray(v)[idx] +var v: TVector +echo v[2] + +# bug #569 + +import deques + +type + TWidget = object + names: Deque[string] + +var w = TWidget(names: initDeque[string]()) + +addLast(w.names, "Whopie") + +for n in w.names: echo(n) + +# bug #681 + +type TSomeRange = object + hour: range[0..23] + +var value: string +var val12 = TSomeRange(hour: 12) + +value = $(if val12.hour > 12: val12.hour - 12 else: val12.hour) +echo value + +# bug #1334 + +var ys = @[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] +#var x = int(ys.high / 2) #echo ys[x] # Works +echo ys[int(ys.high / 2)] # Doesn't work + + +# bug #19680 +var here = "" +when stderr is static: + doAssert false +else: + here = "works" + +doAssert here == "works" diff --git a/tests/misc/tvarnums.nim b/tests/misc/tvarnums.nim new file mode 100644 index 000000000..498099c49 --- /dev/null +++ b/tests/misc/tvarnums.nim @@ -0,0 +1,139 @@ +discard """ + output: "Success!" +""" +# Test variable length binary integers + +import + strutils + +type + TBuffer = array[0..10, uint8] + +proc toVarNum(x: int32, b: var TBuffer) = + # encoding: first bit indicates end of number (0 if at end) + # second bit of the first byte denotes the sign (1 --> negative) + var a = x + if x != low(x): + # low(int) is a special case, + # because abs() does not work here! + # we leave x as it is and use the check >% instead of > + # for low(int) this is needed and positive numbers are not affected + # anyway + a = abs(x) + # first 6 bits: + b[0] = uint8(ord(a >% 63'i32) shl 7 or (ord(x < 0'i32) shl 6) or (int(a) and 63)) + a = (a shr 6'i32) and 0x03ffffff # skip first 6 bits + var i = 1 + while a != 0'i32: + b[i] = uint8(ord(a >% 127'i32) shl 7 or (int(a) and 127)) + inc(i) + a = a shr 7'i32 + +proc toVarNum64(x: int64, b: var TBuffer) = + # encoding: first bit indicates end of number (0 if at end) + # second bit of the first byte denotes the sign (1 --> negative) + var a = x + if x != low(x): + # low(int) is a special case, + # because abs() does not work here! + # we leave x as it is and use the check >% instead of > + # for low(int) this is needed and positive numbers are not affected + # anyway + a = abs(x) + # first 6 bits: + b[0] = uint8(ord(a >% 63'i64) shl 7 or (ord(x < 0'i64) shl 6) or int(a and 63)) + a = (a shr 6) and 0x03ffffffffffffff # skip first 6 bits + var i = 1 + while a != 0'i64: + b[i] = uint8(ord(a >% 127'i64) shl 7 or int(a and 127)) + inc(i) + a = a shr 7 + +proc toNum64(b: TBuffer): int64 = + # treat first byte different: + result = int64(b[0]) and 63 + var + i = 0 + Shift = 6'i64 + while (int(b[i]) and 128) != 0: + inc(i) + result = result or ((int64(b[i]) and 127) shl Shift) + inc(Shift, 7) + if (int(b[0]) and 64) != 0: # sign bit set? + result = not result +% 1 + # this is the same as ``- result`` + # but gives no overflow error for low(int) + +proc toNum(b: TBuffer): int32 = + # treat first byte different: + result = int32(b[0]) and 63 + var + i = 0 + Shift = 6'i32 + while (int(b[i]) and 128) != 0: + inc(i) + result = result or ((int32(b[i]) and 127'i32) shl Shift) + Shift = Shift + 7'i32 + if (int(b[0]) and (1 shl 6)) != 0: # sign bit set? + result = (not result) +% 1'i32 + # this is the same as ``- result`` + # but gives no overflow error for low(int) + +proc toBinary(x: int64): string = + result = newString(64) + for i in 0..63: + result[63-i] = chr((int(x shr i) and 1) + ord('0')) + +proc t64(i: int64) = + var + b: TBuffer + toVarNum64(i, b) + var x = toNum64(b) + if x != i: + writeLine(stdout, $i) + writeLine(stdout, toBinary(i)) + writeLine(stdout, toBinary(x)) + +proc t32(i: int32) = + var + b: TBuffer + toVarNum(i, b) + var x = toNum(b) + if x != i: + writeLine(stdout, toBinary(i)) + writeLine(stdout, toBinary(x)) + +proc tm(i: int32) = + var + b: TBuffer + toVarNum64(i, b) + var x = toNum(b) + if x != i: + writeLine(stdout, toBinary(i)) + writeLine(stdout, toBinary(x)) + +t32(0) +t32(1) +t32(-1) +t32(-100_000) +t32(100_000) +t32(low(int32)) +t32(high(int32)) + +t64(low(int64)) +t64(high(int64)) +t64(0) +t64(-1) +t64(1) +t64(1000_000) +t64(-1000_000) + +tm(0) +tm(1) +tm(-1) +tm(-100_000) +tm(100_000) +tm(low(int32)) +tm(high(int32)) + +writeLine(stdout, "Success!") #OUT Success! diff --git a/tests/misc/tvcc.nim b/tests/misc/tvcc.nim new file mode 100644 index 000000000..10533729c --- /dev/null +++ b/tests/misc/tvcc.nim @@ -0,0 +1,9 @@ +discard """ + matrix: "--cc:vcc" + disabled: "linux" + disabled: "bsd" + disabled: "osx" + disabled: "unix" + disabled: "posix" +""" +doAssert true diff --git a/tests/misc/åäö.nim b/tests/misc/åäö.nim new file mode 100644 index 000000000..b3caa9861 --- /dev/null +++ b/tests/misc/åäö.nim @@ -0,0 +1,11 @@ +discard """ + action: run +""" + +# Tests that module names can contain multi byte characters + +let a = 1 +doAssert åäö.a == 1 + +proc inlined() {.inline.} = discard +inlined() \ No newline at end of file |