224 lines
5.7 KiB
D
224 lines
5.7 KiB
D
|
|
// Copyright Ferdinand Majerech 2011.
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
module dyaml.test.common;
|
|
|
|
version(unittest)
|
|
{
|
|
|
|
import dyaml.node;
|
|
import dyaml.event;
|
|
|
|
import core.exception;
|
|
import std.algorithm;
|
|
import std.array;
|
|
import std.conv;
|
|
import std.file;
|
|
import std.range;
|
|
import std.path;
|
|
import std.traits;
|
|
import std.typecons;
|
|
|
|
package:
|
|
|
|
/**
|
|
Run a test.
|
|
|
|
Params:
|
|
testFunction = Unittest function.
|
|
unittestExt = Extensions of data files needed for the unittest.
|
|
skipExt = Extensions that must not be used for the unittest.
|
|
*/
|
|
void run(D)(D testFunction, string[] unittestExt, string[] skipExt = [])
|
|
{
|
|
immutable string dataDir = __FILE_FULL_PATH__.dirName ~ "/../../../test/data";
|
|
auto testFilenames = findTestFilenames(dataDir);
|
|
|
|
if (unittestExt.length > 0)
|
|
{
|
|
outer: foreach (base, extensions; testFilenames)
|
|
{
|
|
string[] filenames;
|
|
foreach (ext; unittestExt)
|
|
{
|
|
if (!extensions.canFind(ext))
|
|
{
|
|
continue outer;
|
|
}
|
|
filenames ~= base ~ '.' ~ ext;
|
|
}
|
|
foreach (ext; skipExt)
|
|
{
|
|
if (extensions.canFind(ext))
|
|
{
|
|
continue outer;
|
|
}
|
|
}
|
|
|
|
execute(testFunction, filenames);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
execute(testFunction, string[].init);
|
|
}
|
|
}
|
|
|
|
// TODO: remove when a @safe ubyte[] file read can be done.
|
|
/**
|
|
Reads a file as an array of bytes.
|
|
|
|
Params:
|
|
filename = Full path to file to read.
|
|
|
|
Returns: The file's data.
|
|
*/
|
|
ubyte[] readData(string filename) @trusted
|
|
{
|
|
import std.file : read;
|
|
return cast(ubyte[])read(filename);
|
|
}
|
|
void assertNodesEqual(const scope Node gotNode, const scope Node expectedNode) @safe
|
|
{
|
|
import std.format : format;
|
|
assert(gotNode == expectedNode, format!"got %s, expected %s"(gotNode.debugString, expectedNode.debugString));
|
|
}
|
|
|
|
/**
|
|
Determine if events in events1 are equivalent to events in events2.
|
|
|
|
Params:
|
|
events1 = A range of events to compare with.
|
|
events2 = A second range of events to compare.
|
|
|
|
Returns: true if the events are equivalent, false otherwise.
|
|
*/
|
|
bool compareEvents(T, U)(T events1, U events2)
|
|
if (isInputRange!T && isInputRange!U && is(ElementType!T == Event) && is(ElementType!U == Event))
|
|
{
|
|
foreach (e1, e2; zip(events1, events2))
|
|
{
|
|
//Different event types.
|
|
if (e1.id != e2.id)
|
|
{
|
|
return false;
|
|
}
|
|
//Different anchor (if applicable).
|
|
if (e1.id.among!(EventID.sequenceStart, EventID.mappingStart, EventID.alias_, EventID.scalar)
|
|
&& e1.anchor != e2.anchor)
|
|
{
|
|
return false;
|
|
}
|
|
//Different collection tag (if applicable).
|
|
if (e1.id.among!(EventID.sequenceStart, EventID.mappingStart) && e1.tag != e2.tag)
|
|
{
|
|
return false;
|
|
}
|
|
if (e1.id == EventID.scalar)
|
|
{
|
|
//Different scalar tag (if applicable).
|
|
if (!(e1.implicit || e2.implicit) && e1.tag != e2.tag)
|
|
{
|
|
return false;
|
|
}
|
|
//Different scalar value.
|
|
if (e1.value != e2.value)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
/**
|
|
Throw an Error if events in events1 aren't equivalent to events in events2.
|
|
|
|
Params:
|
|
events1 = First event array to compare.
|
|
events2 = Second event array to compare.
|
|
*/
|
|
void assertEventsEqual(T, U)(T events1, U events2)
|
|
if (isInputRange!T && isInputRange!U && is(ElementType!T == Event) && is(ElementType!U == Event))
|
|
{
|
|
auto events1Copy = events1.array;
|
|
auto events2Copy = events2.array;
|
|
assert(compareEvents(events1Copy, events2Copy), text("Got '", events1Copy, "', expected '", events2Copy, "'"));
|
|
}
|
|
|
|
private:
|
|
|
|
/**
|
|
Find unittest input filenames.
|
|
|
|
Params: dir = Directory to look in.
|
|
|
|
Returns: Test input base filenames and their extensions.
|
|
*/
|
|
//@trusted due to dirEntries
|
|
string[][string] findTestFilenames(const string dir) @trusted
|
|
{
|
|
//Groups of extensions indexed by base names.
|
|
string[][string] names;
|
|
foreach (string name; dirEntries(dir, SpanMode.shallow))
|
|
{
|
|
if (isFile(name))
|
|
{
|
|
string base = name.stripExtension();
|
|
string ext = name.extension();
|
|
if (ext is null)
|
|
{
|
|
ext = "";
|
|
}
|
|
if (ext[0] == '.')
|
|
{
|
|
ext = ext[1 .. $];
|
|
}
|
|
|
|
//If the base name doesn't exist yet, add it; otherwise add new extension.
|
|
names[base] = ((base in names) is null) ? [ext] : names[base] ~ ext;
|
|
}
|
|
}
|
|
return names;
|
|
}
|
|
|
|
/**
|
|
Recursively copy an array of strings to a tuple to use for unittest function input.
|
|
|
|
Params:
|
|
index = Current index in the array/tuple.
|
|
tuple = Tuple to copy to.
|
|
strings = Strings to copy.
|
|
*/
|
|
void stringsToTuple(uint index, F ...)(ref F tuple, const string[] strings)
|
|
in(F.length == strings.length)
|
|
do
|
|
{
|
|
tuple[index] = strings[index];
|
|
static if (index > 0)
|
|
{
|
|
stringsToTuple!(index - 1, F)(tuple, strings);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Execute an unittest on specified files.
|
|
|
|
Params:
|
|
testName = Name of the unittest.
|
|
testFunction = Unittest function.
|
|
filenames = Names of input files to test with.
|
|
*/
|
|
void execute(D)(D testFunction, string[] filenames)
|
|
{
|
|
//Convert filenames to parameters tuple and call the test function.
|
|
alias F = Parameters!D[0..$];
|
|
F parameters;
|
|
stringsToTuple!(F.length - 1, F)(parameters, filenames);
|
|
testFunction(parameters);
|
|
}
|
|
|
|
} // version(unittest)
|