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 }