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 
17 unittest {
18     import std.algorithm: sorted = sort;
19 
20     const expected = addModPrefix(
21         [
22             "myUnitTest",
23             "StructWithUnitTests.InStruct",
24             "StructWithUnitTests.unittest_L58_C5",
25             "unittest_L36",
26             "unittest_L41",
27         ]
28     ).sorted.array;
29     const actual = moduleUnitTests!(unit_threaded.ut.modules.module_with_tests).
30         map!(a => a.name).array.sorted.array;
31 
32     assertEqual(actual, expected);
33 }
34 
35 version(unittest) {
36     import unit_threaded.runner.testcase: TestCase;
37     private void assertFail(TestCase test, string file = __FILE__, size_t line = __LINE__) {
38         import core.exception;
39         import std.conv;
40 
41         test.silence;
42         assert(test() != [],
43                file ~ ":" ~ line.to!string ~ " Expected test case " ~ test.getPath ~
44                " to fail but it didn't");
45     }
46 
47     private void assertPass(TestCase test, string file = __FILE__, size_t line = __LINE__) {
48         import unit_threaded.should: fail;
49         if(test() != [])
50             fail("'" ~ test.getPath ~ "' was expected to pass but failed", file, line);
51     }
52 }
53 
54 
55 @("Tests can be selected by tags") unittest {
56     import unit_threaded.runner.factory;
57     import unit_threaded.runner.testcase;
58     import unit_threaded.ut.modules.tags;
59 
60     const testData = allTestData!(unit_threaded.ut.modules.tags).array;
61     auto testsNoTags = createTestCases(testData);
62     assertEqual(testsNoTags.length, 3);
63     assertPass(testsNoTags.find!(a => a.getPath.canFind("unittest_L6")).front);
64     assertFail(testsNoTags.find!(a => a.getPath.canFind("unittest_L8")).front);
65     assertFail(testsNoTags.find!(a => a.getPath.canFind("unittest_L14")).front);
66 
67     auto testsNinja = createTestCases(testData, ["@ninja"]);
68     assertEqual(testsNinja.length, 1);
69     assertPass(testsNinja[0]);
70 
71     auto testsMake = createTestCases(testData, ["@make"]);
72     assertEqual(testsMake.length, 2);
73     assertPass(testsMake.find!(a => a.getPath.canFind("unittest_L6")).front);
74     assertFail(testsMake.find!(a => a.getPath.canFind("unittest_L14")).front);
75 
76     auto testsNotNinja = createTestCases(testData, ["~@ninja"]);
77     assertEqual(testsNotNinja.length, 2);
78     assertFail(testsNotNinja.find!(a => a.getPath.canFind("unittest_L8")).front);
79     assertFail(testsNotNinja.find!(a => a.getPath.canFind("unittest_L14")).front);
80 
81     assertEqual(createTestCases(testData, ["unit_threaded.ut.modules.tags.testMake", "@ninja"]).length, 0);
82 }
83 
84 
85 @("module setup and shutdown")
86 unittest {
87     import unit_threaded.runner.testcase;
88     import unit_threaded.runner.factory;
89     import unit_threaded.ut.modules.module_with_setup: gNumBefore, gNumAfter;
90 
91     const testData = allTestData!"unit_threaded.ut.modules.module_with_setup".array;
92     auto tests = createTestCases(testData);
93     assertEqual(tests.length, 2);
94 
95     assertPass(tests[0]);
96     assertEqual(gNumBefore, 1);
97     assertEqual(gNumAfter, 1);
98 
99     assertFail(tests[1]);
100     assertEqual(gNumBefore, 2);
101     assertEqual(gNumAfter, 2);
102 }
103 
104 @("issue 33") unittest {
105     import unit_threaded.runner.factory;
106     import unit_threaded.runner.testcase;
107 
108     const testData = allTestData!"unit_threaded.ut.modules.issue33";
109     assertEqual(testData.length, 1);
110 }
111 
112 @("issue 43") unittest {
113     import unit_threaded.runner.factory;
114     import unit_threaded.asserts;
115     import unit_threaded.ut.modules.module_with_tests;
116     import std.algorithm: canFind;
117     import std.array: array;
118 
119     const testData = allTestData!"unit_threaded.ut.modules.module_with_tests";
120     assertEqual(testData.canFind!(a => a.getPath.canFind("InStruct" )), true);
121     auto inStructTest = testData
122         .find!(a => a.getPath.canFind("InStruct"))
123         .array
124         .createTestCases[0];
125     assertFail(inStructTest);
126 }
127 
128 @("@DontTest should work for unittest blocks") unittest {
129     import unit_threaded.runner.factory;
130     import unit_threaded.asserts;
131     import unit_threaded.ut.modules.module_with_tests;
132     import std.algorithm: canFind;
133     import std.array: array;
134 
135     const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs";
136     assertEqual(testData.canFind!(a => a.getPath.canFind("DontTestBlock" )), false);
137 }
138 
139 @("@ShouldFail") unittest {
140     import unit_threaded.runner.factory;
141     import unit_threaded.asserts;
142     import unit_threaded.ut.modules.module_with_tests;
143     import std.algorithm: find, canFind;
144     import std.array: array;
145 
146     const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs";
147 
148     auto willFail = testData
149         .filter!(a => a.getPath.canFind("will fail"))
150         .array
151         .createTestCases[0];
152     assertPass(willFail);
153 }
154 
155 
156 @("@ShouldFailWith") unittest {
157     import unit_threaded.runner.factory;
158     import unit_threaded.asserts;
159     import unit_threaded.ut.modules.module_with_attrs;
160     import std.algorithm: find, canFind;
161     import std.array: array;
162 
163     const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs";
164 
165     auto doesntFail = testData
166         .filter!(a => a.getPath.canFind("ShouldFailWith that fails due to not failing"))
167         .array
168         .createTestCases[0];
169     assertFail(doesntFail);
170 
171     auto wrongType = testData
172         .find!(a => a.getPath.canFind("ShouldFailWith that fails due to wrong type"))
173         .array
174         .createTestCases[0];
175     assertFail(wrongType);
176 
177    auto passes = testData
178         .find!(a => a.getPath.canFind("ShouldFailWith that passes"))
179         .array
180         .createTestCases[0];
181     assertPass(passes);
182 }
183 
184 @("structs are not classes") unittest {
185     import unit_threaded.should;
186     import unit_threaded.ut.modules.structs_are_not_classes;
187     const testData = allTestData!"unit_threaded.ut.modules.structs_are_not_classes";
188     testData.shouldBeEmpty;
189 }
190 
191 @("@Flaky") unittest {
192     import unit_threaded.runner.factory;
193     import unit_threaded.asserts;
194     import unit_threaded.ut.modules.module_with_attrs;
195     import std.algorithm: find, canFind;
196     import std.array: array;
197 
198     const testData = allTestData!"unit_threaded.ut.modules.module_with_attrs";
199 
200     auto flakyPasses = testData
201         .filter!(a => a.getPath.canFind("flaky that passes eventually"))
202         .array
203         .createTestCases[0];
204     assertPass(flakyPasses);
205 
206     auto flakyFails = testData
207         .filter!(a => a.getPath.canFind("flaky that fails due to not enough retries"))
208         .array
209         .createTestCases[0];
210     assertFail(flakyFails);
211 }