# Tester for nimsuggest. # 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 filename, cmd, dest: string startup: seq[string] script: seq[(string, string)] disabled: bool const DummyEof = "!EOF!" tpath = "nimsuggest/tests" # we could also use `stdtest/specialpaths` import std/compilesettings proc parseTest(filename: string; epcMode=false): Test = const cursorMarker = "#[!]#" 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 = @[] result.startup = @[] var tmp = open(result.dest, fmWrite) var specSection = 0 var markers = newSeq[string]() var i = 1 for x in lines(filename): let marker = x.find(cursorMarker) if marker >= 0: if epcMode: markers.add "(\"" & filename & "\" " & $i & " " & $marker & " \"" & result.dest & "\")" else: markers.add "\"" & filename & "\";\"" & result.dest & "\":" & $i & ":" & $marker tmp.writeLine x.replace(cursorMarker, "") else: tmp.writeLine x if x.contains("""""""""): inc specSection elif specSection == 1: 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: result.startup.add x else: result.script.add((x, "")) elif x.startsWith(">"): # since 'markers' here are not complete yet, we do the $substitutions # afterwards result.script.add((x.substr(1).replaceWord("$path", tpath), "")) elif x.len > 0: # expected output line: let x = x % ["file", filename, "lib", libpath] result.script[^1][1].add x.replace(";;", "\t") & '\L' # else: ignore empty lines for better readability of the specs inc i tmp.close() # now that we know the markers, substitute them: for a in mitems(result.script): a[0] = a[0] % markers proc parseCmd(c: string): seq[string] = # we don't support double quotes for now so that # we can later support them properly with escapes and stuff. result = @[] var i = 0 var a = "" while i < c.len: setLen(a, 0) # eat all delimiting whitespace 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 i < c.len and c[i] != delim: add a, c[i] inc(i) if i < c.len: inc(i) else: while i < c.len and c[i] > ' ': add(a, c[i]) inc(i) add(result, a) 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 try: let content = readFile(f) let newcontent = content.replace(x[1], x[2]) if content == newcontent: quit "wrong test case: edit had no effect" writeFile(f, newcontent) except IOError: quit "cannot edit file " & tmpfile proc exec(x: seq[string]) = if x.len != 2: quit "!exec takes one argument" if execShellCmd(x[1]) != 0: quit "External program failed " & x[1] proc copy(x: seq[string]) = if x.len != 3: quit "!copy takes two arguments" 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]) proc runCmd(cmd, dest: string): bool = result = cmd[0] == '!' if not result: return let x = cmd.parseCmd() case x[0] of "!edit": edit(dest, x) of "!exec": exec(x) of "!copy": copy(x) of "!del": del(x) else: quit "unknown command: " & cmd proc smartCompare(pattern, x: string): bool = if pattern.contains('*'): result = match(x, re(escapeRe(pattern).replace("\\x2A","(.*)"), {})) proc sendEpcStr(socket: Socket; cmd: string) = let s = cmd.find(' ') doAssert s > 0 var args = cmd.substr(s+1) if not args.startsWith("("): args = escapeJson(args) let c = "(call 567 " & cmd.substr(0, s) & args & ")" socket.send toHex(c.len, 6) socket.send c proc recvEpc(
import os

type
  TStatusEnum* = enum
    sUnknown