1 module unit_threaded.ut.mock;
2 
3 
4 import unit_threaded.mock;
5 import unit_threaded.asserts;
6 
7 
8 @("mock interface verify fails")
9 @safe pure unittest {
10     import unit_threaded.asserts;
11 
12     interface Foo {
13         int foo(int, string) @safe pure;
14         void bar() @safe pure;
15     }
16 
17     int fun(Foo f) {
18         return 2 * f.foo(5, "foobar");
19     }
20 
21     {
22         auto m = mock!Foo;
23         m.expect!"foo"(6, "foobar");
24         fun(m);
25         assertExceptionMsg(m.verify,
26                            `    tests/unit_threaded/ut/mock.d:123 - foo was called with unexpected Tuple!(int, string)(5, "foobar")` ~ "\n" ~
27                            `    tests/unit_threaded/ut/mock.d:123 -        instead of the expected Tuple!(int, string)(6, "foobar")`);
28     }
29 
30     {
31         auto m = mock!Foo;
32         m.expect!"foo"(5, "quux");
33         fun(m);
34         assertExceptionMsg(m.verify,
35                            `    tests/unit_threaded/ut/mock.d:123 - foo was called with unexpected Tuple!(int, string)(5, "foobar")` ~ "\n" ~
36                            `    tests/unit_threaded/ut/mock.d:123 -        instead of the expected Tuple!(int, string)(5, "quux")`);
37     }
38 }
39 
40 @("mock interface negative test")
41 @safe pure unittest {
42     import unit_threaded.should;
43 
44     interface Foo {
45         int foo(int, string) @safe pure;
46     }
47 
48     auto m = mock!Foo;
49     m.expect!"foo";
50     m.verify.shouldThrowWithMessage("Expected nth 0 call to foo did not happen");
51 }
52 
53 // can't be in the unit test itself
54 private class Class {
55     abstract int foo(int, string) @safe pure;
56     final int timesTwo(int i) @safe pure nothrow const { return i * 2; }
57     int timesThree(int i) @safe pure nothrow const { return i * 3; }
58     int timesThreeMutable(int i) @safe pure nothrow { return i * 3; }
59 }
60 
61 @("mock class positive test")
62 @safe pure unittest {
63 
64     int fun(Class f) {
65         return 2 * f.foo(5, "foobar");
66     }
67 
68     auto m = mock!Class;
69     m.expect!"foo";
70     fun(m);
71 }
72 
73 
74 @("mock interface multiple calls")
75 @safe pure unittest {
76     interface Foo {
77         int foo(int, string) @safe pure;
78         int bar(int) @safe pure;
79     }
80 
81     void fun(Foo f) {
82         f.foo(3, "foo");
83         f.bar(5);
84         f.foo(4, "quux");
85     }
86 
87     auto m = mock!Foo;
88     m.expect!"foo"(3, "foo");
89     m.expect!"bar"(5);
90     m.expect!"foo"(4, "quux");
91     fun(m);
92     m.verify;
93 }
94 
95 @("mock struct negative")
96 @safe pure unittest {
97     import unit_threaded.asserts;
98 
99     auto m = mockStruct;
100     m.expect!"foobar";
101     assertExceptionMsg(m.verify,
102                        "    tests/unit_threaded/ut/mock.d:123 - Expected nth 0 call to foobar did not happen\n");
103 
104 }
105 
106 @("mock struct values negative")
107 @safe pure unittest {
108     import unit_threaded.asserts;
109 
110     void fun(T)(T t) {
111         t.foobar(2, "quux");
112     }
113 
114     auto m = mockStruct;
115     m.expect!"foobar"(3, "quux");
116     fun(m);
117     assertExceptionMsg(m.verify,
118                        "    tests/unit_threaded/ut/mock.d:123 - foobar was called with unexpected Tuple!(int, string)(2, \"quux\")\n" ~
119                        "    tests/unit_threaded/ut/mock.d:123 -           instead of the expected Tuple!(int, string)(3, \"quux\")");
120 }
121 
122 
123 @("const(ubyte)[] return type]")
124 @safe pure unittest {
125     interface Interface {
126         const(ubyte)[] fun();
127     }
128 
129     auto m = mock!Interface;
130 }
131 
132 @("safe pure nothrow")
133 @safe pure unittest {
134     interface Interface {
135         int twice(int i) @safe pure nothrow /*@nogc*/;
136     }
137     auto m = mock!Interface;
138 }
139 
140 @("issue 63")
141 @safe pure unittest {
142     import unit_threaded.should;
143 
144     interface InterfaceWithOverloads {
145         int func(int) @safe pure;
146         int func(string) @safe pure;
147     }
148     alias ov = Identity!(__traits(allMembers, InterfaceWithOverloads)[0]);
149     auto m = mock!InterfaceWithOverloads;
150     m.returnValue!(0, "func")(3); // int overload
151     m.returnValue!(1, "func")(7); // string overload
152     m.expect!"func"("foo");
153     m.func("foo").shouldEqual(7);
154     m.verify;
155 }
156 
157 private class FooException: Exception {
158     import std.exception: basicExceptionCtors;
159     mixin basicExceptionCtors;
160 }
161 
162 
163 @("throwStruct custom")
164 @safe pure unittest {
165     import unit_threaded.should: shouldThrow;
166 
167     auto m = throwStruct!FooException;
168     m.foo.shouldThrow!FooException;
169     m.bar(1, "foo").shouldThrow!FooException;
170 }
171 
172 
173 @("throwStruct return value type")
174 @safe pure unittest {
175     import unit_threaded.asserts;
176     import unit_threaded.exception: UnitTestException;
177     auto m = throwStruct!(UnitTestException, int);
178     int i;
179     assertExceptionMsg(i = m.foo,
180                        "    tests/unit_threaded/ut/mock.d:123 - foo was called");
181     assertExceptionMsg(i = m.bar,
182                        "    tests/unit_threaded/ut/mock.d:123 - bar was called");
183 }
184 
185 @("issue 68")
186 @safe pure unittest {
187     import unit_threaded.should;
188 
189     int fun(Class f) {
190         // f.timesTwo is mocked to return 2, no matter what's passed in
191         return f.timesThreeMutable(2);
192     }
193 
194     auto m = mock!Class;
195     m.expect!"timesThreeMutable"(2);
196     m.returnValue!("timesThreeMutable")(42);
197     fun(m).shouldEqual(42);
198 }
199 
200 @("issue69")
201 unittest {
202     import unit_threaded.should;
203 
204     static interface InterfaceWithOverloadedFuncs {
205         string over();
206         string over(string str);
207     }
208 
209     static class ClassWithOverloadedFuncs {
210         string over() { return "oops"; }
211         string over(string str) { return "oopsie"; }
212     }
213 
214     auto iMock = mock!InterfaceWithOverloadedFuncs;
215     iMock.returnValue!(0, "over")("bar");
216     iMock.returnValue!(1, "over")("baz");
217     iMock.over.shouldEqual("bar");
218     iMock.over("zing").shouldEqual("baz");
219 
220     auto cMock = mock!ClassWithOverloadedFuncs;
221     cMock.returnValue!(0, "over")("bar");
222     cMock.returnValue!(1, "over")("baz");
223     cMock.over.shouldEqual("bar");
224     cMock.over("zing").shouldEqual("baz");
225 }
226 
227 
228 ///
229 @("mock struct positive")
230 @safe pure unittest {
231     void fun(T)(T t) {
232         t.foobar;
233     }
234     auto m = mockStruct;
235     m.expect!"foobar";
236     fun(m);
237     m.verify;
238 }
239 
240 
241 ///
242 @("mock struct values positive")
243 @safe pure unittest {
244     void fun(T)(T t) {
245         t.foobar(2, "quux");
246     }
247 
248     auto m = mockStruct;
249     m.expect!"foobar"(2, "quux");
250     fun(m);
251     m.verify;
252 }
253 
254 
255 ///
256 @("struct return value")
257 @safe pure unittest {
258 
259     int fun(T)(T f) {
260         return f.timesN(3) * 2;
261     }
262 
263     auto m = mockStruct(42, 12);
264     assert(fun(m) == 84);
265     assert(fun(m) == 24);
266     assert(fun(m) == 0);
267     m.expectCalled!"timesN";
268 }
269 
270 ///
271 @("struct expectCalled")
272 @safe pure unittest {
273     void fun(T)(T t) {
274         t.foobar(2, "quux");
275     }
276 
277     auto m = mockStruct;
278     fun(m);
279     m.expectCalled!"foobar"(2, "quux");
280 }
281 
282 ///
283 @("mockStruct different return types for different functions")
284 @safe pure unittest {
285     auto m = mockStruct!(ReturnValues!("length", 5),
286                          ReturnValues!("greet", "hello"));
287     assert(m.length == 5);
288     assert(m.greet("bar") == "hello");
289     m.expectCalled!"length";
290     m.expectCalled!"greet"("bar");
291 }
292 
293 ///
294 @("mockStruct different return types for different functions and multiple return values")
295 @safe pure unittest {
296     auto m = mockStruct!(ReturnValues!("length", 5, 3),
297                          ReturnValues!("greet", "hello", "g'day"));
298     assert(m.length == 5);
299     m.expectCalled!"length";
300     assert(m.length == 3);
301     m.expectCalled!"length";
302 
303     assert(m.greet("bar") == "hello");
304     m.expectCalled!"greet"("bar");
305     assert(m.greet("quux") == "g'day");
306     m.expectCalled!"greet"("quux");
307 }
308 
309 
310 ///
311 @("throwStruct default")
312 @safe pure unittest {
313     import std.exception: assertThrown;
314     import unit_threaded.exception: UnitTestException;
315     auto m = throwStruct;
316     assertThrown!UnitTestException(m.foo);
317     assertThrown!UnitTestException(m.bar(1, "foo"));
318 }
319 
320 
321 @("const mockStruct values")
322 @safe pure unittest {
323     const m = mockStruct(42);
324     assertEqual(m.length, 42);
325     assertEqual(m.length, 42);
326 }
327 
328 
329 @("const mockStruct ReturnValues")
330 @safe pure unittest {
331     const m = mockStruct!(ReturnValues!("length", 42));
332     assertEqual(m.length, 42);
333     assertEqual(m.length, 42);
334 }