1 module mocked.tests.expectations;
2 
3 import dshould;
4 import dshould.ShouldType;
5 import mocked;
6 import unit_threaded : ShouldFail;
7 
8 void startWith(Should, T)(Should should, T expected,
9         Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__)
10 if (isInstanceOf!(ShouldType, Should))
11 {
12     auto got = should.got;
13     should.check(got.startsWith(expected), expected, got, file, line);
14 }
15 
16 @ShouldFail("if an expected method hasn't been called")
17 unittest
18 {
19     static class Dependency
20     {
21         string say(string phrase)
22         {
23             return phrase;
24         }
25     }
26     with (Mocker())
27     {
28         auto dependency = mock!Dependency;
29 
30         dependency.expect.say("Man geht zu Grunde,")
31             .returns("wenn man immer zu den Gründen geht.");
32     }
33 }
34 
35 @("repeats expectations infinitely")
36 unittest
37 {
38     enum expected = "Piscis primum a capite foetat";
39 
40     Mocker mocker;
41 
42     auto mock = mocker.mock!Object;
43 
44     mock.expect.toString().returns(expected).repeatAny;
45 
46     Object object = mock.get;
47 
48     object.toString.should.equal(expected);
49     object.toString.should.equal(expected);
50 
51     mocker.verify;
52 }
53 
54 @("prints arguments in the unexpected call error message")
55 unittest
56 {
57     static class Dependency
58     {
59         void say(string phrase1, string phrase2)
60         {
61         }
62     }
63     Mocker mocker;
64 
65     auto mock = mocker.mock!Dependency.get;
66 
67     mock.say("Ton der Jugend", "zu laut.")
68         .should.throwAn!UnexpectedCallError
69         .where.msg.should.be(`Unexpected call: Dependency.say("Ton der Jugend", "zu laut.")`);
70 }
71 
72 @("throws once")
73 unittest
74 {
75     static class Dependency
76     {
77         void say(string phrase)
78         {
79         }
80     }
81     Mocker mocker;
82 
83     auto mock = mocker.mock!Dependency;
84 
85     mock.expect.say("Die Ängstlichkeit vergiftet die Seele.").repeat(2);
86 
87     mocker.verify.should.throwAn!ExpectationViolationException;
88     mocker.verify.should.not.throwAn!ExpectationViolationException;
89 }
90 
91 @("gives multiline error messages on mismatched arguments")
92 unittest
93 {
94     static class Dependency
95     {
96         void say(string phrase)
97         {
98         }
99     }
100     Mocker mocker;
101 
102     auto mock = mocker.mock!Dependency;
103 
104     mock.expect.say("Let's eat, grandma!").repeat(2);
105 
106     mock.say("Let's eat grandma!")
107         .should.throwAn!UnexpectedArgumentError
108         .where.msg.should.be("Expectation failure:
109   Expected: Dependency.say(\"Let's eat, grandma!\")
110   but got:  Dependency.say(\"Let's eat grandma!\")");
111 }
112 
113 @("verify prints what method was expected")
114 unittest
115 {
116     enum string phrase = "Täglich erstaune ich: ich kenne mich selber nicht!";
117     static class Dependency
118     {
119         void say(string)
120         {
121         }
122     }
123     Mocker mocker;
124 
125     auto mock = mocker.mock!Dependency;
126 
127     mock.expect.say(phrase);
128 
129     mocker.verify
130         .should.throwAn!ExpectationViolationException
131         .where.msg.should.be(`Expected method not called: Dependency.say("` ~ phrase ~ `")`);
132 }
133 
134 @("verify prints what method was expected for ints")
135 unittest
136 {
137     static class Dependency
138     {
139         void say(int)
140         {
141         }
142     }
143     Mocker mocker;
144 
145     auto mock = mocker.mock!Dependency;
146 
147     mock.expect.say(5);
148 
149     mocker.verify
150         .should.throwAn!ExpectationViolationException
151         .where.msg.should.be(`Expected method not called: Dependency.say(5)`);
152 }
153 
154 @("allows to pick the overload without specifying the arguments")
155 unittest
156 {
157     enum string expected = "ad nullius rei essentiam pertinet existentia";
158     static class Dependency
159     {
160         string show(bool x)
161         {
162             return x ? "true" : "false";
163         }
164 
165         string show(string x)
166         {
167             return x;
168         }
169     }
170     Mocker mocker;
171 
172     auto mock = mocker.mock!Dependency;
173 
174     mock.expect.show!string.returns(expected);
175 
176     auto dependency = mock.get;
177 
178     dependency.show(null).should.equal(expected);
179 }
180 
181 @("allows to pick the overload without specifying the arguments")
182 unittest
183 {
184     static class Dependency
185     {
186         void show(string, string)
187         {
188         }
189     }
190     Mocker mocker;
191     auto mock = mocker.mock!Dependency;
192 
193     static assert(!is(typeof(mock.expect.show!string)));
194 }
195 
196 @("skips private overloads")
197 unittest
198 {
199     static class Dependency
200     {
201         void handle(string)
202         {
203         }
204 
205         private void handle(int)
206         {
207         }
208     }
209     Mocker mocker;
210     static assert(is(typeof(mocker.mock!Dependency())));
211 }
212 
213 @("picks public overload")
214 unittest
215 {
216     static class Dependency
217     {
218         private void handle(int)
219         {
220         }
221 
222         void handle(string)
223         {
224         }
225     }
226     Mocker mocker;
227     auto builder = mocker.mock!Dependency();
228 
229     builder.expect.handle("In vino veritas");
230 
231     builder.get.handle("In vino veritas");
232 }
233 
234 @("lets .repeatAny() do a forward lookup")
235 unittest
236 {
237     static class Dependency
238     {
239         string finishQuote(string phrase)
240         {
241             return phrase;
242         }
243     }
244     Mocker mocker;
245     auto mock = mocker.mock!Dependency;
246 
247     mock.expect
248         .finishQuote("Ducunt volentem fata,")
249         .returns("nolentem trahunt")
250         .repeatAny;
251     mock.expect.finishQuote("Seneca").returns("epistulae");
252 
253     mock.get.finishQuote("Seneca").should.equal("epistulae");
254 }
255 
256 @ShouldFail("if functions are called not in the given order")
257 unittest
258 {
259     static class Dependency
260     {
261         void callFirst()
262         {
263         }
264 
265         void callSecond()
266         {
267         }
268     }
269     Mocker mocker;
270     auto mock = mocker.mock!Dependency;
271 
272     mock.expect.callFirst;
273     mock.expect.callSecond;
274 
275     mock.get.callSecond;
276     mock.get.callFirst;
277 }
278 
279 @("supports const method")
280 unittest
281 {
282     static class Dependency
283     {
284         void act() const
285         {
286         }
287     }
288     Mocker mocker;
289     auto builder = mocker.mock!Dependency();
290 
291     builder.expect.act;
292 
293     builder.act;
294 }
295 
296 @("works with Nullables")
297 unittest
298 {
299     import std.typecons : Nullable, nullable;
300 
301     static class Dependency
302     {
303         void say(Nullable!string phrase)
304         {
305         }
306     }
307     with (Mocker())
308     {
309         auto dependency = mock!Dependency;
310         auto expected = nullable("procul, o procul...");
311 
312         dependency.expect.say(nullable("procul, o procul..."));
313 
314         dependency.say(Nullable!string())
315             .should.throwAn!UnexpectedArgumentError;
316     }
317 }
318 
319 @("allows functions to be called not in the given order")
320 unittest
321 {
322     static class Dependency
323     {
324         void callFirst(int)
325         {
326         }
327     }
328     Mocker mocker;
329     auto mock = mocker.mock!Dependency.unordered;
330 
331     mock.expect.callFirst(1);
332     mock.expect.callFirst(2);
333 
334     mock.get.callFirst(2);
335     mock.get.callFirst(1);
336 }