1 module test; 2 3 import std.array; 4 import std.process; 5 import std.stdio; 6 import std.file; 7 import std.path; 8 import std.algorithm; 9 import std..string; 10 import std.traits : ReturnType; 11 12 void main () 13 { 14 TestRunner().run(); 15 } 16 17 private: 18 19 /** 20 * The available test groups. 21 * 22 * The tests will be run in the order specified here. 23 */ 24 enum TestGroup 25 { 26 unit = "unit", 27 library = "library", 28 functional = "functional" 29 } 30 31 struct TestRunner 32 { 33 void run () 34 { 35 import std.traits : EnumMembers; 36 37 foreach (test ; EnumMembers!TestGroup) 38 runTest!(test); 39 40 stdout.flush(); 41 } 42 43 /** 44 * Run a single group of tests, i.e. functional, library or unit test. 45 * 46 * Params: 47 * testGroup = the test group to run 48 * 49 * Returns: the exist code of the test run 50 */ 51 void runTest (TestGroup testGroup)() 52 { 53 import std..string : capitalize; 54 55 enum beforeFunction = "before" ~ testGroup.capitalize; 56 57 static if (is(typeof(mixin(beforeFunction)))) 58 mixin(beforeFunction ~ "();"); 59 60 writef("Running %s tests ", testGroup); 61 stdout.flush(); 62 const command = dubShellCommand("--config=test-" ~ testGroup); 63 executeCommand(command); 64 } 65 66 void beforeFunctional() @safe 67 { 68 if (dstepBuilt) 69 return; 70 71 writeln("Building DStep"); 72 const command = dubShellCommand("build", "--build=debug"); 73 executeCommand(command); 74 } 75 } 76 77 @safe: 78 79 bool dstepBuilt() 80 { 81 import std.file : exists; 82 83 version (Windows) 84 enum dstepPath = "bin/dstep.exe"; 85 else version (Posix) 86 enum dstepPath = "bin/dstep"; 87 88 return exists(dstepPath); 89 } 90 91 void executeCommand(const string[] args ...) 92 { 93 import std.process : spawnProcess, wait; 94 import std.array : join; 95 96 if (spawnProcess(args).wait() != 0) 97 throw new Exception("Failed to execute command: " ~ args.join(' ')); 98 } 99 100 string[] dubShellCommand(string[] subCommands ...) 101 { 102 return (["dub", "--verror"] ~ subCommands ~ dubArch) 103 .filter!(e => e.length > 0) 104 .array; 105 } 106 107 string defaultArchitecture() 108 { 109 version (X86_64) 110 return "x86_64"; 111 else 112 { 113 version (DigitalMars) 114 return "x86_mscoff"; 115 else 116 return "x86"; 117 } 118 } 119 120 string dubArch() 121 { 122 version (Windows) 123 { 124 import std.process : environment; 125 import std..string : split; 126 127 const architecture = environment 128 .get("DUB_ARCH", defaultArchitecture) 129 .split(" ")[$ - 1]; 130 131 return "--arch=" ~ architecture; 132 133 } 134 else 135 return ""; 136 }