1 module unit_threaded.ut.should;
2 
3 import unit_threaded.should;
4 import unit_threaded.asserts;
5 
6 private void assertFail(E)(lazy E expression, in string file = __FILE__, in size_t line = __LINE__)
7 {
8     import std.exception: assertThrown;
9     assertThrown!UnitTestException(expression, null, file, line);
10 }
11 
12 
13 @safe pure unittest {
14     static struct Foo {
15         bool opCast(T: bool)() {
16             return true;
17         }
18     }
19     shouldBeTrue(Foo());
20 }
21 
22 
23 @safe pure unittest {
24     static struct Foo {
25         bool opCast(T: bool)() {
26             return false;
27         }
28     }
29     shouldBeFalse(Foo());
30 }
31 
32 @safe unittest {
33     //impure comparisons
34     shouldEqual(1.0, 1.0) ;
35     shouldNotEqual(1.0, 1.0001);
36 }
37 
38 @safe pure unittest {
39     import unit_threaded.asserts;
40 
41     assertExceptionMsg(3.shouldEqual(5),
42                        "    tests/unit_threaded/ut/should.d:123 - Expected: 5\n" ~
43                        "    tests/unit_threaded/ut/should.d:123 -      Got: 3");
44 
45     assertExceptionMsg("foo".shouldEqual("bar"),
46                        "    tests/unit_threaded/ut/should.d:123 - Expected: \"bar\"\n" ~
47                        "    tests/unit_threaded/ut/should.d:123 -      Got: \"foo\"");
48 
49     assertExceptionMsg([1, 2, 4].shouldEqual([1, 2, 3]),
50                        "    tests/unit_threaded/ut/should.d:123 - Expected: [1, 2, 3]\n" ~
51                        "    tests/unit_threaded/ut/should.d:123 -      Got: [1, 2, 4]");
52 
53     assertExceptionMsg([[0, 1, 2, 3, 4], [1], [2], [3], [4], [5]].shouldEqual([[0], [1], [2]]),
54                        "    tests/unit_threaded/ut/should.d:123 - Expected: [[0], [1], [2]]\n" ~
55                        "    tests/unit_threaded/ut/should.d:123 -      Got: [[0, 1, 2, 3, 4], [1], [2], [3], [4], [5]]");
56 
57     assertExceptionMsg([[0, 1, 2, 3, 4, 5], [1], [2], [3]].shouldEqual([[0], [1], [2]]),
58                        "    tests/unit_threaded/ut/should.d:123 - Expected: [[0], [1], [2]]\n" ~
59                        "    tests/unit_threaded/ut/should.d:123 -      Got: [[0, 1, 2, 3, 4, 5], [1], [2], [3]]");
60 
61 
62     assertExceptionMsg([[0, 1, 2, 3, 4, 5], [1], [2], [3], [4], [5]].shouldEqual([[0]]),
63                        "    tests/unit_threaded/ut/should.d:123 - Expected: [[0]]\n" ~
64                        "    tests/unit_threaded/ut/should.d:123 -      Got: [\n" ~
65                        "    tests/unit_threaded/ut/should.d:123 -               [0, 1, 2, 3, 4, 5],\n" ~
66                        "    tests/unit_threaded/ut/should.d:123 -               [1],\n" ~
67                        "    tests/unit_threaded/ut/should.d:123 -               [2],\n" ~
68                        "    tests/unit_threaded/ut/should.d:123 -               [3],\n" ~
69                        "    tests/unit_threaded/ut/should.d:123 -               [4],\n" ~
70                        "    tests/unit_threaded/ut/should.d:123 -               [5],\n" ~
71                        "    tests/unit_threaded/ut/should.d:123 -           ]");
72 
73     assertExceptionMsg(1.shouldNotEqual(1),
74                        "    tests/unit_threaded/ut/should.d:123 - Value:\n" ~
75                        "    tests/unit_threaded/ut/should.d:123 - 1\n" ~
76                        "    tests/unit_threaded/ut/should.d:123 - is not expected to be equal to:\n" ~
77                        "    tests/unit_threaded/ut/should.d:123 - 1");
78 }
79 
80 @safe pure unittest
81 {
82     ubyte[] arr;
83     ubyte[] empty;
84     arr.shouldEqual(empty);
85 }
86 
87 
88 @safe pure unittest
89 {
90     int[] ints = [1, 2, 3];
91     byte[] bytes = [1, 2, 3];
92     byte[] bytes2 = [1, 2, 4];
93     shouldEqual(ints, bytes);
94     shouldEqual(bytes, ints) ;
95     shouldNotEqual(ints, bytes2) ;
96 
97     const constIntToInts = [1 : 2, 3 : 7, 9 : 345];
98     auto intToInts = [1 : 2, 3 : 7, 9 : 345];
99     shouldEqual(intToInts, constIntToInts) ;
100     shouldEqual(constIntToInts, intToInts) ;
101 }
102 
103 @safe unittest {
104     shouldEqual([1 : 2.0, 2 : 4.0], [1 : 2.0, 2 : 4.0]) ;
105     shouldNotEqual([1 : 2.0, 2 : 4.0], [1 : 2.2, 2 : 4.0]) ;
106 }
107 
108 @system pure unittest {
109     import std.range: iota;
110     const constRange = 3.iota;
111     shouldEqual(constRange, constRange);
112 }
113 
114 @system pure unittest
115 {
116     class Foo
117     {
118         this(int i) { this.i = i; }
119         override string toString() @safe const
120         {
121             import std.conv: to;
122             return i.to!string;
123         }
124         int i;
125     }
126 
127     shouldNotBeNull(new Foo(4));
128     assertFail(shouldNotBeNull(null));
129     shouldEqual(new Foo(5), new Foo(5));
130     assertFail(shouldEqual(new Foo(5), new Foo(4)));
131     shouldNotEqual(new Foo(5), new Foo(4));
132     assertFail(shouldNotEqual(new Foo(5), new Foo(5)));
133 }
134 
135 @safe pure unittest
136 {
137     shouldBeNull(null);
138     assertFail(shouldBeNull(new int));
139 }
140 
141 
142 @safe pure unittest {
143     5.shouldBeIn([5: "foo"]);
144 
145     struct AA {
146         int onlyKey;
147         bool opBinaryRight(string op)(in int key) const {
148             return key == onlyKey;
149         }
150     }
151 
152     5.shouldBeIn(AA(5));
153     assertFail(5.shouldBeIn(AA(4)));
154 }
155 
156 @safe pure unittest
157 {
158     shouldBeIn(4, [1, 2, 4]);
159     shouldBeIn("foo", ["foo" : 1]);
160     assertFail("foo".shouldBeIn(["bar"]));
161 }
162 
163 @safe pure unittest {
164     assertExceptionMsg("foo".shouldBeIn(["quux": "toto"]),
165                        `    tests/unit_threaded/ut/should.d:123 - Value "foo"` ~ "\n" ~
166                        `    tests/unit_threaded/ut/should.d:123 - not in ["quux":"toto"]`);
167 }
168 
169 @safe pure unittest {
170     assertExceptionMsg("foo".shouldBeIn("quux"),
171                        `    tests/unit_threaded/ut/should.d:123 - Value "foo"` ~ "\n" ~
172                        `    tests/unit_threaded/ut/should.d:123 - not in "quux"`);
173 
174 }
175 
176 @safe pure unittest {
177     5.shouldNotBeIn([4: "foo"]);
178 
179     struct AA {
180         int onlyKey;
181         bool opBinaryRight(string op)(in int key) const {
182             return key == onlyKey;
183         }
184     }
185 
186     5.shouldNotBeIn(AA(4));
187     assertFail(5.shouldNotBeIn(AA(5)));
188 }
189 
190 @safe pure unittest {
191     assertExceptionMsg("quux".shouldNotBeIn(["quux": "toto"]),
192                        `    tests/unit_threaded/ut/should.d:123 - Value "quux"` ~ "\n" ~
193                        `    tests/unit_threaded/ut/should.d:123 - is in ["quux":"toto"]`);
194 }
195 
196 @safe pure unittest {
197     assertExceptionMsg("foo".shouldNotBeIn("foobar"),
198                        `    tests/unit_threaded/ut/should.d:123 - Value "foo"` ~ "\n" ~
199                        `    tests/unit_threaded/ut/should.d:123 - is in "foobar"`);
200 
201 }
202 
203 
204 @safe pure unittest {
205     assertExceptionMsg((1 == 2).shouldThrow,
206                        `    tests/unit_threaded/ut/should.d:123 - Expression did not throw`);
207 }
208 
209 
210 @safe pure unittest {
211     static void oops() { throw new Exception("oops"); }
212     assertExceptionMsg(oops.shouldThrow!UnitTestException,
213                        `    tests/unit_threaded/ut/should.d:123 - Expression threw object.Exception instead of the expected UnitTestException:`
214                        ~ "\n"  ~ `oops`);
215 }
216 
217 
218 @safe unittest
219 {
220     auto arrayRangeWithoutLength(T)(T[] array)
221     {
222         struct ArrayRangeWithoutLength(T)
223         {
224         private:
225             T[] array;
226         public:
227             T front() const @property
228             {
229                 return array[0];
230             }
231 
232             void popFront()
233             {
234                 array = array[1 .. $];
235             }
236 
237             bool empty() const @property
238             {
239                 import std.array;
240                 return array.empty;
241             }
242         }
243         return ArrayRangeWithoutLength!T(array);
244     }
245     shouldNotBeIn(3.5, [1.1, 2.2, 4.4]);
246     shouldNotBeIn(1.0, [2.0 : 1, 3.0 : 2]);
247     shouldNotBeIn(1, arrayRangeWithoutLength([2, 3, 4]));
248     assertFail(1.shouldNotBeIn(arrayRangeWithoutLength([1, 2, 3])));
249     assertFail("foo".shouldNotBeIn(["foo"]));
250 }
251 
252 @safe pure unittest {
253     import unit_threaded.asserts;
254     void funcThrows(string msg) { throw new Exception(msg); }
255     try {
256         auto exceptionInfo = funcThrows("foo bar").shouldThrow;
257         assertEqual(exceptionInfo.msg, "foo bar");
258     } catch(Exception e) {
259         assert(false, "should not have thrown anything and threw: " ~ e.msg);
260     }
261 }
262 
263 @safe pure unittest {
264     import unit_threaded.asserts;
265     void func() {}
266     try {
267         func.shouldThrow;
268         assert(false, "Should never get here");
269     } catch(Exception e)
270         assertEqual(e.msg, "Expression did not throw");
271 }
272 
273 @safe pure unittest {
274     import unit_threaded.asserts;
275     void funcAsserts() { assert(false, "Oh noes"); }
276     try {
277         funcAsserts.shouldThrow;
278         assert(false, "Should never get here");
279     } catch(Exception e)
280         assertEqual(e.msg,
281                     "Expression threw core.exception.AssertError instead of the expected Exception:\nOh noes");
282 }
283 
284 unittest {
285     void func() {}
286     func.shouldNotThrow;
287     void funcThrows() { throw new Exception("oops"); }
288     assertFail(shouldNotThrow(funcThrows));
289 }
290 
291 @safe pure unittest {
292     void funcThrows(string msg) { throw new Exception(msg); }
293     funcThrows("foo bar").shouldThrowWithMessage!Exception("foo bar");
294     funcThrows("foo bar").shouldThrowWithMessage("foo bar");
295     assertFail(funcThrows("boo boo").shouldThrowWithMessage("foo bar"));
296     void func() {}
297     assertFail(func.shouldThrowWithMessage("oops"));
298 }
299 
300 @("catch Throwables without compromising other safety checks")
301 unittest
302 {
303     int a  = 3;
304     void foo() @system { assert(a == 4); }
305     void bar() @safe { assert(a == 4); }
306     static assert(!__traits(compiles, () @safe => foo.shouldThrow!Throwable));
307     static assert(__traits(compiles, () => foo.shouldThrow!Throwable));
308     static assert(__traits(compiles, () @safe => bar.shouldThrow!Throwable));
309     static assert(__traits(compiles, () => bar.shouldThrow!Throwable));
310 }
311 
312 // can't be made pure because of throwExactly, which in turn
313 // can't be pure because of Object.opEquals
314 @safe unittest
315 {
316     class CustomException : Exception
317     {
318         this(string msg = "")
319         {
320             super(msg);
321         }
322     }
323 
324     class ChildException : CustomException
325     {
326         this(string msg = "")
327         {
328             super(msg);
329         }
330     }
331 
332     void throwCustom()
333     {
334         throw new CustomException();
335     }
336 
337     throwCustom.shouldThrow;
338     throwCustom.shouldThrow!CustomException;
339 
340     void throwChild()
341     {
342         throw new ChildException();
343     }
344 
345     throwChild.shouldThrow;
346     throwChild.shouldThrow!CustomException;
347     throwChild.shouldThrow!ChildException;
348     throwChild.shouldThrowExactly!ChildException;
349     try
350     {
351         throwChild.shouldThrowExactly!CustomException; //should not succeed
352         assert(0, "shouldThrowExactly failed");
353     }
354     catch (Exception ex)
355     {
356     }
357 
358     void doesntThrow() {}
359     assertFail(doesntThrow.shouldThrowExactly!Exception);
360 }
361 
362 @safe pure unittest
363 {
364     void throwRangeError()
365     {
366         ubyte[] bytes;
367         bytes = bytes[1 .. $];
368     }
369 
370     import core.exception : RangeError;
371 
372     throwRangeError.shouldThrow!RangeError;
373 }
374 
375 @safe pure unittest {
376     import std.stdio;
377 
378     import core.exception: OutOfMemoryError;
379 
380     class CustomException : Exception {
381         this(string msg = "", string file = __FILE__, in size_t line = __LINE__) { super(msg, file, line); }
382     }
383 
384     void func() { throw new CustomException("oh noes"); }
385 
386     func.shouldThrow!CustomException;
387     assertFail(func.shouldThrow!OutOfMemoryError);
388 }
389 
390 
391 unittest {
392     import unit_threaded.asserts;
393     class Foo {
394         override string toString() @safe pure nothrow const {
395             return "Foo";
396         }
397     }
398 
399     auto foo = new const Foo;
400     assertEqual(foo.convertToString, "Foo");
401 }
402 
403 @safe pure unittest {
404     assert(isEqual(1.0, 1.0));
405     assert(!isEqual(1.0, 1.0001));
406 }
407 
408 
409 @safe unittest {
410     1.0.shouldApproxEqual(1.0001);
411     1.0.shouldApproxEqual(1.0001, 1e-2, 1e-5);
412     assertFail(2.0.shouldApproxEqual(1.0));
413 }
414 
415 @safe pure unittest {
416     import std.conv: to;
417     import std.range: iota;
418 
419     assert(isEqual(2, 2));
420     assert(!isEqual(2, 3));
421 
422     assert(isEqual(2.1, 2.1));
423     assert(!isEqual(2.1, 2.2));
424 
425     assert(isEqual("foo", "foo"));
426     assert(!isEqual("foo", "fooo"));
427 
428     assert(isEqual([1, 2], [1, 2]));
429     assert(!isEqual([1, 2], [1, 2, 3]));
430 
431     assert(isEqual(iota(2), [0, 1]));
432     assert(!isEqual(iota(2), [1, 2, 3]));
433 
434     assert(isEqual([[0, 1], [0, 1, 2]], [iota(2), iota(3)]));
435     assert(isEqual([[0, 1], [0, 1, 2]], [[0, 1], [0, 1, 2]]));
436     assert(!isEqual([[0, 1], [0, 1, 4]], [iota(2), iota(3)]));
437     assert(!isEqual([[0, 1], [0]], [iota(2), iota(3)]));
438 
439     assert(isEqual([0: 1], [0: 1]));
440 
441     const constIntToInts = [1 : 2, 3 : 7, 9 : 345];
442     auto intToInts = [1 : 2, 3 : 7, 9 : 345];
443 
444     assert(isEqual(intToInts, constIntToInts));
445     assert(isEqual(constIntToInts, intToInts));
446 
447     class Foo
448     {
449         this(int i) { this.i = i; }
450         override string toString() const { return i.to!string; }
451         int i;
452     }
453 
454     assert(isEqual(new Foo(5), new Foo(5)));
455     assert(!isEqual(new Foo(5), new Foo(4)));
456 
457     ubyte[] arr;
458     ubyte[] empty;
459     assert(isEqual(arr, empty));
460 }
461 
462 @safe pure unittest
463 {
464     int[] ints;
465     string[] strings;
466     string[string] aa;
467 
468     shouldBeEmpty(ints);
469     shouldBeEmpty(strings);
470     shouldBeEmpty(aa);
471 
472     ints ~= 1;
473     strings ~= "foo";
474     aa["foo"] = "bar";
475 
476     assertFail(shouldBeEmpty(ints));
477     assertFail(shouldBeEmpty(strings));
478     assertFail(shouldBeEmpty(aa));
479 }
480 
481 
482 @safe pure unittest
483 {
484     int[] ints;
485     string[] strings;
486     string[string] aa;
487 
488     assertFail(shouldNotBeEmpty(ints));
489     assertFail(shouldNotBeEmpty(strings));
490     assertFail(shouldNotBeEmpty(aa));
491 
492     ints ~= 1;
493     strings ~= "foo";
494     aa["foo"] = "bar";
495 
496     shouldNotBeEmpty(ints);
497     shouldNotBeEmpty(strings);
498     shouldNotBeEmpty(aa);
499 }
500 
501 @safe pure unittest
502 {
503     shouldBeGreaterThan(7, 5);
504 }
505 
506 
507 @safe pure unittest
508 {
509     shouldBeSmallerThan(5, 7);
510     assertFail(shouldBeSmallerThan(7, 5));
511     assertFail(shouldBeSmallerThan(7, 7));
512 }
513 
514 @safe pure unittest {
515     "foo"w.shouldEqual("foo");
516 }
517 
518 @("Non-copyable types can be asserted on")
519 @safe pure unittest {
520 
521     struct Move {
522         int i;
523         @disable this(this);
524     }
525 
526     Move(5).shouldEqual(Move(5));
527 }
528 
529 @("issue 88")
530 @safe pure unittest {
531 
532     class C {
533         int foo;
534         override string toString() @safe pure nothrow const { return null; }
535     }
536 
537     C c = null;
538     c.shouldEqual(c);
539     C null_;
540     assertFail((new C).shouldEqual(null_));
541 }
542 
543 @("issue 89")
544 unittest {
545     class C {
546         override string toString() @safe pure nothrow const { return null; }
547     }
548 
549     auto actual = new C;
550     auto expected = new C;
551 
552     // these should both pass
553     actual.shouldEqual(expected);      // passes: actual.tupleof == expected.tupleof
554     [actual].shouldEqual([expected]);  // fails: actual != expected
555 }
556 
557 @("non-const toString should compile")
558 @safe pure unittest {
559     class C {
560         override string toString() @safe pure nothrow { return null; }
561     }
562     (new C).shouldEqual(new C);
563 }
564 
565 @safe pure unittest {
566     ['\xff'].shouldEqual(['\xff']);
567 }
568 
569 @safe unittest {
570     // Object.opEquals isn't scope and therefore not @safe
571     () @trusted {
572         shouldNotEqual(new Object, new Object);
573     }();
574 }
575 
576 
577 @("should ==")
578 @safe pure unittest {
579     1.should == 1;
580     2.should == 2;
581     assertFail(1.should == 2);
582     assertExceptionMsg(1.should == 2,
583                        `    tests/unit_threaded/ut/should.d:123 - Expected: 2` ~ "\n" ~
584                        `    tests/unit_threaded/ut/should.d:123 -      Got: 1`);
585 }
586 
587 @("should.be ==")
588 @safe pure unittest {
589     1.should.be == 1;
590     2.should.be == 2;
591     assertFail(1.should.be == 2);
592     assertExceptionMsg(1.should.be == 2,
593                        `    tests/unit_threaded/ut/should.d:123 - Expected: 2` ~ "\n" ~
594                        `    tests/unit_threaded/ut/should.d:123 -      Got: 1`);
595 }
596 
597 @("should.not ==")
598 @safe pure unittest {
599     1.should.not == 2;
600     assertFail(2.should.not == 2);
601 }
602 
603 @("should.not.be ==")
604 @safe pure unittest {
605     1.should.not.be == 2;
606     assertFail(2.should.not.be == 2);
607 }
608 
609 
610 @("should.be in")
611 @safe pure unittest {
612     1.should.be in [1, 2, 3];
613     2.should.be in [1, 2, 3];
614     3.should.be in [1, 2, 3];
615     assertFail(4.should.be in [1, 2, 3]);
616 }
617 
618 @("should.not.be in")
619 @safe pure unittest {
620     4.should.not.be in [1, 2, 3];
621     assertFail(1.should.not.be in [1, 2, 3]);
622 }
623 
624 @("should ~ for range")
625 @safe pure unittest {
626     [1, 2, 3].should ~ [3, 2, 1];
627     assertFail([1, 2, 3].should ~ [1, 2, 2]);
628 
629     [1, 2, 3].should.not ~ [1, 2, 2];
630     assertFail([1, 2, 3].should.not ~ [3, 2, 1]);
631     assertExceptionMsg([1, 2, 3].should.not ~ [3, 2, 1],
632         `    tests/unit_threaded/ut/should.d:123 - [1, 2, 3] should not be the same set as [3, 2, 1]`
633         );
634 }
635 
636 @("should ~ for float")
637 @safe unittest {
638     1.0.should ~ 1.0001;
639     assertFail(2.0.should ~ 1.0001);
640 
641     1.0.should.not ~ 2.0;
642     assertFail(1.0.should.not ~ 1.0001);
643     assertExceptionMsg(1.0.should.not ~ 1.0001,
644         `    tests/unit_threaded/ut/should.d:123 - 1 should not be approximately equal to 1.0001`
645         );
646 }
647 
648 
649 @("shouldBeBetween")
650 @safe pure unittest {
651     import std.datetime: seconds;
652 
653     5.shouldBeBetween(4, 6);
654     assertExceptionMsg(3.shouldBeBetween(4, 6),
655                        "    tests/unit_threaded/ut/should.d:123 - 3 is not between 4 and 6\n");
656     4.shouldBeBetween(4, 6);
657     assertFail(6.shouldBeBetween(4, 6));
658 
659     3.seconds.shouldBeBetween(2.seconds, 4.seconds);
660     assertFail(1.seconds.shouldBeBetween(2.seconds, 4.seconds));
661 }
662 
663 
664 @("shouldBeSameSetAs")
665 @safe pure unittest {
666     [1, 2, 3].shouldBeSameSetAs([2, 3, 1]);
667     [1, 2, 3].shouldBeSameSetAs([3, 2, 1]);
668     assertExceptionMsg([1, 2, 3].shouldBeSameSetAs([2, 1, 4]),
669                        `    tests/unit_threaded/ut/should.d:123 - Expected: [1, 2, 4]` ~ "\n" ~
670                        `    tests/unit_threaded/ut/should.d:123 -      Got: [1, 2, 3]`);
671 }