dyaml/source/dyaml/test/constructor.d

445 lines
15 KiB
D
Raw Normal View History

2011-08-16 12:53:13 +00:00
// 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.constructor;
2011-08-16 12:53:13 +00:00
version(unittest)
{
2011-08-16 12:53:13 +00:00
import std.datetime;
import std.exception;
import std.path;
import std.string;
import std.typecons;
2011-08-16 12:53:13 +00:00
import dyaml.test.common;
2011-08-16 12:53:13 +00:00
///Expected results of loading test inputs.
Node[][string] expected;
///Initialize expected.
2018-03-23 21:35:16 +00:00
static this() @safe
2011-08-16 12:53:13 +00:00
{
expected["aliases-cdumper-bug"] = constructAliasesCDumperBug();
expected["construct-binary"] = constructBinary();
expected["construct-bool"] = constructBool();
expected["construct-custom"] = constructCustom();
expected["construct-float"] = constructFloat();
expected["construct-int"] = constructInt();
expected["construct-map"] = constructMap();
expected["construct-merge"] = constructMerge();
expected["construct-null"] = constructNull();
expected["construct-omap"] = constructOMap();
expected["construct-pairs"] = constructPairs();
expected["construct-seq"] = constructSeq();
expected["construct-set"] = constructSet();
expected["construct-str-ascii"] = constructStrASCII();
expected["construct-str"] = constructStr();
expected["construct-str-utf8"] = constructStrUTF8();
expected["construct-timestamp"] = constructTimestamp();
expected["construct-value"] = constructValue();
expected["duplicate-merge-key"] = duplicateMergeKey();
expected["float-representer-2.3-bug"] = floatRepresenterBug();
expected["invalid-single-quote-bug"] = invalidSingleQuoteBug();
expected["more-floats"] = moreFloats();
expected["negative-float-bug"] = negativeFloatBug();
expected["single-dot-is-not-float-bug"] = singleDotFloatBug();
expected["timestamp-bugs"] = timestampBugs();
expected["utf16be"] = utf16be();
expected["utf16le"] = utf16le();
expected["utf8"] = utf8();
expected["utf8-implicit"] = utf8implicit();
2011-08-16 12:53:13 +00:00
}
///Construct a pair of nodes with specified values.
Node.Pair pair(A, B)(A a, B b)
{
return Node.Pair(a,b);
2011-08-16 12:53:13 +00:00
}
///Test cases:
2018-03-23 21:35:16 +00:00
Node[] constructAliasesCDumperBug() @safe
{
return [Node(["today", "today"])];
}
2018-03-23 21:35:16 +00:00
Node[] constructBinary() @safe
2011-08-16 12:53:13 +00:00
{
auto canonical = "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;".representation.dup;
auto generic = "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;".representation.dup;
2011-08-16 12:53:13 +00:00
auto description = "The binary value above is a tiny arrow encoded as a gif image.";
return [Node([pair("canonical", canonical),
2011-08-16 12:53:13 +00:00
pair("generic", generic),
pair("description", description)])];
}
2018-03-23 21:35:16 +00:00
Node[] constructBool() @safe
2011-08-16 12:53:13 +00:00
{
const(bool) a = true;
immutable(bool) b = true;
const bool aa = true;
immutable bool bb = true;
return [Node([pair("canonical", true),
2011-08-16 12:53:13 +00:00
pair("answer", false),
pair("logical", true),
pair("option", true),
pair("constbool", a),
pair("imutbool", b),
pair("const_bool", aa),
pair("imut_bool", bb),
2011-08-16 12:53:13 +00:00
pair("but", [pair("y", "is a string"), pair("n", "is a string")])])];
}
2018-03-23 21:35:16 +00:00
Node[] constructCustom() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([Node(new TestClass(1, 2, 3)),
Node(TestStruct(10))])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructFloat() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("canonical", 685230.15L),
pair("exponential", 685230.15L),
pair("fixed", 685230.15L),
pair("sexagesimal", 685230.15L),
2011-08-16 12:53:13 +00:00
pair("negative infinity", -real.infinity),
pair("not a number", real.nan)])];
}
2018-03-23 21:35:16 +00:00
Node[] constructInt() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("canonical", 685230L),
2011-08-16 12:53:13 +00:00
pair("decimal", 685230L),
pair("octal", 685230L),
pair("hexadecimal", 685230L),
pair("binary", 685230L),
pair("sexagesimal", 685230L)])];
}
2018-03-23 21:35:16 +00:00
Node[] constructMap() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("Block style",
[pair("Clark", "Evans"),
pair("Brian", "Ingerson"),
2011-08-16 12:53:13 +00:00
pair("Oren", "Ben-Kiki")]),
pair("Flow style",
[pair("Clark", "Evans"),
pair("Brian", "Ingerson"),
2011-08-16 12:53:13 +00:00
pair("Oren", "Ben-Kiki")])])];
}
2018-03-23 21:35:16 +00:00
Node[] constructMerge() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([Node([pair("x", 1L), pair("y", 2L)]),
Node([pair("x", 0L), pair("y", 2L)]),
Node([pair("r", 10L)]),
Node([pair("r", 1L)]),
Node([pair("x", 1L), pair("y", 2L), pair("r", 10L), pair("label", "center/big")]),
Node([pair("r", 10L), pair("label", "center/big"), pair("x", 1L), pair("y", 2L)]),
Node([pair("label", "center/big"), pair("x", 1L), pair("y", 2L), pair("r", 10L)]),
Node([pair("x", 1L), pair("label", "center/big"), pair("r", 10L), pair("y", 2L)])])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructNull() @safe
2011-08-16 12:53:13 +00:00
{
return [Node(YAMLNull()),
Node([pair("empty", YAMLNull()),
pair("canonical", YAMLNull()),
pair("english", YAMLNull()),
2011-08-16 12:53:13 +00:00
pair(YAMLNull(), "null key")]),
Node([pair("sparse",
[Node(YAMLNull()),
Node("2nd entry"),
Node(YAMLNull()),
Node("4th entry"),
Node(YAMLNull())])])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructOMap() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("Bestiary",
[pair("aardvark", "African pig-like ant eater. Ugly."),
pair("anteater", "South-American ant eater. Two species."),
pair("anaconda", "South-American constrictor snake. Scaly.")]),
pair("Numbers",[pair("one", 1L),
pair("two", 2L),
2011-08-16 12:53:13 +00:00
pair("three", 3L)])])];
}
2018-03-23 21:35:16 +00:00
Node[] constructPairs() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("Block tasks",
Node([pair("meeting", "with team."),
pair("meeting", "with boss."),
pair("break", "lunch."),
pair("meeting", "with client.")], "tag:yaml.org,2002:pairs")),
pair("Flow tasks",
Node([pair("meeting", "with team"),
pair("meeting", "with boss")], "tag:yaml.org,2002:pairs"))])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructSeq() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("Block style",
[Node("Mercury"), Node("Venus"), Node("Earth"), Node("Mars"),
Node("Jupiter"), Node("Saturn"), Node("Uranus"), Node("Neptune"),
Node("Pluto")]),
2011-08-16 12:53:13 +00:00
pair("Flow style",
[Node("Mercury"), Node("Venus"), Node("Earth"), Node("Mars"),
Node("Jupiter"), Node("Saturn"), Node("Uranus"), Node("Neptune"),
Node("Pluto")])])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructSet() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("baseball players",
[Node("Mark McGwire"), Node("Sammy Sosa"), Node("Ken Griffey")]),
pair("baseball teams",
[Node("Boston Red Sox"), Node("Detroit Tigers"), Node("New York Yankees")])])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructStrASCII() @safe
2011-08-16 12:53:13 +00:00
{
return [Node("ascii string")];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructStr() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("string", "abcd")])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructStrUTF8() @safe
2011-08-16 12:53:13 +00:00
{
return [Node("\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430")];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructTimestamp() @safe
2011-08-16 12:53:13 +00:00
{
alias DT = DateTime;
alias ST = SysTime;
return [Node([pair("canonical", ST(DT(2001, 12, 15, 2, 59, 43), 1000000.dur!"hnsecs", UTC())),
pair("valid iso8601", ST(DT(2001, 12, 15, 2, 59, 43), 1000000.dur!"hnsecs", UTC())),
pair("space separated", ST(DT(2001, 12, 15, 2, 59, 43), 1000000.dur!"hnsecs", UTC())),
pair("no time zone (Z)", ST(DT(2001, 12, 15, 2, 59, 43), 1000000.dur!"hnsecs", UTC())),
pair("date (00:00:00Z)", ST(DT(2002, 12, 14), UTC()))])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] constructValue() @safe
2011-08-16 12:53:13 +00:00
{
return[Node([pair("link with",
[Node("library1.dll"), Node("library2.dll")])]),
Node([pair("link with",
[Node([pair("=", "library1.dll"), pair("version", 1.2L)]),
Node([pair("=", "library2.dll"), pair("version", 2.3L)])])])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] duplicateMergeKey() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair("foo", "bar"),
pair("x", 1L),
pair("y", 2L),
pair("z", 3L),
2011-08-16 12:53:13 +00:00
pair("t", 4L)])];
}
2018-03-23 21:35:16 +00:00
Node[] floatRepresenterBug() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([pair(1.0L, 1L),
pair(real.infinity, 10L),
2011-08-16 12:53:13 +00:00
pair(-real.infinity, -10L),
pair(real.nan, 100L)])];
}
2018-03-23 21:35:16 +00:00
Node[] invalidSingleQuoteBug() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([Node("foo \'bar\'"), Node("foo\n\'bar\'")])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] moreFloats() @safe
2011-08-16 12:53:13 +00:00
{
return [Node([Node(0.0L),
Node(1.0L),
Node(-1.0L),
Node(real.infinity),
Node(-real.infinity),
Node(real.nan),
Node(real.nan)])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] negativeFloatBug() @safe
2011-08-16 12:53:13 +00:00
{
return [Node(-1.0L)];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] singleDotFloatBug() @safe
2011-08-16 12:53:13 +00:00
{
return [Node(".")];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] timestampBugs() @safe
2011-08-16 12:53:13 +00:00
{
alias DT = DateTime;
alias ST = SysTime;
2014-07-19 02:08:20 +00:00
alias STZ = immutable SimpleTimeZone;
return [Node([Node(ST(DT(2001, 12, 15, 3, 29, 43), 1000000.dur!"hnsecs", UTC())),
Node(ST(DT(2001, 12, 14, 16, 29, 43), 1000000.dur!"hnsecs", UTC())),
Node(ST(DT(2001, 12, 14, 21, 59, 43), 10100.dur!"hnsecs", UTC())),
Node(ST(DT(2001, 12, 14, 21, 59, 43), new STZ(60.dur!"minutes"))),
2014-07-19 02:08:20 +00:00
Node(ST(DT(2001, 12, 14, 21, 59, 43), new STZ(-90.dur!"minutes"))),
Node(ST(DT(2005, 7, 8, 17, 35, 4), 5176000.dur!"hnsecs", UTC()))])];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] utf16be() @safe
2011-08-16 12:53:13 +00:00
{
return [Node("UTF-16-BE")];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] utf16le() @safe
2011-08-16 12:53:13 +00:00
{
return [Node("UTF-16-LE")];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] utf8() @safe
2011-08-16 12:53:13 +00:00
{
return [Node("UTF-8")];
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node[] utf8implicit() @safe
2011-08-16 12:53:13 +00:00
{
return [Node("implicit UTF-8")];
2011-08-16 12:53:13 +00:00
}
///Testing custom YAML class type.
class TestClass
{
int x, y, z;
2018-03-23 21:35:16 +00:00
this(int x, int y, int z) @safe
2011-08-16 12:53:13 +00:00
{
this.x = x;
this.y = y;
2011-08-16 12:53:13 +00:00
this.z = z;
}
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
2018-03-23 21:35:16 +00:00
override int opCmp(Object o) @safe
2011-08-16 12:53:13 +00:00
{
TestClass s = cast(TestClass)o;
if(s is null){return -1;}
if(x != s.x){return x - s.x;}
if(y != s.y){return y - s.y;}
if(z != s.z){return z - s.z;}
return 0;
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
override string toString() @safe
{
return format("TestClass(", x, ", ", y, ", ", z, ")");
}
2011-08-16 12:53:13 +00:00
}
///Testing custom YAML struct type.
struct TestStruct
{
int value;
//Any D:YAML type must have a custom opCmp operator.
//This is used for ordering in mappings.
2018-03-23 21:35:16 +00:00
const int opCmp(ref const TestStruct s) @safe
2011-08-16 12:53:13 +00:00
{
return value - s.value;
}
2011-08-16 12:53:13 +00:00
}
///Constructor function for TestClass.
2018-03-23 21:35:16 +00:00
TestClass constructClass(ref Node node) @safe
2011-08-16 12:53:13 +00:00
{
2011-11-17 22:53:24 +00:00
return new TestClass(node["x"].as!int, node["y"].as!int, node["z"].as!int);
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
Node representClass(ref Node node, Representer representer) @safe
{
auto value = node.as!TestClass;
auto pairs = [Node.Pair("x", value.x),
Node.Pair("y", value.y),
Node.Pair("z", value.z)];
auto result = representer.representMapping("!tag1", pairs);
return result;
}
2011-08-16 12:53:13 +00:00
///Constructor function for TestStruct.
2018-03-23 21:35:16 +00:00
TestStruct constructStruct(ref Node node) @safe
2011-08-16 12:53:13 +00:00
{
return TestStruct(to!int(node.as!string));
2011-08-16 12:53:13 +00:00
}
///Representer function for TestStruct.
2018-03-23 21:35:16 +00:00
Node representStruct(ref Node node, Representer representer) @safe
{
string[] keys, values;
auto value = node.as!TestStruct;
return representer.representScalar("!tag2", to!string(value.value));
}
2011-08-16 12:53:13 +00:00
/**
* Constructor unittest.
*
* Params: dataFilename = File name to read from.
2011-08-16 12:53:13 +00:00
* codeDummy = Dummy .code filename, used to determine that
* .data file with the same name should be used in this test.
*/
void testConstructor(string dataFilename, string codeDummy) @safe
2011-08-16 12:53:13 +00:00
{
string base = dataFilename.baseName.stripExtension;
2011-08-16 12:53:13 +00:00
enforce((base in expected) !is null,
new Exception("Unimplemented constructor test: " ~ base));
auto constructor = new Constructor;
constructor.addConstructorMapping("!tag1", &constructClass);
constructor.addConstructorScalar("!tag2", &constructStruct);
2011-08-16 12:53:13 +00:00
auto loader = Loader.fromFile(dataFilename);
loader.constructor = constructor;
loader.resolver = new Resolver;
2011-08-16 12:53:13 +00:00
Node[] exp = expected[base];
2011-08-16 12:53:13 +00:00
//Compare with expected results document by document.
size_t i = 0;
foreach(node; loader)
{
if(!node.equals!(No.useTag)(exp[i]))
2011-08-16 12:53:13 +00:00
{
static if(verbose)
2011-08-16 12:53:13 +00:00
{
writeln("Expected value:");
writeln(exp[i].debugString);
2011-08-16 12:53:13 +00:00
writeln("\n");
writeln("Actual value:");
writeln(node.debugString);
}
assert(false);
}
++i;
}
assert(i == exp.length);
2011-08-16 12:53:13 +00:00
}
2018-03-23 21:35:16 +00:00
@safe unittest
2011-08-16 12:53:13 +00:00
{
2018-04-30 22:11:36 +00:00
printProgress("D:YAML Constructor unittest");
2011-08-16 12:53:13 +00:00
run("testConstructor", &testConstructor, ["data", "code"]);
}
} // version(unittest)