Index: polemy/lex.d ================================================================== --- polemy/lex.d +++ polemy/lex.d @@ -29,16 +29,16 @@ unittest { auto p = new LexPosition("hello.cpp", 123, 45); auto q = new LexPosition("hello.cpp", 123, 46); - assert( p.filename == "hello.cpp" ); - assert( p.lineno == 123 ); - assert( p.column == 45 ); - assert( to!string(p) == "hello.cpp:123:45" ); - assert( p < q ); - assert( p != q ); + assert_eq( p.filename, "hello.cpp" ); + assert_eq( p.lineno, 123 ); + assert_eq( p.column, 45 ); + assert_eq( to!string(p), "hello.cpp:123:45" ); + assert_lt( p, q ); + assert_ne( p, q ); assert( !__traits(compiles, new LexPosition) ); assert( !__traits(compiles, p.filename="foo") ); assert( !__traits(compiles, p.lineno =789) ); assert( !__traits(compiles, p.column =222) ); @@ -65,14 +65,14 @@ unittest { auto p = new immutable(LexPosition)("hello.cpp", 123, 45); auto t = new Token(p, "class", Token.Kind.identifier); - assert( t.pos == p ); - assert( t.str == "class" ); - assert( t == new Token(p, "class", Token.Kind.identifier) ); - assert( t < new Token(p, "struct", Token.Kind.identifier) ); + assert_eq( t.pos, p ); + assert_eq( t.str, "class" ); + assert_eq( t, new Token(p, "class", Token.Kind.identifier) ); + assert_lt( t, new Token(p, "struct", Token.Kind.identifier) ); assert( !__traits(compiles, new Token) ); assert( !__traits(compiles, t.pos=p) ); assert( !__traits(compiles, t.str=789) ); } Index: polemy/tricks.d ================================================================== --- polemy/tricks.d +++ polemy/tricks.d @@ -5,10 +5,11 @@ * Common tricks and utilities for programming in D. */ module polemy.tricks; static import std.array; static import std.format; +static import core.exception; /// Simple Wrapper for std.format.doFormat string sprintf(string fmt, T...)(T params) { @@ -21,33 +22,98 @@ { assert( sprintf!"%s == %d"("1+2", 3) == "1+2 == 3" ); assert( sprintf!"%s == %04d"("1+2", 3) == "1+2 == 0003" ); } +/// Unittest helpers asserting two values are in some relation ==, !=, <, <=, >, >= + +template assertOp(string op) +{ + void assertOp(A, B, string fn=__FILE__, int ln=__LINE__)(A a, B b, string msg="") + { + try { + if( mixin("a"~op~"b") ) return; + } catch(Throwable e) { + core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); + } + core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"%s !%s %s"(a,op,b)); + } +} + +alias assertOp!(`==`) assert_eq; +alias assertOp!(`!=`) assert_ne; +alias assertOp!(`<`) assert_lt; +alias assertOp!(`<=`) assert_le; +alias assertOp!(`>`) assert_gt; +alias assertOp!(`>=`) assert_ge; + +/// Unittest helper that asserts an expression must throw something + +void assert_throw(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="") +{ + try { + t(); + } catch(ExceptionType) { + return; + } catch(Throwable e) { + core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); + } + core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : "no execption"); +} + +/// Unittest helper that asserts an expression must not throw anything + +void assert_nothrow(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="") +{ + try { + t(); + } catch(Throwable e) { + core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); + } +} + +/* [Todo] is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */ + /// Mixing-in the bean constructor for a class -/*mixin*/ template SimpleConstructor() +template SimpleConstructor() { static if( is(typeof(super) == Object) || super.tupleof.length==0 ) this( typeof(this.tupleof) params ) { static if(this.tupleof.length>0) this.tupleof = params; } else - // this parameter list is not always desirable but should work for many cases this( typeof(super.tupleof) ps, typeof(this.tupleof) params ) { + // including (only) the direct super class members + // may not always be a desirable choice, but should work for many cases super(ps); static if(this.tupleof.length>0) this.tupleof = params; } } + +unittest +{ + class Temp + { + int x; + string y; + mixin SimpleConstructor; + } + assert_eq( (new Temp(1,"foo")).x, 1 ); + assert_eq( (new Temp(1,"foo")).y, "foo" ); + assert( !__traits(compiles, new Temp) ); + assert( !__traits(compiles, new Temp(1)) ); + assert( !__traits(compiles, new Temp("foo",1)) ); +} /// Mixing-in the MOST-DERIVED-member-wise comparator for a class -/*mixin*/ template SimpleCompare() +template SimpleCompare() { override bool opEquals(Object rhs_) const { if( auto rhs = cast(typeof(this))rhs_ ) { @@ -87,17 +153,12 @@ int x; string y; mixin SimpleConstructor; mixin SimpleCompare; } - assert( (new Temp(1,"foo")).x == 1 ); - assert( (new Temp(1,"foo")).y == "foo" ); - assert( !__traits(compiles, new Temp) ); - assert( !__traits(compiles, new Temp(1)) ); - assert( !__traits(compiles, new Temp("foo",1)) ); - assert( new Temp(1,"foo") == new Temp(1,"foo") ); - assert( (new Temp(1,"foo")).toHash == (new Temp(1,"foo")).toHash ); - assert( new Temp(1,"foo") != new Temp(2,"foo") ); - assert( new Temp(1,"foo") != new Temp(1,"bar") ); - assert( new Temp(1,"foo") > new Temp(1,"bar") ); - assert( new Temp(1,"foo") < new Temp(2,"bar") ); + assert_eq( new Temp(1,"foo"), new Temp(1,"foo") ); + assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash ); + assert_ne( new Temp(1,"foo"), new Temp(2,"foo") ); + assert_ne( new Temp(1,"foo"), new Temp(1,"bar") ); + assert_gt( new Temp(1,"foo"), new Temp(1,"bar") ); + assert_lt( new Temp(1,"foo"), new Temp(2,"bar") ); }