1 /** 2 * This module implements functionality helpful for writing integration tests 3 * as opposed to the unit variety where unit-tests are defined as not 4 * having global side-effects. In constrast, this module implements 5 * assertions that check for global side-effects such as writing to the 6 * file system. 7 */ 8 9 module unit_threaded.integration; 10 11 //version(Windows) { 12 // extern(C) int mkdir(char*); 13 // extern(C) char* mktemp(char* template_); 14 // 15 // char* mkdtemp(char* t) { 16 // version(unitUnthreaded) 17 // return mkdtempImpl(t); 18 // else { 19 // synchronized { 20 // return mkdtempImpl(t); 21 // } 22 // } 23 // } 24 // 25 // char* mkdtempImpl(char* t) { 26 // char* result = mktemp(t); 27 // 28 // if(result is null) return null; 29 // if (mkdir(result)) return null; 30 // 31 // return result; 32 // } 33 // 34 //} else { 35 // extern(C) char* mkdtemp(char* template_); 36 //} 37 // 38 // 39 //shared static this() { 40 // import std.file: exists, rmdirRecurse; 41 // 42 // if(Sandbox.sandboxesPath.exists) 43 // rmdirRecurse(Sandbox.sandboxesPath); 44 //} 45 // 46 // 47 //@safe: 48 // 49 ///** 50 // Responsible for creating a temporary directory to serve as a sandbox where 51 // files can be created, written to or deleted. 52 // */ 53 //struct Sandbox { 54 // import std.path; 55 // 56 // enum defaultSandboxesPath = buildPath("tmp", "unit-threaded"); 57 // static string sandboxesPath = defaultSandboxesPath; 58 // string testPath; 59 // 60 // /// Instantiate a Sandbox object 61 // static Sandbox opCall() { 62 // Sandbox ret; 63 // ret.testPath = newTestDir; 64 // return ret; 65 // } 66 // 67 // 68 // static void setPath(string path) { 69 // import std.file: exists, mkdirRecurse; 70 // sandboxesPath = path; 71 // if(!sandboxesPath.exists) () @trusted { mkdirRecurse(sandboxesPath); }(); 72 // } 73 // 74 // 75 // static void resetPath() { 76 // sandboxesPath = defaultSandboxesPath; 77 // } 78 // 79 // /// Write a file to the sandbox 80 // void writeFile(in string fileName, in string output = "") const { 81 // import std.stdio: File; 82 // import std.path: buildPath, dirName; 83 // import std.file: mkdirRecurse; 84 // 85 // () @trusted { mkdirRecurse(buildPath(testPath, fileName.dirName)); }(); 86 // File(buildPath(testPath, fileName), "w").writeln(output); 87 // } 88 // 89 // /// Write a file to the sanbox 90 // void writeFile(in string fileName, in string[] lines) const { 91 // import std.array; 92 // writeFile(fileName, lines.join("\n")); 93 // } 94 // 95 // 96 // /// Assert that a file exists in the sandbox 97 // void shouldExist(string fileName, in string file = __FILE__, in size_t line = __LINE__) const { 98 // import std.file: exists; 99 // import std.path: buildPath; 100 // import unit_threaded.exception: fail; 101 // 102 // fileName = buildPath(testPath, fileName); 103 // if(!fileName.exists) 104 // fail("Expected " ~ fileName ~ " to exist but it didn't", file, line); 105 // } 106 // 107 // /// Assert that a file does not exist in the sandbox 108 // void shouldNotExist(string fileName, in string file = __FILE__, in size_t line = __LINE__) const { 109 // import std.file: exists; 110 // import std.path: buildPath; 111 // import unit_threaded.exception: fail; 112 // 113 // fileName = buildPath(testPath, fileName); 114 // if(fileName.exists) 115 // fail("Expected " ~ fileName ~ " to not exist but it did", file, line); 116 // } 117 // 118 // /// read a file in the test sandbox and verify its contents 119 // void shouldEqualContent(in string fileName, in string content, 120 // in string file = __FILE__, in size_t line = __LINE__) 121 // const 122 // { 123 // import std.file: readText; 124 // import std.string: chomp, splitLines; 125 // import unit_threaded.assertions: shouldEqual; 126 // 127 // readText(buildPath(testPath, fileName)).shouldEqual(content, file, line); 128 // } 129 // 130 // /// read a file in the test sandbox and verify its contents 131 // void shouldEqualLines(in string fileName, in string[] lines, 132 // string file = __FILE__, size_t line = __LINE__) 133 // const 134 // { 135 // import std.file: readText; 136 // import std.string: chomp, splitLines; 137 // import unit_threaded.assertions: shouldEqual; 138 // 139 // readText(buildPath(testPath, fileName)).chomp.splitLines 140 // .shouldEqual(lines, file, line); 141 // } 142 // 143 // // `fileName` should contain `needle` 144 // void fileShouldContain(in string fileName, 145 // in string needle, 146 // in string file = __FILE__, 147 // in size_t line = __LINE__) 148 // { 149 // import std.file: readText; 150 // import unit_threaded.assertions: shouldBeIn; 151 // needle.shouldBeIn(readText(inSandboxPath(fileName)), file, line); 152 // } 153 // 154 // string sandboxPath() @safe @nogc pure nothrow const { 155 // return testPath; 156 // } 157 // 158 // string inSandboxPath(in string fileName) @safe pure nothrow const { 159 // import std.path: buildPath; 160 // return buildPath(sandboxPath, fileName); 161 // } 162 // 163 // /** 164 // Executing `args` should succeed 165 // */ 166 // void shouldSucceed(string file = __FILE__, size_t line = __LINE__) 167 // (in string[] args...) 168 // @safe const 169 // { 170 // import unit_threaded.exception: UnitTestException; 171 // import std.conv: text; 172 // import std.array: join; 173 // 174 // const res = executeInSandbox(args); 175 // if(res.status != 0) 176 // throw new UnitTestException(text("Could not execute `", args.join(" "), "`:\n", res.output), 177 // file, line); 178 // } 179 // 180 // alias shouldExecuteOk = shouldSucceed; 181 // 182 // /** 183 // Executing `args` should fail 184 // */ 185 // void shouldFail(string file = __FILE__, size_t line = __LINE__) 186 // (in string[] args...) 187 // @safe const 188 // { 189 // import unit_threaded.exception: UnitTestException; 190 // import std.conv: text; 191 // import std.array: join; 192 // 193 // const res = executeInSandbox(args); 194 // if(res.status == 0) 195 // throw new UnitTestException( 196 // text("`", args.join(" "), "` should have failed but didn't:\n", res.output), 197 // file, 198 // line); 199 // } 200 // 201 // 202 //private: 203 // 204 // auto executeInSandbox(in string[] args) @safe const { 205 // import std.process: execute, Config; 206 // import std.algorithm: startsWith; 207 // import std.array: replace; 208 // 209 // const string[string] env = null; 210 // const config = Config.none; 211 // const maxOutput = size_t.max; 212 // const workDir = testPath; 213 // 214 // const executable = args[0].startsWith("./") 215 // ? inSandboxPath(args[0].replace("./", "")) 216 // : args[0]; 217 // 218 // return execute(executable ~ args[1..$], env, config, maxOutput, workDir); 219 // } 220 // 221 // static string newTestDir() { 222 // import std.file: exists, mkdirRecurse; 223 // 224 // if(!sandboxesPath.exists) { 225 // () @trusted { mkdirRecurse(sandboxesPath); }(); 226 // } 227 // 228 // return makeTempDir(); 229 // } 230 // 231 // static string makeTempDir() { 232 // import std.algorithm: copy; 233 // import std.exception: enforce; 234 // import std.conv: to; 235 // import std.string: fromStringz; 236 // import core.stdc.string: strerror; 237 // import core.stdc.errno: errno; 238 // 239 // char[2048] template_; 240 // copy(buildPath(sandboxesPath, "XXXXXX") ~ '\0', template_[]); 241 // 242 // auto path = () @trusted { return mkdtemp(&template_[0]).to!string; }(); 243 // 244 // enforce(path != "", 245 // "\n" ~ 246 // "Failed to create temporary directory name using template '" ~ 247 // () @trusted { return fromStringz(&template_[0]); }() ~ "': " ~ 248 // () @trusted { return strerror(errno).to!string; }()); 249 // 250 // return path.absolutePath; 251 // } 252 //}