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