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 54 // can't be in the unit test itself 55 private class Class { 56 abstract int foo(int, string) @safe pure; 57 final int timesTwo(int i) @safe pure nothrow const { return i * 2; } 58 int timesThree(int i) @safe pure nothrow const { return i * 3; } 59 int timesThreeMutable(int i) @safe pure nothrow { return i * 3; } 60 } 61 62 @("mock class positive test") 63 @safe pure unittest { 64 65 int fun(Class f) { 66 return 2 * f.foo(5, "foobar"); 67 } 68 69 auto m = mock!Class; 70 m.expect!"foo"; 71 fun(m); 72 } 73 74 75 @("mock interface multiple calls") 76 @safe pure unittest { 77 interface Foo { 78 int foo(int, string) @safe pure; 79 int bar(int) @safe pure; 80 } 81 82 void fun(Foo f) { 83 f.foo(3, "foo"); 84 f.bar(5); 85 f.foo(4, "quux"); 86 } 87 88 auto m = mock!Foo; 89 m.expect!"foo"(3, "foo"); 90 m.expect!"bar"(5); 91 m.expect!"foo"(4, "quux"); 92 fun(m); 93 m.verify; 94 } 95 96 97 @("mock struct negative") 98 @safe pure unittest { 99 import unit_threaded.asserts; 100 101 auto m = mockStruct; 102 m.expect!"foobar"; 103 assertExceptionMsg(m.verify, 104 " tests/unit_threaded/ut/mock.d:123 - Expected nth 0 call to `foobar` did not happen\n"); 105 } 106 107 @("mock struct values negative") 108 @safe pure unittest { 109 import unit_threaded.asserts; 110 111 void fun(T)(T t) { 112 t.foobar(2, "quux"); 113 } 114 115 auto m = mockStruct; 116 m.expect!"foobar"(3, "quux"); 117 fun(m); 118 assertExceptionMsg(m.verify, 119 " tests/unit_threaded/ut/mock.d:123 - foobar was called with unexpected Tuple!(int, string)(2, \"quux\")\n" ~ 120 " tests/unit_threaded/ut/mock.d:123 - instead of the expected Tuple!(int, string)(3, \"quux\")"); 121 } 122 123 124 @("const(ubyte)[] return type]") 125 @safe pure unittest { 126 interface Interface { 127 const(ubyte)[] fun(); 128 } 129 130 auto m = mock!Interface; 131 } 132 133 @("safe pure nothrow") 134 @safe pure unittest { 135 interface Interface { 136 int twice(int i) @safe pure nothrow /*@nogc*/; 137 } 138 auto m = mock!Interface; 139 } 140 141 @("issue 63") 142 @safe pure unittest { 143 import unit_threaded.should; 144 145 interface InterfaceWithOverloads { 146 int func(int) @safe pure; 147 int func(string) @safe pure; 148 } 149 alias ov = Identity!(__traits(allMembers, InterfaceWithOverloads)[0]); 150 auto m = mock!InterfaceWithOverloads; 151 m.returnValue!(0, "func")(3); // int overload 152 m.returnValue!(1, "func")(7); // string overload 153 m.expect!"func"("foo"); 154 m.func("foo").shouldEqual(7); 155 m.verify; 156 } 157 158 private class FooException: Exception { 159 import std.exception: basicExceptionCtors; 160 mixin basicExceptionCtors; 161 } 162 163 164 @("throwStruct custom") 165 @safe pure unittest { 166 import unit_threaded.should: shouldThrow; 167 168 auto m = throwStruct!FooException; 169 m.foo.shouldThrow!FooException; 170 m.bar(1, "foo").shouldThrow!FooException; 171 } 172 173 174 @("throwStruct return value type") 175 @safe pure unittest { 176 import unit_threaded.asserts; 177 import unit_threaded.exception: UnitTestException; 178 auto m = throwStruct!(UnitTestException, int); 179 int i; 180 assertExceptionMsg(i = m.foo, 181 " tests/unit_threaded/ut/mock.d:123 - foo was called"); 182 assertExceptionMsg(i = m.bar, 183 " tests/unit_threaded/ut/mock.d:123 - bar was called"); 184 } 185 186 @("issue 68") 187 @safe pure unittest { 188 import unit_threaded.should; 189 190 int fun(Class f) { 191 // f.timesTwo is mocked to return 2, no matter what's passed in 192 return f.timesThreeMutable(2); 193 } 194 195 auto m = mock!Class; 196 m.expect!"timesThreeMutable"(2); 197 m.returnValue!("timesThreeMutable")(42); 198 fun(m).shouldEqual(42); 199 } 200 201 @("issue69") 202 unittest { 203 import unit_threaded.should; 204 205 static interface InterfaceWithOverloadedFuncs { 206 string over(); 207 string over(string str); 208 } 209 210 static class ClassWithOverloadedFuncs { 211 string over() { return "oops"; } 212 string over(string str) { return "oopsie"; } 213 } 214 215 auto iMock = mock!InterfaceWithOverloadedFuncs; 216 iMock.returnValue!(0, "over")("bar"); 217 iMock.returnValue!(1, "over")("baz"); 218 iMock.over.shouldEqual("bar"); 219 iMock.over("zing").shouldEqual("baz"); 220 221 auto cMock = mock!ClassWithOverloadedFuncs; 222 cMock.returnValue!(0, "over")("bar"); 223 cMock.returnValue!(1, "over")("baz"); 224 cMock.over.shouldEqual("bar"); 225 cMock.over("zing").shouldEqual("baz"); 226 } 227 228 229 /// 230 @("mock struct positive") 231 @safe pure unittest { 232 void fun(T)(T t) { 233 t.foobar; 234 } 235 auto m = mockStruct; 236 m.expect!"foobar"; 237 fun(m); 238 m.verify; 239 } 240 241 242 /// 243 @("mock struct values positive") 244 @safe pure unittest { 245 void fun(T)(T t) { 246 t.foobar(2, "quux"); 247 } 248 249 auto m = mockStruct; 250 m.expect!"foobar"(2, "quux"); 251 fun(m); 252 m.verify; 253 } 254 255 256 /// 257 @("struct return value") 258 @safe pure unittest { 259 260 int fun(T)(T f) { 261 return f.timesN(3) * 2; 262 } 263 264 auto m = mockStruct(42, 12); 265 assert(fun(m) == 84); 266 assert(fun(m) == 24); 267 assert(fun(m) == 0); 268 m.expectCalled!"timesN"; 269 } 270 271 /// 272 @("struct expectCalled") 273 @safe pure unittest { 274 void fun(T)(T t) { 275 t.foobar(2, "quux"); 276 } 277 278 auto m = mockStruct; 279 fun(m); 280 m.expectCalled!"foobar"(2, "quux"); 281 } 282 283 /// 284 @("mockStruct different return types for different functions") 285 @safe pure unittest { 286 auto m = mockStruct!(ReturnValues!("length", 5), 287 ReturnValues!("greet", "hello")); 288 assert(m.length == 5); 289 assert(m.greet("bar") == "hello"); 290 m.expectCalled!"length"; 291 m.expectCalled!"greet"("bar"); 292 } 293 294 /// 295 @("mockStruct different return types for different functions and multiple return values") 296 @safe pure unittest { 297 auto m = mockStruct!( 298 ReturnValues!("length", 5, 3), 299 ReturnValues!("greet", "hello", "g'day"), 300 ReturnValues!("list", [1, 2, 3]), 301 ); 302 303 assert(m.length == 5); 304 m.expectCalled!"length"; 305 assert(m.length == 3); 306 m.expectCalled!"length"; 307 308 assert(m.greet("bar") == "hello"); 309 m.expectCalled!"greet"("bar"); 310 assert(m.greet("quux") == "g'day"); 311 m.expectCalled!"greet"("quux"); 312 313 assertEqual(m.list, [1, 2, 3]); 314 } 315 316 317 /// 318 @("throwStruct default") 319 @safe pure unittest { 320 import std.exception: assertThrown; 321 import unit_threaded.exception: UnitTestException; 322 auto m = throwStruct; 323 assertThrown!UnitTestException(m.foo); 324 assertThrown!UnitTestException(m.bar(1, "foo")); 325 } 326 327 328 @("const mockStruct values") 329 @safe pure unittest { 330 const m = mockStruct(42); 331 assertEqual(m.length, 42); 332 assertEqual(m.length, 42); 333 } 334 335 336 @("const mockStruct ReturnValues") 337 @safe pure unittest { 338 const m = mockStruct!(ReturnValues!("length", 42)); 339 assertEqual(m.length, 42); 340 assertEqual(m.length, 42); 341 } 342 343 344 @("mockReturn") 345 @safe pure unittest { 346 auto m = mockStruct( 347 mockReturn!"length"(5, 3), 348 mockReturn!"greet"("hello", "g'day"), 349 mockReturn!"list"([1, 2, 3]), 350 ); 351 352 assert(m.length == 5); 353 m.expectCalled!"length"; 354 assertEqual(m.length, 3); 355 m.expectCalled!"length"; 356 357 assertEqual(m.greet("bar"), "hello"); 358 m.expectCalled!"greet"("bar"); 359 assertEqual(m.greet("quux"), "g'day"); 360 m.expectCalled!"greet"("quux"); 361 362 assertEqual(m.list, [1, 2, 3]); 363 } 364 365 366 @safe pure unittest { 367 368 static struct Cursor { 369 enum Kind { 370 StructDecl, 371 FieldDecl, 372 } 373 } 374 375 static struct Type { 376 enum Kind { 377 Int, 378 Double, 379 } 380 } 381 382 const cursor = mockStruct( 383 mockReturn!"kind"(Cursor.Kind.StructDecl), 384 mockReturn!"spelling"("Foo"), 385 mockReturn!"children"( 386 [ 387 mockStruct(mockReturn!("kind")(Cursor.Kind.FieldDecl), 388 mockReturn!"spelling"("i"), 389 mockReturn!("type")( 390 mockStruct( 391 mockReturn!"kind"(Type.Kind.Int), 392 mockReturn!"spelling"("int"), 393 ) 394 ) 395 ), 396 mockStruct(mockReturn!("kind")(Cursor.Kind.FieldDecl), 397 mockReturn!"spelling"("d"), 398 mockReturn!("type")( 399 mockStruct( 400 mockReturn!"kind"(Type.Kind.Double), 401 mockReturn!"spelling"("double"), 402 ) 403 ) 404 ), 405 ], 406 ), 407 ); 408 409 assertEqual(cursor.kind, Cursor.Kind.StructDecl); 410 assertEqual(cursor.spelling, "Foo"); 411 assertEqual(cursor.children.length, 2); 412 413 const i = cursor.children[0]; 414 assertEqual(i.kind, Cursor.Kind.FieldDecl); 415 assertEqual(i.spelling, "i"); 416 assertEqual(i.type.kind, Type.Kind.Int); 417 assertEqual(i.type.spelling, "int"); 418 419 const d = cursor.children[1]; 420 assertEqual(d.kind, Cursor.Kind.FieldDecl); 421 assertEqual(d.spelling, "d"); 422 assertEqual(d.type.kind, Type.Kind.Double); 423 assertEqual(d.type.spelling, "double"); 424 }