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 @("Value parametrized built-in unittests") 120 unittest { 121 import unit_threaded.runner.factory; 122 import unit_threaded.runner.testcase; 123 import unit_threaded.ut.modules.parametrized; 124 125 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 126 filter!(a => a.name.canFind("builtinIntValues")).array; 127 128 auto tests = createTestCases(testData); 129 assertEqual(tests.length, 4); 130 131 // these should be ok 132 assertPass(tests[1]); 133 134 //these should fail 135 assertFail(tests[0]); 136 assertFail(tests[2]); 137 assertFail(tests[3]); 138 } 139 140 141 @("Tests can be selected by tags") unittest { 142 import unit_threaded.runner.factory; 143 import unit_threaded.runner.testcase; 144 import unit_threaded.ut.modules.tags; 145 146 const testData = allTestData!(unit_threaded.ut.modules.tags).array; 147 auto testsNoTags = createTestCases(testData); 148 assertEqual(testsNoTags.length, 4); 149 assertPass(testsNoTags.find!(a => a.getPath.canFind("unittest_L6")).front); 150 assertFail(testsNoTags.find!(a => a.getPath.canFind("unittest_L8")).front); 151 assertPass(testsNoTags.find!(a => a.getPath.canFind("testMake")).front); 152 assertFail(testsNoTags.find!(a => a.getPath.canFind("unittest_L22")).front); 153 154 auto testsNinja = createTestCases(testData, ["@ninja"]); 155 assertEqual(testsNinja.length, 1); 156 assertPass(testsNinja[0]); 157 158 auto testsMake = createTestCases(testData, ["@make"]); 159 assertEqual(testsMake.length, 3); 160 assertPass(testsMake.find!(a => a.getPath.canFind("testMake")).front); 161 assertPass(testsMake.find!(a => a.getPath.canFind("unittest_L6")).front); 162 assertFail(testsMake.find!(a => a.getPath.canFind("unittest_L22")).front); 163 164 auto testsNotNinja = createTestCases(testData, ["~@ninja"]); 165 assertEqual(testsNotNinja.length, 3); 166 assertPass(testsNotNinja.find!(a => a.getPath.canFind("testMake")).front); 167 assertFail(testsNotNinja.find!(a => a.getPath.canFind("unittest_L8")).front); 168 assertFail(testsNotNinja.find!(a => a.getPath.canFind("unittest_L22")).front); 169 170 assertEqual(createTestCases(testData, ["unit_threaded.ut.modules.tags.testMake", "@ninja"]).length, 0); 171 172 } 173 174 @("Parametrized built-in tests with @AutoTags get tagged by value") 175 unittest { 176 import unit_threaded.runner.factory; 177 import unit_threaded.runner.testcase; 178 import unit_threaded.ut.modules.parametrized; 179 180 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 181 filter!(a => a.name.canFind("builtinIntValues")).array; 182 183 auto two = createTestCases(testData, ["@2"]); 184 185 assertEqual(two.length, 1); 186 assertFail(two[0]); 187 188 auto three = createTestCases(testData, ["@3"]); 189 assertEqual(three.length, 1); 190 assertPass(three[0]); 191 } 192 193 @("Value parametrized function tests with @AutoTags get tagged by value") 194 unittest { 195 import unit_threaded.runner.factory; 196 import unit_threaded.runner.testcase; 197 import unit_threaded.ut.modules.parametrized; 198 199 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 200 filter!(a => a.name.canFind("testValues")).array; 201 202 auto two = createTestCases(testData, ["@2"]); 203 assertEqual(two.length, 1); 204 assertFail(two[0]); 205 } 206 207 @("Type parameterized tests with @AutoTags get tagged by type") 208 unittest { 209 import unit_threaded.runner.factory; 210 import unit_threaded.runner.testcase; 211 import unit_threaded.ut.modules.parametrized; 212 213 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 214 filter!(a => a.name.canFind("testTypes")).array; 215 216 auto tests = createTestCases(testData, ["@int"]); 217 assertEqual(tests.length, 1); 218 assertPass(tests[0]); 219 } 220 221 @("Cartesian parameterized built-in values") unittest { 222 import unit_threaded.runner.factory; 223 import unit_threaded.runner.testcase; 224 import unit_threaded.should: shouldBeSameSetAs; 225 import unit_threaded.ut.modules.parametrized; 226 import unit_threaded.runner.attrs: getValue; 227 228 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 229 filter!(a => a.name.canFind("cartesianBuiltinNoAutoTags")).array; 230 231 auto tests = createTestCases(testData); 232 tests.map!(a => a.getPath).array.shouldBeSameSetAs( 233 addModPrefix(["foo.red", "foo.blue", "foo.green", "bar.red", "bar.blue", "bar.green"]. 234 map!(a => "cartesianBuiltinNoAutoTags." ~ a).array, 235 "unit_threaded.ut.modules.parametrized")); 236 assertEqual(tests.length, 6); 237 238 auto fooRed = tests.find!(a => a.getPath.canFind("foo.red")).front; 239 assertPass(fooRed); 240 assertEqual(getValue!(string, 0), "foo"); 241 assertEqual(getValue!(string, 1), "red"); 242 assertEqual(testData.find!(a => a.getPath.canFind("foo.red")).front.tags, []); 243 244 auto barGreen = tests.find!(a => a.getPath.canFind("bar.green")).front; 245 assertFail(barGreen); 246 assertEqual(getValue!(string, 0), "bar"); 247 assertEqual(getValue!(string, 1), "green"); 248 249 assertEqual(testData.find!(a => a.getPath.canFind("bar.green")).front.tags, []); 250 assertEqual(allTestData!(unit_threaded.ut.modules.parametrized). 251 filter!(a => a.name.canFind("cartesianBuiltinAutoTags")).array. 252 find!(a => a.getPath.canFind("bar.green")).front.tags, 253 ["bar", "green"]); 254 } 255 256 @("Cartesian parameterized function values") unittest { 257 import unit_threaded.runner.factory; 258 import unit_threaded.runner.testcase; 259 import unit_threaded.should: shouldBeSameSetAs; 260 261 const testData = allTestData!(unit_threaded.ut.modules.parametrized). 262 filter!(a => a.name.canFind("CartesianFunction")).array; 263 264 auto tests = createTestCases(testData); 265 tests.map!(a => a.getPath).array.shouldBeSameSetAs( 266 addModPrefix(["1.foo", "1.bar", "2.foo", "2.bar", "3.foo", "3.bar"]. 267 map!(a => "testCartesianFunction." ~ a).array, 268 "unit_threaded.ut.modules.parametrized")); 269 270 foreach(test; tests) { 271 test.getPath.canFind("2.bar") 272 ? assertPass(test) 273 : assertFail(test); 274 } 275 276 assertEqual(testData.find!(a => a.getPath.canFind("2.bar")).front.tags, 277 ["2", "bar"]); 278 279 } 280 281 @("module setup and shutdown") 282 unittest { 283 import unit_threaded.runner.testcase; 284 import unit_threaded.runner.factory; 285 import unit_threaded.ut.modules.module_with_setup: gNumBefore, gNumAfter; 286 287 const testData = allTestData!"unit_threaded.ut.modules.module_with_setup".array; 288 auto tests = createTestCases(testData); 289 assertEqual(tests.length, 2); 290 291 assertPass(tests[0]); 292 assertEqual(gNumBefore, 1); 293 assertEqual(gNumAfter, 1); 294 295 assertFail(tests[1]); 296 assertEqual(gNumBefore, 2); 297 assertEqual(gNumAfter, 2); 298 } 299 300 @("issue 33") unittest { 301 import unit_threaded.runner.factory; 302 import unit_threaded.runner.testcase; 303 304 const testData = allTestData!"unit_threaded.ut.modules.issue33"; 305 assertEqual(testData.length, 1); 306 } 307 308 @("issue 43") unittest { 309 import unit_threaded.runner.factory; 310 import unit_threaded.asserts; 311 import unit_threaded.ut.modules.module_with_tests; 312 import std.algorithm: canFind; 313 import std.array: array; 314 315 const testData = allTestData!"unit_threaded.ut.modules.module_with_tests"; 316 assertEqual(testData.canFind!(a => a.getPath.canFind("InStruct" )), true); 317 auto inStructTest = testData 318 .find!(a => a.getPath.canFind("InStruct")) 319 .array 320 .createTestCases[0]; 321 assertFail(inStructTest); 322 } 323 324 @("@DontTest should work for unittest blocks") unittest { 325 import unit_threaded.runner.factory; 326 import unit_threaded.asserts; 327 import unit_threaded.ut.modules.module_with_tests; 328 import std.algorithm: canFind; 329 import std.array: array; 330 331 const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs"; 332 assertEqual(testData.canFind!(a => a.getPath.canFind("DontTestBlock" )), false); 333 } 334 335 @("@ShouldFail") unittest { 336 import unit_threaded.runner.factory; 337 import unit_threaded.asserts; 338 import unit_threaded.ut.modules.module_with_tests; 339 import std.algorithm: find, canFind; 340 import std.array: array; 341 342 const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs"; 343 344 auto willFail = testData 345 .filter!(a => a.getPath.canFind("will fail")) 346 .array 347 .createTestCases[0]; 348 assertPass(willFail); 349 } 350 351 352 @("@ShouldFailWith") unittest { 353 import unit_threaded.runner.factory; 354 import unit_threaded.asserts; 355 import unit_threaded.ut.modules.module_with_attrs; 356 import std.algorithm: find, canFind; 357 import std.array: array; 358 359 const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs"; 360 361 auto doesntFail = testData 362 .filter!(a => a.getPath.canFind("ShouldFailWith that fails due to not failing")) 363 .array 364 .createTestCases[0]; 365 assertFail(doesntFail); 366 367 auto wrongType = testData 368 .find!(a => a.getPath.canFind("ShouldFailWith that fails due to wrong type")) 369 .array 370 .createTestCases[0]; 371 assertFail(wrongType); 372 373 auto passes = testData 374 .find!(a => a.getPath.canFind("ShouldFailWith that passes")) 375 .array 376 .createTestCases[0]; 377 assertPass(passes); 378 } 379 380 @("structs are not classes") unittest { 381 import unit_threaded.should; 382 import unit_threaded.ut.modules.structs_are_not_classes; 383 const testData = allTestData!"unit_threaded.ut.modules.structs_are_not_classes"; 384 testData.shouldBeEmpty; 385 } 386 387 @("@Flaky") unittest { 388 import unit_threaded.runner.factory; 389 import unit_threaded.asserts; 390 import unit_threaded.ut.modules.module_with_attrs; 391 import std.algorithm: find, canFind; 392 import std.array: array; 393 394 const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs"; 395 396 auto flakyPasses = testData 397 .filter!(a => a.getPath.canFind("flaky that passes eventually")) 398 .array 399 .createTestCases[0]; 400 assertPass(flakyPasses); 401 402 auto flakyFails = testData 403 .filter!(a => a.getPath.canFind("flaky that fails due to not enough retries")) 404 .array 405 .createTestCases[0]; 406 assertFail(flakyFails); 407 } 408 409 @("mixin") unittest { 410 import unit_threaded.runner.factory; 411 import unit_threaded.asserts; 412 import unit_threaded.ut.modules.module_with_tests; 413 import std.algorithm: canFind; 414 import std.array: array; 415 416 const testData = allTestData!"unit_threaded.ut.modules.module_with_tests"; 417 418 auto failingMixinTest = testData 419 .find!(a => a.getPath.canFind("this is my unsuccessful test name")) 420 .array 421 .createTestCases[0]; 422 assertFail(failingMixinTest); 423 }