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