Index: main.d ================================================================== --- main.d +++ main.d @@ -53,21 +53,14 @@ } return true; } } -version(unittest) { - bool success = false; - static ~this(){ if(!success){writeln("(press enter to exit)"); readln();} } -} - /// Entry point. If args.length==1, invoke REPL. /// Otherwise interpret the argument as a filename. void main( string[] args ) { - version(unittest) success=true; - if( args.length <= 1 ) { writeln("Welcome to Polemy 0.1.0"); for(auto r = new REPL; r.singleInteraction();) {} } Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -245,11 +245,11 @@ void eat(string kwd, lazy string msg) { if( !tryEat(kwd) ) if( lex.empty ) throw genex!UnexpectedEOF( - currentPosition(), sprintf!"%s is expected for %s but not found"(kwd,msg)); + currentPosition(), sprintf!"%s is expected %s but not found"(kwd,msg)); else throw genex!ParseException( currentPosition(), sprintf!"%s is expected for %s but not found"(kwd,msg)); } Index: tricks/test.d ================================================================== --- tricks/test.d +++ tricks/test.d @@ -1,32 +1,70 @@ /** * Authors: k.inaba * License: NYSL 0.9982 http://www.kmonos.net/nysl/ * - * Unittest helpers. + * Unittest helpers. + * TODO: use stderr instead of stdout. the problem is that std.cstream is xxxx.... + * TODO: is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */ module tricks.test; import std.conv : to; import core.exception; - + +version(unittest) +{ + import std.stdio; + import core.runtime; + + // Install custom test runner + static this() + { + Runtime.moduleUnitTester = function() + { + Throwable ee = null; + size_t failed=0; + foreach(m; ModuleInfo) if(m) if(auto fp=m.unitTest) + { + writeln("[TEST] ", m.name); + try { + fp(); + } catch( Throwable e ) { + if(ee is null) + ee = e; + failed++; + writeln(" !! ",e.file,"(",e.line,"): ",e.msg); + } + } + if(ee !is null) + { + writeln("[TEST] ",failed," modules failed. The first error was:"); + writeln(ee); + write("[TEST] press enter to exit."); + readln(); + return false; + } + return true; + }; + } +} + /// Unittest helper that asserts an expression must throw something -void assert_throw(ExceptionType=Throwable, - T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="") +void assert_throw(ExcT=Throwable, T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="") { - static if( is(ExceptionType == Throwable) ) + static if( is(ExcT == Throwable) ) try { t(); } - catch(ExceptionType) + catch(ExcT) { return; } else try { t(); } - catch(ExceptionType) + catch(ExcT) { return; } catch(Throwable e) - { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception\n >> "~e.toString()); } + { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n >> "~e.toString()); } onAssertErrorMsg(fn, ln, msg.length ? msg : "not thrown"); } /// Unittest helper that asserts an expression must not throw anything @@ -33,14 +71,14 @@ T assert_nothrow(T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="") { try { return t(); } catch(Throwable e) - { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception\n >> "~e.toString()); } + { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n >> "~e.toString()); } assert(false); } - + unittest { auto error = {throw new Error("hello");}; auto nothing = (){}; auto assertError = {assert(0);}; @@ -52,30 +90,30 @@ assert_nothrow ( assert_throw!Error(error()) ); assert_throw!AssertError( assert_throw!Error(nothing()) ); assert_nothrow ( assert_throw!Error(assertError()) ); assert_throw!AssertError( assert_throw!AssertError(error()) ); } - + template assertOp(string op) { void assertOp(A, B, string fn=__FILE__, size_t ln=__LINE__)(A a, B b, string msg="") { try { if( mixin("a"~op~"b") ) return; } catch(Throwable e) - { onAssertErrorMsg(fn, ln, msg.length ? msg : "exception ["~e.toString()~"]"); } + { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n >> "~e.toString()); } onAssertErrorMsg(fn, ln, msg.length ? msg : to!string(a)~" !"~op~" "~to!string(b)); } } alias assertOp!(`==`) assert_eq; /// asserts two operands are == alias assertOp!(`!=`) assert_ne; /// asserts two operands are != alias assertOp!(`<`) assert_lt; /// asserts two operands are < alias assertOp!(`<=`) assert_le; /// asserts two operands are <= alias assertOp!(`>`) assert_gt; /// asserts two operands are > -alias assertOp!(`>=`) assert_ge; /// asserts two operands are >= - +alias assertOp!(`>=`) assert_ge; /// asserts two operands are >= + unittest { assert_nothrow( assert_eq(1, 1) ); assert_nothrow( assert_ne(1, 0) ); assert_nothrow( assert_lt(0, 1) ); @@ -97,7 +135,5 @@ class Temp { bool opEquals(int x){return x/x==x;} } assert_throw!AssertError( assert_eq(new Temp, 0) ); assert_nothrow ( assert_eq(new Temp, 1) ); assert_throw!AssertError( assert_eq(new Temp, 2) ); } - -/* [Todo] is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */