1 module unit_threaded.ut.reflection; 2 3 import unit_threaded.runner.reflection; 4 import unit_threaded.ut.modules.module_with_tests; //defines tests and non-tests 5 import unit_threaded.asserts; 6 import std.algorithm; 7 import std.array; 8 9 //helper function for the unittest blocks below 10 private auto addModPrefix(string[] elements, 11 string module_ = "unit_threaded.ut.modules.module_with_tests") nothrow { 12 return elements.map!(a => module_ ~ "." ~ a).array; 13 } 14 15 16 unittest { 17 const expected = addModPrefix([ "FooTest", "BarTest", "Blergh", "Issue83"]); 18 const actual = moduleTestClasses!(unit_threaded.ut.modules.module_with_tests). 19 map!(a => a.name).array; 20 assertEqual(actual, expected); 21 } 22 23 unittest { 24 import std.algorithm: sorted = sort; 25 26 const expected = addModPrefix( 27 [ 28 "testFoo", 29 "testBar", 30 "funcThatShouldShowUpCosOfAttr", 31 "this is my successful test name", 32 "this is my unsuccessful test name", 33 ] 34 ).sorted.array; 35 const actual = moduleTestFunctions!(unit_threaded.ut.modules.module_with_tests). 36 map!(a => a.getPath).array.sorted.array; 37 38 assertEqual(actual, expected); 39 } 40 41 42 unittest { 43 import std.algorithm: sorted = sort; 44 45 const expected = addModPrefix( 46 [ 47 "myUnitTest", 48 "StructWithUnitTests.InStruct", 49 "StructWithUnitTests.unittest_L65_C5", 50 "unittest_L43", 51 "unittest_L48", 52 ] 53 ).sorted.array; 54 const actual = moduleUnitTests!(unit_threaded.ut.modules.module_with_tests). 55 map!(a => a.name).array.sorted.array; 56 57 assertEqual(actual, expected); 58 } 59 60 version(unittest) { 61 import unit_threaded.runner.testcase: TestCase; 62 private void assertFail(TestCase test, string file = __FILE__, size_t line = __LINE__) { 63 import core.exception; 64 import std.conv; 65 66 test.silence; 67 assert(test() != [], 68 file ~ ":" ~ line.to!string ~ " Expected test case " ~ test.getPath ~ 69 " to fail but it didn't"); 70 } 71 72 private void assertPass(TestCase test, string file = __FILE__, size_t line = __LINE__) { 73 import unit_threaded.should: fail; 74 if(test() != []) 75 fail("'" ~ test.getPath ~ "' was expected to pass but failed", file, line); 76 } 77 } 78 79 @("Test that parametrized value tests work") 80 unittest { 81 import unit_threaded.runner.factory; 82 import unit_threaded.runner.testcase; 83 import unit_threaded.ut.modules.parametrized; 84 85 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 86 filter!(a => a.name.endsWith("testValues")).array; 87 88 auto tests = createTestCases(testData); 89 assertEqual(tests.length, 3); 90 91 // the first and third test should pass, the second should fail 92 assertPass(tests[0]); 93 assertPass(tests[2]); 94 95 assertFail(tests[1]); 96 } 97 98 99 @("Test that parametrized type tests work") 100 unittest { 101 import unit_threaded.runner.factory; 102 import unit_threaded.runner.testcase; 103 import unit_threaded.ut.modules.parametrized; 104 105 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 106 filter!(a => a.name.endsWith("testTypes")).array; 107 const expected = addModPrefix(["testTypes.float", "testTypes.int"], 108 "unit_threaded.ut.modules.parametrized"); 109 const actual = testData.map!(a => a.getPath).array; 110 assertEqual(actual, expected); 111 112 auto tests = createTestCases(testData); 113 assertEqual(tests.map!(a => a.getPath).array, expected); 114 115 assertPass(tests[1]); 116 assertFail(tests[0]); 117 } 118 119 120 @("Test that parametrized type tests work with @Name") 121 unittest { 122 import unit_threaded.runner.factory; 123 import unit_threaded.runner.testcase; 124 import unit_threaded.ut.modules.parametrized; 125 126 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 127 filter!(a => a.name.canFind("my_name_is_test")).array; 128 const expected = addModPrefix(["my_name_is_test.float", "my_name_is_test.int"], 129 "unit_threaded.ut.modules.parametrized"); 130 const actual = testData.map!(a => a.getPath).array; 131 assertEqual(actual, expected); 132 133 auto tests = createTestCases(testData); 134 assertEqual(tests.map!(a => a.getPath).array, expected); 135 136 assertPass(tests[1]); 137 assertFail(tests[0]); 138 } 139 140 141 @("Value parametrized built-in unittests") 142 unittest { 143 import unit_threaded.runner.factory; 144 import unit_threaded.runner.testcase; 145 import unit_threaded.ut.modules.parametrized; 146 147 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 148 filter!(a => a.name.canFind("builtinIntValues")).array; 149 150 auto tests = createTestCases(testData); 151 assertEqual(tests.length, 4); 152 153 // these should be ok 154 assertPass(tests[1]); 155 156 //these should fail 157 assertFail(tests[0]); 158 assertFail(tests[2]); 159 assertFail(tests[3]); 160 } 161 162 163 @("Tests can be selected by tags") unittest { 164 import unit_threaded.runner.factory; 165 import unit_threaded.runner.testcase; 166 import unit_threaded.ut.modules.tags; 167 168 const testData = allTestData!(unit_threaded.ut.modules.tags).array; 169 auto testsNoTags = createTestCases(testData); 170 assertEqual(testsNoTags.length, 4); 171 assertPass(testsNoTags.find!(a => a.getPath.canFind("unittest_L6")).front); 172 assertFail(testsNoTags.find!(a => a.getPath.canFind("unittest_L8")).front); 173 assertPass(testsNoTags.find!(a => a.getPath.canFind("testMake")).front); 174 assertFail(testsNoTags.find!(a => a.getPath.canFind("unittest_L22")).front); 175 176 auto testsNinja = createTestCases(testData, ["@ninja"]); 177 assertEqual(testsNinja.length, 1); 178 assertPass(testsNinja[0]); 179 180 auto testsMake = createTestCases(testData, ["@make"]); 181 assertEqual(testsMake.length, 3); 182 assertPass(testsMake.find!(a => a.getPath.canFind("testMake")).front); 183 assertPass(testsMake.find!(a => a.getPath.canFind("unittest_L6")).front); 184 assertFail(testsMake.find!(a => a.getPath.canFind("unittest_L22")).front); 185 186 auto testsNotNinja = createTestCases(testData, ["~@ninja"]); 187 assertEqual(testsNotNinja.length, 3); 188 assertPass(testsNotNinja.find!(a => a.getPath.canFind("testMake")).front); 189 assertFail(testsNotNinja.find!(a => a.getPath.canFind("unittest_L8")).front); 190 assertFail(testsNotNinja.find!(a => a.getPath.canFind("unittest_L22")).front); 191 192 assertEqual(createTestCases(testData, ["unit_threaded.ut.modules.tags.testMake", "@ninja"]).length, 0); 193 194 } 195 196 @("Parametrized built-in tests with @AutoTags get tagged by value") 197 unittest { 198 import unit_threaded.runner.factory; 199 import unit_threaded.runner.testcase; 200 import unit_threaded.ut.modules.parametrized; 201 202 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 203 filter!(a => a.name.canFind("builtinIntValues")).array; 204 205 auto two = createTestCases(testData, ["@2"]); 206 207 assertEqual(two.length, 1); 208 assertFail(two[0]); 209 210 auto three = createTestCases(testData, ["@3"]); 211 assertEqual(three.length, 1); 212 assertPass(three[0]); 213 } 214 215 @("Value parametrized function tests with @AutoTags get tagged by value") 216 unittest { 217 import unit_threaded.runner.factory; 218 import unit_threaded.runner.testcase; 219 import unit_threaded.ut.modules.parametrized; 220 221 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 222 filter!(a => a.name.canFind("testValues")).array; 223 224 auto two = createTestCases(testData, ["@2"]); 225 assertEqual(two.length, 1); 226 assertFail(two[0]); 227 } 228 229 @("Type parameterized tests with @AutoTags get tagged by type") 230 unittest { 231 import unit_threaded.runner.factory; 232 import unit_threaded.runner.testcase; 233 import unit_threaded.ut.modules.parametrized; 234 235 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 236 filter!(a => a.name.canFind("testTypes")).array; 237 238 auto tests = createTestCases(testData, ["@int"]); 239 assertEqual(tests.length, 1); 240 assertPass(tests[0]); 241 } 242 243 @("Cartesian parameterized built-in values") unittest { 244 import unit_threaded.runner.factory; 245 import unit_threaded.runner.testcase; 246 import unit_threaded.should: shouldBeSameSetAs; 247 import unit_threaded.ut.modules.parametrized; 248 import unit_threaded.runner.attrs: getValue; 249 250 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 251 filter!(a => a.name.canFind("cartesianBuiltinNoAutoTags")).array; 252 253 auto tests = createTestCases(testData); 254 tests.map!(a => a.getPath).array.shouldBeSameSetAs( 255 addModPrefix(["foo.red", "foo.blue", "foo.green", "bar.red", "bar.blue", "bar.green"]. 256 map!(a => "cartesianBuiltinNoAutoTags." ~ a).array, 257 "unit_threaded.ut.modules.parametrized")); 258 assertEqual(tests.length, 6); 259 260 auto fooRed = tests.find!(a => a.getPath.canFind("foo.red")).front; 261 assertPass(fooRed); 262 assertEqual(getValue!(string, 0), "foo"); 263 assertEqual(getValue!(string, 1), "red"); 264 assertEqual(testData.find!(a => a.getPath.canFind("foo.red")).front.tags, []); 265 266 auto barGreen = tests.find!(a => a.getPath.canFind("bar.green")).front; 267 assertFail(barGreen); 268 assertEqual(getValue!(string, 0), "bar"); 269 assertEqual(getValue!(string, 1), "green"); 270 271 assertEqual(testData.find!(a => a.getPath.canFind("bar.green")).front.tags, []); 272 assertEqual(allTestData!(unit_threaded.ut.modules.parametrized). 273 filter!(a => a.name.canFind("cartesianBuiltinAutoTags")).array. 274 find!(a => a.getPath.canFind("bar.green")).front.tags, 275 ["bar", "green"]); 276 } 277 278 @("Cartesian parameterized function values") unittest { 279 import unit_threaded.runner.factory; 280 import unit_threaded.runner.testcase; 281 import unit_threaded.should: shouldBeSameSetAs; 282 283 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 284 filter!(a => a.name.canFind("CartesianFunction")).array; 285 286 auto tests = createTestCases(testData); 287 tests.map!(a => a.getPath).array.shouldBeSameSetAs( 288 addModPrefix(["1.foo", "1.bar", "2.foo", "2.bar", "3.foo", "3.bar"]. 289 map!(a => "testCartesianFunction." ~ a).array, 290 "unit_threaded.ut.modules.parametrized")); 291 292 foreach(test; tests) { 293 test.getPath.canFind("2.bar") 294 ? assertPass(test) 295 : assertFail(test); 296 } 297 298 assertEqual(testData.find!(a => a.getPath.canFind("2.bar")).front.tags, 299 ["2", "bar"]); 300 } 301 302 303 @("Cartesian types") unittest { 304 import unit_threaded.runner.factory; 305 import unit_threaded.runner.testcase; 306 import unit_threaded.should: shouldBeSameSetAs; 307 import unit_threaded.ut.modules.parametrized; 308 import unit_threaded.runner.attrs: getValue; 309 310 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 311 filter!(a => a.name.canFind("cartesian_types")).array; 312 assertEqual(testData.length, 6); 313 314 auto tests = createTestCases(testData); 315 tests.map!(a => a.getPath).array.shouldBeSameSetAs( 316 addModPrefix(["int.string", "int.Foo", "int.Bar", "float.string", "float.Foo", "float.Bar"]. 317 map!(a => "cartesian_types." ~ a).array, 318 "unit_threaded.ut.modules.parametrized")); 319 assertEqual(tests.length, 6); 320 321 auto intFoo = tests.find!(a => a.getPath.canFind("int.Foo")).front; 322 assertPass(intFoo); 323 324 auto floatString = tests.find!(a => a.getPath.canFind("float.string")).front; 325 assertFail(floatString); 326 } 327 328 329 @("module setup and shutdown") 330 unittest { 331 import unit_threaded.runner.testcase; 332 import unit_threaded.runner.factory; 333 import unit_threaded.ut.modules.module_with_setup: gNumBefore, gNumAfter; 334 335 const testData = allTestData!"unit_threaded.ut.modules.module_with_setup".array; 336 auto tests = createTestCases(testData); 337 assertEqual(tests.length, 2); 338 339 assertPass(tests[0]); 340 assertEqual(gNumBefore, 1); 341 assertEqual(gNumAfter, 1); 342 343 assertFail(tests[1]); 344 assertEqual(gNumBefore, 2); 345 assertEqual(gNumAfter, 2); 346 } 347 348 @("issue 33") unittest { 349 import unit_threaded.runner.factory; 350 import unit_threaded.runner.testcase; 351 352 const testData = allTestData!"unit_threaded.ut.modules.issue33"; 353 assertEqual(testData.length, 1); 354 } 355 356 @("issue 43") unittest { 357 import unit_threaded.runner.factory; 358 import unit_threaded.asserts; 359 import unit_threaded.ut.modules.module_with_tests; 360 import std.algorithm: canFind; 361 import std.array: array; 362 363 const testData = allTestData!"unit_threaded.ut.modules.module_with_tests"; 364 assertEqual(testData.canFind!(a => a.getPath.canFind("InStruct" )), true); 365 auto inStructTest = testData 366 .find!(a => a.getPath.canFind("InStruct")) 367 .array 368 .createTestCases[0]; 369 assertFail(inStructTest); 370 } 371 372 @("@DontTest should work for unittest blocks") unittest { 373 import unit_threaded.runner.factory; 374 import unit_threaded.asserts; 375 import unit_threaded.ut.modules.module_with_tests; 376 import std.algorithm: canFind; 377 import std.array: array; 378 379 const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs"; 380 assertEqual(testData.canFind!(a => a.getPath.canFind("DontTestBlock" )), false); 381 } 382 383 @("@ShouldFail") unittest { 384 import unit_threaded.runner.factory; 385 import unit_threaded.asserts; 386 import unit_threaded.ut.modules.module_with_tests; 387 import std.algorithm: find, canFind; 388 import std.array: array; 389 390 const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs"; 391 392 auto willFail = testData 393 .filter!(a => a.getPath.canFind("will fail")) 394 .array 395 .createTestCases[0]; 396 assertPass(willFail); 397 } 398 399 400 @("@ShouldFailWith") unittest { 401 import unit_threaded.runner.factory; 402 import unit_threaded.asserts; 403 import unit_threaded.ut.modules.module_with_attrs; 404 import std.algorithm: find, canFind; 405 import std.array: array; 406 407 const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs"; 408 409 auto doesntFail = testData 410 .filter!(a => a.getPath.canFind("ShouldFailWith that fails due to not failing")) 411 .array 412 .createTestCases[0]; 413 assertFail(doesntFail); 414 415 auto wrongType = testData 416 .find!(a => a.getPath.canFind("ShouldFailWith that fails due to wrong type")) 417 .array 418 .createTestCases[0]; 419 assertFail(wrongType); 420 421 auto passes = testData 422 .find!(a => a.getPath.canFind("ShouldFailWith that passes")) 423 .array 424 .createTestCases[0]; 425 assertPass(passes); 426 } 427 428 @("structs are not classes") unittest { 429 import unit_threaded.should; 430 import unit_threaded.ut.modules.structs_are_not_classes; 431 const testData = allTestData!"unit_threaded.ut.modules.structs_are_not_classes"; 432 testData.shouldBeEmpty; 433 } 434 435 @("@Flaky") unittest { 436 import unit_threaded.runner.factory; 437 import unit_threaded.asserts; 438 import unit_threaded.ut.modules.module_with_attrs; 439 import std.algorithm: find, canFind; 440 import std.array: array; 441 442 const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs"; 443 444 auto flakyPasses = testData 445 .filter!(a => a.getPath.canFind("flaky that passes eventually")) 446 .array 447 .createTestCases[0]; 448 assertPass(flakyPasses); 449 450 auto flakyFails = testData 451 .filter!(a => a.getPath.canFind("flaky that fails due to not enough retries")) 452 .array 453 .createTestCases[0]; 454 assertFail(flakyFails); 455 } 456 457 @("mixin") unittest { 458 import unit_threaded.runner.factory; 459 import unit_threaded.asserts; 460 import unit_threaded.ut.modules.module_with_tests; 461 import std.algorithm: canFind; 462 import std.array: array; 463 464 const testData = allTestData!"unit_threaded.ut.modules.module_with_tests"; 465 466 auto failingMixinTest = testData 467 .find!(a => a.getPath.canFind("this is my unsuccessful test name")) 468 .array 469 .createTestCases[0]; 470 assertFail(failingMixinTest); 471 }