only run `teardown` if `setup` completed (#36)

* only run `teardown` if `setup` completed

With #35, it is no longer possible in `teardown` to refer to variables
introduced in `setup`. To avoid having to rewrite tests, address the
issue in #35 by wrapping `body` with an additional exception catching
layer. This then allows to re-use the previous `teardown` semantics
where `teardown` only ran if `setup` fully completed and also has access
to the variables introduced in `setup`.

* workaround shadowing bug

* Add test

---------

Co-authored-by: jangko <jangko128@gmail.com>
This commit is contained in:
Etan Kissling 2024-01-22 07:27:34 +01:00 committed by GitHub
parent 13bf4d444d
commit 0fe665e509
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 25 deletions

View File

@ -46,6 +46,20 @@ suite "PR #35":
# emulate exception # emulate exception
raise newException(ValueError, "error") raise newException(ValueError, "error")
suite "PR #36":
# ensure variables declared in setup section
# still accessible from teardown section
setup:
var server: ref string
teardown:
if server.isNil.not:
testStatusIMPL = TestStatus.OK
test "test body":
server = new(string)
server[] = "hello"
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# Regular tests # Regular tests
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@ -213,3 +227,4 @@ when defined(testing):
# Also supposed to work outside tests: # Also supposed to work outside tests:
check 1 == 1 check 1 == 1

View File

@ -1103,36 +1103,28 @@ template runtimeTest*(nameParam: string, body: untyped) =
let suiteName {.inject, used.} = suiteName let suiteName {.inject, used.} = suiteName
let testName {.inject, used.} = testName let testName {.inject, used.} = testName
try: template fail(prefix: string, eClass: string, e: auto): untyped =
when declared(testSetupIMPLFlag): testSetupIMPL() let eName = "[" & $e.name & "]"
block: checkpoint(prefix & "Unhandled " & eClass & ": " & e.msg & " " & eName)
body var stackTrace {.inject.} = e.getStackTrace()
fail()
template failingOnExceptions(prefix: string, code: untyped): untyped =
try:
code
except CatchableError as e: except CatchableError as e:
let eTypeDesc = "[" & $e.name & "]" prefix.fail("error", e)
checkpoint("Unhandled error: " & e.msg & " " & eTypeDesc)
var stackTrace {.inject.} = e.getStackTrace()
fail()
except Defect as e: # This may or may not work dependings on --panics except Defect as e: # This may or may not work dependings on --panics
let eTypeDesc = "[" & $e.name & "]" prefix.fail("defect", e)
checkpoint("Unhandled defect: " & e.msg & " " & eTypeDesc)
var stackTrace {.inject.} = e.getStackTrace()
fail()
except Exception as e: except Exception as e:
let eTypeDesc = "[" & $e.name & "]" prefix.fail("exception that may cause undefined behavior", e)
checkpoint("Unhandled exception that may cause undefined behavior: " & e.msg & " " & eTypeDesc)
var stackTrace {.inject.} = e.getStackTrace() failingOnExceptions("[setup] "):
fail() when declared(testSetupIMPLFlag): testSetupIMPL()
finally: defer: failingOnExceptions("[teardown] "):
try: when declared(testTeardownIMPLFlag): testTeardownIMPL()
when declared(testTeardownIMPLFlag): failingOnExceptions(""):
testTeardownIMPL() body
except Exception as e:
let eTypeDesc = "[" & $e.name & "]"
checkpoint("Exception when calling teardown: " & e.msg & " " & eTypeDesc)
var stackTrace {.inject.} = e.getStackTrace()
fail()
checkpoints = @[] checkpoints = @[]