1 #!/usr/bin/env rdmd-dev
2 
3 /** A Better assert.
4 
5     Copyright: Per Nordlöw 2018-.
6     License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
7     Authors: $(WEB Per Nordlöw)
8 
9     TODO make these @safe pure nothrow @nogc by utilizing dynamic_array and printf
10 
11     extend to something like:
12 
13     - must!"a == b"(x, y);
14     - check!"a == b"(x, y);
15     - require!"a == b"(x, y);
16 */
17 module nxt.assert_ex;
18 
19 // import std.string : format;
20 import core.exception : AssertError;
21 import std.conv: to;
22 
23 @trusted:
24 
25 /// Returns: true if the expression throws.
26 bool assertThrows(T:Throwable = Exception, E)(lazy E expression,
27                                               string msg = T.stringof,
28                                               string file = __FILE__,
29                                               int line = __LINE__ )
30 {
31     try
32     {
33         std.exception.assertThrown!T(expression, msg, file, line);
34         return true;
35     }
36     catch (Throwable exc)
37     {
38         // FIXTHIS: unhelpful error message
39         writeln("failed at ", baseName(file), "(", line, "):",
40                 " Did not throw \"", msg, "\".");
41         return false;
42     }
43 }
44 
45 nothrow:
46 
47 /** A Better assert.
48     See_Also: http://poita.org/2012/09/02/a-better-assert-for-d.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+poita+%28poita.org%29
49     TODO Can we convert args to strings like GCC's __STRING(expression)?
50     TODO Make these be able to be called in unittest placed in struct scopes
51 */
52 void assertTrue(T,
53                 string file = __FILE__, uint line = __LINE__,
54                 Args...) (T test, lazy Args args)
55 {
56     version(assert) if (!test)
57     {
58         throw new AssertError("at \n" ~file~ ":" ~to!string(line)~ ":\n  test: " ~to!string(test));
59     }
60 }
61 alias assertT = assertTrue;
62 
63 void assertEqual(T, U,
64                  string file = __FILE__, uint line = __LINE__,
65                  Args...)(T lhs, U rhs,
66                           lazy Args args) // TODO use args
67 {
68     version(assert) if (lhs != rhs)
69     {
70         throw new AssertError("at \n" ~file~ ":" ~to!string(line)~ ":\n  lhs: " ~to!string(lhs)~ " !=\n  rhs: " ~to!string(rhs));
71     }
72 }
73 alias assertE = assertEqual;
74 
75 // @safe pure unittest
76 // {
77 //     assertEqual([1], [2, 3]);
78 // }
79 
80 void assertLessThanOrEqual(T, U,
81                            string file = __FILE__,
82                            uint line = __LINE__,
83                            Args...) (T lhs, U rhs,
84                                      lazy Args args) // TODO use args
85 {
86     version(assert) if (lhs > rhs)
87     {
88         throw new AssertError("at \n" ~file~ ":" ~to!string(line)~ ":\n  lhs: " ~to!string(lhs)~ " >\n  rhs: " ~to!string(rhs));
89     }
90 }
91 alias assertLTE = assertLessThanOrEqual;
92 
93 void assertLessThan(T, U,
94                     string file = __FILE__, uint line = __LINE__,
95                     Args...) (T lhs, U rhs,
96                               lazy Args args) // TODO use args
97 {
98     version(assert) if (lhs >= rhs)
99     {
100         throw new AssertError("at \n" ~file~ ":" ~to!string(line)~ ":\n  lhs: " ~to!string(lhs)~ " >=\n  rhs: " ~to!string(rhs));
101     }
102 }
103 alias assertLT = assertLessThan;
104 
105 void assertNotEqual(T, U,
106                     string file = __FILE__, uint line = __LINE__,
107                     Args...) (T lhs, U rhs,
108                               lazy Args args) // TODO use args
109 {
110     version(assert) if (lhs == rhs)
111     {
112         throw new AssertError("at \n" ~file~ ":" ~to!string(line)~ ":\n  lhs: " ~to!string(lhs)~ " ==\n  rhs: " ~to!string(rhs));
113     }
114 }
115 alias assertNE = assertNotEqual;