From 9451bfcbf5aa606c70a2afad88bcbf0dad7fcdd7 Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Fri, 10 Jul 2015 00:00:20 -0600 Subject: [PATCH] Added more complex inspection of arguments. Changed assert to check. --- README.md | 118 +++++++++++++++++++++++--------------- einheit.nim | 151 +++++++++++++++++++++++++++++++------------------ einheit.nimble | 2 +- test.nim | 28 ++++----- 4 files changed, 185 insertions(+), 114 deletions(-) diff --git a/README.md b/README.md index 52c7e0c..31fb064 100644 --- a/README.md +++ b/README.md @@ -51,24 +51,24 @@ testSuite SuiteName of TestSuite: method testAddingString()= ## adds a string to the suiteVar self.suiteVar &= " 123" - self.assert(self.suiteVar == "Testing 123") +r self.check(self.suiteVar == "Testing 123") proc raisesOs()= # This proc won't be invoked as a test, it must begin with "test" in lowercase raise newException(OSError, "Oh no! OS malfunction!") method testRaises()= - # Two ways of asserting - self.assertRaises OSError: + # Two ways of checking + self.checkRaises OSError: self.raisesOs() - self.assertRaises(OSError, self.raisesOs()) + self.checkRaises(OSError, self.raisesOs()) method testTestObj()= - self.assert(self.testObj == 90) + self.check(self.testObj == 90) method testMoreMore()= - self.assert("String" == "String") + self.check("String" == "String") when isMainModule: einheit.runTests() @@ -86,74 +86,102 @@ nim c -r test.nim is this: ``` -[Running] UnitTests +[Running] UnitTests ----------------------------------------------------------- [OK] testForB [Failed] testArrayAssert - Condition: assert(self.testArray == [0, 1, 2]) - Reason: self.testArray == [0, 1, 2, 3] - Location: einheit.nim; line 160 + Condition: check(self.testArray == [0, 1, 2]) + Where: + self.testArray -> [0, 1, 2, 3] + Location: test.nim; line 27 + [Failed] testForC - Condition: assert(c == 1) - Reason: c == 0 - Location: einheit.nim; line 160 - -[1/3] tests passed. + Condition: check(c == 1) + Where: + c -> 0 + Location: test.nim; line 32 -[Running] UnitTestsNew +[1/3] tests passed for UnitTests. ---------------------------------------------- + + +[Running] UnitTestsNew -------------------------------------------------------- [OK] testTestObj [OK] testStuff [Failed] testMore - Condition: assert(more == 1) - Reason: more == 23 - Location: einheit.nim; line 160 + Condition: check(more == 1) + Where: + more -> 23 + Location: test.nim; line 56 + [Failed] testMoreMore - Condition: assert(self.returnTrue()) - Reason: self.returnTrue() == false - Location: einheit.nim; line 160 - -[2/4] tests passed. + Condition: check(self.returnTrue()) + Where: + self.returnTrue() -> false + Location: test.nim; line 59 -[Running] TestInherit +[2/4] tests passed for UnitTestsNew. ------------------------------------------- + + +[Running] TestInherit --------------------------------------------------------- [OK] testTestObj [OK] testStuff [Failed] testMore - Condition: assert(more == 1) - Reason: more == 23 - Location: einheit.nim; line 160 + Condition: check(more == 1) + Where: + more -> 23 + Location: test.nim; line 56 + [Failed] testMoreMore - Condition: assert(self.returnTrue()) - Reason: self.returnTrue() == false - Location: einheit.nim; line 160 -[OK] testRaises + Condition: check(self.returnTrue()) + Where: + self.returnTrue() -> false + Location: test.nim; line 59 -[3/5] tests passed. +[Failed] testRaises + Condition: checkRaises(self.raisesOs()) + Where: + self.raisesOs() -> not equal to OSError + Location: test.nim; line 72 -[Running] MoreInheritance +[2/5] tests passed for TestInherit. -------------------------------------------- + + +[Running] MoreInheritance ----------------------------------------------------- [Failed] testTestObj - Condition: assert(self.testObj == 90) - Reason: self.testObj == 12345 - Location: einheit.nim; line 160 + Condition: check(self.testObj == 90) + Where: + self.testObj -> 12345 + Location: test.nim; line 46 + [OK] testStuff [Failed] testMore - Condition: assert(more == 1) - Reason: more == 23 - Location: einheit.nim; line 160 + Condition: check(more == 1) + Where: + more -> 23 + Location: test.nim; line 56 + [Failed] testMoreMore - Condition: assert(self.returnTrue()) - Reason: self.returnTrue() == false - Location: einheit.nim; line 160 -[OK] testRaises + Condition: check(self.returnTrue()) + Where: + self.returnTrue() -> false + Location: test.nim; line 59 + +[Failed] testRaises + Condition: checkRaises(self.raisesOs()) + Where: + self.raisesOs() -> not equal to OSError + Location: test.nim; line 72 + [OK] testTestObj [OK] testNewObj -[4/7] tests passed. +[3/7] tests passed for MoreInheritance. ---------------------------------------- ``` Notice that on failure, the test runner gives some useful information about the test in question. This is useful for determining why the test failed. diff --git a/einheit.nim b/einheit.nim index 2a709cd..49d63fc 100644 --- a/einheit.nim +++ b/einheit.nim @@ -9,13 +9,13 @@ ## ## testSuite UnitTests: ## proc thisIsATest()= -## self.assertEquals(1, 1) -## self.assertTrue(2 != 3) -## self.assertFalse(3 == 4) -## self.assertRaises(OSError, newException(OSError, "OS is exploding!")) +## self.check(1 == 1) +## self.checkRaises(OSError, newException(OSError, "OS is exploding!")) ## import macros import strutils +import tables + when not defined(ECMAScript): import terminal @@ -46,7 +46,7 @@ type numTests: int TestAssertError = object of Exception - ## assertTrue and other assert_* statements will raise + ## checkTrue and other check_* statements will raise ## this exception when the condition fails lineNumber: int fileName: string @@ -69,17 +69,20 @@ method runTests*(suite: TestSuite)= # ------------------------------------ - -template returnException(name, testName, snip, vals)= +template returnException(name, testName, snip, vals, pos, posRel)= ## private template for raising an exception - let pos = instantiationInfo(fullpaths=true) - let posRel = instantiationInfo() var filename = posRel.filename line = pos.line var message = "\n" message &= " Condition: $2($1)\n".format(snip.replace("\n","").strip(), name) - message &= " Reason: $1\n".format(vals) + try: + message &= " Where:\n" + for k, v in vals.pairs: + message &= " $1 -> $2\n".format(k, v) + except: + message &= " Reason: $1\n".format(vals) + message &= " Location: $1; line $2".format(filename, line) var exc = newException(TestAssertError, message) @@ -89,20 +92,24 @@ template returnException(name, testName, snip, vals)= exc.testName = testName raise exc -# ------------------------ Templates for assertion ---------------------------- +# ------------------------ Templates for checkion ---------------------------- -template assertRaises*(self: TestSuite, error: Exception, +template checkRaises*(self: TestSuite, error: Exception, code: untyped): untyped {.immediate.}= ## Raises a TestAssertError when the exception "error" is ## not thrown in the code + let + pos = instantiationInfo(fullpaths=true) + posRel = instantiationInfo() + try: code var - snip = astToStr(code) - vals = "No Exception Raised" + snip = astToStr(code).strip() + vals = {snip: "No Exception Raised"}.toTable() testName = self.currentTestName - returnException("assertRaises", testName, snip, vals) + returnException("checkRaises", testName, snip, vals, pos, posRel) except error: discard @@ -110,54 +117,76 @@ template assertRaises*(self: TestSuite, error: Exception, raise except Exception: var - snip = astToStr(code) - vals = "Exception != $1".format(astToStr(error)) + snip = astToStr(code).strip() + vals = {snip: "not equal to $1".format(astToStr(error))}.toTable() testName = self.currentTestName - returnException("assertRaises", testName, snip, vals) + returnException("checkRaises", testName, snip, vals, pos, posRel) -macro isInfix(code: untyped): untyped= - if code.kind == nnkInfix: - return newLit(true) - return newLit(false) +template recursive(node, action): expr {.dirty.} = + proc helper(child: NimNode): NimNode {.gensym.} = + action + result = child.copy() + for c in child.children: + if child.kind == nnkCall and c.kind == nnkDotExpr: + continue + result.add helper(c) + discard helper(node) -macro getLhs(code: untyped): untyped= - return code[1].toStrLit() +template strRep(n: NimNode): untyped= + newNimNode(nnkPrefix).add(ident("$"), newNimNode(nnkPar).add(n)) -macro getLhsVal(code: untyped): untyped= - return code[1] +template tableEntry(n: NimNode): untyped= + newNimNode(nnkExprColonExpr).add(n.toStrLit(), strRep(n)) -macro getRhs(code: untyped): untyped= - return code[2] +macro getSyms(code:untyped): untyped= + var + tableCall = newNimNode(nnkCall).add(ident("toTable")) + tableConstr = newNimNode(nnkTableConstr) -macro getRhsVal(code: untyped): untyped= - return code[2] + recursive(code): + let ch1 = child + if ch1.kind == nnkInfix: + if child[1].kind == nnkIdent: + tableConstr.add(tableEntry(child[1])) + if child[2].kind == nnkIdent: + tableConstr.add(tableEntry(child[2])) + elif ch1.kind == nnkExprColonExpr: + if child[0].kind == nnkIdent: + tableConstr.add(tableEntry(child[0])) + if child[1].kind == nnkIdent: + tableConstr.add(tableEntry(child[1])) + elif ch1.kind == nnkCall or ch1.kind == nnkCommand: + tableConstr.add(tableEntry(ch1)) + for i in 1..