1 module des.util.testsuite; 2 3 import std.traits; 4 import std.typetuple; 5 import std.math; 6 7 /// 8 template isElemHandler(A) 9 { 10 enum isElemHandler = !is( Unqual!A == void[] ) && 11 is( typeof(A.init[0]) ) && 12 !is( Unqual!(typeof(A.init[0])) == void ) && 13 is( typeof( A.init.length ) == size_t ); 14 } 15 16 /// 17 unittest 18 { 19 static assert( isElemHandler!(int[]) ); 20 static assert( isElemHandler!(float[]) ); 21 static assert( isElemHandler!(string) ); 22 static assert( !isElemHandler!int ); 23 static assert( !isElemHandler!float ); 24 static assert( !isElemHandler!(immutable(void)[]) ); 25 } 26 27 /// 28 bool eq(A,B)( in A a, in B b ) pure 29 { 30 static if( allSatisfy!(isElemHandler,A,B) ) 31 { 32 if( a.length != b.length ) return false; 33 foreach( i; 0 .. a.length ) 34 if( !eq(a[i],b[i]) ) return false; 35 return true; 36 } 37 else static if( allSatisfy!(isNumeric,A,B) && anySatisfy!(isFloatingPoint,A,B) ) 38 { 39 static if( isFloatingPoint!A && !isFloatingPoint!B ) 40 auto epsilon = A.epsilon; 41 else static if( isFloatingPoint!B && !isFloatingPoint!A ) 42 auto epsilon = B.epsilon; 43 else 44 auto epsilon = fmax( A.epsilon, B.epsilon ); 45 return abs(a-b) < epsilon; 46 } 47 else return a == b; 48 } 49 50 /// 51 unittest 52 { 53 assert( eq( 1, 1.0 ) ); 54 assert( eq( "hello", "hello"w ) ); 55 assert( !eq( cast(void[])"hello", cast(void[])"hello"w ) ); 56 assert( eq( cast(void[])"hello", cast(void[])"hello" ) ); 57 assert( eq( cast(void[])"hello", "hello" ) ); 58 assert( !eq( cast(void[])"hello", "hello"w ) ); 59 assert( eq( [[1,2],[3,4]], [[1.0f,2],[3.0f,4]] ) ); 60 assert( !eq( [[1,2],[3,4]], [[1.1f,2],[3.0f,4]] ) ); 61 assert( !eq( [[1,2],[3,4]], [[1.0f,2],[3.0f]] ) ); 62 assert( eq( [1,2,3], [1.0,2,3] ) ); 63 assert( eq( [1.0f,2,3], [1.0,2,3] ) ); 64 assert( eq( [1,2,3], [1,2,3] ) ); 65 assert( !eq( [1.0000001,2,3], [1,2,3] ) ); 66 assert( eq( ["hello","world"], ["hello","world"] ) ); 67 assert( !eq( "hello", [1,2,3] ) ); 68 static assert( !__traits(compiles, eq(["hello"],1)) ); 69 static assert( !__traits(compiles, eq(["hello"],[1,2,3])) ); 70 } 71 72 /// 73 bool eq_approx(A,B,E)( in A a, in B b, in E eps ) pure 74 if( allSatisfy!(isNumeric,A,B,E) || allSatisfy!(isElemHandler,A,B) ) 75 { 76 static if( allSatisfy!(isElemHandler,A,B) ) 77 { 78 if( a.length != b.length ) return false; 79 foreach( i; 0 .. a.length ) 80 if( !eq_approx(a[i],b[i],eps) ) return false; 81 return true; 82 } 83 else return abs(a-b) < eps; 84 } 85 86 /// 87 unittest 88 { 89 assert( eq_approx( [1.1f,2,3], [1,2,3], 0.2 ) ); 90 assert( !eq_approx( [1.1f,2,3], [1,2,3], 0.1 ) ); 91 assert( !eq_approx( [1.0f,2], [1,2,3], 1 ) ); 92 } 93 94 /// 95 bool mustExcept(E=Exception)( void delegate() fnc, bool throwUnexpected=false ) 96 if( is( E : Throwable ) ) 97 in { assert( fnc ); } body 98 { 99 static if( !is( E == Throwable ) ) 100 { 101 try fnc(); 102 catch( E e ) return true; 103 catch( Throwable t ) 104 if( throwUnexpected ) throw t; 105 return false; 106 } 107 else 108 { 109 try fnc(); 110 catch( Throwable t ) return true; 111 return false; 112 } 113 } 114 115 /// 116 unittest 117 { 118 assert( mustExcept!Exception( { throw new Exception("test"); } ) ); 119 assert( !mustExcept!Exception( { throw new Throwable("test"); } ) ); 120 assert( !mustExcept!Exception( { auto a = 4; } ) ); 121 }