1 /**
2 * Copyright © DiamondMVC 2019
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.unittesting.initialization;
7 
8 import diamond.core.apptype;
9 
10 static if (isWeb && isTesting)
11 {
12   /// Boolean determinng whether all tests has passed or not.
13   package(diamond) __gshared bool testsPassed;
14 
15   /// Wrapper around a test's failure result.
16   private class TestFailResult
17   {
18     /// The name of the test.
19     string name;
20     /// The error.
21     string error;
22   }
23 
24   /// Initializes the tests.
25   package(diamond) void initializeTests()
26   {
27     TestFailResult[] failedTests;
28 
29     mixin HandleTests;
30     handleTests();
31 
32     import diamond.core.io;
33 
34     if (failedTests && failedTests.length)
35     {
36       import vibe.core.core : exitEventLoop;
37 
38       exitEventLoop();
39 
40       print("The following tests has failed:");
41 
42       foreach (test; failedTests)
43       {
44         print("-------------------");
45         print("Test: %s", test.name);
46         print("Error:");
47         print(test.error);
48         print("-------------------");
49       }
50     }
51     else
52     {
53       testsPassed = true;
54       print("All tests has passed.");
55     }
56   }
57 
58   /// Mixin template to handle the tests.
59   private mixin template HandleTests()
60   {
61     static string[] getModules()
62     {
63       import std..string : strip;
64       import std.array : replace, split;
65 
66       string[] modules = [];
67 
68       import diamond.core.io : handleCTFEFile;
69 
70       mixin handleCTFEFile!("unittests.config", q{
71         auto lines = __fileResult.replace("\r", "").split("\n");
72 
73         foreach (line; lines)
74         {
75           if (!line || !line.strip().length)
76           {
77             continue;
78           }
79 
80           modules ~= line.strip();
81         }
82       });
83       handle();
84 
85       return modules;
86     }
87 
88     enum moduleNames = getModules();
89 
90     static string generateTests()
91     {
92       string s = "";
93 
94       foreach (moduleName; moduleNames)
95       {
96         s ~= "{ import " ~ moduleName ~ ";\r\n";
97         s ~= "foreach (member; __traits(allMembers, " ~ moduleName ~ "))\r\n";
98 
99         s ~= q{
100           {
101             mixin(q{
102               static if (mixin("hasUDA!(%1$s, HttpTest)"))
103               {
104                 static test_%1$s = getUDAs!(%1$s, HttpTest)[0];
105 
106                 auto testName =
107                   test_%1$s.name && test_%1$s.name.length ? test_%1$s.name : "%1$s";
108 
109                 try
110                 {
111                   static if (is(ReturnType!%1$s == bool))
112                   {
113                     if (!%1$s())
114                     {
115                       auto testFailResult = new TestFailResult;
116                       testFailResult.name = testName;
117                       testFailResult.error = "Returned false.";
118 
119                       failedTests ~= testFailResult;
120                     }
121                   }
122                   else
123                   {
124                     %1$s();
125                   }
126                 }
127                 catch (Throwable t)
128                 {
129                   auto testFailResult = new TestFailResult;
130                   testFailResult.name = testName;
131                   testFailResult.error = t.toString();
132 
133                   failedTests ~= testFailResult;
134                 }
135               }
136             }.format(member));
137           }
138         };
139 
140         s ~= "}\r\n";
141       }
142 
143       return s;
144     }
145 
146     void handleTests()
147     {
148       import std..string : format;
149       import std.traits : hasUDA, getUDAs, ReturnType;
150       import diamond.core.collections;
151       import diamond.unittesting.attributes;
152 
153       mixin(generateTests());
154     }
155   }
156 }