#include "yaml-cpp/yaml.h" // IWYU pragma: keep #include "gtest/gtest.h" namespace YAML { namespace { TEST(LoadNodeTest, Reassign) { Node node = Load("foo"); node = Node(); EXPECT_TRUE(node.IsNull()); } TEST(LoadNodeTest, FallbackValues) { Node node = Load("foo: bar\nx: 2"); EXPECT_EQ("bar", node["foo"].as()); EXPECT_EQ("bar", node["foo"].as("hello")); EXPECT_EQ("hello", node["baz"].as("hello")); EXPECT_EQ(2, node["x"].as()); EXPECT_EQ(2, node["x"].as(5)); EXPECT_EQ(5, node["y"].as(5)); } TEST(LoadNodeTest, NumericConversion) { EXPECT_EQ(1.5f, Load("1.5").as()); EXPECT_EQ(1.5, Load("1.5").as()); EXPECT_THROW(Load("1.5").as(), TypedBadConversion); EXPECT_EQ(1, Load("1").as()); EXPECT_EQ(1.0f, Load("1").as()); EXPECT_NE(Load(".nan").as(), Load(".nan").as()); EXPECT_EQ(std::numeric_limits::infinity(), Load(".inf").as()); EXPECT_EQ(-std::numeric_limits::infinity(), Load("-.inf").as()); EXPECT_EQ(21, Load("0x15").as()); EXPECT_EQ(13, Load("015").as()); EXPECT_EQ(-128, +Load("-128").as()); EXPECT_EQ(127, +Load("127").as()); EXPECT_THROW(Load("128").as(), TypedBadConversion); EXPECT_EQ(255, +Load("255").as()); EXPECT_THROW(Load("256").as(), TypedBadConversion); // test as/as with ‘a’,"ab",'1',"127" EXPECT_EQ('a', Load("a").as()); EXPECT_THROW(Load("ab").as(), TypedBadConversion); EXPECT_EQ('1', Load("1").as()); EXPECT_THROW(Load("127").as(), TypedBadConversion); EXPECT_THROW(Load("a").as(), TypedBadConversion); EXPECT_THROW(Load("ab").as(), TypedBadConversion); EXPECT_EQ(1, +Load("1").as()); // Throw exception: convert a negative number to an unsigned number. EXPECT_THROW(Load("-128").as(), TypedBadConversion); EXPECT_THROW(Load("-128").as(), TypedBadConversion); EXPECT_THROW(Load("-128").as(), TypedBadConversion); EXPECT_THROW(Load("-128").as(), TypedBadConversion); EXPECT_THROW(Load("-128").as(), TypedBadConversion); } TEST(LoadNodeTest, Binary) { Node node = Load( "[!!binary \"SGVsbG8sIFdvcmxkIQ==\", !!binary " "\"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieS" "B0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIG" "x1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbi" "B0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZG" "dlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS" "4K\"]"); EXPECT_EQ(Binary(reinterpret_cast("Hello, World!"), 13), node[0].as()); EXPECT_EQ(Binary(reinterpret_cast( "Man is distinguished, not only by his reason, " "but by this singular passion from other " "animals, which is a lust of the mind, that by " "a perseverance of delight in the continued and " "indefatigable generation of knowledge, exceeds " "the short vehemence of any carnal pleasure.\n"), 270), node[1].as()); } TEST(LoadNodeTest, BinaryWithWhitespaces) { Node node = Load( "binaryText: !binary |-\n" " TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieS\n" " B0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIG\n" " x1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbi\n" " B0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZG\n" " dlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS\n" " 4K"); EXPECT_EQ(Binary(reinterpret_cast( "Man is distinguished, not only by his reason, " "but by this singular passion from other " "animals, which is a lust of the mind, that by " "a perseverance of delight in the continued and " "indefatigable generation of knowledge, exceeds " "the short vehemence of any carnal pleasure.\n"), 270), node["binaryText"].as()); } TEST(LoadNodeTest, IterateSequence) { Node node = Load("[1, 3, 5, 7]"); int seq[] = {1, 3, 5, 7}; int i = 0; for (const_iterator it = node.begin(); it != node.end(); ++it) { EXPECT_TRUE(i < 4); int x = seq[i++]; EXPECT_EQ(x, it->as()); } EXPECT_EQ(4, i); } TEST(LoadNodeTest, IterateMap) { Node node = Load("{a: A, b: B, c: C}"); int i = 0; for (const_iterator it = node.begin(); it != node.end(); ++it) { EXPECT_TRUE(i < 3); i++; EXPECT_EQ(it->second.as(), it->first.as() + 'A' - 'a'); } EXPECT_EQ(3, i); } #ifdef BOOST_FOREACH TEST(LoadNodeTest, ForEach) { Node node = Load("[1, 3, 5, 7]"); int seq[] = {1, 3, 5, 7}; int i = 0; BOOST_FOREACH (const Node& item, node) { int x = seq[i++]; EXPECT_EQ(x, item.as()); } } TEST(LoadNodeTest, ForEachMap) { Node node = Load("{a: A, b: B, c: C}"); BOOST_FOREACH (const const_iterator::value_type& p, node) { EXPECT_EQ(p.second.as(), p.first.as() + 'A' - 'a'); } } #endif TEST(LoadNodeTest, CloneScalar) { Node node = Load("!foo monkey"); Node clone = Clone(node); EXPECT_FALSE(clone == node); EXPECT_EQ(clone.as(), node.as()); EXPECT_EQ(clone.Tag(), node.Tag()); } TEST(LoadNodeTest, CloneSeq) { Node node = Load("[1, 3, 5, 7]"); Node clone = Clone(node); EXPECT_FALSE(clone == node); EXPECT_EQ(NodeType::Sequence, clone.Type()); EXPECT_EQ(clone.size(), node.size()); for (std::size_t i = 0; i < node.size(); i++) { EXPECT_EQ(clone[i].as(), node[i].as()); } } TEST(LoadNodeTest, CloneMap) { Node node = Load("{foo: bar}"); Node clone = Clone(node); EXPECT_FALSE(clone == node); EXPECT_EQ(NodeType::Map, clone.Type()); EXPECT_EQ(clone.size(), node.size()); EXPECT_EQ(clone["foo"].as(), node["foo"].as()); } TEST(LoadNodeTest, CloneAlias) { Node node = Load("&foo [*foo]"); Node clone = Clone(node); EXPECT_FALSE(clone == node); EXPECT_EQ(NodeType::Sequence, clone.Type()); EXPECT_EQ(clone.size(), node.size()); EXPECT_EQ(clone[0], clone); } TEST(LoadNodeTest, ForceInsertIntoMap) { Node node; node["a"] = "b"; node.force_insert("x", "y"); node.force_insert("a", 5); EXPECT_EQ(3, node.size()); EXPECT_EQ(NodeType::Map, node.Type()); bool ab = false; bool a5 = false; bool xy = false; for (const_iterator it = node.begin(); it != node.end(); ++it) { if (it->first.as() == "a") { if (it->second.as() == "b") ab = true; else if (it->second.as() == "5") a5 = true; } else if (it->first.as() == "x" && it->second.as() == "y") xy = true; } EXPECT_TRUE(ab); EXPECT_TRUE(a5); EXPECT_TRUE(xy); } TEST(LoadNodeTest, ResetNode) { Node node = Load("[1, 2, 3]"); EXPECT_TRUE(!node.IsNull()); Node other = node; node.reset(); EXPECT_TRUE(node.IsNull()); EXPECT_TRUE(!other.IsNull()); node.reset(other); EXPECT_TRUE(!node.IsNull()); EXPECT_EQ(node, other); } TEST(LoadNodeTest, EmptyString) { Node node = Load("\"\""); EXPECT_TRUE(!node.IsNull()); } TEST(LoadNodeTest, DereferenceIteratorError) { Node node = Load("[{a: b}, 1, 2]"); EXPECT_THROW(node.begin()->first.as(), InvalidNode); EXPECT_EQ(true, (*node.begin()).IsMap()); EXPECT_EQ(true, node.begin()->IsMap()); EXPECT_THROW((*node.begin()->begin()).Type(), InvalidNode); EXPECT_THROW(node.begin()->begin()->Type(), InvalidNode); } TEST(NodeTest, EmitEmptyNode) { Node node; Emitter emitter; emitter << node; EXPECT_EQ("", std::string(emitter.c_str())); } TEST(NodeTest, ParseNodeStyle) { EXPECT_EQ(EmitterStyle::Flow, Load("[1, 2, 3]").Style()); EXPECT_EQ(EmitterStyle::Flow, Load("{foo: bar}").Style()); EXPECT_EQ(EmitterStyle::Block, Load("- foo\n- bar").Style()); EXPECT_EQ(EmitterStyle::Block, Load("foo: bar").Style()); } struct ParserExceptionTestCase { std::string name; std::string input; std::string expected_exception; }; TEST(NodeTest, IncompleteJson) { std::vector tests = { {"JSON map without value", "{\"access\"", ErrorMsg::END_OF_MAP_FLOW}, {"JSON map with colon but no value", "{\"access\":", ErrorMsg::END_OF_MAP_FLOW}, {"JSON map with unclosed value quote", "{\"access\":\"", ErrorMsg::END_OF_MAP_FLOW}, {"JSON map without end brace", "{\"access\":\"abc\"", ErrorMsg::END_OF_MAP_FLOW}, }; for (const ParserExceptionTestCase& test : tests) { try { Load(test.input); FAIL() << "Expected exception " << test.expected_exception << " for " << test.name << ", input: " << test.input; } catch (const ParserException& e) { EXPECT_EQ(test.expected_exception, e.msg); } } } struct SingleNodeTestCase { std::string input; NodeType::value nodeType; int nodeSize; std::string expected_content; }; TEST(NodeTest, SpecialFlow) { std::vector tests = { {"[:]", NodeType::Sequence, 1, "[{~: ~}]"}, {"[a:]", NodeType::Sequence, 1, "[{a: ~}]"}, {"[:a]", NodeType::Sequence, 1, "[:a]"}, {"[,]", NodeType::Sequence, 1, "[~]"}, {"[a:,]", NodeType::Sequence, 1, "[{a: ~}]"}, {"{:}", NodeType::Map, 1, "{~: ~}"}, {"{a:}", NodeType::Map, 1, "{a: ~}"}, {"{:a}", NodeType::Map, 1, "{:a: ~}"}, {"{,}", NodeType::Map, 1, "{~: ~}"}, {"{a:,}", NodeType::Map, 1, "{a: ~}"}, //testcase for the trailing TAB of scalar {"key\t: value\t", NodeType::Map, 1, "key: value"}, {"key\t: value\t #comment", NodeType::Map, 1, "key: value"}, {"{key\t: value\t}", NodeType::Map, 1, "{key: value}"}, {"{key\t: value\t #comment\n}", NodeType::Map, 1, "{key: value}"}, }; for (const SingleNodeTestCase& test : tests) { Node node = Load(test.input); Emitter emitter; emitter << node; EXPECT_EQ(test.nodeType, node.Type()); EXPECT_EQ(test.nodeSize, node.size()); EXPECT_EQ(test.expected_content, std::string(emitter.c_str())); } } TEST(NodeTest, IncorrectFlow) { std::vector tests = { {"Incorrect yaml: \"{:]\"", "{:]", ErrorMsg::FLOW_END}, {"Incorrect yaml: \"[:}\"", "[:}", ErrorMsg::FLOW_END}, }; for (const ParserExceptionTestCase test : tests) { try { Load(test.input); FAIL() << "Expected exception " << test.expected_exception << " for " << test.name << ", input: " << test.input; } catch (const ParserException& e) { EXPECT_EQ(test.expected_exception, e.msg); } } } TEST(NodeTest, LoadTildeAsNull) { Node node = Load("~"); ASSERT_TRUE(node.IsNull()); EXPECT_EQ(node.as(), "null"); EXPECT_EQ(node.as("~"), "null"); } TEST(NodeTest, LoadNullWithStrTag) { Node node = Load("!!str null"); EXPECT_EQ(node.Tag(), "tag:yaml.org,2002:str"); EXPECT_EQ(node.as(), "null"); } TEST(NodeTest, LoadQuotedNull) { Node node = Load("\"null\""); EXPECT_EQ(node.as(), "null"); } TEST(NodeTest, LoadTagWithParenthesis) { Node node = Load("!Complex(Tag) foo"); EXPECT_EQ(node.Tag(), "!Complex(Tag)"); EXPECT_EQ(node.as(), "foo"); } TEST(NodeTest, LoadTagWithNullScalar) { Node node = Load("!2"); EXPECT_TRUE(node.IsNull()); } TEST(LoadNodeTest, BlockCRNLEncoded) { Node node = Load( "blockText: |\r\n" " some arbitrary text \r\n" " spanning some \r\n" " lines, that are split \r\n" " by CR and NL\r\n" "followup: 1"); EXPECT_EQ( "some arbitrary text \nspanning some \nlines, that are split \nby CR and " "NL\n", node["blockText"].as()); EXPECT_EQ(1, node["followup"].as()); } } // namespace } // namespace YAML