4198578702 2010-11-07 kinaba: /** 4198578702 2010-11-07 kinaba: * Authors: k.inaba 4198578702 2010-11-07 kinaba: * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4198578702 2010-11-07 kinaba: * 4198578702 2010-11-07 kinaba: * Common tricks and utilities for programming in D. 423f308350 2010-11-07 kinaba: */ 4198578702 2010-11-07 kinaba: module polemy.tricks; 423f308350 2010-11-07 kinaba: static import std.array; 423f308350 2010-11-07 kinaba: static import std.format; 61998c472a 2010-11-08 kinaba: static import core.exception; 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// Simple Wrapper for std.format.doFormat 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: string sprintf(string fmt, T...)(T params) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: auto writer = std.array.appender!string(); 423f308350 2010-11-07 kinaba: std.format.formattedWrite(writer, fmt, params); 423f308350 2010-11-07 kinaba: return writer.data; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: assert( sprintf!"%s == %d"("1+2", 3) == "1+2 == 3" ); 423f308350 2010-11-07 kinaba: assert( sprintf!"%s == %04d"("1+2", 3) == "1+2 == 0003" ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 61998c472a 2010-11-08 kinaba: /// Unittest helpers asserting two values are in some relation ==, !=, <, <=, >, >= 61998c472a 2010-11-08 kinaba: 61998c472a 2010-11-08 kinaba: template assertOp(string op) 61998c472a 2010-11-08 kinaba: { 61998c472a 2010-11-08 kinaba: void assertOp(A, B, string fn=__FILE__, int ln=__LINE__)(A a, B b, string msg="") 61998c472a 2010-11-08 kinaba: { 61998c472a 2010-11-08 kinaba: try { 61998c472a 2010-11-08 kinaba: if( mixin("a"~op~"b") ) return; 61998c472a 2010-11-08 kinaba: } catch(Throwable e) { 61998c472a 2010-11-08 kinaba: core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"%s !%s %s"(a,op,b)); 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: 61998c472a 2010-11-08 kinaba: alias assertOp!(`==`) assert_eq; 61998c472a 2010-11-08 kinaba: alias assertOp!(`!=`) assert_ne; 61998c472a 2010-11-08 kinaba: alias assertOp!(`<`) assert_lt; 61998c472a 2010-11-08 kinaba: alias assertOp!(`<=`) assert_le; 61998c472a 2010-11-08 kinaba: alias assertOp!(`>`) assert_gt; 61998c472a 2010-11-08 kinaba: alias assertOp!(`>=`) assert_ge; 61998c472a 2010-11-08 kinaba: 61998c472a 2010-11-08 kinaba: /// Unittest helper that asserts an expression must throw something 61998c472a 2010-11-08 kinaba: 61998c472a 2010-11-08 kinaba: void assert_throw(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="") 61998c472a 2010-11-08 kinaba: { 61998c472a 2010-11-08 kinaba: try { 61998c472a 2010-11-08 kinaba: t(); 61998c472a 2010-11-08 kinaba: } catch(ExceptionType) { 61998c472a 2010-11-08 kinaba: return; 61998c472a 2010-11-08 kinaba: } catch(Throwable e) { 61998c472a 2010-11-08 kinaba: core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : "no execption"); 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: 61998c472a 2010-11-08 kinaba: /// Unittest helper that asserts an expression must not throw anything 61998c472a 2010-11-08 kinaba: 61998c472a 2010-11-08 kinaba: void assert_nothrow(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="") 61998c472a 2010-11-08 kinaba: { 61998c472a 2010-11-08 kinaba: try { 61998c472a 2010-11-08 kinaba: t(); 61998c472a 2010-11-08 kinaba: } catch(Throwable e) { 61998c472a 2010-11-08 kinaba: core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: 61998c472a 2010-11-08 kinaba: /* [Todo] is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */ 61998c472a 2010-11-08 kinaba: 423f308350 2010-11-07 kinaba: /// Mixing-in the bean constructor for a class 423f308350 2010-11-07 kinaba: 61998c472a 2010-11-08 kinaba: template SimpleConstructor() 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: static if( is(typeof(super) == Object) || super.tupleof.length==0 ) 423f308350 2010-11-07 kinaba: this( typeof(this.tupleof) params ) 423f308350 2010-11-07 kinaba: { 0569f7b8c2 2010-11-07 kinaba: static if(this.tupleof.length>0) 0569f7b8c2 2010-11-07 kinaba: this.tupleof = params; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: else 423f308350 2010-11-07 kinaba: this( typeof(super.tupleof) ps, typeof(this.tupleof) params ) 423f308350 2010-11-07 kinaba: { 61998c472a 2010-11-08 kinaba: // including (only) the direct super class members 61998c472a 2010-11-08 kinaba: // may not always be a desirable choice, but should work for many cases 423f308350 2010-11-07 kinaba: super(ps); 0569f7b8c2 2010-11-07 kinaba: static if(this.tupleof.length>0) 0569f7b8c2 2010-11-07 kinaba: this.tupleof = params; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 61998c472a 2010-11-08 kinaba: unittest 61998c472a 2010-11-08 kinaba: { 61998c472a 2010-11-08 kinaba: class Temp 61998c472a 2010-11-08 kinaba: { 61998c472a 2010-11-08 kinaba: int x; 61998c472a 2010-11-08 kinaba: string y; 61998c472a 2010-11-08 kinaba: mixin SimpleConstructor; 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: assert_eq( (new Temp(1,"foo")).x, 1 ); 61998c472a 2010-11-08 kinaba: assert_eq( (new Temp(1,"foo")).y, "foo" ); 61998c472a 2010-11-08 kinaba: assert( !__traits(compiles, new Temp) ); 61998c472a 2010-11-08 kinaba: assert( !__traits(compiles, new Temp(1)) ); 61998c472a 2010-11-08 kinaba: assert( !__traits(compiles, new Temp("foo",1)) ); 61998c472a 2010-11-08 kinaba: } 61998c472a 2010-11-08 kinaba: 820e7198cc 2010-11-07 kinaba: /// Mixing-in the MOST-DERIVED-member-wise comparator for a class 423f308350 2010-11-07 kinaba: 61998c472a 2010-11-08 kinaba: template SimpleCompare() 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: override bool opEquals(Object rhs_) const 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: if( auto rhs = cast(typeof(this))rhs_ ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: foreach(i,_; this.tupleof) 423f308350 2010-11-07 kinaba: if( this.tupleof[i] != rhs.tupleof[i] ) 423f308350 2010-11-07 kinaba: return false; 423f308350 2010-11-07 kinaba: return true; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: override hash_t toHash() const 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: hash_t h = 0; 423f308350 2010-11-07 kinaba: foreach(mem; this.tupleof) 423f308350 2010-11-07 kinaba: h += typeid(mem).getHash(&mem); 423f308350 2010-11-07 kinaba: return h; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: override int opCmp(Object rhs_) const 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: if( auto rhs = cast(typeof(this))rhs_ ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: foreach(i,_; this.tupleof) 423f308350 2010-11-07 kinaba: if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i])) 423f308350 2010-11-07 kinaba: return c; 423f308350 2010-11-07 kinaba: return 0; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: class Temp 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: int x; 423f308350 2010-11-07 kinaba: string y; 423f308350 2010-11-07 kinaba: mixin SimpleConstructor; 423f308350 2010-11-07 kinaba: mixin SimpleCompare; 423f308350 2010-11-07 kinaba: } 61998c472a 2010-11-08 kinaba: assert_eq( new Temp(1,"foo"), new Temp(1,"foo") ); 61998c472a 2010-11-08 kinaba: assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash ); 61998c472a 2010-11-08 kinaba: assert_ne( new Temp(1,"foo"), new Temp(2,"foo") ); 61998c472a 2010-11-08 kinaba: assert_ne( new Temp(1,"foo"), new Temp(1,"bar") ); 61998c472a 2010-11-08 kinaba: assert_gt( new Temp(1,"foo"), new Temp(1,"bar") ); 61998c472a 2010-11-08 kinaba: assert_lt( new Temp(1,"foo"), new Temp(2,"bar") ); 423f308350 2010-11-07 kinaba: }