mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 04:41:16 +00:00
Merged emitter refactor from core
This commit is contained in:
@@ -1,206 +1,10 @@
|
||||
#include "spectests.h"
|
||||
#include "handlermacros.h"
|
||||
#include "specexamples.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include "yaml-cpp/eventhandler.h"
|
||||
#include <cassert>
|
||||
|
||||
#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false)
|
||||
|
||||
namespace Test {
|
||||
struct Event {
|
||||
enum Type { DocStart, DocEnd, Null, Alias, Scalar, SeqStart, SeqEnd, MapStart, MapEnd };
|
||||
|
||||
typedef YAML::Mark Mark;
|
||||
typedef YAML::anchor_t anchor_t;
|
||||
|
||||
Event(Type type_, const std::string& tag_, anchor_t anchor_, const std::string& scalar_): type(type_), tag(tag_), anchor(anchor_), scalar(scalar_) {}
|
||||
|
||||
Type type;
|
||||
std::string tag;
|
||||
anchor_t anchor;
|
||||
std::string scalar;
|
||||
|
||||
std::ostream& write(std::ostream& out) const {
|
||||
switch(type) {
|
||||
case DocStart:
|
||||
return out << "DocStart";
|
||||
case DocEnd:
|
||||
return out << "DocEnd";
|
||||
case Null:
|
||||
return out << "Null(" << anchor << ")";
|
||||
case Alias:
|
||||
return out << "Alias(" << anchor << ")";
|
||||
case Scalar:
|
||||
return out << "Scalar(" << tag << ", " << anchor << ", " << scalar << ")";
|
||||
case SeqStart:
|
||||
return out << "SeqStart(" << tag << ", " << anchor << ")";
|
||||
case SeqEnd:
|
||||
return out << "SeqEnd";
|
||||
case MapStart:
|
||||
return out << "MapStart(" << tag << ", " << anchor << ")";
|
||||
case MapEnd:
|
||||
return out << "MapEnd";
|
||||
}
|
||||
assert(false);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& out, const Event& event) {
|
||||
return event.write(out);
|
||||
}
|
||||
|
||||
bool operator == (const Event& a, const Event& b) {
|
||||
return a.type == b.type && a.tag == b.tag && a.anchor == b.anchor && a.scalar == b.scalar;
|
||||
}
|
||||
|
||||
bool operator != (const Event& a, const Event& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
class MockEventHandler: public YAML::EventHandler
|
||||
{
|
||||
public:
|
||||
typedef YAML::Mark Mark;
|
||||
typedef YAML::anchor_t anchor_t;
|
||||
|
||||
MockEventHandler() {}
|
||||
|
||||
virtual void OnDocumentStart(const Mark&) {
|
||||
m_actualEvents.push_back(Event(Event::DocStart, "", 0, ""));
|
||||
}
|
||||
|
||||
virtual void OnDocumentEnd() {
|
||||
m_actualEvents.push_back(Event(Event::DocEnd, "", 0, ""));
|
||||
}
|
||||
|
||||
virtual void OnNull(const Mark&, anchor_t anchor) {
|
||||
m_actualEvents.push_back(Event(Event::Null, "", anchor, ""));
|
||||
}
|
||||
|
||||
virtual void OnAlias(const Mark&, anchor_t anchor) {
|
||||
m_actualEvents.push_back(Event(Event::Alias, "", anchor, ""));
|
||||
}
|
||||
|
||||
virtual void OnScalar(const Mark&, const std::string& tag, anchor_t anchor, const std::string& value) {
|
||||
m_actualEvents.push_back(Event(Event::Scalar, tag, anchor, value));
|
||||
}
|
||||
|
||||
virtual void OnSequenceStart(const Mark&, const std::string& tag, anchor_t anchor) {
|
||||
m_actualEvents.push_back(Event(Event::SeqStart, tag, anchor, ""));
|
||||
}
|
||||
|
||||
virtual void OnSequenceEnd() {
|
||||
m_actualEvents.push_back(Event(Event::SeqEnd, "", 0, ""));
|
||||
}
|
||||
|
||||
virtual void OnMapStart(const Mark&, const std::string& tag, anchor_t anchor) {
|
||||
m_actualEvents.push_back(Event(Event::MapStart, tag, anchor, ""));
|
||||
}
|
||||
|
||||
virtual void OnMapEnd() {
|
||||
m_actualEvents.push_back(Event(Event::MapEnd, "", 0, ""));
|
||||
}
|
||||
|
||||
void Expect(const Event& event) { m_expectedEvents.push_back(event); }
|
||||
|
||||
Test::TEST Check() const {
|
||||
std::size_t N = std::max(m_expectedEvents.size(), m_actualEvents.size());
|
||||
for(std::size_t i=0;i<N;i++) {
|
||||
if(i >= m_expectedEvents.size()) {
|
||||
std::stringstream out;
|
||||
for(std::size_t j=0;j<i;j++) {
|
||||
out << m_expectedEvents[j] << "\n";
|
||||
}
|
||||
out << "EXPECTED: (no event expected)\n";
|
||||
out << "ACTUAL : " << m_actualEvents[i] << "\n";
|
||||
return out.str().c_str();
|
||||
}
|
||||
|
||||
if(i >= m_actualEvents.size()) {
|
||||
std::stringstream out;
|
||||
for(std::size_t j=0;j<i;j++) {
|
||||
out << m_expectedEvents[j] << "\n";
|
||||
}
|
||||
out << "EXPECTED: " << m_expectedEvents[i] << "\n";
|
||||
out << "ACTUAL : (no event recorded)\n";
|
||||
return out.str().c_str();
|
||||
}
|
||||
|
||||
if(m_expectedEvents[i] != m_actualEvents[i]) {
|
||||
std::stringstream out;
|
||||
for(std::size_t j=0;j<i;j++) {
|
||||
out << m_expectedEvents[j] << "\n";
|
||||
}
|
||||
out << "EXPECTED: " << m_expectedEvents[i] << "\n";
|
||||
out << "ACTUAL : " << m_actualEvents[i] << "\n";
|
||||
return out.str().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Event> m_expectedEvents;
|
||||
std::vector<Event> m_actualEvents;
|
||||
};
|
||||
|
||||
#define HANDLE(ex)\
|
||||
MockEventHandler handler;\
|
||||
std::stringstream stream(ex);\
|
||||
YAML::Parser parser(stream);\
|
||||
while(parser.HandleNextDocument(handler))\
|
||||
|
||||
#define EXPECT_DOC_START()\
|
||||
do {\
|
||||
handler.Expect(Event(Event::DocStart, "", 0, ""));\
|
||||
} while(false)
|
||||
|
||||
#define EXPECT_DOC_END()\
|
||||
do {\
|
||||
handler.Expect(Event(Event::DocEnd, "", 0, ""));\
|
||||
} while(false)
|
||||
|
||||
#define EXPECT_NULL(anchor)\
|
||||
do {\
|
||||
handler.Expect(Event(Event::Null, "", anchor, ""));\
|
||||
} while(false)
|
||||
|
||||
#define EXPECT_ALIAS(anchor)\
|
||||
do {\
|
||||
handler.Expect(Event(Event::Alias, "", anchor, ""));\
|
||||
} while(false)
|
||||
|
||||
#define EXPECT_SCALAR(tag, anchor, value)\
|
||||
do {\
|
||||
handler.Expect(Event(Event::Scalar, tag, anchor, value));\
|
||||
} while(false)
|
||||
|
||||
#define EXPECT_SEQ_START(tag, anchor)\
|
||||
do {\
|
||||
handler.Expect(Event(Event::SeqStart, tag, anchor, ""));\
|
||||
} while(false)
|
||||
|
||||
#define EXPECT_SEQ_END()\
|
||||
do {\
|
||||
handler.Expect(Event(Event::SeqEnd, "", 0, ""));\
|
||||
} while(false)
|
||||
|
||||
#define EXPECT_MAP_START(tag, anchor)\
|
||||
do {\
|
||||
handler.Expect(Event(Event::MapStart, tag, anchor, ""));\
|
||||
} while(false)
|
||||
|
||||
#define EXPECT_MAP_END()\
|
||||
do {\
|
||||
handler.Expect(Event(Event::MapEnd, "", 0, ""));\
|
||||
} while(false)
|
||||
|
||||
#define DONE()\
|
||||
do {\
|
||||
return handler.Check();\
|
||||
} while(false)
|
||||
|
||||
namespace Spec {
|
||||
// 2.1
|
||||
TEST SeqScalars()
|
||||
|
184
test/create-emitter-tests.py
Normal file
184
test/create-emitter-tests.py
Normal file
@@ -0,0 +1,184 @@
|
||||
import sys
|
||||
import yaml
|
||||
import hashlib
|
||||
|
||||
NS = 'Emitter'
|
||||
DEFINE = 'YAML_GEN_TESTS'
|
||||
EVENT_COUNT = 5
|
||||
|
||||
def encode_stream(line):
|
||||
for c in line:
|
||||
if c == '\n':
|
||||
yield '\\n'
|
||||
elif c == '"':
|
||||
yield '\\"'
|
||||
elif c == '\t':
|
||||
yield '\\t'
|
||||
elif ord(c) < 0x20:
|
||||
yield '\\x' + hex(ord(c))
|
||||
else:
|
||||
yield c
|
||||
|
||||
def encode(line):
|
||||
return ''.join(encode_stream(line))
|
||||
|
||||
def doc_start(implicit=False):
|
||||
if implicit:
|
||||
return {'emit': '', 'handle': 'DOC_START()'}
|
||||
else:
|
||||
return {'emit': 'YAML::BeginDoc', 'handle': 'DOC_START()'}
|
||||
|
||||
def doc_end(implicit=False):
|
||||
if implicit:
|
||||
return {'emit': '', 'handle': 'DOC_END()'}
|
||||
else:
|
||||
return {'emit': 'YAML::EndDoc', 'handle': 'DOC_END()'}
|
||||
|
||||
def scalar(value, tag='', anchor='', anchor_id=0):
|
||||
emit = []
|
||||
if tag:
|
||||
emit += ['YAML::VerbatimTag("%s")' % encode(tag)]
|
||||
if anchor:
|
||||
emit += ['YAML::Anchor("%s")' % encode(anchor)]
|
||||
if tag:
|
||||
out_tag = encode(tag)
|
||||
else:
|
||||
if value == encode(value):
|
||||
out_tag = '?'
|
||||
else:
|
||||
out_tag = '!'
|
||||
emit += ['"%s"' % encode(value)]
|
||||
return {'emit': emit, 'handle': 'SCALAR("%s", %s, "%s")' % (out_tag, anchor_id, encode(value))}
|
||||
|
||||
def comment(value):
|
||||
return {'emit': 'YAML::Comment("%s")' % value, 'handle': ''}
|
||||
|
||||
def seq_start(tag='', anchor='', anchor_id=0):
|
||||
emit = []
|
||||
if tag:
|
||||
emit += ['YAML::VerbatimTag("%s")' % encode(tag)]
|
||||
if anchor:
|
||||
emit += ['YAML::Anchor("%s")' % encode(anchor)]
|
||||
if tag:
|
||||
out_tag = encode(tag)
|
||||
else:
|
||||
out_tag = '?'
|
||||
emit += ['YAML::BeginSeq']
|
||||
return {'emit': emit, 'handle': 'SEQ_START("%s", %s)' % (out_tag, anchor_id)}
|
||||
|
||||
def seq_end():
|
||||
return {'emit': 'YAML::EndSeq', 'handle': 'SEQ_END()'}
|
||||
|
||||
def map_start(tag='', anchor='', anchor_id=0):
|
||||
emit = []
|
||||
if tag:
|
||||
emit += ['YAML::VerbatimTag("%s")' % encode(tag)]
|
||||
if anchor:
|
||||
emit += ['YAML::Anchor("%s")' % encode(anchor)]
|
||||
if tag:
|
||||
out_tag = encode(tag)
|
||||
else:
|
||||
out_tag = '?'
|
||||
emit += ['YAML::BeginMap']
|
||||
return {'emit': emit, 'handle': 'MAP_START("%s", %s)' % (out_tag, anchor_id)}
|
||||
|
||||
def map_end():
|
||||
return {'emit': 'YAML::EndMap', 'handle': 'MAP_END()'}
|
||||
|
||||
def gen_templates():
|
||||
yield [[doc_start(), doc_start(True)],
|
||||
[scalar('foo'), scalar('foo\n'), scalar('foo', 'tag'), scalar('foo', '', 'anchor', 1)],
|
||||
[doc_end(), doc_end(True)]]
|
||||
yield [[doc_start(), doc_start(True)],
|
||||
[seq_start()],
|
||||
[[], [scalar('foo')], [scalar('foo', 'tag')], [scalar('foo', '', 'anchor', 1)], [scalar('foo', 'tag', 'anchor', 1)], [scalar('foo'), scalar('bar')], [scalar('foo', 'tag', 'anchor', 1), scalar('bar', 'tag', 'other', 2)]],
|
||||
[seq_end()],
|
||||
[doc_end(), doc_end(True)]]
|
||||
yield [[doc_start(), doc_start(True)],
|
||||
[map_start()],
|
||||
[[], [scalar('foo'), scalar('bar')], [scalar('foo', 'tag', 'anchor', 1), scalar('bar', 'tag', 'other', 2)]],
|
||||
[map_end()],
|
||||
[doc_end(), doc_end(True)]]
|
||||
yield [[doc_start(True)],
|
||||
[map_start()],
|
||||
[[scalar('foo')], [seq_start(), scalar('foo'), seq_end()], [map_start(), scalar('foo'), scalar('bar'), map_end()]],
|
||||
[[scalar('foo')], [seq_start(), scalar('foo'), seq_end()], [map_start(), scalar('foo'), scalar('bar'), map_end()]],
|
||||
[map_end()],
|
||||
[doc_end(True)]]
|
||||
yield [[doc_start(True)],
|
||||
[seq_start()],
|
||||
[[scalar('foo')], [seq_start(), scalar('foo'), seq_end()], [map_start(), scalar('foo'), scalar('bar'), map_end()]],
|
||||
[[scalar('foo')], [seq_start(), scalar('foo'), seq_end()], [map_start(), scalar('foo'), scalar('bar'), map_end()]],
|
||||
[seq_end()],
|
||||
[doc_end(True)]]
|
||||
|
||||
def expand(template):
|
||||
if len(template) == 0:
|
||||
pass
|
||||
elif len(template) == 1:
|
||||
for item in template[0]:
|
||||
if isinstance(item, list):
|
||||
yield item
|
||||
else:
|
||||
yield [item]
|
||||
else:
|
||||
for car in expand(template[:1]):
|
||||
for cdr in expand(template[1:]):
|
||||
yield car + cdr
|
||||
|
||||
|
||||
def gen_events():
|
||||
for template in gen_templates():
|
||||
for events in expand(template):
|
||||
base = list(events)
|
||||
for i in range(0, len(base)+1):
|
||||
cpy = list(base)
|
||||
cpy.insert(i, comment('comment'))
|
||||
yield cpy
|
||||
|
||||
def gen_tests():
|
||||
for events in gen_events():
|
||||
name = 'test' + hashlib.sha1(''.join(yaml.dump(event) for event in events)).hexdigest()[:20]
|
||||
yield {'name': name, 'events': events}
|
||||
|
||||
|
||||
def create_emitter_tests(out):
|
||||
out.write('#ifdef %s\n' % DEFINE)
|
||||
out.write('namespace %s {\n' % NS)
|
||||
|
||||
tests = list(gen_tests())
|
||||
|
||||
for test in tests:
|
||||
out.write('TEST %s(YAML::Emitter& out)\n' % test['name'])
|
||||
out.write('{\n')
|
||||
for event in test['events']:
|
||||
emit = event['emit']
|
||||
if isinstance(emit, list):
|
||||
for e in emit:
|
||||
out.write(' out << %s;\n' % e)
|
||||
elif emit:
|
||||
out.write(' out << %s;\n' % emit)
|
||||
out.write('\n')
|
||||
out.write(' HANDLE(out.c_str());\n')
|
||||
for event in test['events']:
|
||||
handle = event['handle']
|
||||
if handle:
|
||||
out.write(' EXPECT_%s;\n' % handle)
|
||||
out.write(' DONE();\n')
|
||||
out.write('}\n')
|
||||
|
||||
out.write('}\n')
|
||||
out.write('#endif // %s\n\n' % DEFINE)
|
||||
|
||||
out.write('void RunGenEmitterTests(int& passed, int& total)\n')
|
||||
out.write('{\n')
|
||||
out.write('#ifdef %s\n' % DEFINE)
|
||||
for test in tests:
|
||||
out.write(' RunGenEmitterTest(&Emitter::%s, "%s", passed, total);\n' % (test['name'], encode(test['name'])))
|
||||
out.write('#else // %s\n' % DEFINE)
|
||||
out.write(' (void)passed; (void)total;\n')
|
||||
out.write('#endif // %s\n' % DEFINE)
|
||||
out.write('}\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
create_emitter_tests(sys.stdout)
|
@@ -1,4 +1,5 @@
|
||||
#include "tests.h"
|
||||
#include "handlermacros.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include <iostream>
|
||||
|
||||
@@ -190,7 +191,7 @@ namespace Test
|
||||
out << YAML::Value << "demon";
|
||||
out << YAML::EndMap;
|
||||
|
||||
desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon";
|
||||
desiredOutput = "? - 1\n - 3\n: monster\n? [2, 0]\n: demon";
|
||||
}
|
||||
|
||||
void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -204,7 +205,7 @@ namespace Test
|
||||
out << YAML::Value << "angel";
|
||||
out << YAML::EndMap;
|
||||
|
||||
desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel";
|
||||
desiredOutput = "? - 1\n - 3\n: monster\n[2, 0]: demon\nthe origin: angel";
|
||||
}
|
||||
|
||||
void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -218,7 +219,7 @@ namespace Test
|
||||
out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like";
|
||||
out << YAML::EndSeq;
|
||||
|
||||
desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like";
|
||||
desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\ndouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like";
|
||||
}
|
||||
|
||||
void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -256,7 +257,7 @@ namespace Test
|
||||
out << "total value";
|
||||
out << YAML::EndMap;
|
||||
|
||||
desiredOutput = "?\n key: value\n next key: next value\n: total value";
|
||||
desiredOutput = "? key: value\n next key: next value\n: total value";
|
||||
}
|
||||
|
||||
void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -539,7 +540,7 @@ namespace Test
|
||||
{
|
||||
out << YAML::Flow << YAML::BeginSeq << "foo" << YAML::Comment("foo!") << "bar" << YAML::EndSeq;
|
||||
|
||||
desiredOutput = "[foo # foo!\n, bar]";
|
||||
desiredOutput = "[foo, # foo!\nbar]";
|
||||
}
|
||||
|
||||
void CommentInFlowMap(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -550,7 +551,7 @@ namespace Test
|
||||
out << YAML::Key << "baz" << YAML::Value << "baz value" << YAML::Comment("baz!");
|
||||
out << YAML::EndMap;
|
||||
|
||||
desiredOutput = "{foo: foo value, bar: bar value # bar!\n, baz: baz value # baz!\n}";
|
||||
desiredOutput = "{foo: foo value, bar: bar value, # bar!\nbaz: baz value, # baz!\n}";
|
||||
}
|
||||
|
||||
void Indentation(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -563,7 +564,7 @@ namespace Test
|
||||
out << YAML::EndMap;
|
||||
out << YAML::EndSeq;
|
||||
|
||||
desiredOutput = "- key 1: value 1\n key 2:\n - a\n - b\n - c";
|
||||
desiredOutput = "- key 1: value 1\n key 2:\n - a\n - b\n - c";
|
||||
}
|
||||
|
||||
void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -597,7 +598,7 @@ namespace Test
|
||||
out << YAML::EndMap;
|
||||
out << YAML::EndSeq;
|
||||
|
||||
desiredOutput = "- key 1: value 1\n key 2: [a, b, c]\n- ? [1, 2]\n :\n a: b";
|
||||
desiredOutput = "- key 1: value 1\n key 2: [a, b, c]\n- [1, 2]:\n a: b";
|
||||
}
|
||||
|
||||
void Null(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -720,7 +721,7 @@ namespace Test
|
||||
out << YAML::Flow << YAML::BeginSeq;
|
||||
out << "a" << YAML::Newline << "b" << "c" << YAML::Newline << "d";
|
||||
out << YAML::EndSeq;
|
||||
desiredOutput = "[a\n, b, c\n, d]";
|
||||
desiredOutput = "[a,\nb, c,\nd]";
|
||||
}
|
||||
|
||||
void NewlineInBlockMap(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -730,7 +731,7 @@ namespace Test
|
||||
out << YAML::Key << "b" << YAML::Newline << YAML::Value << "bar";
|
||||
out << YAML::LongKey << YAML::Key << "c" << YAML::Newline << YAML::Value << "car";
|
||||
out << YAML::EndMap;
|
||||
desiredOutput = "a: foo\n\nb: bar\n? c\n\n: car";
|
||||
desiredOutput = "a: foo\nb:\n bar\n? c\n\n: car";
|
||||
}
|
||||
|
||||
void NewlineInFlowMap(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -739,7 +740,7 @@ namespace Test
|
||||
out << YAML::Key << "a" << YAML::Value << "foo" << YAML::Newline;
|
||||
out << YAML::Key << "b" << YAML::Value << "bar";
|
||||
out << YAML::EndMap;
|
||||
desiredOutput = "{a: foo\n, b: bar}";
|
||||
desiredOutput = "{a: foo,\nb: bar}";
|
||||
}
|
||||
|
||||
void LotsOfNewlines(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -755,7 +756,7 @@ namespace Test
|
||||
out << YAML::LongKey << YAML::Key << "f" << YAML::Newline << YAML::Value << "foo";
|
||||
out << YAML::EndMap;
|
||||
out << YAML::EndSeq;
|
||||
desiredOutput = "- a\n\n-\n - b\n - c\n\n\n-\n d: e\n ? f\n\n : foo";
|
||||
desiredOutput = "- a\n\n-\n - b\n - c\n\n\n-\n d:\n e\n ? f\n\n : foo";
|
||||
}
|
||||
|
||||
void Binary(YAML::Emitter& out, std::string& desiredOutput)
|
||||
@@ -911,7 +912,40 @@ namespace Test
|
||||
desiredOutput = "[31, 0x1f, 037]";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void CompactMapWithNewline(YAML::Emitter& out, std::string& desiredOutput)
|
||||
{
|
||||
out << YAML::Comment("Characteristics");
|
||||
out << YAML::BeginSeq;
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "color" << YAML::Value << "blue";
|
||||
out << YAML::Key << "height" << YAML::Value << 120;
|
||||
out << YAML::EndMap;
|
||||
out << YAML::Newline << YAML::Newline;
|
||||
out << YAML::Comment("Skills");
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "attack" << YAML::Value << 23;
|
||||
out << YAML::Key << "intelligence" << YAML::Value << 56;
|
||||
out << YAML::EndMap;
|
||||
out << YAML::EndSeq;
|
||||
|
||||
desiredOutput =
|
||||
"# Characteristics\n"
|
||||
"- color: blue\n"
|
||||
" height: 120\n"
|
||||
"\n"
|
||||
"# Skills\n"
|
||||
"- attack: 23\n"
|
||||
" intelligence: 56";
|
||||
}
|
||||
|
||||
void ForceSingleQuotedToDouble(YAML::Emitter& out, std::string& desiredOutput)
|
||||
{
|
||||
out << YAML::SingleQuoted << "Hello\nWorld";
|
||||
|
||||
desiredOutput = "\"Hello\\nWorld\"";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// incorrect emitting
|
||||
|
||||
void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError)
|
||||
@@ -935,13 +969,6 @@ namespace Test
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
|
||||
void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError)
|
||||
{
|
||||
desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR;
|
||||
|
||||
out << YAML::SingleQuoted << "Hello\nWorld";
|
||||
}
|
||||
|
||||
void InvalidAnchor(YAML::Emitter& out, std::string& desiredError)
|
||||
{
|
||||
desiredError = YAML::ErrorMsg::INVALID_ANCHOR;
|
||||
@@ -959,43 +986,6 @@ namespace Test
|
||||
out << YAML::Alias("new\nline");
|
||||
out << YAML::EndSeq;
|
||||
}
|
||||
|
||||
void MissingKey(YAML::Emitter& out, std::string& desiredError)
|
||||
{
|
||||
desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN;
|
||||
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "key" << YAML::Value << "value";
|
||||
out << "missing key" << YAML::Value << "value";
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
|
||||
void MissingValue(YAML::Emitter& out, std::string& desiredError)
|
||||
{
|
||||
desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN;
|
||||
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "key" << "value";
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
|
||||
void UnexpectedKey(YAML::Emitter& out, std::string& desiredError)
|
||||
{
|
||||
desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN;
|
||||
|
||||
out << YAML::BeginSeq;
|
||||
out << YAML::Key << "hi";
|
||||
out << YAML::EndSeq;
|
||||
}
|
||||
|
||||
void UnexpectedValue(YAML::Emitter& out, std::string& desiredError)
|
||||
{
|
||||
desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN;
|
||||
|
||||
out << YAML::BeginSeq;
|
||||
out << YAML::Value << "hi";
|
||||
out << YAML::EndSeq;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -1043,7 +1033,37 @@ namespace Test
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
void RunGenEmitterTest(TEST (*test)(YAML::Emitter&), const std::string& name, int& passed, int& total) {
|
||||
YAML::Emitter out;
|
||||
TEST ret;
|
||||
|
||||
try {
|
||||
ret = test(out);
|
||||
} catch(const YAML::Exception& e) {
|
||||
ret.ok = false;
|
||||
ret.error = std::string(" Exception caught: ") + e.what();
|
||||
}
|
||||
|
||||
if(!out.good()) {
|
||||
ret.ok = false;
|
||||
ret.error = out.GetLastError();
|
||||
}
|
||||
|
||||
if(!ret.ok) {
|
||||
std::cout << "Generated emitter test failed: " << name << "\n";
|
||||
std::cout << "Output:\n";
|
||||
std::cout << out.c_str() << "<<<\n";
|
||||
std::cout << ret.error << "\n";
|
||||
}
|
||||
|
||||
if(ret.ok)
|
||||
passed++;
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
#include "genemittertests.h"
|
||||
|
||||
bool RunEmitterTests()
|
||||
{
|
||||
@@ -1126,17 +1146,16 @@ namespace Test
|
||||
RunEmitterTest(&Emitter::SetPrecision, "set precision", passed, total);
|
||||
RunEmitterTest(&Emitter::DashInBlockContext, "dash in block context", passed, total);
|
||||
RunEmitterTest(&Emitter::HexAndOct, "hex and oct", passed, total);
|
||||
RunEmitterTest(&Emitter::CompactMapWithNewline, "compact map with newline", passed, total);
|
||||
RunEmitterTest(&Emitter::ForceSingleQuotedToDouble, "force single quoted to double", passed, total);
|
||||
|
||||
RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::InvalidAlias, "invalid alias", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::MissingKey, "missing key", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::BadLocalTag, "bad local tag", passed, total);
|
||||
|
||||
RunGenEmitterTests(passed, total);
|
||||
|
||||
std::cout << "Emitter tests: " << passed << "/" << total << " passed\n";
|
||||
return passed == total;
|
||||
|
10256
test/genemittertests.h
Normal file
10256
test/genemittertests.h
Normal file
File diff suppressed because it is too large
Load Diff
190
test/handlermacros.h
Normal file
190
test/handlermacros.h
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "teststruct.h"
|
||||
#pragma once
|
||||
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include "yaml-cpp/eventhandler.h"
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
namespace Test {
|
||||
inline std::string Quote(const std::string& text) {
|
||||
YAML::Emitter out;
|
||||
out << YAML::DoubleQuoted << text;
|
||||
return out.c_str();
|
||||
}
|
||||
|
||||
struct Event {
|
||||
enum Type { DocStart, DocEnd, Null, Alias, Scalar, SeqStart, SeqEnd, MapStart, MapEnd };
|
||||
|
||||
typedef YAML::Mark Mark;
|
||||
typedef YAML::anchor_t anchor_t;
|
||||
|
||||
Event(Type type_, const std::string& tag_, anchor_t anchor_, const std::string& scalar_): type(type_), tag(tag_), anchor(anchor_), scalar(scalar_) {}
|
||||
|
||||
Type type;
|
||||
std::string tag;
|
||||
anchor_t anchor;
|
||||
std::string scalar;
|
||||
|
||||
std::ostream& write(std::ostream& out) const {
|
||||
switch(type) {
|
||||
case DocStart:
|
||||
return out << "DocStart";
|
||||
case DocEnd:
|
||||
return out << "DocEnd";
|
||||
case Null:
|
||||
return out << "Null(" << anchor << ")";
|
||||
case Alias:
|
||||
return out << "Alias(" << anchor << ")";
|
||||
case Scalar:
|
||||
return out << "Scalar(" << Quote(tag) << ", " << anchor << ", " << Quote(scalar) << ")";
|
||||
case SeqStart:
|
||||
return out << "SeqStart(" << Quote(tag) << ", " << anchor << ")";
|
||||
case SeqEnd:
|
||||
return out << "SeqEnd";
|
||||
case MapStart:
|
||||
return out << "MapStart(" << Quote(tag) << ", " << anchor << ")";
|
||||
case MapEnd:
|
||||
return out << "MapEnd";
|
||||
}
|
||||
assert(false);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator << (std::ostream& out, const Event& event) {
|
||||
return event.write(out);
|
||||
}
|
||||
|
||||
inline bool operator == (const Event& a, const Event& b) {
|
||||
return a.type == b.type && a.tag == b.tag && a.anchor == b.anchor && a.scalar == b.scalar;
|
||||
}
|
||||
|
||||
inline bool operator != (const Event& a, const Event& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
class MockEventHandler: public YAML::EventHandler
|
||||
{
|
||||
public:
|
||||
typedef YAML::Mark Mark;
|
||||
typedef YAML::anchor_t anchor_t;
|
||||
|
||||
MockEventHandler() {}
|
||||
|
||||
virtual void OnDocumentStart(const Mark&) {
|
||||
m_actualEvents.push_back(Event(Event::DocStart, "", 0, ""));
|
||||
}
|
||||
|
||||
virtual void OnDocumentEnd() {
|
||||
m_actualEvents.push_back(Event(Event::DocEnd, "", 0, ""));
|
||||
}
|
||||
|
||||
virtual void OnNull(const Mark&, anchor_t anchor) {
|
||||
m_actualEvents.push_back(Event(Event::Null, "", anchor, ""));
|
||||
}
|
||||
|
||||
virtual void OnAlias(const Mark&, anchor_t anchor) {
|
||||
m_actualEvents.push_back(Event(Event::Alias, "", anchor, ""));
|
||||
}
|
||||
|
||||
virtual void OnScalar(const Mark&, const std::string& tag, anchor_t anchor, const std::string& value) {
|
||||
m_actualEvents.push_back(Event(Event::Scalar, tag, anchor, value));
|
||||
}
|
||||
|
||||
virtual void OnSequenceStart(const Mark&, const std::string& tag, anchor_t anchor) {
|
||||
m_actualEvents.push_back(Event(Event::SeqStart, tag, anchor, ""));
|
||||
}
|
||||
|
||||
virtual void OnSequenceEnd() {
|
||||
m_actualEvents.push_back(Event(Event::SeqEnd, "", 0, ""));
|
||||
}
|
||||
|
||||
virtual void OnMapStart(const Mark&, const std::string& tag, anchor_t anchor) {
|
||||
m_actualEvents.push_back(Event(Event::MapStart, tag, anchor, ""));
|
||||
}
|
||||
|
||||
virtual void OnMapEnd() {
|
||||
m_actualEvents.push_back(Event(Event::MapEnd, "", 0, ""));
|
||||
}
|
||||
|
||||
void Expect(const Event& event) { m_expectedEvents.push_back(event); }
|
||||
|
||||
Test::TEST Check() const {
|
||||
std::size_t N = std::max(m_expectedEvents.size(), m_actualEvents.size());
|
||||
for(std::size_t i=0;i<N;i++) {
|
||||
if(i >= m_expectedEvents.size()) {
|
||||
std::stringstream out;
|
||||
for(std::size_t j=0;j<i;j++) {
|
||||
out << " " << m_expectedEvents[j] << "\n";
|
||||
}
|
||||
out << " EXPECTED: (no event expected)\n";
|
||||
out << " ACTUAL : " << m_actualEvents[i] << "\n";
|
||||
return out.str().c_str();
|
||||
}
|
||||
|
||||
if(i >= m_actualEvents.size()) {
|
||||
std::stringstream out;
|
||||
for(std::size_t j=0;j<i;j++) {
|
||||
out << " " << m_expectedEvents[j] << "\n";
|
||||
}
|
||||
out << " EXPECTED: " << m_expectedEvents[i] << "\n";
|
||||
out << " ACTUAL : (no event recorded)\n";
|
||||
return out.str().c_str();
|
||||
}
|
||||
|
||||
if(m_expectedEvents[i] != m_actualEvents[i]) {
|
||||
std::stringstream out;
|
||||
for(std::size_t j=0;j<i;j++) {
|
||||
out << " " << m_expectedEvents[j] << "\n";
|
||||
}
|
||||
out << " EXPECTED: " << m_expectedEvents[i] << "\n";
|
||||
out << " ACTUAL : " << m_actualEvents[i] << "\n";
|
||||
return out.str().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Event> m_expectedEvents;
|
||||
std::vector<Event> m_actualEvents;
|
||||
};
|
||||
|
||||
#define HANDLE(ex)\
|
||||
MockEventHandler handler;\
|
||||
std::stringstream stream(ex);\
|
||||
YAML::Parser parser(stream);\
|
||||
while(parser.HandleNextDocument(handler)) {}
|
||||
|
||||
#define EXPECT_DOC_START()\
|
||||
handler.Expect(Event(Event::DocStart, "", 0, ""))
|
||||
|
||||
#define EXPECT_DOC_END()\
|
||||
handler.Expect(Event(Event::DocEnd, "", 0, ""))
|
||||
|
||||
#define EXPECT_NULL(anchor)\
|
||||
handler.Expect(Event(Event::Null, "", anchor, ""))
|
||||
|
||||
#define EXPECT_ALIAS(anchor)\
|
||||
handler.Expect(Event(Event::Alias, "", anchor, ""))
|
||||
|
||||
#define EXPECT_SCALAR(tag, anchor, value)\
|
||||
handler.Expect(Event(Event::Scalar, tag, anchor, value))
|
||||
|
||||
#define EXPECT_SEQ_START(tag, anchor)\
|
||||
handler.Expect(Event(Event::SeqStart, tag, anchor, ""))
|
||||
|
||||
#define EXPECT_SEQ_END()\
|
||||
handler.Expect(Event(Event::SeqEnd, "", 0, ""))
|
||||
|
||||
#define EXPECT_MAP_START(tag, anchor)\
|
||||
handler.Expect(Event(Event::MapStart, tag, anchor, ""))
|
||||
|
||||
#define EXPECT_MAP_END()\
|
||||
handler.Expect(Event(Event::MapEnd, "", 0, ""))
|
||||
|
||||
#define DONE()\
|
||||
return handler.Check()
|
||||
|
||||
}
|
@@ -5,18 +5,9 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include "teststruct.h"
|
||||
|
||||
namespace Test {
|
||||
struct TEST {
|
||||
TEST(): ok(false) {}
|
||||
TEST(bool ok_): ok(ok_) {}
|
||||
TEST(const char *error_): ok(false), error(error_) {}
|
||||
|
||||
bool ok;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
namespace Spec {
|
||||
// 2.1
|
||||
TEST SeqScalars();
|
||||
|
18
test/teststruct.h
Normal file
18
test/teststruct.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false)
|
||||
|
||||
namespace Test
|
||||
{
|
||||
struct TEST {
|
||||
TEST(): ok(false) {}
|
||||
TEST(bool ok_): ok(ok_) {}
|
||||
TEST(const char *error_): ok(false), error(error_) {}
|
||||
|
||||
bool ok;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
}
|
Reference in New Issue
Block a user