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..>> ")) == "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