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