diff --git a/test/core/spectests.cpp b/test/core/spectests.cpp index b707a21..9d13465 100644 --- a/test/core/spectests.cpp +++ b/test/core/spectests.cpp @@ -1,212 +1,10 @@ #include "spectests.h" +#include "handlermacros.h" #include "specexamples.h" #include "yaml-cpp/yaml.h" -#include "yaml-cpp/eventhandler.h" #include -#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false) - namespace Test { - 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; - } - }; - - 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= m_expectedEvents.size()) { - std::stringstream out; - for(std::size_t j=0;j= m_actualEvents.size()) { - std::stringstream out; - for(std::size_t j=0;j m_expectedEvents; - std::vector 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() diff --git a/test/create-emitter-tests.py b/test/create-emitter-tests.py index 4bc622e..6bc0096 100644 --- a/test/create-emitter-tests.py +++ b/test/create-emitter-tests.py @@ -5,13 +5,52 @@ import hashlib NS = 'Emitter' EVENT_COUNT = 5 -EVENTS = [ - {'emit': 'YAML::DocStart', 'handle': 'DOC_START()'}, - {'emit': 'YAML::DocEnd', 'handle': 'DOC_END()'}, -] +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::DocStart', 'handle': 'DOC_START()'} + +def doc_end(implicit=False): + if implicit: + return {'emit': '', 'handle': 'DOC_END()'} + else: + return {'emit': 'YAML::DocEnd', '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)] + emit += ['"%s"' % encode(value)] + return {'emit': emit, 'handle': 'SCALAR("%s", %s, "%s")' % (encode(tag), anchor_id, encode(value))} + +def gen_outlines(): + yield [doc_start(), scalar('foo\n'), doc_end()] + yield [doc_start(True), scalar('foo\n'), doc_end()] + yield [doc_start(), scalar('foo\n'), doc_end(True)] + yield [doc_start(True), scalar('foo\n'), doc_end(True)] def gen_events(): - pass + for events in gen_outlines(): + yield events def gen_tests(): for events in gen_events(): @@ -23,11 +62,14 @@ def create_emitter_tests(out): out.write('namespace %s {\n' % NS) for test in gen_tests(): - out.write('TEST %s(YAML::Emitter& out)\n' % test['name']) + out.write('inline TEST %s(YAML::Emitter& out)\n' % test['name']) out.write('{\n') for event in test['events']: emit = event['emit'] - if 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') diff --git a/test/handlermacros.h b/test/handlermacros.h new file mode 100644 index 0000000..c36d502 --- /dev/null +++ b/test/handlermacros.h @@ -0,0 +1,211 @@ +#pragma once + +#include "yaml-cpp/yaml.h" +#include "yaml-cpp/eventhandler.h" +#include +#include + +#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false) + +namespace Test { + 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; + } + }; + + 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= m_expectedEvents.size()) { + std::stringstream out; + for(std::size_t j=0;j= m_actualEvents.size()) { + std::stringstream out; + for(std::size_t j=0;j m_expectedEvents; + std::vector 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) + +}