diff options
Diffstat (limited to 'nimsuggest/tester.nim')
-rw-r--r-- | nimsuggest/tester.nim | 122 |
1 files changed, 87 insertions, 35 deletions
diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 4cda272af..9b9488348 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -2,25 +2,32 @@ # Every test file can have a #[!]# comment that is deleted from the input # before 'nimsuggest' is invoked to ensure this token doesn't make a # crucial difference for Nim's parser. +# When debugging, to run a single test, use for e.g.: +# `nim r nimsuggest/tester.nim nimsuggest/tests/tsug_accquote.nim` import os, osproc, strutils, streams, re, sexp, net +from sequtils import toSeq type Test = object - cmd, dest: string + filename, cmd, dest: string startup: seq[string] script: seq[(string, string)] + disabled: bool const - curDir = when defined(windows): "" else: "" DummyEof = "!EOF!" + tpath = "nimsuggest/tests" + # we could also use `stdtest/specialpaths` -template tpath(): untyped = getAppDir() / "tests" +import std/compilesettings proc parseTest(filename: string; epcMode=false): Test = const cursorMarker = "#[!]#" - let nimsug = curDir & addFileExt("nimsuggest", ExeExt) - let libpath = findExe("nim").splitFile().dir /../ "lib" + let nimsug = "bin" / addFileExt("nimsuggest_testing", ExeExt) + doAssert nimsug.fileExists, nimsug + const libpath = querySetting(libPath) + result.filename = filename result.dest = getTempDir() / extractFilename(filename) result.cmd = nimsug & " --tester " & result.dest result.script = @[] @@ -42,7 +49,14 @@ proc parseTest(filename: string; epcMode=false): Test = if x.contains("""""""""): inc specSection elif specSection == 1: - if x.startsWith("$nimsuggest"): + if x.startsWith("disabled:"): + if x.startsWith("disabled:true"): + result.disabled = true + else: + # be strict about format + doAssert x.startsWith("disabled:false") + result.disabled = false + elif x.startsWith("$nimsuggest"): result.cmd = x % ["nimsuggest", nimsug, "file", filename, "lib", libpath] elif x.startsWith("!"): if result.cmd.len == 0: @@ -52,7 +66,7 @@ proc parseTest(filename: string; epcMode=false): Test = elif x.startsWith(">"): # since 'markers' here are not complete yet, we do the $substitutions # afterwards - result.script.add((x.substr(1).replaceWord("$path", tpath()), "")) + result.script.add((x.substr(1).replaceWord("$path", tpath).replaceWord("$file", filename), "")) elif x.len > 0: # expected output line: let x = x % ["file", filename, "lib", libpath] @@ -70,22 +84,22 @@ proc parseCmd(c: string): seq[string] = result = @[] var i = 0 var a = "" - while true: + while i < c.len: setLen(a, 0) # eat all delimiting whitespace - while c[i] in {' ', '\t', '\l', '\r'}: inc(i) + while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i) + if i >= c.len: break case c[i] of '"': raise newException(ValueError, "double quotes not yet supported: " & c) of '\'': var delim = c[i] inc(i) # skip ' or " - while c[i] != '\0' and c[i] != delim: + while i < c.len and c[i] != delim: add a, c[i] inc(i) - if c[i] != '\0': inc(i) - of '\0': break + if i < c.len: inc(i) else: - while c[i] > ' ': + while i < c.len and c[i] > ' ': add(a, c[i]) inc(i) add(result, a) @@ -93,7 +107,7 @@ proc parseCmd(c: string): seq[string] = proc edit(tmpfile: string; x: seq[string]) = if x.len != 3 and x.len != 4: quit "!edit takes two or three arguments" - let f = if x.len >= 4: tpath() / x[3] else: tmpfile + let f = if x.len >= 4: tpath / x[3] else: tmpfile try: let content = readFile(f) let newcontent = content.replace(x[1], x[2]) @@ -110,12 +124,12 @@ proc exec(x: seq[string]) = proc copy(x: seq[string]) = if x.len != 3: quit "!copy takes two arguments" - let rel = tpath() + let rel = tpath copyFile(rel / x[1], rel / x[2]) proc del(x: seq[string]) = if x.len != 2: quit "!del takes one argument" - removeFile(tpath() / x[1]) + removeFile(tpath / x[1]) proc runCmd(cmd, dest: string): bool = result = cmd[0] == '!' @@ -131,7 +145,7 @@ proc runCmd(cmd, dest: string): bool = of "!del": del(x) else: - quit "unkown command: " & cmd + quit "unknown command: " & cmd proc smartCompare(pattern, x: string): bool = if pattern.contains('*'): @@ -197,14 +211,19 @@ proc sexpToAnswer(s: SexpNode): string = result.add '\t' result.add file result.add '\t' - result.add line + result.addInt line result.add '\t' - result.add col + result.addInt col result.add '\t' result.add doc result.add '\t' - result.add a[8].getNum - if a.len >= 10: + result.addInt a[8].getNum + if a.len >= 11: + result.add '\t' + result.addInt a[9].getNum + result.add '\t' + result.addInt a[10].getNum + elif a.len >= 10: result.add '\t' result.add a[9].getStr result.add '\L' @@ -215,26 +234,38 @@ proc doReport(filename, answer, resp: string; report: var string) = var hasDiff = false for i in 0..min(resp.len-1, answer.len-1): if resp[i] != answer[i]: - report.add "\n Expected: " & resp.substr(i, i+200) - report.add "\n But got: " & answer.substr(i, i+200) + report.add "\n Expected:\n" & resp + report.add "\n But got:\n" & answer hasDiff = true break if not hasDiff: report.add "\n Expected: " & resp report.add "\n But got: " & answer +proc skipDisabledTest(test: Test): bool = + if test.disabled: + echo "disabled: " & test.filename + result = test.disabled + proc runEpcTest(filename: string): int = let s = parseTest(filename, true) + if s.skipDisabledTest: return 0 + for req, _ in items(s.script): + if req.startsWith("highlight"): + echo "disabled epc: " & s.filename + return 0 for cmd in s.startup: if not runCmd(cmd, s.dest): quit "invalid command: " & cmd - let epccmd = s.cmd.replace("--tester", "--epc --v2 --log") + let epccmd = if s.cmd.contains("--v3"): + s.cmd.replace("--tester", "--epc --log") + else: + s.cmd.replace("--tester", "--epc --v2 --log") let cl = parseCmdLine(epccmd) var p = startProcess(command=cl[0], args=cl[1 .. ^1], options={poStdErrToStdOut, poUsePath, - poInteractive, poDemon}) + poInteractive, poDaemon}) let outp = p.outputStream - let inp = p.inputStream var report = "" var socket = newSocket() try: @@ -248,17 +279,28 @@ proc runEpcTest(filename: string): int = os.sleep(50) inc i let a = outp.readAll().strip() - let port = parseInt(a) + var port: int + try: + port = parseInt(a) + except ValueError: + echo "Error parsing port number: " & a + echo outp.readAll() + quit 1 socket.connect("localhost", Port(port)) + for req, resp in items(s.script): if not runCmd(req, s.dest): socket.sendEpcStr(req) let sx = parseSexp(socket.recvEpc()) if not req.startsWith("mod "): - let answer = sexpToAnswer(sx) + let answer = if sx[2].kind == SNil: "" else: sexpToAnswer(sx) doReport(filename, answer, resp, report) - finally: + socket.sendEpcStr "return arg" + # bugfix: this was in `finally` block, causing the original error to be + # potentially masked by another one in case `socket.sendEpcStr` raises + # (e.g. if socket couldn't connect in the 1st place) + finally: close(p) if report.len > 0: echo "==== EPC ========================================" @@ -267,13 +309,14 @@ proc runEpcTest(filename: string): int = proc runTest(filename: string): int = let s = parseTest filename + if s.skipDisabledTest: return 0 for cmd in s.startup: if not runCmd(cmd, s.dest): quit "invalid command: " & cmd let cl = parseCmdLine(s.cmd) var p = startProcess(command=cl[0], args=cl[1 .. ^1], options={poStdErrToStdOut, poUsePath, - poInteractive, poDemon}) + poInteractive, poDaemon}) let outp = p.outputStream let inp = p.inputStream var report = "" @@ -293,8 +336,12 @@ proc runTest(filename: string): int = answer.add '\L' doReport(filename, answer, resp, report) finally: - inp.writeLine("quit") - inp.flush() + try: + inp.writeLine("quit") + inp.flush() + except IOError, OSError: + # assume it's SIGPIPE, ie, the child already died + discard close(p) if report.len > 0: echo "==== STDIN ======================================" @@ -306,11 +353,16 @@ proc main() = if os.paramCount() > 0: let x = os.paramStr(1) let xx = expandFilename x + # run only stdio when running single test failures += runTest(xx) - failures += runEpcTest(xx) else: - for x in walkFiles(getAppDir() / "tests/t*.nim"): - echo "Test ", x + let files = toSeq(walkFiles(tpath / "t*.nim")) + for i, x in files: + echo "$#/$# test: $#" % [$i, $files.len, x] + when defined(i386): + if x == "nimsuggest/tests/tmacro_highlight.nim": + echo "skipping" # workaround bug #17945 + continue let xx = expandFilename x when not defined(windows): # XXX Windows IO redirection seems bonkers: |