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 }