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