diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp index 95c0ac4..9af202f 100644 --- a/yaml-reader/emittertests.cpp +++ b/yaml-reader/emittertests.cpp @@ -534,4 +534,94 @@ namespace Test out << YAML::EndSeq; } } + + namespace { + void RunEmitterTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) { + YAML::Emitter out; + std::string desiredOutput; + test(out, desiredOutput); + std::string output = out.c_str(); + + if(output == desiredOutput) { + passed++; + } else { + std::cout << "Emitter test failed: " << name << "\n"; + std::cout << "Output:\n"; + std::cout << output << "<<<\n"; + std::cout << "Desired output:\n"; + std::cout << desiredOutput << "<<<\n"; + } + total++; + } + + void RunEmitterErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) { + YAML::Emitter out; + std::string desiredError; + test(out, desiredError); + std::string lastError = out.GetLastError(); + if(!out.good() && lastError == desiredError) { + passed++; + } else { + std::cout << "Emitter test failed: " << name << "\n"; + if(out.good()) + std::cout << "No error detected\n"; + else + std::cout << "Detected error: " << lastError << "\n"; + std::cout << "Expected error: " << desiredError << "\n"; + } + total++; + } + } + + bool RunEmitterTests() + { + int passed = 0; + int total = 0; + RunEmitterTest(&Emitter::SimpleScalar, "simple scalar", passed, total); + RunEmitterTest(&Emitter::SimpleSeq, "simple seq", passed, total); + RunEmitterTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed, total); + RunEmitterTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed, total); + RunEmitterTest(&Emitter::NestedBlockSeq, "nested block seq", passed, total); + RunEmitterTest(&Emitter::NestedFlowSeq, "nested flow seq", passed, total); + RunEmitterTest(&Emitter::SimpleMap, "simple map", passed, total); + RunEmitterTest(&Emitter::SimpleFlowMap, "simple flow map", passed, total); + RunEmitterTest(&Emitter::MapAndList, "map and list", passed, total); + RunEmitterTest(&Emitter::ListAndMap, "list and map", passed, total); + RunEmitterTest(&Emitter::NestedBlockMap, "nested block map", passed, total); + RunEmitterTest(&Emitter::NestedFlowMap, "nested flow map", passed, total); + RunEmitterTest(&Emitter::MapListMix, "map list mix", passed, total); + RunEmitterTest(&Emitter::SimpleLongKey, "simple long key", passed, total); + RunEmitterTest(&Emitter::SingleLongKey, "single long key", passed, total); + RunEmitterTest(&Emitter::ComplexLongKey, "complex long key", passed, total); + RunEmitterTest(&Emitter::AutoLongKey, "auto long key", passed, total); + RunEmitterTest(&Emitter::ScalarFormat, "scalar format", passed, total); + RunEmitterTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed, total); + RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed, total); + RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total); + RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total); + RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total); + RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total); + RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total); + RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total); + RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed, total); + RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed, total); + RunEmitterTest(&Emitter::Indentation, "indentation", passed, total); + RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total); + RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total); + RunEmitterTest(&Emitter::Null, "null", 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); + + std::cout << "Emitter tests: " << passed << "/" << total << " passed\n"; + return passed == total; + } } + diff --git a/yaml-reader/emittertests.h b/yaml-reader/emittertests.h new file mode 100644 index 0000000..e746e5a --- /dev/null +++ b/yaml-reader/emittertests.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +namespace Test { + bool RunEmitterTests(); +} + +#endif // EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index 6aa524f..138143c 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -611,4 +611,278 @@ namespace Test return true; } } + + namespace { + void RunScalarParserTest(void (*test)(std::string&, std::string&), const std::string& name, int& passed, int& total) { + std::string error; + std::string inputScalar, desiredOutput; + std::string output; + bool ok = true; + try { + test(inputScalar, desiredOutput); + std::stringstream stream(inputScalar); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + doc >> output; + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok && output == desiredOutput) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + else { + std::cout << "Output:\n" << output << "<<<\n"; + std::cout << "Desired output:\n" << desiredOutput << "<<<\n"; + } + } + total++; + } + + void RunParserTest(bool (*test)(), const std::string& name, int& passed, int& total) { + std::string error; + bool ok = true; + try { + ok = test(); + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + total++; + } + + typedef void (*EncodingFn)(std::ostream&, int); + + inline char Byte(int ch) + { + return static_cast(static_cast(static_cast(ch))); + } + + void EncodeToUtf8(std::ostream& stream, int ch) + { + if (ch <= 0x7F) + { + stream << Byte(ch); + } + else if (ch <= 0x7FF) + { + stream << Byte(0xC0 | (ch >> 6)); + stream << Byte(0x80 | (ch & 0x3F)); + } + else if (ch <= 0xFFFF) + { + stream << Byte(0xE0 | (ch >> 12)); + stream << Byte(0x80 | ((ch >> 6) & 0x3F)); + stream << Byte(0x80 | (ch & 0x3F)); + } + else if (ch <= 0x1FFFFF) + { + stream << Byte(0xF0 | (ch >> 18)); + stream << Byte(0x80 | ((ch >> 12) & 0x3F)); + stream << Byte(0x80 | ((ch >> 6) & 0x3F)); + stream << Byte(0x80 | (ch & 0x3F)); + } + } + + bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch) + { + int biasedValue = ch - 0x10000; + if (biasedValue < 0) + { + return false; + } + int high = 0xD800 | (biasedValue >> 10); + int low = 0xDC00 | (biasedValue & 0x3FF); + encoding(stream, high); + encoding(stream, low); + return true; + } + + void EncodeToUtf16LE(std::ostream& stream, int ch) + { + if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch)) + { + stream << Byte(ch & 0xFF) << Byte(ch >> 8); + } + } + + void EncodeToUtf16BE(std::ostream& stream, int ch) + { + if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch)) + { + stream << Byte(ch >> 8) << Byte(ch & 0xFF); + } + } + + void EncodeToUtf32LE(std::ostream& stream, int ch) + { + stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF) + << Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF); + } + + void EncodeToUtf32BE(std::ostream& stream, int ch) + { + stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF) + << Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF); + } + + class EncodingTester + { + public: + EncodingTester(EncodingFn encoding, bool declareEncoding) + { + if (declareEncoding) + { + encoding(m_yaml, 0xFEFF); + } + + AddEntry(encoding, 0x0021, 0x007E); // Basic Latin + AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement + AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block) + + // CJK unified ideographs (multiple lines) + AddEntry(encoding, 0x4E00, 0x4EFF); + AddEntry(encoding, 0x4F00, 0x4FFF); + AddEntry(encoding, 0x5000, 0x51FF); // 512 character line + AddEntry(encoding, 0x5200, 0x54FF); // 768 character line + AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line + + AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian + + m_yaml.seekg(0, std::ios::beg); + } + + std::istream& stream() {return m_yaml;} + const std::vector& entries() {return m_entries;} + + private: + std::stringstream m_yaml; + std::vector m_entries; + + void AddEntry(EncodingFn encoding, int startCh, int endCh) + { + encoding(m_yaml, '-'); + encoding(m_yaml, ' '); + encoding(m_yaml, '|'); + encoding(m_yaml, '\n'); + encoding(m_yaml, ' '); + encoding(m_yaml, ' '); + + std::stringstream entry; + for (int ch = startCh; ch <= endCh; ++ch) + { + encoding(m_yaml, ch); + EncodeToUtf8(entry, ch); + } + encoding(m_yaml, '\n'); + + m_entries.push_back(entry.str()); + } + }; + + void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, int& passed, int& total) + { + EncodingTester tester(encoding, declareEncoding); + std::string error; + bool ok = true; + try { + YAML::Parser parser(tester.stream()); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML::Iterator itNode = doc.begin(); + std::vector::const_iterator itEntry = tester.entries().begin(); + for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry) + { + std::string stScalarValue; + if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry)) + { + break; + } + } + + if ((itNode != doc.end()) || (itEntry != tester.entries().end())) + { + ok = false; + } + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + total++; + } + } + + bool RunParserTests() + { + int passed = 0; + int total = 0; + RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed, total); + RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed, total); + RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed, total); + RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed, total); + RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed, total); + RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed, total); + RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed, total); + RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed, total); + RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed, total); + RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed, total); + RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed, total); + RunScalarParserTest(&Parser::URLScalar, "url scalar", passed, total); + + RunParserTest(&Parser::SimpleSeq, "simple seq", passed, total); + RunParserTest(&Parser::SimpleMap, "simple map", passed, total); + RunParserTest(&Parser::FlowSeq, "flow seq", passed, total); + RunParserTest(&Parser::FlowMap, "flow map", passed, total); + RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed, total); + RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed, total); + RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed, total); + RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed, total); + RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed, total); + RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed, total); + RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed, total); + RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed, total); + RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed, total); + RunParserTest(&Parser::SimpleAlias, "simple alias", passed, total); + RunParserTest(&Parser::AliasWithNull, "alias with null", passed, total); + RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed, total); + RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed, total); + RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed, total); + RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total); + RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total); + RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total); + + RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); + RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed, total); + + std::cout << "Parser tests: " << passed << "/" << total << " passed\n"; + return passed == total; + } } + diff --git a/yaml-reader/parsertests.h b/yaml-reader/parsertests.h new file mode 100644 index 0000000..e63a2eb --- /dev/null +++ b/yaml-reader/parsertests.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +namespace Test { + bool RunParserTests(); +} + +#endif // PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index dd5ae85..1093a71 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -20,7 +20,7 @@ namespace { namespace Test { namespace { - void RunSpecTest(TEST (*test)(), const std::string& index, const std::string& name, bool& passed) { + void RunSpecTest(TEST (*test)(), const std::string& index, const std::string& name, int& passed, int& total) { TEST ret; try { ret = test(); @@ -29,13 +29,14 @@ namespace Test { ret.error = " Exception caught: " + e.msg; } - if(ret.ok) { - std::cout << "Spec test " << index << " passed: " << name << "\n"; - } else { - passed = false; + if(!ret.ok) { std::cout << "Spec test " << index << " failed: " << name << "\n"; std::cout << ret.error << "\n"; } + + if(ret.ok) + passed++; + total++; } } @@ -955,45 +956,48 @@ namespace Test { bool RunSpecTests() { - bool passed = true; - RunSpecTest(&Spec::SeqScalars, "2.1", "Sequence of Scalars", passed); - RunSpecTest(&Spec::MappingScalarsToScalars, "2.2", "Mapping Scalars to Scalars", passed); - RunSpecTest(&Spec::MappingScalarsToSequences, "2.3", "Mapping Scalars to Sequences", passed); - RunSpecTest(&Spec::SequenceOfMappings, "2.4", "Sequence of Mappings", passed); - RunSpecTest(&Spec::SequenceOfSequences, "2.5", "Sequence of Sequences", passed); - RunSpecTest(&Spec::MappingOfMappings, "2.6", "Mapping of Mappings", passed); - RunSpecTest(&Spec::TwoDocumentsInAStream, "2.7", "Two Documents in a Stream", passed); - RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed); - RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed); - RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed); - RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed); - RunSpecTest(&Spec::CompactNestedMapping, "2.12", "Compact Nested Mapping", passed); - RunSpecTest(&Spec::InLiteralsNewlinesArePreserved, "2.13", "In literals, newlines are preserved", passed); - RunSpecTest(&Spec::InFoldedScalarsNewlinesBecomeSpaces, "2.14", "In folded scalars, newlines become spaces", passed); - RunSpecTest(&Spec::FoldedNewlinesArePreservedForMoreIndentedAndBlankLines, "2.15", "Folded newlines are preserved for \"more indented\" and blank lines", passed); - RunSpecTest(&Spec::IndentationDeterminesScope, "2.16", "Indentation determines scope", passed); - RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed); - RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed); + int passed = 0; + int total = 0; + RunSpecTest(&Spec::SeqScalars, "2.1", "Sequence of Scalars", passed, total); + RunSpecTest(&Spec::MappingScalarsToScalars, "2.2", "Mapping Scalars to Scalars", passed, total); + RunSpecTest(&Spec::MappingScalarsToSequences, "2.3", "Mapping Scalars to Sequences", passed, total); + RunSpecTest(&Spec::SequenceOfMappings, "2.4", "Sequence of Mappings", passed, total); + RunSpecTest(&Spec::SequenceOfSequences, "2.5", "Sequence of Sequences", passed, total); + RunSpecTest(&Spec::MappingOfMappings, "2.6", "Mapping of Mappings", passed, total); + RunSpecTest(&Spec::TwoDocumentsInAStream, "2.7", "Two Documents in a Stream", passed, total); + RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed, total); + RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed, total); + RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed, total); + RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed, total); + RunSpecTest(&Spec::CompactNestedMapping, "2.12", "Compact Nested Mapping", passed, total); + RunSpecTest(&Spec::InLiteralsNewlinesArePreserved, "2.13", "In literals, newlines are preserved", passed, total); + RunSpecTest(&Spec::InFoldedScalarsNewlinesBecomeSpaces, "2.14", "In folded scalars, newlines become spaces", passed, total); + RunSpecTest(&Spec::FoldedNewlinesArePreservedForMoreIndentedAndBlankLines, "2.15", "Folded newlines are preserved for \"more indented\" and blank lines", passed, total); + RunSpecTest(&Spec::IndentationDeterminesScope, "2.16", "Indentation determines scope", passed, total); + RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed, total); + RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed, total); - RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed); - RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed); + RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed, total); + RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed, total); - RunSpecTest(&Spec::BlockStructureIndicators, "5.3", "Block Structure Indicators", passed); - RunSpecTest(&Spec::FlowStructureIndicators, "5.4", "Flow Structure Indicators", passed); - RunSpecTest(&Spec::NodePropertyIndicators, "5.6", "Node Property Indicators", passed); - RunSpecTest(&Spec::BlockScalarIndicators, "5.7", "Block Scalar Indicators", passed); - RunSpecTest(&Spec::QuotedScalarIndicators, "5.8", "Quoted Scalar Indicators", passed); - RunSpecTest(&Spec::LineBreakCharacters, "5.11", "Line Break Characters", passed); - RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed); - RunSpecTest(&Spec::EscapedCharacters, "5.13", "Escaped Characters", passed); - RunSpecTest(&Spec::InvalidEscapedCharacters, "5.14", "Invalid Escaped Characters", passed); + RunSpecTest(&Spec::BlockStructureIndicators, "5.3", "Block Structure Indicators", passed, total); + RunSpecTest(&Spec::FlowStructureIndicators, "5.4", "Flow Structure Indicators", passed, total); + RunSpecTest(&Spec::NodePropertyIndicators, "5.6", "Node Property Indicators", passed, total); + RunSpecTest(&Spec::BlockScalarIndicators, "5.7", "Block Scalar Indicators", passed, total); + RunSpecTest(&Spec::QuotedScalarIndicators, "5.8", "Quoted Scalar Indicators", passed, total); + RunSpecTest(&Spec::LineBreakCharacters, "5.11", "Line Break Characters", passed, total); + RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed, total); + RunSpecTest(&Spec::EscapedCharacters, "5.13", "Escaped Characters", passed, total); + RunSpecTest(&Spec::InvalidEscapedCharacters, "5.14", "Invalid Escaped Characters", passed, total); - RunSpecTest(&Spec::IndentationSpaces, "6.1", "Indentation Spaces", passed); - RunSpecTest(&Spec::IndentationIndicators, "6.2", "Indentation Indicators", passed); - RunSpecTest(&Spec::SeparationSpaces, "6.3", "Separation Spaces", passed); - RunSpecTest(&Spec::LinePrefixes, "6.4", "Line Prefixes", passed); - RunSpecTest(&Spec::EmptyLines, "6.5", "Empty Lines", passed); - return passed; + RunSpecTest(&Spec::IndentationSpaces, "6.1", "Indentation Spaces", passed, total); + RunSpecTest(&Spec::IndentationIndicators, "6.2", "Indentation Indicators", passed, total); + RunSpecTest(&Spec::SeparationSpaces, "6.3", "Separation Spaces", passed, total); + RunSpecTest(&Spec::LinePrefixes, "6.4", "Line Prefixes", passed, total); + RunSpecTest(&Spec::EmptyLines, "6.5", "Empty Lines", passed, total); + + std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; + return passed == total; } } diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index f95ba12..492a5d1 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -1,4 +1,6 @@ #include "tests.h" +#include "emittertests.h" +#include "parsertests.h" #include "spectests.h" #include "yaml.h" #include @@ -23,367 +25,5 @@ namespace Test if(passed) std::cout << "All tests passed!\n"; } - - //////////////////////////////////////////////////////////////////////////////////////// - // Parser tests - - namespace { - void RunScalarParserTest(void (*test)(std::string&, std::string&), const std::string& name, bool& passed) { - std::string error; - std::string inputScalar, desiredOutput; - std::string output; - bool ok = true; - try { - test(inputScalar, desiredOutput); - std::stringstream stream(inputScalar); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - doc >> output; - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok && output == desiredOutput) { - std::cout << "Parser test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - else { - std::cout << "Output:\n" << output << "<<<\n"; - std::cout << "Desired output:\n" << desiredOutput << "<<<\n"; - } - } - } - - void RunParserTest(bool (*test)(), const std::string& name, bool& passed) { - std::string error; - bool ok = true; - try { - ok = test(); - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok) { - std::cout << "Parser test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - } - } - - typedef void (*EncodingFn)(std::ostream&, int); - - inline char Byte(int ch) - { - return static_cast(static_cast(static_cast(ch))); - } - - void EncodeToUtf8(std::ostream& stream, int ch) - { - if (ch <= 0x7F) - { - stream << Byte(ch); - } - else if (ch <= 0x7FF) - { - stream << Byte(0xC0 | (ch >> 6)); - stream << Byte(0x80 | (ch & 0x3F)); - } - else if (ch <= 0xFFFF) - { - stream << Byte(0xE0 | (ch >> 12)); - stream << Byte(0x80 | ((ch >> 6) & 0x3F)); - stream << Byte(0x80 | (ch & 0x3F)); - } - else if (ch <= 0x1FFFFF) - { - stream << Byte(0xF0 | (ch >> 18)); - stream << Byte(0x80 | ((ch >> 12) & 0x3F)); - stream << Byte(0x80 | ((ch >> 6) & 0x3F)); - stream << Byte(0x80 | (ch & 0x3F)); - } - } - - bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch) - { - int biasedValue = ch - 0x10000; - if (biasedValue < 0) - { - return false; - } - int high = 0xD800 | (biasedValue >> 10); - int low = 0xDC00 | (biasedValue & 0x3FF); - encoding(stream, high); - encoding(stream, low); - return true; - } - - void EncodeToUtf16LE(std::ostream& stream, int ch) - { - if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch)) - { - stream << Byte(ch & 0xFF) << Byte(ch >> 8); - } - } - - void EncodeToUtf16BE(std::ostream& stream, int ch) - { - if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch)) - { - stream << Byte(ch >> 8) << Byte(ch & 0xFF); - } - } - - void EncodeToUtf32LE(std::ostream& stream, int ch) - { - stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF) - << Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF); - } - - void EncodeToUtf32BE(std::ostream& stream, int ch) - { - stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF) - << Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF); - } - - class EncodingTester - { - public: - EncodingTester(EncodingFn encoding, bool declareEncoding) - { - if (declareEncoding) - { - encoding(m_yaml, 0xFEFF); - } - - AddEntry(encoding, 0x0021, 0x007E); // Basic Latin - AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement - AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block) - - // CJK unified ideographs (multiple lines) - AddEntry(encoding, 0x4E00, 0x4EFF); - AddEntry(encoding, 0x4F00, 0x4FFF); - AddEntry(encoding, 0x5000, 0x51FF); // 512 character line - AddEntry(encoding, 0x5200, 0x54FF); // 768 character line - AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line - - AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian - - m_yaml.seekg(0, std::ios::beg); - } - - std::istream& stream() {return m_yaml;} - const std::vector& entries() {return m_entries;} - - private: - std::stringstream m_yaml; - std::vector m_entries; - - void AddEntry(EncodingFn encoding, int startCh, int endCh) - { - encoding(m_yaml, '-'); - encoding(m_yaml, ' '); - encoding(m_yaml, '|'); - encoding(m_yaml, '\n'); - encoding(m_yaml, ' '); - encoding(m_yaml, ' '); - - std::stringstream entry; - for (int ch = startCh; ch <= endCh; ++ch) - { - encoding(m_yaml, ch); - EncodeToUtf8(entry, ch); - } - encoding(m_yaml, '\n'); - - m_entries.push_back(entry.str()); - } - }; - - void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, bool& passed) - { - EncodingTester tester(encoding, declareEncoding); - std::string error; - bool ok = true; - try { - YAML::Parser parser(tester.stream()); - YAML::Node doc; - parser.GetNextDocument(doc); - - YAML::Iterator itNode = doc.begin(); - std::vector::const_iterator itEntry = tester.entries().begin(); - for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry) - { - std::string stScalarValue; - if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry)) - { - break; - } - } - - if ((itNode != doc.end()) || (itEntry != tester.entries().end())) - { - ok = false; - } - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok) { - std::cout << "Parser test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - } - } - } - - bool RunParserTests() - { - bool passed = true; - RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed); - RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed); - RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed); - RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed); - RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed); - RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed); - RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed); - RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed); - RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed); - RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed); - RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed); - RunScalarParserTest(&Parser::URLScalar, "url scalar", passed); - - RunParserTest(&Parser::SimpleSeq, "simple seq", passed); - RunParserTest(&Parser::SimpleMap, "simple map", passed); - RunParserTest(&Parser::FlowSeq, "flow seq", passed); - RunParserTest(&Parser::FlowMap, "flow map", passed); - RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed); - RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed); - RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed); - RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed); - RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed); - RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed); - RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed); - RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed); - RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed); - RunParserTest(&Parser::SimpleAlias, "simple alias", passed); - RunParserTest(&Parser::AliasWithNull, "alias with null", passed); - RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed); - RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed); - RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed); - RunParserTest(&Parser::MultipleDocs, "multiple docs", passed); - RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed); - RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed); - - RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed); - RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed); - RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed); - RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed); - RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed); - RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed); - RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed); - RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed); - RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed); - RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed); - return passed; - } - - //////////////////////////////////////////////////////////////////////////////////////// - // Emitter tests - - namespace { - void RunEmitterTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { - YAML::Emitter out; - std::string desiredOutput; - test(out, desiredOutput); - std::string output = out.c_str(); - - if(output == desiredOutput) { - std::cout << "Emitter test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Emitter test failed: " << name << "\n"; - std::cout << "Output:\n"; - std::cout << output << "<<<\n"; - std::cout << "Desired output:\n"; - std::cout << desiredOutput << "<<<\n"; - } - } - - void RunEmitterErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { - YAML::Emitter out; - std::string desiredError; - test(out, desiredError); - std::string lastError = out.GetLastError(); - if(!out.good() && lastError == desiredError) { - std::cout << "Emitter test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Emitter test failed: " << name << "\n"; - if(out.good()) - std::cout << "No error detected\n"; - else - std::cout << "Detected error: " << lastError << "\n"; - std::cout << "Expected error: " << desiredError << "\n"; - } - } - } - - bool RunEmitterTests() - { - bool passed = true; - RunEmitterTest(&Emitter::SimpleScalar, "simple scalar", passed); - RunEmitterTest(&Emitter::SimpleSeq, "simple seq", passed); - RunEmitterTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed); - RunEmitterTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed); - RunEmitterTest(&Emitter::NestedBlockSeq, "nested block seq", passed); - RunEmitterTest(&Emitter::NestedFlowSeq, "nested flow seq", passed); - RunEmitterTest(&Emitter::SimpleMap, "simple map", passed); - RunEmitterTest(&Emitter::SimpleFlowMap, "simple flow map", passed); - RunEmitterTest(&Emitter::MapAndList, "map and list", passed); - RunEmitterTest(&Emitter::ListAndMap, "list and map", passed); - RunEmitterTest(&Emitter::NestedBlockMap, "nested block map", passed); - RunEmitterTest(&Emitter::NestedFlowMap, "nested flow map", passed); - RunEmitterTest(&Emitter::MapListMix, "map list mix", passed); - RunEmitterTest(&Emitter::SimpleLongKey, "simple long key", passed); - RunEmitterTest(&Emitter::SingleLongKey, "single long key", passed); - RunEmitterTest(&Emitter::ComplexLongKey, "complex long key", passed); - RunEmitterTest(&Emitter::AutoLongKey, "auto long key", passed); - RunEmitterTest(&Emitter::ScalarFormat, "scalar format", passed); - RunEmitterTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed); - RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed); - RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed); - RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed); - RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed); - RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed); - RunEmitterTest(&Emitter::STLContainers, "STL containers", passed); - RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed); - RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed); - RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed); - RunEmitterTest(&Emitter::Indentation, "indentation", passed); - RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed); - RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed); - RunEmitterTest(&Emitter::Null, "null", passed); - - RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed); - RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed); - RunEmitterErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed); - RunEmitterErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed); - RunEmitterErrorTest(&Emitter::InvalidAlias, "invalid alias", passed); - RunEmitterErrorTest(&Emitter::MissingKey, "missing key", passed); - RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed); - RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed); - RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed); - return passed; - } - } + diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index bcdc33e..0d39007 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -5,13 +5,8 @@ #include -namespace YAML { class Emitter; } - namespace Test { void RunAll(); - - bool RunParserTests(); - bool RunEmitterTests(); namespace Parser { // scalar tests @@ -51,53 +46,6 @@ namespace Test { bool ExplicitEndDoc(); bool MultipleDocsWithSomeExplicitIndicators(); } - - namespace Emitter { - // correct emitting - void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput); - void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput); - void SimpleFlowSeq(YAML::Emitter& ouptut, std::string& desiredOutput); - void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput); - void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput); - void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput); - void SimpleMap(YAML::Emitter& out, std::string& desiredOutput); - void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput); - void MapAndList(YAML::Emitter& out, std::string& desiredOutput); - void ListAndMap(YAML::Emitter& out, std::string& desiredOutput); - void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput); - void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput); - void MapListMix(YAML::Emitter& out, std::string& desiredOutput); - void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput); - void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput); - void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput); - void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput); - void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput); - void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput); - void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput); - void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput); - void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput); - void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput); - void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput); - void STLContainers(YAML::Emitter& out, std::string& desiredOutput); - void SimpleComment(YAML::Emitter& out, std::string& desiredOutput); - void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput); - void ComplexComments(YAML::Emitter& out, std::string& desiredOutput); - void Indentation(YAML::Emitter& out, std::string& desiredOutput); - void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput); - void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput); - void Null(YAML::Emitter& out, std::string& desiredOutput); - - // incorrect emitting - void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError); - void ExtraEndMap(YAML::Emitter& out, std::string& desiredError); - void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError); - void InvalidAnchor(YAML::Emitter& out, std::string& desiredError); - void InvalidAlias(YAML::Emitter& out, std::string& desiredError); - void MissingKey(YAML::Emitter& out, std::string& desiredError); - void MissingValue(YAML::Emitter& out, std::string& desiredError); - void UnexpectedKey(YAML::Emitter& out, std::string& desiredError); - void UnexpectedValue(YAML::Emitter& out, std::string& desiredError); - } } #endif // TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66