1 module shoul;
2 
3 import std.conv;
4 import std.stdio;
5 
6 public auto should(T)(T v)
7 {
8 	return Should!T(v);
9 }
10 
11 private struct Should(T)
12 {
13 	T actual;
14 	bool negative;
15 	this(T actual)
16 	{
17 		this.actual = actual;
18 	}
19 
20 	void opEquals(R)(const R other) const
21 	{
22 		assert(negative ^ (other == actual), text("expected - " ~ (negative ? "not " : ""), other, ", but got - ", actual));
23 	}
24 
25 	auto not()
26 	{
27 		this.negative = !this.negative;
28 		return this;
29 	}
30 
31 	void opBinary(string op, R)(const R rhs) const
32 	{
33 		static if (op == "in")
34 		{
35 			import std.algorithm : canFind;
36 
37 			static if (__traits(compiles, (actual in rhs)))
38 			{
39 				assert(negative ^ ((actual in rhs) != null), text("expected - ", actual, " in ", rhs));
40 			}
41 			else
42 			{
43 				assert(negative ^ canFind(rhs, actual), text("expected - ", actual, " in ", rhs));
44 			}
45 		}
46 		else
47 			static assert(0, "not supported op");
48 	}
49 
50 	void less(R)(R rhs)
51 	{
52 		assert(negative ^ (actual < rhs), text("expected - ", actual, " < ", rhs));
53 	}
54 
55 	void more(R)(R rhs)
56 	{
57 		assert(negative ^ (actual > rhs), text("expected - ", actual, " > ", rhs));
58 	}
59 }
60 
61 @("Equal") @should
62 unittest
63 {
64 	10.should == 10;
65 	10.should.not == 11;
66 	try
67 		10.should.not == 10;
68 	catch (Throwable e)
69 	{
70 	}
71 }
72 
73 @("In") @should
74 unittest
75 {
76 	10.should in [10, 11, 12];
77 	10.should.not in [11, 12, 13];
78 	try
79 		10.should.not in [10, 11, 12];
80 	catch (Throwable e)
81 	{
82 	}
83 	10.should in [10: 11, 12: 13];
84 	"Hello".should in "Hello World";
85 }
86 
87 @("Less") @should
88 unittest
89 {
90 	10.should.less = 11;
91 	10.should.not.less = 10;
92 	10.should.not.less = 9;
93 }
94 
95 @("more") @should
96 unittest
97 {
98 	10.should.more = 9;
99 	10.should.not.more = 10;
100 	10.should.not.more = 11;
101 }