From 489340658ea855d01de853d3c95c928d6e1b9f86 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 10 Nov 2011 04:10:03 +0200 Subject: [PATCH 1/3] Added system.program_results for controlling the exit code of the program under normal circumstances Implemented operators like +=, -=, etc for ordinals, floats and string Programs using the UnitTest module will now report the number of failed tests as the exit code of test runs (0 for successful run) --- compiler/cgen.nim | 4 ++-- lib/nimbase.h | 2 ++ lib/pure/unittest.nim | 31 ++++++++++++++++++++----------- lib/system.nim | 33 +++++++++++++++++++++++++++++++++ web/news.txt | 1 + 5 files changed, 58 insertions(+), 13 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 671fdd05f..6573771dc 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -707,13 +707,13 @@ proc genMainProc(m: BModule) = CommonMainBody & "}$n" PosixCMain = "int main(int argc, char** args, char** env) {$n" & " cmdLine = args;$n" & " cmdCount = argc;$n" & " gEnv = env;$n" & - " NimMain();$n" & " return 0;$n" & "}$n" + " NimMain();$n" & " return nim_program_result;$n" & "}$n" WinNimMain = "N_CDECL(void, NimMain)(void) {$n" & CommonMainBody & "}$n" WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" & " HINSTANCE hPrevInstance, $n" & " LPSTR lpCmdLine, int nCmdShow) {$n" & - " NimMain();$n" & " return 0;$n" & "}$n" + " NimMain();$n" & " return nim_program_result;$n" & "}$n" WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n" & CommonMainBody & "}$n" WinCDllMain = diff --git a/lib/nimbase.h b/lib/nimbase.h index cc0419f55..11278ccd2 100755 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -331,6 +331,8 @@ typedef long long int NI64; typedef unsigned int NU32; #endif +extern NI nim_program_result; + typedef float NF32; typedef double NF64; typedef double NF; diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 87c2b6ed7..6fee618b9 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -20,12 +20,14 @@ import macros, terminal type - TestStatus* = enum OK, FAILED - # ETestFailed* = object of ESynch - + TTestStatus* = enum OK, FAILED + TOutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE + var # XXX: These better be thread-local AbortOnError* = false + OutputLevel* = PRINT_ALL + checkpoints: seq[string] = @[] template TestSetupIMPL*: stmt = nil @@ -36,20 +38,25 @@ proc shouldRun(testName: string): bool = template suite*(name: expr, body: stmt): stmt = block: - template setup(setupBody: stmt): stmt = + template setup*(setupBody: stmt): stmt = template TestSetupIMPL: stmt = setupBody - template teardown(teardownBody: stmt): stmt = + template teardown*(teardownBody: stmt): stmt = template TestTeardownIMPL: stmt = teardownBody body -proc printStatus*(s: TestStatus, name: string) = - var color = (if s == OK: fgGreen else: fgRed) - styledEcho styleBright, color, "[", $s, "] ", fgWhite, name, "\n" +proc testDone(name: string, s: TTestStatus) = + if s == FAILED: + program_result += 1 + + if OutputLevel != PRINT_NONE and (OutputLevel == PRINT_ALL or s == FAILED): + var color = (if s == OK: fgGreen else: fgRed) + styledEcho styleBright, color, "[", $s, "] ", fgWhite, name, "\n" template test*(name: expr, body: stmt): stmt = - bind shouldRun, checkPoints + bind shouldRun, checkpoints, testDone + if shouldRun(name): checkpoints = @[] var TestStatusIMPL = OK @@ -60,7 +67,7 @@ template test*(name: expr, body: stmt): stmt = finally: TestTeardownIMPL() - printStatus(TestStatusIMPL, name) + testDone name, TestStatusIMPL proc checkpoint*(msg: string) = checkpoints.add(msg) @@ -85,6 +92,8 @@ macro check*(conditions: stmt): stmt = result = getAst(rewrite(e, e.lineinfo, e.toStrLit)) + echo conditions.lispRepr + case conditions.kind of nnkCall, nnkCommand, nnkMacroStmt: case conditions[1].kind @@ -124,7 +133,7 @@ macro check*(conditions: stmt): stmt = result = standardRewrite(conditions[1]) else: - error conditions.lineinfo & ": Malformed check statement" + error conditions.lineinfo & ": Malformed check statement:" template require*(conditions: stmt): stmt = block: diff --git a/lib/system.nim b/lib/system.nim index 8657efe2a..00555fa45 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -402,6 +402,9 @@ proc `+` *(x, y: int32): int32 {.magic: "AddI", noSideEffect.} proc `+` *(x, y: int64): int64 {.magic: "AddI64", noSideEffect.} ## Binary `+` operator for an integer. +proc `+=`*[T](x, y: ordinal[T]) {.magic: "Inc", noSideEffect.} + ## Increments an ordinal + proc `-` *(x, y: int): int {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int8): int8 {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int16): int16 {.magic: "SubI", noSideEffect.} @@ -409,6 +412,9 @@ proc `-` *(x, y: int32): int32 {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int64): int64 {.magic: "SubI64", noSideEffect.} ## Binary `-` operator for an integer. +proc `-=`*[T](x, y: ordinal[T]) {.magic: "Dec", noSideEffect.} + ## Decrements an ordinal + proc `*` *(x, y: int): int {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int8): int8 {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int16): int16 {.magic: "MulI", noSideEffect.} @@ -416,6 +422,10 @@ proc `*` *(x, y: int32): int32 {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int64): int64 {.magic: "MulI64", noSideEffect.} ## Binary `*` operator for an integer. +proc `*=`*[T](x: var ordinal[T], y: ordinal[T]) {.inline noSideEffect.} = + ## Binary `*=` operator for oridinals + x = x * y + proc `div` *(x, y: int): int {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int8): int8 {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int16): int16 {.magic: "DivI", noSideEffect.} @@ -569,6 +579,22 @@ proc `*` *(x, y: float): float {.magic: "MulF64", noSideEffect.} proc `/` *(x, y: float): float {.magic: "DivF64", noSideEffect.} ## computes the floating point division +proc `+=` *(x: var float, y:float) {.inline noSideEffect.} = + ## Increments in placee a floating point number + x = x + y + +proc `-=` *(x: var float, y:float) {.inline noSideEffect.} = + ## Decrements in place a floating point number + x = x - y + +proc `*=` *(x: var float, y:float) {.inline noSideEffect.} = + ## Multiplies in place a floating point number + x = x * y + +proc `/=` *(x: var float, y:float) {.inline noSideEffect.} = + ## Divides in place a floating point number + x = x / y + proc `==` *(x, y: float): bool {.magic: "EqF64", noSideEffect.} proc `<=` *(x, y: float): bool {.magic: "LeF64", noSideEffect.} proc `<` *(x, y: float): bool {.magic: "LtF64", noSideEffect.} @@ -717,6 +743,8 @@ proc `&` * (x: char, y: string): string {. proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} +proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} + type TEndian* = enum ## is a type describing the endianness of a processor. littleEndian, bigEndian @@ -1541,6 +1569,11 @@ const ## is the value that should be passed to ``quit`` to indicate ## failure. +var program_result* {.exportc: "nim_$1".} = QuitSuccess + ## modify this varialbe to specify the exit code of the program + ## under normal circumstances. when the program is terminated + ## prematurelly using ``quit``, this value is ignored. + proc quit*(errorcode: int = QuitSuccess) {. magic: "Exit", importc: "exit", noDecl, noReturn.} ## stops the program immediately; before stopping the program the diff --git a/web/news.txt b/web/news.txt index 3e107511f..699b2c87f 100755 --- a/web/news.txt +++ b/web/news.txt @@ -102,6 +102,7 @@ Library Additions - Added ``strutils.unindent``, ``strutils.countLines``. - Added ``system.slurp`` for easy resource embedding. - Added ``system.running`` for threads. +- Added ``system.program_result``. - Added ``xmltree.innerText``. - Added ``os.isAbsolute``, ``os.dynLibFormat``. - Added ``parseutils.interpolatedFragments``. From da4076e0b7d3336d28893feba1399028abdbd52e Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 10 Nov 2011 04:39:46 +0200 Subject: [PATCH 2/3] when running unit tests, the tester will print only failures using colorless output (this should be better for nimbuild) --- {tests/accept/run => examples}/tunit.nim | 0 lib/pure/unittest.nim | 32 ++++++++++++++++++------ tests/tester.nim | 3 +++ 3 files changed, 27 insertions(+), 8 deletions(-) rename {tests/accept/run => examples}/tunit.nim (100%) diff --git a/tests/accept/run/tunit.nim b/examples/tunit.nim similarity index 100% rename from tests/accept/run/tunit.nim rename to examples/tunit.nim diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 6fee618b9..e2906dd1a 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -17,16 +17,17 @@ ## It is loosely based on C++'s boost.test and Haskell's QuickTest import - macros, terminal + macros, terminal, os type TTestStatus* = enum OK, FAILED TOutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE - + var # XXX: These better be thread-local - AbortOnError* = false - OutputLevel* = PRINT_ALL + AbortOnError*: bool + OutputLevel*: TOutputLevel + ColorOutput*: bool checkpoints: seq[string] = @[] @@ -52,7 +53,11 @@ proc testDone(name: string, s: TTestStatus) = if OutputLevel != PRINT_NONE and (OutputLevel == PRINT_ALL or s == FAILED): var color = (if s == OK: fgGreen else: fgRed) - styledEcho styleBright, color, "[", $s, "] ", fgWhite, name, "\n" + + if ColorOutput: + styledEcho styleBright, color, "[", $s, "] ", fgWhite, name, "\n" + else: + echo "[", $s, "] ", name, "\n" template test*(name: expr, body: stmt): stmt = bind shouldRun, checkpoints, testDone @@ -92,8 +97,6 @@ macro check*(conditions: stmt): stmt = result = getAst(rewrite(e, e.lineinfo, e.toStrLit)) - echo conditions.lispRepr - case conditions.kind of nnkCall, nnkCommand, nnkMacroStmt: case conditions[1].kind @@ -133,7 +136,8 @@ macro check*(conditions: stmt): stmt = result = standardRewrite(conditions[1]) else: - error conditions.lineinfo & ": Malformed check statement:" + var ast = conditions.treeRepr + error conditions.lineinfo & ": Malformed check statement:\n" & ast template require*(conditions: stmt): stmt = block: @@ -158,3 +162,15 @@ macro expect*(exp: stmt): stmt = result = getAst(expectBody(errorTypes, exp.lineinfo, body)) + +## Reading settings +var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string + +if envOutLvl.len > 0: + for opt in countup(low(TOutputLevel), high(TOutputLevel)): + if $opt == envOutLvl: + OutputLevel = opt + break + +AbortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR") +ColorOutput = not existsEnv("NIMTEST_NO_COLOR") diff --git a/tests/tester.nim b/tests/tester.nim index 3f563de4a..1b88f9292 100755 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -391,6 +391,9 @@ proc outputJSON(reject, compile, run: TResults) = writeFile(jsonFile, s) proc main() = + os.putenv "NIMTEST_NO_COLOR", "1" + os.putenv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES" + const compileJson = "compile.json" runJson = "run.json" From 032ff877801ba6c9c6e40a4a1bbea25fe4961559 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 10 Nov 2011 20:11:22 +0200 Subject: [PATCH 3/3] fixing bootstrapping when stack frames are enabled --- lib/system.nim | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 00555fa45..460bca5c0 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -402,9 +402,6 @@ proc `+` *(x, y: int32): int32 {.magic: "AddI", noSideEffect.} proc `+` *(x, y: int64): int64 {.magic: "AddI64", noSideEffect.} ## Binary `+` operator for an integer. -proc `+=`*[T](x, y: ordinal[T]) {.magic: "Inc", noSideEffect.} - ## Increments an ordinal - proc `-` *(x, y: int): int {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int8): int8 {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int16): int16 {.magic: "SubI", noSideEffect.} @@ -412,9 +409,6 @@ proc `-` *(x, y: int32): int32 {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int64): int64 {.magic: "SubI64", noSideEffect.} ## Binary `-` operator for an integer. -proc `-=`*[T](x, y: ordinal[T]) {.magic: "Dec", noSideEffect.} - ## Decrements an ordinal - proc `*` *(x, y: int): int {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int8): int8 {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int16): int16 {.magic: "MulI", noSideEffect.} @@ -422,10 +416,6 @@ proc `*` *(x, y: int32): int32 {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int64): int64 {.magic: "MulI64", noSideEffect.} ## Binary `*` operator for an integer. -proc `*=`*[T](x: var ordinal[T], y: ordinal[T]) {.inline noSideEffect.} = - ## Binary `*=` operator for oridinals - x = x * y - proc `div` *(x, y: int): int {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int8): int8 {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int16): int16 {.magic: "DivI", noSideEffect.} @@ -579,22 +569,6 @@ proc `*` *(x, y: float): float {.magic: "MulF64", noSideEffect.} proc `/` *(x, y: float): float {.magic: "DivF64", noSideEffect.} ## computes the floating point division -proc `+=` *(x: var float, y:float) {.inline noSideEffect.} = - ## Increments in placee a floating point number - x = x + y - -proc `-=` *(x: var float, y:float) {.inline noSideEffect.} = - ## Decrements in place a floating point number - x = x - y - -proc `*=` *(x: var float, y:float) {.inline noSideEffect.} = - ## Multiplies in place a floating point number - x = x * y - -proc `/=` *(x: var float, y:float) {.inline noSideEffect.} = - ## Divides in place a floating point number - x = x / y - proc `==` *(x, y: float): bool {.magic: "EqF64", noSideEffect.} proc `<=` *(x, y: float): bool {.magic: "LeF64", noSideEffect.} proc `<` *(x, y: float): bool {.magic: "LtF64", noSideEffect.} @@ -743,8 +717,6 @@ proc `&` * (x: char, y: string): string {. proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} -proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} - type TEndian* = enum ## is a type describing the endianness of a processor. littleEndian, bigEndian @@ -2062,3 +2034,31 @@ proc slurp*(filename: string): string {.magic: "Slurp".} ## const myResource = slurp"mydatafile.bin" ## +proc `+=`*[T](x, y: ordinal[T]) {.magic: "Inc", noSideEffect.} + ## Increments an ordinal + +proc `-=`*[T](x, y: ordinal[T]) {.magic: "Dec", noSideEffect.} + ## Decrements an ordinal + +proc `*=`*[T](x: var ordinal[T], y: ordinal[T]) {.inline noSideEffect.} = + ## Binary `*=` operator for oridinals + x = x * y + +proc `+=` *(x: var float, y:float) {.inline noSideEffect.} = + ## Increments in placee a floating point number + x = x + y + +proc `-=` *(x: var float, y:float) {.inline noSideEffect.} = + ## Decrements in place a floating point number + x = x - y + +proc `*=` *(x: var float, y:float) {.inline noSideEffect.} = + ## Multiplies in place a floating point number + x = x * y + +proc `/=` *(x: var float, y:float) {.inline noSideEffect.} = + ## Divides in place a floating point number + x = x / y + +proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} +