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 }