root/trunk/src/semitwist/util/deferAssert.d

Revision 146, 5.4 kB (checked in by Abscissa, 1 week ago)

(NB) deferAssertTest: Works now.

Line 
1 // SemiTwist Library
2 // Written in the D programming language.
3
4 module semitwist.util.deferAssert;
5
6 // deferEnsure requires this to exist in the calling context
7 import std.traits;//tango.core.Traits : _deferAssert_ExprTypeOf = ExprTypeOf;
8 public import semitwist.util.reflect : _deferAssert_ExprTypeOf = ExprTypeOf;
9
10 import std.stdio;//tango.io.Stdout;
11 //import tango.util.Convert;
12 import std.conv;
13
14 import semitwist.util.all;
15 import semitwist.util.compat.all;
16
17 //TODO: Properly handle stuff that (for whatever bizarre reason) throws null.
18 //TODO: Modify deferEnsureThrows to (optionally?) accept subclasses of TExpected
19 //TODO? Change deferEnsureThrows to take an expression instead of a statement
20 //TODO? Better naming convention
21
22
23 /**
24 Sounds like a contradiction of terms, but this is just
25 intended to allow unittests to output ALL failures instead
26 of only outputting the first one and then stopping.
27 */
28 template deferAssert(string condStr, string msg="")
29 {
30     const string deferAssert =
31     // The "_deferAssert_line" is a workaround for DMD Bug #2887
32     "{ const long _deferAssert_line = __LINE__;\n"~
33     "    try\n"~
34     "    {\n"~
35     "        bool _deferAssert_condResult = ("~condStr~");\n"~
36     "        _deferAssert!(_deferAssert_line, __FILE__, "~condStr.stringof~", "~msg.stringof~")(_deferAssert_condResult);\n"~
37     "    }\n"~
38     "    catch(Object _deferAssert_e)\n"~
39     "        _deferAssertException!(_deferAssert_line, __FILE__, "~condStr.stringof~", "~msg.stringof~")(_deferAssert_e);\n"~
40     "}\n";
41 }
42
43 bool _deferAssert(long line, string file, string condStr, string msg="")(bool condResult)
44 {
45     if(!condResult)
46     {
47         assertCount++;
48         writefln("%s(%s): Assert Failed (%s)%s",
49                  file, line, condStr,
50                  msg=="" ? "" : ": " ~ msg);
51     }
52    
53     return condResult;
54 }
55
56 void _deferAssertException(long line, string file, string condStr, string msg="")(Object thrown)
57 {
58     assertCount++;
59     writef("%s(%s): Assert Threw (%s)%s:\nThrew: ",
60            file, line, condStr,
61            msg=="" ? "" : ": " ~ msg);
62     Exception e = cast(Exception)thrown;
63     if(e)
64         writeln(thrown);
65     else
66         writefln("Object: type '%s': %s", thrown.classinfo.name, thrown);
67 }
68
69 //TODO: Something like: mixin(blah!(`_1 == (_2 ~ _3)`, `"Hello"`, `"He"`, `"llo"`));
70
71 template deferEnsure(string value, string condStr, string msg="")
72 {
73     const string deferEnsure =
74     // The "_deferAssert_line" is a workaround for DMD Bug #2887
75     "{ const long _deferAssert_line = __LINE__;\n"~
76     "    try\n"~
77     "    {\n"~
78     "        auto _ = ("~value~");\n"~
79     "        bool _deferAssert_condResult = ("~condStr~");\n"~
80     "        _deferEnsure!(_deferAssert_line, __FILE__, "~value.stringof~", "~condStr.stringof~", _deferAssert_ExprTypeOf!(typeof("~value~")), "~msg.stringof~")(_, _deferAssert_condResult);\n"~
81     "    }\n"~
82     "    catch(Object _deferAssert_e)\n"~
83     "        _deferEnsureException!(_deferAssert_line, __FILE__, "~value.stringof~", "~condStr.stringof~", "~msg.stringof~")(_deferAssert_e);\n"~
84     "}\n";
85 }
86
87 bool _deferEnsure(long line, string file, string valueStr, string condStr, T, string msg="")(T valueResult, bool condResult)
88 {
89     if(!condResult)
90     {
91         assertCount++;
92         writefln("%s(%s): Ensure Failed%s\n"~
93                  "Expression '%s':\n"~
94                  "Expected: %s\n"~
95                  "Actual: %s",
96                  file, line, msg=="" ? "" : ": " ~ msg,
97                  valueStr, condStr, valueResult);
98     }
99    
100     return condResult;
101 }
102
103 void _deferEnsureException(long line, string file, string valueStr, string condStr, string msg="")(Object thrown)
104 {
105     assertCount++;
106     writef("%s(%s): Ensure Threw%s:\n"~
107            "Expression '%s':\n"~
108            "Expected: %s\n"~
109            "Threw: ",
110            file, line, msg=="" ? "" : ": " ~ msg,
111            valueStr, condStr);
112     Exception e = cast(Exception)thrown;
113     if(e)
114         writeln(thrown);
115     else
116         writefln("Object: type '%s': %s", thrown.classinfo.name, thrown);
117 }
118
119 template deferEnsureThrows(string stmtStr, TExpected, string msg="")
120 {
121     const string deferEnsureThrows =
122     // The "_deferAssert_line" is a workaround for DMD Bug #2887
123     "{ const long _deferAssert_line = __LINE__;\n"~
124     "    Object _deferAssert_caught=null;\n"~
125     "    try\n"~
126     "    {"~stmtStr~"}\n"~
127     "    catch(Object _deferAssert_e)\n"~
128     "        _deferAssert_caught = _deferAssert_e;\n"~
129     "    _deferEnsureThrows!(_deferAssert_line, __FILE__, "~stmtStr.stringof~", "~TExpected.stringof~", "~msg.stringof~")(_deferAssert_caught);\n"~
130     "}\n";
131 }
132
133 void _deferEnsureThrows(long line, string file, string stmtStr, TExpected, string msg="")(Object thrown)
134 {
135     string actualType = (thrown is null)? "{null}" : thrown.classinfo.name;
136    
137     if(actualType != TExpected.classinfo.name)
138     {
139         assertCount++;
140         writef("%s(%s): Ensure Throw Failed%s\n"~
141                "Statement '%s':\n"~
142                "Expected: %s\n"~
143                "Actual:   ",
144                file, line, msg=="" ? "" : ": " ~ msg,
145                stmtStr, TExpected.classinfo.name, actualType);
146         Throwable e = cast(Exception)thrown;
147         if(e)
148             writeln(e); //e.writeOut( (string msg) {Stdout(msg);} );
149         else
150             writefln("%s: %s", actualType, thrown);
151     }
152 }
153
154 private uint assertCount=0;
155 uint getAssertCount()
156 {
157     return assertCount;
158 }
159 void resetAssertCount()
160 {
161     assertCount = 0;
162 }
163
164 void flushAsserts()
165 {
166     if(assertCount > 0)
167     {
168         uint saveAssertCount = assertCount;
169         assertCount = 0;
170         stdout.flush();
171         assert(false,
172             to!(string)(saveAssertCount) ~
173             " Assert Failure" ~
174             (saveAssertCount == 1 ? "" : "s")
175         );
176     }
177 }
Note: See TracBrowser for help on using the browser.