1 /**
2 * Authors: k.inaba
3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/
4 *
5 * Unittest helpers.
6 * TODO: use stderr instead of stdout. the problem is that std.cstream is xxxx....
7 * TODO: is there any way to clearnly implement "assert_compiles" and "assert_not_compile"?
8 */
9 module tricks.test;
10 import std.conv : to;
11 import core.exception;
12
13 version(unittest)
14 {
15 import std.stdio;
16 import core.runtime;
17
18 // Install custom test runner
19 static this()
20 {
21 Runtime.moduleUnitTester = function()
22 {
23 Throwable ee = null;
24 size_t failed=0;
25 foreach(m; ModuleInfo) if(m) if(auto fp=m.unitTest)
26 {
27 writeln("[TEST] ", m.name);
28 try {
29 fp();
30 } catch( Throwable e ) {
31 if(ee is null)
32 ee = e;
33 failed++;
34 writeln(" !! ",e.file,"(",e.line,"): ",e.msg);
35 }
36 }
37 if(ee !is null)
38 {
39 writeln("[TEST] ",failed," modules failed. The first error was:");
40 writeln(ee);
41 write("[TEST] press enter to exit.");
42 readln();
43 return false;
44 }
45 return true;
46 };
47 }
48 }
49
50 /// Unittest helper that asserts an expression must throw something
51
52 void assert_throw(ExcT=Throwable, T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="")
53 {
54 static if( is(ExcT == Throwable) )
55 try
56 { t(); }
57 catch(ExcT)
58 { return; }
59 else
60 try
61 { t(); }
62 catch(ExcT)
63 { return; }
64 catch(Throwable e)
65 { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n >> "~e.toString()); }
66 onAssertErrorMsg(fn, ln, msg.length ? msg : "not thrown");
67 }
68
69 /// Unittest helper that asserts an expression must not throw anything
70
71 T assert_nothrow(T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="")
72 {
73 try
74 { return t(); }
75 catch(Throwable e)
76 { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n >> "~e.toString()); }
77 assert(false);
78 }
79
80 unittest
81 {
82 auto error = {throw new Error("hello");};
83 auto nothing = (){};
84 auto assertError = {assert(0);};
85
86 assert_nothrow ( assert_nothrow(nothing()) );
87 assert_throw!AssertError( assert_nothrow(error()) );
88 assert_throw!AssertError( assert_nothrow(assertError()) );
89
90 assert_nothrow ( assert_throw!Error(error()) );
91 assert_throw!AssertError( assert_throw!Error(nothing()) );
92 assert_nothrow ( assert_throw!Error(assertError()) );
93 assert_throw!AssertError( assert_throw!AssertError(error()) );
94 }
95
96 template assertOp(string op)
97 {
98 void assertOp(A, B, string fn=__FILE__, size_t ln=__LINE__)(A a, B b, string msg="")
99 {
100 try
101 { if( mixin("a"~op~"b") ) return; }
102 catch(Throwable e)
103 { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n >> "~e.toString()); }
104 onAssertErrorMsg(fn, ln, msg.length ? msg : to!string(a)~" !"~op~" "~to!string(b));
105 }
106 }
107
108 alias assertOp!(`==`) assert_eq; /// asserts two operands are ==
109 alias assertOp!(`!=`) assert_ne; /// asserts two operands are !=
110 alias assertOp!(`<`) assert_lt; /// asserts two operands are <
111 alias assertOp!(`<=`) assert_le; /// asserts two operands are <=
112 alias assertOp!(`>`) assert_gt; /// asserts two operands are >
113 alias assertOp!(`>=`) assert_ge; /// asserts two operands are >=
114
115 unittest
116 {
117 assert_nothrow( assert_eq(1, 1) );
118 assert_nothrow( assert_ne(1, 0) );
119 assert_nothrow( assert_lt(0, 1) );
120 assert_nothrow( assert_le(0, 1) );
121 assert_nothrow( assert_le(0, 0) );
122 assert_nothrow( assert_gt(1, 0) );
123 assert_nothrow( assert_ge(1, 0) );
124 assert_nothrow( assert_ge(0, 0) );
125
126 assert_throw!AssertError( assert_eq(1, 0) );
127 assert_throw!AssertError( assert_ne(1, 1) );
128 assert_throw!AssertError( assert_lt(1, 1) );
129 assert_throw!AssertError( assert_lt(1, 0) );
130 assert_throw!AssertError( assert_le(1, 0) );
131 assert_throw!AssertError( assert_gt(0, 0) );
132 assert_throw!AssertError( assert_gt(0, 1) );
133 assert_throw!AssertError( assert_ge(0, 1) );
134
135 class Temp { bool opEquals(int x){return x/x==x;} }
136 assert_throw!AssertError( assert_eq(new Temp, 0) );
137 assert_nothrow ( assert_eq(new Temp, 1) );
138 assert_throw!AssertError( assert_eq(new Temp, 2) );
139 }