Skip to content

Instantly share code, notes, and snippets.

@JesseKPhillips
Created April 3, 2013 05:35
Show Gist options
  • Save JesseKPhillips/5298688 to your computer and use it in GitHub Desktop.
Save JesseKPhillips/5298688 to your computer and use it in GitHub Desktop.
Unittests pulled from std.process (DLang)
import std.process2;
import std.stdio, std.array;
void main(string[] args) { write(args.join("\0")); }
unittest
{
import std.ascii;
auto x = executeShell("echo wyda");
// @@@ This fails on wine
version(Posix)
assert(x.output == "wyda" ~ newline);
}
version (Posix) unittest
{
environment["wyda"] = "geeba";
assert(environment["wyda"] == "geeba");
// Get again to make sure caching works
assert(environment["wyda"] == "geeba");
environment.remove("wyda");
assert(environment.get("wyda", "empty") == "empty");
}
unittest
{
// New variable
environment["std_process"] = "foo";
assert (environment["std_process"] == "foo");
// Set variable again
environment["std_process"] = "bar";
assert (environment["std_process"] == "bar");
// Remove variable
environment.remove("std_process");
// Remove again, should succeed
environment.remove("std_process");
// Throw on not found.
try { environment["std_process"]; assert(0); } catch(Exception e) { }
// get() without default value
assert (environment.get("std.process") == null);
// get() with default value
assert (environment.get("std_process", "baz") == "baz");
// Convert to associative array
auto aa = environment.toAA();
assert (aa.length > 0);
foreach (n, v; aa)
{
// Wine has some bugs related to environment variables:
// - Wine allows the existence of an env. variable with the name
// "\0", but GetEnvironmentVariable refuses to retrieve it.
// - If an env. variable has zero length, i.e. is "\0",
// GetEnvironmentVariable should return 1. Instead it returns
// 0, indicating the variable doesn't exist.
version(Windows) if (n.length == 0 || v.length == 0) continue;
// why does this happen?
// n = "temp" || "tmp"
// v = "C:\Users\ADMINI~1\AppData\Local\Temp\2"
// e[n] = "C:\cygwin\tmp"
// for n = "TEMP" or "TMP", v and en[v] are both "C:\cygwin\tmp"
version(Windows) if (n == "temp" || n == "tmp") continue;
//printf("%.*s, %.*s, %.*s\n", n.length, n.ptr, v.length, v.ptr, environment[n].length, environment[n].ptr);
assert (v == environment[n]);
}
}
version(Windows) version(unittest)
{
import core.sys.windows.windows;
import core.stdc.stddef;
extern (Windows) wchar_t** CommandLineToArgvW(wchar_t*, int*);
extern (C) size_t wcslen(in wchar *);
unittest
{
string[] testStrings = [
`Hello`,
`Hello, world`,
`Hello, "world"`,
`C:\`,
`C:\dmd`,
`C:\Program Files\`,
];
enum CHARS = `_x\" *&^`; // _ is placeholder for nothing
foreach (c1; CHARS)
foreach (c2; CHARS)
foreach (c3; CHARS)
foreach (c4; CHARS)
testStrings ~= [c1, c2, c3, c4].replace("_", "");
foreach (s; testStrings)
{
auto q = escapeWindowsArgument(s);
LPWSTR lpCommandLine = (to!(wchar[])("Dummy.exe " ~ q) ~ "\0"w).ptr;
int numArgs;
LPWSTR* args = CommandLineToArgvW(lpCommandLine, &numArgs);
scope(exit) LocalFree(args);
assert(numArgs==2, s ~ " => " ~ q ~ " #" ~ text(numArgs-1));
auto arg = to!string(args[1][0..wcslen(args[1])]);
assert(arg == s, s ~ " => " ~ q ~ " => " ~ arg);
}
}
}
version(unittest_burnin)
unittest
{
// There are no readily-available commands on all platforms suitable
// for properly testing command escaping. The behavior of CMD's "echo"
// built-in differs from the POSIX program, and Windows ports of POSIX
// environments (Cygwin, msys, gnuwin32) may interfere with their own
// "echo" ports.
// To run this unit test, create std_process_unittest_helper.d with the
// following content and compile it:
// import std.stdio, std.array; void main(string[] args) { write(args.join("\0")); }
// Then, test this module with:
// rdmd --main -unittest -version=unittest_burnin process.d
import std.path;
import std.string;
import std.random;
import std.file;
auto helper = absolutePath("std_process_unittest_helper");
assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction");
void test(string[] s, string fn)
{
string e;
string[] g;
e = escapeShellCommand(helper ~ s);
{
scope(failure) writefln("shell() failed.\nExpected:\t%s\nEncoded:\t%s", s, [e]);
g = executeShell(e).output.split("\0")[1..$];
}
assert(s == g, format("shell() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
e = escapeShellCommand(helper ~ s) ~ ">" ~ escapeShellFileName(fn);
{
scope(failure) writefln("system() failed.\nExpected:\t%s\nFilename:\t%s\nEncoded:\t%s", s, [fn], [e]);
executeShell(e);
g = readText(fn).split("\0")[1..$];
}
remove(fn);
assert(s == g, format("system() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
}
while (true)
{
string[] args;
foreach (n; 0..uniform(1, 4))
{
string arg;
foreach (l; 0..uniform(0, 10))
{
dchar c;
while (true)
{
version (Windows)
{
// As long as DMD's system() uses CreateProcessA,
// we can't reliably pass Unicode
c = uniform(0, 128);
}
else
c = uniform!ubyte();
if (c == 0)
continue; // argv-strings are zero-terminated
version (Windows)
if (c == '\r' || c == '\n')
continue; // newlines are unescapable on Windows
break;
}
arg ~= c;
}
args ~= arg;
}
// generate filename
string fn = "test_";
foreach (l; 0..uniform(1, 10))
{
dchar c;
while (true)
{
version (Windows)
c = uniform(0, 128); // as above
else
c = uniform!ubyte();
if (c == 0 || c == '/')
continue; // NUL and / are the only characters
// forbidden in POSIX filenames
version (Windows)
if (c < '\x20' || c == '<' || c == '>' || c == ':' ||
c == '"' || c == '\\' || c == '|' || c == '?' || c == '*')
continue; // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
break;
}
fn ~= c;
}
test(args, fn);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment