1 module unit_threaded.ut.reflection;
2 
3 import unit_threaded.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     const expected = addModPrefix([ "testFoo", "testBar", "funcThatShouldShowUpCosOfAttr"]);
25     const actual = moduleTestFunctions!(unit_threaded.ut.modules.module_with_tests).
26         map!(a => a.getPath).array;
27     assertEqual(actual, expected);
28 }
29 
30 
31 unittest {
32     const expected = addModPrefix(
33         [
34             "unittest_L44", "unittest_L49", "myUnitTest",
35             "StructWithUnitTests.InStruct", "StructWithUnitTests.unittest_L66_C5"
36         ]
37     );
38     const actual = moduleUnitTests!(unit_threaded.ut.modules.module_with_tests).
39         map!(a => a.name).array;
40     assertEqual(actual, expected);
41 }
42 
43 version(unittest) {
44     import unit_threaded.testcase: TestCase;
45     private void assertFail(TestCase test, string file = __FILE__, size_t line = __LINE__) {
46         import core.exception;
47         import std.conv;
48 
49         test.silence;
50         assert(test() != [],
51                file ~ ":" ~ line.to!string ~ " Expected test case " ~ test.getPath ~
52                " to fail but it didn't");
53     }
54 
55     private void assertPass(TestCase test, string file = __FILE__, size_t line = __LINE__) {
56         import unit_threaded.should: fail;
57         if(test() != [])
58             fail("'" ~ test.getPath ~ "' was expected to pass but failed", file, line);
59     }
60 }
61 
62 @("Test that parametrized value tests work")
63 unittest {
64     import unit_threaded.factory;
65     import unit_threaded.testcase;
66     import unit_threaded.ut.modules.parametrized;
67 
68     const testData = allTestData!(unit_threaded.ut.modules.parametrized).
69         filter!(a => a.name.endsWith("testValues")).array;
70 
71     auto tests = createTestCases(testData);
72     assertEqual(tests.length, 3);
73 
74     // the first and third test should pass, the second should fail
75     assertPass(tests[0]);
76     assertPass(tests[2]);
77 
78     assertFail(tests[1]);
79 }
80 
81 
82 @("Test that parametrized type tests work")
83 unittest {
84     import unit_threaded.factory;
85     import unit_threaded.testcase;
86     import unit_threaded.ut.modules.parametrized;
87 
88     const testData = allTestData!(unit_threaded.ut.modules.parametrized).
89         filter!(a => a.name.endsWith("testTypes")).array;
90     const expected = addModPrefix(["testTypes.float", "testTypes.int"],
91                                   "unit_threaded.ut.modules.parametrized");
92     const actual = testData.map!(a => a.getPath).array;
93     assertEqual(actual, expected);
94 
95     auto tests = createTestCases(testData);
96     assertEqual(tests.map!(a => a.getPath).array, expected);
97 
98     assertPass(tests[1]);
99     assertFail(tests[0]);
100 }
101 
102 @("Value parametrized built-in unittests")
103 unittest {
104     import unit_threaded.factory;
105     import unit_threaded.testcase;
106     import unit_threaded.ut.modules.parametrized;
107 
108     const testData = allTestData!(unit_threaded.ut.modules.parametrized).
109         filter!(a => a.name.canFind("builtinIntValues")).array;
110 
111     auto tests = createTestCases(testData);
112     assertEqual(tests.length, 4);
113 
114     // these should be ok
115     assertPass(tests[1]);
116 
117     //these should fail
118     assertFail(tests[0]);
119     assertFail(tests[2]);
120     assertFail(tests[3]);
121 }
122 
123 
124 @("Tests can be selected by tags") unittest {
125     import unit_threaded.factory;
126     import unit_threaded.testcase;
127     import unit_threaded.ut.modules.tags;
128 
129     const testData = allTestData!(unit_threaded.ut.modules.tags).array;
130     auto testsNoTags = createTestCases(testData);
131     assertEqual(testsNoTags.length, 4);
132     assertPass(testsNoTags.find!(a => a.getPath.canFind("unittest_L6")).front);
133     assertFail(testsNoTags.find!(a => a.getPath.canFind("unittest_L8")).front);
134     assertPass(testsNoTags.find!(a => a.getPath.canFind("testMake")).front);
135     assertFail(testsNoTags.find!(a => a.getPath.canFind("unittest_L22")).front);
136 
137     auto testsNinja = createTestCases(testData, ["@ninja"]);
138     assertEqual(testsNinja.length, 1);
139     assertPass(testsNinja[0]);
140 
141     auto testsMake = createTestCases(testData, ["@make"]);
142     assertEqual(testsMake.length, 3);
143     assertPass(testsMake.find!(a => a.getPath.canFind("testMake")).front);
144     assertPass(testsMake.find!(a => a.getPath.canFind("unittest_L6")).front);
145     assertFail(testsMake.find!(a => a.getPath.canFind("unittest_L22")).front);
146 
147     auto testsNotNinja = createTestCases(testData, ["~@ninja"]);
148     assertEqual(testsNotNinja.length, 3);
149     assertPass(testsNotNinja.find!(a => a.getPath.canFind("testMake")).front);
150     assertFail(testsNotNinja.find!(a => a.getPath.canFind("unittest_L8")).front);
151     assertFail(testsNotNinja.find!(a => a.getPath.canFind("unittest_L22")).front);
152 
153     assertEqual(createTestCases(testData, ["unit_threaded.ut.modules.tags.testMake", "@ninja"]).length, 0);
154 
155 }
156 
157 @("Parametrized built-in tests with @AutoTags get tagged by value")
158 unittest {
159     import unit_threaded.factory;
160     import unit_threaded.testcase;
161     import unit_threaded.ut.modules.parametrized;
162 
163     const testData = allTestData!(unit_threaded.ut.modules.parametrized).
164         filter!(a => a.name.canFind("builtinIntValues")).array;
165 
166     auto two = createTestCases(testData, ["@2"]);
167 
168     assertEqual(two.length, 1);
169     assertFail(two[0]);
170 
171     auto three = createTestCases(testData, ["@3"]);
172     assertEqual(three.length, 1);
173     assertPass(three[0]);
174 }
175 
176 @("Value parametrized function tests with @AutoTags get tagged by value")
177 unittest {
178     import unit_threaded.factory;
179     import unit_threaded.testcase;
180     import unit_threaded.ut.modules.parametrized;
181 
182     const testData = allTestData!(unit_threaded.ut.modules.parametrized).
183         filter!(a => a.name.canFind("testValues")).array;
184 
185     auto two = createTestCases(testData, ["@2"]);
186     assertEqual(two.length, 1);
187     assertFail(two[0]);
188 }
189 
190 @("Type parameterized tests with @AutoTags get tagged by type")
191 unittest {
192     import unit_threaded.factory;
193     import unit_threaded.testcase;
194     import unit_threaded.ut.modules.parametrized;
195 
196     const testData = allTestData!(unit_threaded.ut.modules.parametrized).
197         filter!(a => a.name.canFind("testTypes")).array;
198 
199     auto tests = createTestCases(testData, ["@int"]);
200     assertEqual(tests.length, 1);
201     assertPass(tests[0]);
202 }
203 
204 @("Cartesian parameterized built-in values") unittest {
205     import unit_threaded.factory;
206     import unit_threaded.testcase;
207     import unit_threaded.should: shouldBeSameSetAs;
208     import unit_threaded.ut.modules.parametrized;
209     import unit_threaded.attrs: getValue;
210 
211     const testData = allTestData!(unit_threaded.ut.modules.parametrized).
212         filter!(a => a.name.canFind("cartesianBuiltinNoAutoTags")).array;
213 
214     auto tests = createTestCases(testData);
215     tests.map!(a => a.getPath).array.shouldBeSameSetAs(
216                 addModPrefix(["foo.red", "foo.blue", "foo.green", "bar.red", "bar.blue", "bar.green"].
217                              map!(a => "cartesianBuiltinNoAutoTags." ~ a).array,
218                              "unit_threaded.ut.modules.parametrized"));
219     assertEqual(tests.length, 6);
220 
221     auto fooRed = tests.find!(a => a.getPath.canFind("foo.red")).front;
222     assertPass(fooRed);
223     assertEqual(getValue!(string, 0), "foo");
224     assertEqual(getValue!(string, 1), "red");
225     assertEqual(testData.find!(a => a.getPath.canFind("foo.red")).front.tags, []);
226 
227     auto barGreen = tests.find!(a => a.getPath.canFind("bar.green")).front;
228     assertFail(barGreen);
229     assertEqual(getValue!(string, 0), "bar");
230     assertEqual(getValue!(string, 1), "green");
231 
232     assertEqual(testData.find!(a => a.getPath.canFind("bar.green")).front.tags, []);
233     assertEqual(allTestData!(unit_threaded.ut.modules.parametrized).
234                 filter!(a => a.name.canFind("cartesianBuiltinAutoTags")).array.
235                 find!(a => a.getPath.canFind("bar.green")).front.tags,
236                 ["bar", "green"]);
237 }
238 
239 @("Cartesian parameterized function values") unittest {
240     import unit_threaded.factory;
241     import unit_threaded.testcase;
242     import unit_threaded.should: shouldBeSameSetAs;
243 
244     const testData = allTestData!(unit_threaded.ut.modules.parametrized).
245         filter!(a => a.name.canFind("CartesianFunction")).array;
246 
247     auto tests = createTestCases(testData);
248         tests.map!(a => a.getPath).array.shouldBeSameSetAs(
249             addModPrefix(["1.foo", "1.bar", "2.foo", "2.bar", "3.foo", "3.bar"].
250                              map!(a => "testCartesianFunction." ~ a).array,
251                              "unit_threaded.ut.modules.parametrized"));
252 
253     foreach(test; tests) {
254         test.getPath.canFind("2.bar")
255             ? assertPass(test)
256             : assertFail(test);
257     }
258 
259     assertEqual(testData.find!(a => a.getPath.canFind("2.bar")).front.tags,
260                 ["2", "bar"]);
261 
262 }
263 
264 @("module setup and shutdown")
265 unittest {
266     import unit_threaded.testcase;
267     import unit_threaded.factory;
268     import unit_threaded.ut.modules.module_with_setup: gNumBefore, gNumAfter;
269 
270     const testData = allTestData!"unit_threaded.ut.modules.module_with_setup".array;
271     auto tests = createTestCases(testData);
272     assertEqual(tests.length, 2);
273 
274     assertPass(tests[0]);
275     assertEqual(gNumBefore, 1);
276     assertEqual(gNumAfter, 1);
277 
278     assertFail(tests[1]);
279     assertEqual(gNumBefore, 2);
280     assertEqual(gNumAfter, 2);
281 }
282 
283 @("issue 33") unittest {
284     import unit_threaded.factory;
285     import unit_threaded.testcase;
286 
287     const testData = allTestData!"unit_threaded.ut.modules.issue33";
288     assertEqual(testData.length, 1);
289 }
290 
291 @("issue 43") unittest {
292     import unit_threaded.factory;
293     import unit_threaded.asserts;
294     import unit_threaded.ut.modules.module_with_tests;
295     import std.algorithm: canFind;
296     import std.array: array;
297 
298     const testData = allTestData!"unit_threaded.ut.modules.module_with_tests";
299     assertEqual(testData.canFind!(a => a.getPath.canFind("InStruct" )), true);
300     auto inStructTest = testData
301         .find!(a => a.getPath.canFind("InStruct"))
302         .array
303         .createTestCases[0];
304     assertFail(inStructTest);
305 }
306 
307 @("@DontTest should work for unittest blocks") unittest {
308     import unit_threaded.factory;
309     import unit_threaded.asserts;
310     import unit_threaded.ut.modules.module_with_tests;
311     import std.algorithm: canFind;
312     import std.array: array;
313 
314     const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs";
315     assertEqual(testData.canFind!(a => a.getPath.canFind("DontTestBlock" )), false);
316 }
317 
318 @("@ShouldFail") unittest {
319     import unit_threaded.factory;
320     import unit_threaded.asserts;
321     import unit_threaded.ut.modules.module_with_tests;
322     import std.algorithm: find, canFind;
323     import std.array: array;
324 
325     const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs";
326 
327     auto willFail = testData
328         .filter!(a => a.getPath.canFind("will fail"))
329         .array
330         .createTestCases[0];
331     assertPass(willFail);
332 }
333 
334 
335 @("@ShouldFailWith") unittest {
336     import unit_threaded.factory;
337     import unit_threaded.asserts;
338     import unit_threaded.ut.modules.module_with_attrs;
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 doesntFail = testData
345         .filter!(a => a.getPath.canFind("ShouldFailWith that fails due to not failing"))
346         .array
347         .createTestCases[0];
348     assertFail(doesntFail);
349 
350     auto wrongType = testData
351         .find!(a => a.getPath.canFind("ShouldFailWith that fails due to wrong type"))
352         .array
353         .createTestCases[0];
354     assertFail(wrongType);
355 
356    auto passes = testData
357         .find!(a => a.getPath.canFind("ShouldFailWith that passes"))
358         .array
359         .createTestCases[0];
360     assertPass(passes);
361 }
362 
363 @("structs are not classes") unittest {
364     import unit_threaded.should;
365     import unit_threaded.ut.modules.structs_are_not_classes;
366     const testData = allTestData!"unit_threaded.ut.modules.structs_are_not_classes";
367     testData.shouldBeEmpty;
368 }
369 
370 @("@Flaky") unittest {
371     import unit_threaded.factory;
372     import unit_threaded.asserts;
373     import unit_threaded.ut.modules.module_with_attrs;
374     import std.algorithm: find, canFind;
375     import std.array: array;
376 
377     const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs";
378 
379     auto flakyPasses = testData
380         .filter!(a => a.getPath.canFind("flaky that passes eventually"))
381         .array
382         .createTestCases[0];
383     assertPass(flakyPasses);
384 
385     auto flakyFails = testData
386         .filter!(a => a.getPath.canFind("flaky that fails due to not enough retries"))
387         .array
388         .createTestCases[0];
389     assertFail(flakyFails);
390 }