Most of emitter work done. There are some more changes left until 0.2,

and the turorials and documentation still need some updating.
This commit is contained in:
Ferdinand Majerech 2011-10-11 15:58:23 +02:00
parent 967fe8c48b
commit 934df763ad
38 changed files with 3976 additions and 404 deletions

View file

@ -1,3 +0,0 @@
dumper = yaml.Dumper(StringIO())
dumper.open()
dumper.open()

View file

@ -1,4 +0,0 @@
dumper = yaml.Dumper(StringIO())
dumper.open()
dumper.close()
dumper.open()

View file

@ -1,4 +0,0 @@
dumper = yaml.Dumper(StringIO())
dumper.open()
dumper.close()
dumper.serialize(yaml.ScalarNode(tag='!foo', value='bar'))

View file

@ -1,2 +0,0 @@
dumper = yaml.Dumper(StringIO())
dumper.close()

View file

@ -1,2 +0,0 @@
dumper = yaml.Dumper(StringIO())
dumper.serialize(yaml.ScalarNode(tag='!foo', value='bar'))

View file

@ -1 +0,0 @@
yaml.safe_dump(object)

View file

@ -1 +0,0 @@
tag:yaml.org,2002:yaml

View file

@ -93,9 +93,10 @@ string[][string] findTestFilenames(in string dir)
{
if(isFile(name))
{
string base = name.getName();
string ext = name.getExt();
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;

View file

@ -10,6 +10,7 @@ module dyaml.testconstructor;
import std.datetime;
import std.exception;
import std.path;
import std.string;
import dyaml.tag;
import dyaml.testcommon;
@ -21,68 +22,64 @@ Node[][string] expected;
///Initialize expected.
static this()
{
expected["construct-binary.data"] = constructBinary();
expected["construct-bool.data"] = constructBool();
expected["construct-custom.data"] = constructCustom();
expected["construct-float.data"] = constructFloat();
expected["construct-int.data"] = constructInt();
expected["construct-map.data"] = constructMap();
expected["construct-merge.data"] = constructMerge();
expected["construct-null.data"] = constructNull();
expected["construct-omap.data"] = constructOMap();
expected["construct-pairs.data"] = constructPairs();
expected["construct-seq.data"] = constructSeq();
expected["construct-set.data"] = constructSet();
expected["construct-str-ascii.data"] = constructStrASCII();
expected["construct-str.data"] = constructStr();
expected["construct-str-utf8.data"] = constructStrUTF8();
expected["construct-timestamp.data"] = constructTimestamp();
expected["construct-value.data"] = constructValue();
expected["duplicate-merge-key.data"] = duplicateMergeKey();
expected["float-representer-2.3-bug.data"] = floatRepresenterBug();
expected["invalid-single-quote-bug.data"] = invalidSingleQuoteBug();
expected["more-floats.data"] = moreFloats();
expected["negative-float-bug.data"] = negativeFloatBug();
expected["single-dot-is-not-float-bug.data"] = singleDotFloatBug();
expected["timestamp-bugs.data"] = timestampBugs();
expected["utf16be.data"] = utf16be();
expected["utf16le.data"] = utf16le();
expected["utf8.data"] = utf8();
expected["utf8-implicit.data"] = utf8implicit();
}
///Construct a node with specified value.
Node node(T)(T value)
{
static if(Node.Value.allowed!T){return Node.rawNode(Node.Value(value));}
else{return Node.rawNode(Node.userValue(value));}
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();
}
///Construct a pair of nodes with specified values.
Node.Pair pair(A, B)(A a, B b)
{
static if(is(A == Node) && is(B == Node)){return Node.Pair(a, b);}
else static if(is(A == Node)) {return Node.Pair(a, node(b));}
else static if(is(B == Node)) {return Node.Pair(node(a), b);}
else {return Node.Pair(node(a), node(b));}
return Node.Pair(a,b);
}
///Test cases:
Node[] constructAliasesCDumperBug()
{
return [Node(["today", "today"])];
}
Node[] constructBinary()
{
auto canonical = cast(ubyte[])"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;";
auto generic = cast(ubyte[])"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;";
auto description = "The binary value above is a tiny arrow encoded as a gif image.";
return [node([pair("canonical", canonical),
return [Node([pair("canonical", canonical),
pair("generic", generic),
pair("description", description)])];
}
Node[] constructBool()
{
return [node([pair("canonical", true),
return [Node([pair("canonical", true),
pair("answer", false),
pair("logical", true),
pair("option", true),
@ -91,14 +88,14 @@ Node[] constructBool()
Node[] constructCustom()
{
return [node([node(new TestClass(1, 0, 0)),
node(new TestClass(1, 2, 3)),
node(TestStruct(10))])];
return [Node([Node(new TestClass(1, 0, 0)),
Node(new TestClass(1, 2, 3)),
Node(TestStruct(10))])];
}
Node[] constructFloat()
{
return [node([pair("canonical", cast(real)685230.15),
return [Node([pair("canonical", cast(real)685230.15),
pair("exponential", cast(real)685230.15),
pair("fixed", cast(real)685230.15),
pair("sexagesimal", cast(real)685230.15),
@ -108,7 +105,7 @@ Node[] constructFloat()
Node[] constructInt()
{
return [node([pair("canonical", 685230L),
return [Node([pair("canonical", 685230L),
pair("decimal", 685230L),
pair("octal", 685230L),
pair("hexadecimal", 685230L),
@ -118,7 +115,7 @@ Node[] constructInt()
Node[] constructMap()
{
return [node([pair("Block style",
return [Node([pair("Block style",
[pair("Clark", "Evans"),
pair("Brian", "Ingerson"),
pair("Oren", "Ben-Kiki")]),
@ -130,34 +127,34 @@ Node[] constructMap()
Node[] constructMerge()
{
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)])])];
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)])])];
}
Node[] constructNull()
{
return [node(YAMLNull()),
node([pair("empty", YAMLNull()),
return [Node(YAMLNull()),
Node([pair("empty", YAMLNull()),
pair("canonical", YAMLNull()),
pair("english", YAMLNull()),
pair(YAMLNull(), "null key")]),
node([pair("sparse",
[node(YAMLNull()),
node("2nd entry"),
node(YAMLNull()),
node("4th entry"),
node(YAMLNull())])])];
Node([pair("sparse",
[Node(YAMLNull()),
Node("2nd entry"),
Node(YAMLNull()),
Node("4th entry"),
Node(YAMLNull())])])];
}
Node[] constructOMap()
{
return [node([pair("Bestiary",
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.")]),
@ -168,54 +165,54 @@ Node[] constructOMap()
Node[] constructPairs()
{
return [node([pair("Block tasks",
[pair("meeting", "with team."),
pair("meeting", "with boss."),
pair("break", "lunch."),
pair("meeting", "with client.")]),
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",
[pair("meeting", "with team"),
pair("meeting", "with boss")])])];
Node([pair("meeting", "with team"),
pair("meeting", "with boss")], "tag:yaml.org,2002:pairs"))])];
}
Node[] constructSeq()
{
return [node([pair("Block style",
[node("Mercury"), node("Venus"), node("Earth"), node("Mars"),
node("Jupiter"), node("Saturn"), node("Uranus"), node("Neptune"),
node("Pluto")]),
return [Node([pair("Block style",
[Node("Mercury"), Node("Venus"), Node("Earth"), Node("Mars"),
Node("Jupiter"), Node("Saturn"), Node("Uranus"), Node("Neptune"),
Node("Pluto")]),
pair("Flow style",
[node("Mercury"), node("Venus"), node("Earth"), node("Mars"),
node("Jupiter"), node("Saturn"), node("Uranus"), node("Neptune"),
node("Pluto")])])];
[Node("Mercury"), Node("Venus"), Node("Earth"), Node("Mars"),
Node("Jupiter"), Node("Saturn"), Node("Uranus"), Node("Neptune"),
Node("Pluto")])])];
}
Node[] constructSet()
{
return [node([pair("baseball players",
[node("Mark McGwire"), node("Sammy Sosa"), node("Ken Griffey")]),
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")])])];
[Node("Boston Red Sox"), Node("Detroit Tigers"), Node("New York Yankees")])])];
}
Node[] constructStrASCII()
{
return [node("ascii string")];
return [Node("ascii string")];
}
Node[] constructStr()
{
return [node([pair("string", "abcd")])];
return [Node([pair("string", "abcd")])];
}
Node[] constructStrUTF8()
{
return [node("\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430")];
return [Node("\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430")];
}
Node[] constructTimestamp()
{
return [node([pair("canonical", SysTime(DateTime(2001, 12, 15, 2, 59, 43), FracSec.from!"hnsecs"(1000000), UTC())),
return [Node([pair("canonical", SysTime(DateTime(2001, 12, 15, 2, 59, 43), FracSec.from!"hnsecs"(1000000), UTC())),
pair("valid iso8601", SysTime(DateTime(2001, 12, 15, 2, 59, 43), FracSec.from!"hnsecs"(1000000), UTC())),
pair("space separated", SysTime(DateTime(2001, 12, 15, 2, 59, 43), FracSec.from!"hnsecs"(1000000), UTC())),
pair("no time zone (Z)", SysTime(DateTime(2001, 12, 15, 2, 59, 43), FracSec.from!"hnsecs"(1000000), UTC())),
@ -224,16 +221,16 @@ Node[] constructTimestamp()
Node[] constructValue()
{
return[node([pair("link with",
[node("library1.dll"), node("library2.dll")])]),
node([pair("link with",
[node([pair("=", "library1.dll"), pair("version", cast(real)1.2)]),
node([pair("=", "library2.dll"), pair("version", cast(real)2.3)])])])];
return[Node([pair("link with",
[Node("library1.dll"), Node("library2.dll")])]),
Node([pair("link with",
[Node([pair("=", "library1.dll"), pair("version", cast(real)1.2)]),
Node([pair("=", "library2.dll"), pair("version", cast(real)2.3)])])])];
}
Node[] duplicateMergeKey()
{
return [node([pair("foo", "bar"),
return [Node([pair("foo", "bar"),
pair("x", 1L),
pair("y", 2L),
pair("z", 3L),
@ -242,7 +239,7 @@ Node[] duplicateMergeKey()
Node[] floatRepresenterBug()
{
return [node([pair(cast(real)1.0, 1L),
return [Node([pair(cast(real)1.0, 1L),
pair(real.infinity, 10L),
pair(-real.infinity, -10L),
pair(real.nan, 100L)])];
@ -250,58 +247,58 @@ Node[] floatRepresenterBug()
Node[] invalidSingleQuoteBug()
{
return [node([node("foo \'bar\'"), node("foo\n\'bar\'")])];
return [Node([Node("foo \'bar\'"), Node("foo\n\'bar\'")])];
}
Node[] moreFloats()
{
return [node([node(cast(real)0.0),
node(cast(real)1.0),
node(cast(real)-1.0),
node(real.infinity),
node(-real.infinity),
node(real.nan),
node(real.nan)])];
return [Node([Node(cast(real)0.0),
Node(cast(real)1.0),
Node(cast(real)-1.0),
Node(real.infinity),
Node(-real.infinity),
Node(real.nan),
Node(real.nan)])];
}
Node[] negativeFloatBug()
{
return [node(cast(real)-1.0)];
return [Node(cast(real)-1.0)];
}
Node[] singleDotFloatBug()
{
return [node(".")];
return [Node(".")];
}
Node[] timestampBugs()
{
return [node([node(SysTime(DateTime(2001, 12, 15, 3, 29, 43), FracSec.from!"hnsecs"(1000000), UTC())),
node(SysTime(DateTime(2001, 12, 14, 16, 29, 43), FracSec.from!"hnsecs"(1000000), UTC())),
node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), FracSec.from!"hnsecs"(10100), UTC())),
node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), new SimpleTimeZone(60))),
node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), new SimpleTimeZone(-90))),
node(SysTime(DateTime(2005, 7, 8, 17, 35, 4), FracSec.from!"hnsecs"(5176000), UTC()))])];
return [Node([Node(SysTime(DateTime(2001, 12, 15, 3, 29, 43), FracSec.from!"hnsecs"(1000000), UTC())),
Node(SysTime(DateTime(2001, 12, 14, 16, 29, 43), FracSec.from!"hnsecs"(1000000), UTC())),
Node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), FracSec.from!"hnsecs"(10100), UTC())),
Node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), new SimpleTimeZone(60))),
Node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), new SimpleTimeZone(-90))),
Node(SysTime(DateTime(2005, 7, 8, 17, 35, 4), FracSec.from!"hnsecs"(5176000), UTC()))])];
}
Node[] utf16be()
{
return [node("UTF-16-BE")];
return [Node("UTF-16-BE")];
}
Node[] utf16le()
{
return [node("UTF-16-LE")];
return [Node("UTF-16-LE")];
}
Node[] utf8()
{
return [node("UTF-8")];
return [Node("UTF-8")];
}
Node[] utf8implicit()
{
return [node("implicit UTF-8")];
return [Node("implicit UTF-8")];
}
///Testing custom YAML class type.
@ -322,6 +319,11 @@ class TestClass
auto t = cast(TestClass)rhs;
return x == t.x && y == t.y && z == t.z;
}
override string toString()
{
return format("TestClass(", x, ", ", y, ", ", z, ")");
}
}
///Testing custom YAML struct type.
@ -352,6 +354,17 @@ TestClass constructClass(Mark start, Mark end, Node.Pair[] pairs)
return new TestClass(x, y, z);
}
Node representClass(ref Node node, Representer representer)
{
auto value = node.get!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;
}
///Constructor function for TestStruct.
TestStruct constructStruct(Mark start, Mark end, string value)
@ -359,6 +372,14 @@ TestStruct constructStruct(Mark start, Mark end, string value)
return TestStruct(to!int(value));
}
///Representer function for TestStruct.
Node representStruct(ref Node node, Representer representer)
{
string[] keys, values;
auto value = node.get!TestStruct;
return representer.representScalar("!tag2", to!string(value.value));
}
/**
* Constructor unittest.
*
@ -369,7 +390,7 @@ TestStruct constructStruct(Mark start, Mark end, string value)
*/
void testConstructor(bool verbose, string dataFilename, string codeDummy)
{
string base = dataFilename.basename;
string base = dataFilename.baseName.stripExtension;
enforce((base in expected) !is null,
new Exception("Unimplemented constructor test: " ~ base));
@ -380,16 +401,18 @@ void testConstructor(bool verbose, string dataFilename, string codeDummy)
auto resolver = new Resolver;
auto loader = Loader(dataFilename, constructor, resolver);
Node[] exp = expected[base];
//Compare with expected results document by document.
size_t i = 0;
foreach(node; loader)
{
if(!node.equals!(Node, false)(expected[base][i]))
if(!node.equals!(Node, false)(exp[i]))
{
if(verbose)
{
writeln("Expected value:");
writeln(expected[base][i].debugString);
writeln(exp[i].debugString);
writeln("\n");
writeln("Actual value:");
writeln(node.debugString);
@ -398,7 +421,7 @@ void testConstructor(bool verbose, string dataFilename, string codeDummy)
}
++i;
}
assert(i == expected[base].length);
assert(i == exp.length);
}

196
test/src/emitter.d Normal file
View file

@ -0,0 +1,196 @@
// 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.testemitter;
import std.algorithm;
import std.file;
import std.range;
import dyaml.dumper;
import dyaml.event;
import dyaml.testcommon;
import dyaml.token;
/**
* Determine if events in events1 are equivalent to events in events2.
*
* Params: events1 = First event array to compare.
* events2 = Second event array to compare.
*
* Returns: true if the events are equivalent, false otherwise.
*/
bool compareEvents(Event[] events1, Event[] events2)
{
if(events1.length != events2.length){return false;}
for(uint e = 0; e < events1.length; ++e)
{
auto e1 = events1[e];
auto e2 = events2[e];
//Different event types.
if(e1.id != e2.id){return false;}
//Different anchor (if applicable).
if([EventID.SequenceStart,
EventID.MappingStart,
EventID.Alias,
EventID.Scalar].canFind(e1.id)
&& e1.anchor != e2.anchor)
{
return false;
}
//Different collection tag (if applicable).
if([EventID.SequenceStart, EventID.MappingStart].canFind(e1.id) && e1.tag != e2.tag)
{
return false;
}
if(e1.id == EventID.Scalar)
{
//Different scalar tag (if applicable).
if(![e1.implicit, e1.implicit_2, e2.implicit, e2.implicit_2].canFind(true)
&& e1.tag != e2.tag)
{
return false;
}
//Different scalar value.
if(e1.value != e2.value)
{
return false;
}
}
}
return true;
}
/**
* Test emitter by getting events from parsing a file, emitting them, parsing
* the emitted result and comparing events from parsing the emitted result with
* originally parsed events.
*
* Params: verbose = Print verbose output?
* dataFilename = YAML file to parse.
* canonicalFilename = Canonical YAML file used as dummy to determine
* which data files to load.
*/
void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilename)
{
//Must exist due to Anchor, Tags reference counts.
auto loader = Loader(dataFilename);
auto events = loader.parse();
auto emitStream = new MemoryStream;
Dumper(emitStream).emit(events);
if(verbose)
{
writeln(dataFilename);
writeln("ORIGINAL:\n", readText(dataFilename));
writeln("OUTPUT:\n", cast(string)emitStream.data);
}
auto loadStream = new MemoryStream(emitStream.data);
auto newEvents = Loader(loadStream, "DUMMY", new Constructor, new Resolver).parse();
assert(compareEvents(events, newEvents));
}
/**
* Test emitter by getting events from parsing a canonical YAML file, emitting
* them both in canonical and normal format, parsing the emitted results and
* comparing events from parsing the emitted result with originally parsed events.
*
* Params: verbose = Print verbose output?
* canonicalFilename = Canonical YAML file to parse.
*/
void testEmitterOnCanonical(bool verbose, string canonicalFilename)
{
//Must exist due to Anchor, Tags reference counts.
auto loader = Loader(canonicalFilename);
auto events = loader.parse();
foreach(canonical; [false, true])
{
auto emitStream = new MemoryStream;
auto dumper = Dumper(emitStream);
dumper.canonical = canonical;
dumper.emit(events);
if(verbose)
{
writeln("OUTPUT (canonical=", canonical, "):\n",
cast(string)emitStream.data);
}
auto loadStream = new MemoryStream(emitStream.data);
auto newEvents = Loader(loadStream, "DUMMY", new Constructor, new Resolver).parse();
assert(compareEvents(events, newEvents));
}
}
/**
* Test emitter by getting events from parsing a file, emitting them with all
* possible scalar and collection styles, parsing the emitted results and
* comparing events from parsing the emitted result with originally parsed events.
*
* Params: verbose = Print verbose output?
* dataFilename = YAML file to parse.
* canonicalFilename = Canonical YAML file used as dummy to determine
* which data files to load.
*/
void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilename)
{
foreach(filename; [dataFilename, canonicalFilename])
{
//must exist due to Anchor, Tags reference counts
auto loader = Loader(canonicalFilename);
auto events = loader.parse();
foreach(flowStyle; [CollectionStyle.Block, CollectionStyle.Flow])
{
foreach(style; [ScalarStyle.Literal, ScalarStyle.Folded,
ScalarStyle.DoubleQuoted, ScalarStyle.SingleQuoted,
ScalarStyle.Plain])
{
Event[] styledEvents;
foreach(event; events)
{
if(event.id == EventID.Scalar)
{
event = scalarEvent(Mark(), Mark(), event.anchor, event.tag,
[event.implicit, event.implicit_2],
event.value, style);
}
else if(event.id == EventID.SequenceStart)
{
event = sequenceStartEvent(Mark(), Mark(), event.anchor,
event.tag, event.implicit, flowStyle);
}
else if(event.id == EventID.MappingStart)
{
event = mappingStartEvent(Mark(), Mark(), event.anchor,
event.tag, event.implicit, flowStyle);
}
styledEvents ~= event;
}
auto emitStream = new MemoryStream;
Dumper(emitStream).emit(styledEvents);
if(verbose)
{
writeln("OUTPUT (", filename, ", ", to!string(flowStyle), ", ",
to!string(style), ")");
writeln(emitStream.data);
}
auto loadStream = new MemoryStream(emitStream.data);
auto newEvents = Loader(loadStream, "DUMMY", new Constructor, new Resolver).parse();
assert(compareEvents(events, newEvents));
}
}
}
}
unittest
{
writeln("D:YAML Emitter unittest");
run("testEmitterOnData", &testEmitterOnData, ["data", "canonical"]);
run("testEmitterOnCanonical", &testEmitterOnCanonical, ["canonical"]);
run("testEmitterStyles", &testEmitterStyles, ["data", "canonical"]);
}

View file

@ -27,8 +27,8 @@ wchar bom16(bool wrong = false) pure
{
wchar little = *(cast(wchar*)ByteOrderMarks[BOM.UTF16LE]);
wchar big = *(cast(wchar*)ByteOrderMarks[BOM.UTF16BE]);
if(!wrong){return endian == Endian.LittleEndian ? little : big;}
return endian == Endian.LittleEndian ? big : little;
if(!wrong){return endian == Endian.littleEndian ? little : big;}
return endian == Endian.littleEndian ? big : little;
}
/**
@ -42,8 +42,8 @@ dchar bom32(bool wrong = false) pure
{
dchar little = *(cast(dchar*)ByteOrderMarks[BOM.UTF32LE]);
dchar big = *(cast(dchar*)ByteOrderMarks[BOM.UTF32BE]);
if(!wrong){return endian == Endian.LittleEndian ? little : big;}
return endian == Endian.LittleEndian ? big : little;
if(!wrong){return endian == Endian.littleEndian ? little : big;}
return endian == Endian.littleEndian ? big : little;
}
/**

80
test/src/representer.d Normal file
View file

@ -0,0 +1,80 @@
// 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.testrepresenter;
import std.path;
import std.exception;
import dyaml.testcommon;
import dyaml.testconstructor;
/**
* Representer unittest.
*
* Params: verbose = Print verbose output?
* codeFilename = File name to determine test case from.
* Nothing is read from this file, it only exists
* to specify that we need a matching unittest.
*/
void testRepresenterTypes(bool verbose, string codeFilename)
{
string baseName = codeFilename.baseName.stripExtension;
enforce((baseName in dyaml.testconstructor.expected) !is null,
new Exception("Unimplemented representer test: " ~ baseName));
Node[] expectedNodes = expected[baseName];
foreach(encoding; [Encoding.UTF_8, Encoding.UTF_16, Encoding.UTF_32])
{
string output;
Node[] readNodes;
scope(failure)
{
if(verbose)
{
writeln("Expected nodes:");
foreach(ref n; expectedNodes){writeln(n.debugString, "\n---\n");}
writeln("Read nodes:");
foreach(ref n; readNodes){writeln(n.debugString, "\n---\n");}
writeln("OUTPUT:\n", output);
}
}
auto emitStream = new MemoryStream;
auto representer = new Representer;
representer.addRepresenter!TestClass(&representClass);
representer.addRepresenter!TestStruct(&representStruct);
auto dumper = Dumper(emitStream);
dumper.representer = representer;
dumper.encoding = encoding;
dumper.dump(expectedNodes);
output = cast(string)emitStream.data;
auto loadStream = new MemoryStream(emitStream.data);
auto constructor = new Constructor;
constructor.addConstructor("!tag1", &constructClass);
constructor.addConstructor("!tag2", &constructStruct);
auto resolver = new Resolver;
auto loader = Loader(loadStream, "DUMMY", constructor, resolver);
foreach(node; loader){readNodes ~= node;}
assert(expectedNodes.length == readNodes.length);
foreach(n; 0 .. expectedNodes.length)
{
assert(expectedNodes[n].equals!(Node, false)(readNodes[n]));
}
}
}
unittest
{
writeln("D:YAML Representer unittest");
run("testRepresenterTypes", &testRepresenterTypes, ["code"]);
}

48
test/src/resolver.d Normal file
View file

@ -0,0 +1,48 @@
// 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.testresolver;
import std.file;
import std.string;
import dyaml.testcommon;
/**
* Implicit tag resolution unittest.
*
* Params: verbose = Print verbose output?
* dataFilename = TODO
* detectFilename = TODO
*/
void testImplicitResolver(bool verbose, string dataFilename, string detectFilename)
{
string correctTag;
Node node;
scope(exit)
{
if(verbose)
{
writeln("Correct tag: ", correctTag);
writeln("Node: ", node.debugString);
assert(node.isSequence);
assert(node.tag.get == correctTag);
}
}
correctTag = readText(dataFilename).strip();
node = yaml.load(dataFilename);
}
unittest
{
writeln("D:YAML Resolver unittest");
run("testImplicitResolver", &testImplicitResolver, ["data", "detect"]);
}