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