small bugfix for lambdalifting; preparations for a better testing framework
This commit is contained in:
parent
a4b1ca3306
commit
9257c29ffd
5 changed files with 82 additions and 42 deletions
|
|
@ -257,6 +257,8 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
|
||||||
# Currently captures are restricted to a single level of nesting:
|
# Currently captures are restricted to a single level of nesting:
|
||||||
LocalError(info, errIllegalCaptureX, local.name.s)
|
LocalError(info, errIllegalCaptureX, local.name.s)
|
||||||
i.fn.typ.callConv = ccClosure
|
i.fn.typ.callConv = ccClosure
|
||||||
|
#echo "captureVar ", i.fn.name.s, i.fn.id, " ", local.name.s, local.id
|
||||||
|
|
||||||
incl(i.fn.typ.flags, tfCapturesEnv)
|
incl(i.fn.typ.flags, tfCapturesEnv)
|
||||||
|
|
||||||
# we need to remember which inner most closure belongs to this lambda:
|
# we need to remember which inner most closure belongs to this lambda:
|
||||||
|
|
@ -286,9 +288,10 @@ proc interestingVar(s: PSym): bool {.inline.} =
|
||||||
sfGlobal notin s.flags
|
sfGlobal notin s.flags
|
||||||
|
|
||||||
proc semCaptureSym*(s, owner: PSym) =
|
proc semCaptureSym*(s, owner: PSym) =
|
||||||
if interestingVar(s) and owner.id != s.owner.id:
|
if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult:
|
||||||
if owner.typ != nil and not isGenericRoutine(owner):
|
if owner.typ != nil and not isGenericRoutine(owner):
|
||||||
owner.typ.callConv = ccClosure
|
owner.typ.callConv = ccClosure
|
||||||
|
#echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id
|
||||||
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
||||||
# here
|
# here
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -636,7 +636,7 @@ proc `[]`*(node: PJsonNode, name: String): PJsonNode =
|
||||||
return item
|
return item
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
proc `[]`*(node: PJsonNode, index: Int): PJsonNode {.raises: [EInvalidIndex].} =
|
proc `[]`*(node: PJsonNode, index: Int): PJsonNode =
|
||||||
## Gets the node at `index` in an Array.
|
## Gets the node at `index` in an Array.
|
||||||
assert(node.kind == JArray)
|
assert(node.kind == JArray)
|
||||||
return node.elems[index]
|
return node.elems[index]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
output: "1.0000000000000000e+00 10"
|
output: "1.0000000000000000e+00 10"
|
||||||
|
ccodecheck: "!@'ClEnv'"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc p[T](a, b: T): T
|
proc p[T](a, b: T): T
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod Tester
|
# Nimrod Tester
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
|
||||||
114
tests/tester.nim
114
tests/tester.nim
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod Tester
|
# Nimrod Tester
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -25,22 +25,35 @@ const
|
||||||
type
|
type
|
||||||
TTestAction = enum
|
TTestAction = enum
|
||||||
actionCompile, actionRun, actionReject
|
actionCompile, actionRun, actionReject
|
||||||
TSpec {.pure.} = object
|
TResultEnum = enum
|
||||||
|
reNimrodcCrash, # nimrod compiler seems to have crashed
|
||||||
|
reMsgsDiffer, # error messages differ
|
||||||
|
reFilesDiffer, # expected and given filenames differ
|
||||||
|
reLinesDiffer, # expected and given line numbers differ
|
||||||
|
reOutputsDiffer,
|
||||||
|
reExitcodesDiffer,
|
||||||
|
reInvalidPeg,
|
||||||
|
reCodegenFailure,
|
||||||
|
reCodeNotFound,
|
||||||
|
reExeNotFound,
|
||||||
|
reIgnored, # test is ignored
|
||||||
|
reSuccess # test was successful
|
||||||
|
TTarget = enum
|
||||||
|
targetC, targetCpp, targetObjC, targetJS
|
||||||
|
|
||||||
|
TSpec = object
|
||||||
action: TTestAction
|
action: TTestAction
|
||||||
file, cmd: string
|
file, cmd: string
|
||||||
outp: string
|
outp: string
|
||||||
line, exitCode: int
|
line, exitCode: int
|
||||||
msg: string
|
msg: string
|
||||||
err: bool
|
ccodeCheck: string
|
||||||
disabled: bool
|
err: TResultEnum
|
||||||
substr: bool
|
substr: bool
|
||||||
TResults {.pure.} = object
|
TResults = object
|
||||||
total, passed, skipped: int
|
total, passed, skipped: int
|
||||||
data: string
|
data: string
|
||||||
|
|
||||||
TResultEnum = enum
|
|
||||||
reFailure, reIgnored, reSuccess
|
|
||||||
|
|
||||||
# ----------------------- Spec parser ----------------------------------------
|
# ----------------------- Spec parser ----------------------------------------
|
||||||
|
|
||||||
when not defined(parseCfgBool):
|
when not defined(parseCfgBool):
|
||||||
|
|
@ -82,9 +95,9 @@ template parseSpecAux(fillResult: stmt) {.immediate.} =
|
||||||
|
|
||||||
proc parseSpec(filename: string): TSpec =
|
proc parseSpec(filename: string): TSpec =
|
||||||
result.file = filename
|
result.file = filename
|
||||||
result.err = true
|
|
||||||
result.msg = ""
|
result.msg = ""
|
||||||
result.outp = ""
|
result.outp = ""
|
||||||
|
result.ccodeCheck = ""
|
||||||
result.cmd = cmdTemplate
|
result.cmd = cmdTemplate
|
||||||
parseSpecAux:
|
parseSpecAux:
|
||||||
case normalize(e.key)
|
case normalize(e.key)
|
||||||
|
|
@ -103,8 +116,10 @@ proc parseSpec(filename: string): TSpec =
|
||||||
of "exitcode":
|
of "exitcode":
|
||||||
discard parseInt(e.value, result.exitCode)
|
discard parseInt(e.value, result.exitCode)
|
||||||
of "errormsg", "msg": result.msg = e.value
|
of "errormsg", "msg": result.msg = e.value
|
||||||
of "disabled": result.disabled = parseCfgBool(e.value)
|
of "disabled":
|
||||||
|
if parseCfgBool(e.value): result.err = reIgnored
|
||||||
of "cmd": result.cmd = e.value
|
of "cmd": result.cmd = e.value
|
||||||
|
of "ccodecheck": result.ccodeCheck = e.value
|
||||||
else: echo ignoreMsg(p, e)
|
else: echo ignoreMsg(p, e)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
@ -134,7 +149,6 @@ proc callCompiler(cmdTemplate, filename, options: string): TSpec =
|
||||||
result.msg = ""
|
result.msg = ""
|
||||||
result.file = ""
|
result.file = ""
|
||||||
result.outp = ""
|
result.outp = ""
|
||||||
result.err = true
|
|
||||||
result.line = -1
|
result.line = -1
|
||||||
if err =~ pegLineError:
|
if err =~ pegLineError:
|
||||||
result.file = extractFilename(matches[0])
|
result.file = extractFilename(matches[0])
|
||||||
|
|
@ -143,7 +157,7 @@ proc callCompiler(cmdTemplate, filename, options: string): TSpec =
|
||||||
elif err =~ pegOtherError:
|
elif err =~ pegOtherError:
|
||||||
result.msg = matches[0]
|
result.msg = matches[0]
|
||||||
elif suc =~ pegSuccess:
|
elif suc =~ pegSuccess:
|
||||||
result.err = false
|
result.err = reSuccess
|
||||||
|
|
||||||
proc initResults: TResults =
|
proc initResults: TResults =
|
||||||
result.total = 0
|
result.total = 0
|
||||||
|
|
@ -164,9 +178,9 @@ proc `$`(x: TResults): string =
|
||||||
|
|
||||||
proc colorResult(r: TResultEnum): string =
|
proc colorResult(r: TResultEnum): string =
|
||||||
case r
|
case r
|
||||||
of reFailure: result = "<span style=\"color:red\">no</span>"
|
|
||||||
of reIgnored: result = "<span style=\"color:fuchsia\">ignored</span>"
|
of reIgnored: result = "<span style=\"color:fuchsia\">ignored</span>"
|
||||||
of reSuccess: result = "<span style=\"color:green\">yes</span>"
|
of reSuccess: result = "<span style=\"color:green\">yes</span>"
|
||||||
|
else: result = "<span style=\"color:red\">no</span>"
|
||||||
|
|
||||||
const
|
const
|
||||||
TableHeader4 = "<table border=\"1\"><tr><td>Test</td><td>Expected</td>" &
|
TableHeader4 = "<table border=\"1\"><tr><td>Test</td><td>Expected</td>" &
|
||||||
|
|
@ -217,12 +231,12 @@ proc listResults(reject, compile, run: TResults) =
|
||||||
|
|
||||||
proc cmpMsgs(r: var TResults, expected, given: TSpec, test: string) =
|
proc cmpMsgs(r: var TResults, expected, given: TSpec, test: string) =
|
||||||
if strip(expected.msg) notin strip(given.msg):
|
if strip(expected.msg) notin strip(given.msg):
|
||||||
r.addResult(test, expected.msg, given.msg, reFailure)
|
r.addResult(test, expected.msg, given.msg, reMsgsDiffer)
|
||||||
elif extractFilename(expected.file) != extractFilename(given.file) and
|
elif extractFilename(expected.file) != extractFilename(given.file) and
|
||||||
"internal error:" notin expected.msg:
|
"internal error:" notin expected.msg:
|
||||||
r.addResult(test, expected.file, given.file, reFailure)
|
r.addResult(test, expected.file, given.file, reFilesDiffer)
|
||||||
elif expected.line != given.line and expected.line != 0:
|
elif expected.line != given.line and expected.line != 0:
|
||||||
r.addResult(test, $expected.line, $given.line, reFailure)
|
r.addResult(test, $expected.line, $given.line, reLinesDiffer)
|
||||||
else:
|
else:
|
||||||
r.addResult(test, expected.msg, given.msg, reSuccess)
|
r.addResult(test, expected.msg, given.msg, reSuccess)
|
||||||
inc(r.passed)
|
inc(r.passed)
|
||||||
|
|
@ -233,7 +247,7 @@ proc rejectSingleTest(r: var TResults, test, options: string) =
|
||||||
inc(r.total)
|
inc(r.total)
|
||||||
echo t
|
echo t
|
||||||
var expected = parseSpec(test)
|
var expected = parseSpec(test)
|
||||||
if expected.disabled:
|
if expected.err == reIgnored:
|
||||||
r.addResult(t, "", "", reIgnored)
|
r.addResult(t, "", "", reIgnored)
|
||||||
inc(r.skipped)
|
inc(r.skipped)
|
||||||
else:
|
else:
|
||||||
|
|
@ -244,31 +258,47 @@ proc reject(r: var TResults, dir, options: string) =
|
||||||
## handle all the tests that the compiler should reject
|
## handle all the tests that the compiler should reject
|
||||||
for test in os.walkFiles(dir / "t*.nim"): rejectSingleTest(r, test, options)
|
for test in os.walkFiles(dir / "t*.nim"): rejectSingleTest(r, test, options)
|
||||||
|
|
||||||
|
proc codegenCheck(test, check, ext: string, given: var TSpec) =
|
||||||
|
if check.len > 0:
|
||||||
|
try:
|
||||||
|
let (path, name, ext2) = test.splitFile
|
||||||
|
echo path / "nimcache" / name.changeFileExt(ext)
|
||||||
|
let contents = readFile(path / "nimcache" / name.changeFileExt(ext)).string
|
||||||
|
if contents.find(check.peg) < 0:
|
||||||
|
given.err = reCodegenFailure
|
||||||
|
except EInvalidValue:
|
||||||
|
given.err = reInvalidPeg
|
||||||
|
except EIO:
|
||||||
|
given.err = reCodeNotFound
|
||||||
|
|
||||||
|
proc codegenChecks(test: string, expected: TSpec, given: var TSpec) =
|
||||||
|
codegenCheck(test, expected.ccodeCheck, ".c", given)
|
||||||
|
|
||||||
proc compile(r: var TResults, pattern, options: string) =
|
proc compile(r: var TResults, pattern, options: string) =
|
||||||
for test in os.walkFiles(pattern):
|
for test in os.walkFiles(pattern):
|
||||||
let t = extractFilename(test)
|
let t = extractFilename(test)
|
||||||
echo t
|
echo t
|
||||||
inc(r.total)
|
inc(r.total)
|
||||||
let expected = parseSpec(test)
|
let expected = parseSpec(test)
|
||||||
if expected.disabled:
|
if expected.err == reIgnored:
|
||||||
r.addResult(t, "", reIgnored)
|
r.addResult(t, "", reIgnored)
|
||||||
inc(r.skipped)
|
inc(r.skipped)
|
||||||
else:
|
else:
|
||||||
var given = callCompiler(expected.cmd, test, options)
|
var given = callCompiler(expected.cmd, test, options)
|
||||||
r.addResult(t, given.msg, if given.err: reFailure else: reSuccess)
|
if given.err == reSuccess:
|
||||||
if not given.err: inc(r.passed)
|
codegenChecks(test, expected, given)
|
||||||
|
r.addResult(t, given.msg, given.err)
|
||||||
|
if given.err == reSuccess: inc(r.passed)
|
||||||
|
|
||||||
proc compileSingleTest(r: var TResults, test, options: string) =
|
proc compileSingleTest(r: var TResults, test, options: string) =
|
||||||
|
# does not extract the spec because the file is not supposed to have any
|
||||||
let test = test.addFileExt(".nim")
|
let test = test.addFileExt(".nim")
|
||||||
let t = extractFilename(test)
|
let t = extractFilename(test)
|
||||||
inc(r.total)
|
inc(r.total)
|
||||||
echo t
|
echo t
|
||||||
let given = callCompiler(cmdTemplate, test, options)
|
let given = callCompiler(cmdTemplate, test, options)
|
||||||
r.addResult(t, given.msg, if given.err: reFailure else: reSuccess)
|
r.addResult(t, given.msg, given.err)
|
||||||
if not given.err: inc(r.passed)
|
if given.err == reSuccess: inc(r.passed)
|
||||||
|
|
||||||
type
|
|
||||||
TTarget = enum targetC, targetJS
|
|
||||||
|
|
||||||
proc runSingleTest(r: var TResults, test, options: string, target: TTarget) =
|
proc runSingleTest(r: var TResults, test, options: string, target: TTarget) =
|
||||||
var test = test.addFileExt(".nim")
|
var test = test.addFileExt(".nim")
|
||||||
|
|
@ -276,13 +306,13 @@ proc runSingleTest(r: var TResults, test, options: string, target: TTarget) =
|
||||||
echo t
|
echo t
|
||||||
inc(r.total)
|
inc(r.total)
|
||||||
var expected = parseSpec(test)
|
var expected = parseSpec(test)
|
||||||
if expected.disabled:
|
if expected.err == reIgnored:
|
||||||
r.addResult(t, "", "", reIgnored)
|
r.addResult(t, "", "", reIgnored)
|
||||||
inc(r.skipped)
|
inc(r.skipped)
|
||||||
else:
|
else:
|
||||||
var given = callCompiler(expected.cmd, test, options)
|
var given = callCompiler(expected.cmd, test, options)
|
||||||
if given.err:
|
if given.err != reSuccess:
|
||||||
r.addResult(t, "", given.msg, reFailure)
|
r.addResult(t, "", given.msg, given.err)
|
||||||
else:
|
else:
|
||||||
var exeFile: string
|
var exeFile: string
|
||||||
if target == targetC:
|
if target == targetC:
|
||||||
|
|
@ -296,25 +326,26 @@ proc runSingleTest(r: var TResults, test, options: string, target: TTarget) =
|
||||||
(if target==targetJS: "node " else: "") & exeFile)
|
(if target==targetJS: "node " else: "") & exeFile)
|
||||||
if exitCode != expected.ExitCode:
|
if exitCode != expected.ExitCode:
|
||||||
r.addResult(t, "exitcode: " & $expected.ExitCode,
|
r.addResult(t, "exitcode: " & $expected.ExitCode,
|
||||||
"exitcode: " & $exitCode, reFailure)
|
"exitcode: " & $exitCode, reExitCodesDiffer)
|
||||||
else:
|
else:
|
||||||
var success = strip(buf.string) == strip(expected.outp)
|
if strip(buf.string) != strip(expected.outp):
|
||||||
if expected.substr and not success:
|
if not (expected.substr and expected.outp in buf.string):
|
||||||
success = expected.outp in buf.string
|
given.err = reOutputsDiffer
|
||||||
if success: inc(r.passed)
|
if given.err == reSuccess:
|
||||||
r.addResult(t, expected.outp,
|
codeGenChecks(test, expected, given)
|
||||||
buf.string, if success: reSuccess else: reFailure)
|
if given.err == reSuccess: inc(r.passed)
|
||||||
|
r.addResult(t, expected.outp, buf.string, given.err)
|
||||||
else:
|
else:
|
||||||
r.addResult(t, expected.outp, "executable not found", reFailure)
|
r.addResult(t, expected.outp, "executable not found", reExeNotFound)
|
||||||
|
|
||||||
proc runSingleTest(r: var TResults, test, options: string) =
|
proc runSingleTest(r: var TResults, test, options: string) =
|
||||||
runSingleTest(r, test, options, targetC)
|
runSingleTest(r, test, options, targetC)
|
||||||
|
|
||||||
proc run(r: var TResults, dir, options: string) =
|
proc run(r: var TResults, dir, options: string) =
|
||||||
for test in os.walkFiles(dir / "t*.nim"): runSingleTest(r, test, options)
|
for test in os.walkFiles(dir / "t*.nim"): runSingleTest(r, test, options)
|
||||||
|
|
||||||
include specials
|
include specials
|
||||||
|
|
||||||
proc compileExample(r: var TResults, pattern, options: string) =
|
proc compileExample(r: var TResults, pattern, options: string) =
|
||||||
for test in os.walkFiles(pattern): compileSingleTest(r, test, options)
|
for test in os.walkFiles(pattern): compileSingleTest(r, test, options)
|
||||||
|
|
||||||
|
|
@ -392,7 +423,12 @@ proc main() =
|
||||||
runDLLTests r, p.cmdLineRest.string
|
runDLLTests r, p.cmdLineRest.string
|
||||||
of "gc":
|
of "gc":
|
||||||
runGCTests(r, p.cmdLineRest.string)
|
runGCTests(r, p.cmdLineRest.string)
|
||||||
of "test", "comp", "rej":
|
of "test":
|
||||||
|
if p.kind != cmdArgument: quit usage
|
||||||
|
var testFile = p.key.string
|
||||||
|
p.next()
|
||||||
|
runSingleTest(r, testFile, p.cmdLineRest.string)
|
||||||
|
of "comp", "rej":
|
||||||
if p.kind != cmdArgument: quit usage
|
if p.kind != cmdArgument: quit usage
|
||||||
var testFile = p.key.string
|
var testFile = p.key.string
|
||||||
p.next()
|
p.next()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue