Files
yaml-cpp/test/node/node_test.cpp
Jonathan Hamilton b426fafff6 Fix some Node::operator[] regressions from 0.5.1
"const Node Node::operator[](const Key& key) const" changed from
returning new empty node if the key was missing in 0.5.1 to returning
a shared 'zombie' node in 0.5.2 to resolve a memory leak.

(Specifically 1025f76df1 was where this
was introduced)

This caused some regressions where this 'zombie' object threw exceptions
in some functions where the 'empty' object would not.

This change fixes the Node::as(fallback) method (to return the
'fallback' instead of throwing an exception) and the
Node::begin()/Node::end() methods to return default-constructed
iterators (so begin() == end() in such cases) instead of another
exception.
2015-06-08 11:47:10 -07:00

456 lines
10 KiB
C++

#include "yaml-cpp/emitter.h"
#include "yaml-cpp/node/emit.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/impl.h"
#include "yaml-cpp/node/convert.h"
#include "yaml-cpp/node/iterator.h"
#include "yaml-cpp/node/detail/impl.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using ::testing::AnyOf;
using ::testing::Eq;
namespace YAML {
namespace {
TEST(NodeTest, SimpleScalar) {
Node node = Node("Hello, World!");
EXPECT_TRUE(node.IsScalar());
EXPECT_EQ("Hello, World!", node.as<std::string>());
}
TEST(NodeTest, IntScalar) {
Node node = Node(15);
EXPECT_TRUE(node.IsScalar());
EXPECT_EQ(15, node.as<int>());
}
TEST(NodeTest, SimpleAppendSequence) {
Node node;
node.push_back(10);
node.push_back("foo");
node.push_back("monkey");
EXPECT_TRUE(node.IsSequence());
EXPECT_EQ(3, node.size());
EXPECT_EQ(10, node[0].as<int>());
EXPECT_EQ("foo", node[1].as<std::string>());
EXPECT_EQ("monkey", node[2].as<std::string>());
EXPECT_TRUE(node.IsSequence());
}
TEST(NodeTest, MapElementRemoval) {
Node node;
node["foo"] = "bar";
node.remove("foo");
EXPECT_TRUE(!node["foo"]);
}
TEST(NodeTest, SimpleAssignSequence) {
Node node;
node[0] = 10;
node[1] = "foo";
node[2] = "monkey";
EXPECT_TRUE(node.IsSequence());
EXPECT_EQ(3, node.size());
EXPECT_EQ(10, node[0].as<int>());
EXPECT_EQ("foo", node[1].as<std::string>());
EXPECT_EQ("monkey", node[2].as<std::string>());
EXPECT_TRUE(node.IsSequence());
}
TEST(NodeTest, SimpleMap) {
Node node;
node["key"] = "value";
EXPECT_TRUE(node.IsMap());
EXPECT_EQ("value", node["key"].as<std::string>());
EXPECT_EQ(1, node.size());
}
TEST(NodeTest, MapWithUndefinedValues) {
Node node;
node["key"] = "value";
node["undefined"];
EXPECT_TRUE(node.IsMap());
EXPECT_EQ("value", node["key"].as<std::string>());
EXPECT_EQ(1, node.size());
node["undefined"] = "monkey";
EXPECT_EQ("monkey", node["undefined"].as<std::string>());
EXPECT_EQ(2, node.size());
}
TEST(NodeTest, UndefinedConstNodeWithFallback) {
Node node;
const Node& cn = node;
EXPECT_EQ(cn["undefined"].as<int>(3), 3);
}
TEST(NodeTest, MapIteratorWithUndefinedValues) {
Node node;
node["key"] = "value";
node["undefined"];
std::size_t count = 0;
for (const_iterator it = node.begin(); it != node.end(); ++it)
count++;
EXPECT_EQ(1, count);
}
TEST(NodeTest, ConstIteratorOnConstUndefinedNode) {
Node node;
const Node& cn = node;
const Node& undefinedCn = cn["undefined"];
std::size_t count = 0;
for (const_iterator it = undefinedCn.begin(); it != undefinedCn.end(); ++it) {
count++;
}
EXPECT_EQ(0, count);
}
TEST(NodeTest, IteratorOnConstUndefinedNode) {
Node node;
const Node& cn = node;
const Node& undefinedCn = cn["undefined"];
Node& nonConstUndefinedNode = const_cast<Node&>(undefinedCn);
std::size_t count = 0;
for (iterator it = nonConstUndefinedNode.begin(); it != nonConstUndefinedNode.end(); ++it) {
count++;
}
EXPECT_EQ(0, count);
}
TEST(NodeTest, SimpleSubkeys) {
Node node;
node["device"]["udid"] = "12345";
node["device"]["name"] = "iPhone";
node["device"]["os"] = "4.0";
node["username"] = "monkey";
EXPECT_EQ("12345", node["device"]["udid"].as<std::string>());
EXPECT_EQ("iPhone", node["device"]["name"].as<std::string>());
EXPECT_EQ("4.0", node["device"]["os"].as<std::string>());
EXPECT_EQ("monkey", node["username"].as<std::string>());
}
TEST(NodeTest, StdVector) {
std::vector<int> primes;
primes.push_back(2);
primes.push_back(3);
primes.push_back(5);
primes.push_back(7);
primes.push_back(11);
primes.push_back(13);
Node node;
node["primes"] = primes;
EXPECT_EQ(primes, node["primes"].as<std::vector<int> >());
}
TEST(NodeTest, StdList) {
std::list<int> primes;
primes.push_back(2);
primes.push_back(3);
primes.push_back(5);
primes.push_back(7);
primes.push_back(11);
primes.push_back(13);
Node node;
node["primes"] = primes;
EXPECT_EQ(primes, node["primes"].as<std::list<int> >());
}
TEST(NodeTest, StdMap) {
std::map<int, int> squares;
squares[0] = 0;
squares[1] = 1;
squares[2] = 4;
squares[3] = 9;
squares[4] = 16;
Node node;
node["squares"] = squares;
std::map<int, int> actualSquares = node["squares"].as<std::map<int, int> >();
EXPECT_EQ(squares, actualSquares);
}
TEST(NodeTest, StdPair) {
std::pair<int, std::string> p;
p.first = 5;
p.second = "five";
Node node;
node["pair"] = p;
std::pair<int, std::string> actualP =
node["pair"].as<std::pair<int, std::string> >();
EXPECT_EQ(p, actualP);
}
TEST(NodeTest, SimpleAlias) {
Node node;
node["foo"] = "value";
node["bar"] = node["foo"];
EXPECT_EQ("value", node["foo"].as<std::string>());
EXPECT_EQ("value", node["bar"].as<std::string>());
EXPECT_EQ(node["bar"], node["foo"]);
EXPECT_EQ(2, node.size());
}
TEST(NodeTest, AliasAsKey) {
Node node;
node["foo"] = "value";
Node value = node["foo"];
node[value] = "foo";
EXPECT_EQ("value", node["foo"].as<std::string>());
EXPECT_EQ("foo", node[value].as<std::string>());
EXPECT_EQ("foo", node["value"].as<std::string>());
EXPECT_EQ(2, node.size());
}
TEST(NodeTest, SelfReferenceSequence) {
Node node;
node[0] = node;
EXPECT_TRUE(node.IsSequence());
EXPECT_EQ(1, node.size());
EXPECT_EQ(node, node[0]);
EXPECT_EQ(node, node[0][0]);
EXPECT_EQ(node[0], node[0][0]);
}
TEST(NodeTest, ValueSelfReferenceMap) {
Node node;
node["key"] = node;
EXPECT_TRUE(node.IsMap());
EXPECT_EQ(1, node.size());
EXPECT_EQ(node, node["key"]);
EXPECT_EQ(node, node["key"]["key"]);
EXPECT_EQ(node["key"], node["key"]["key"]);
}
TEST(NodeTest, KeySelfReferenceMap) {
Node node;
node[node] = "value";
EXPECT_TRUE(node.IsMap());
EXPECT_EQ(1, node.size());
EXPECT_EQ("value", node[node].as<std::string>());
}
TEST(NodeTest, SelfReferenceMap) {
Node node;
node[node] = node;
EXPECT_TRUE(node.IsMap());
EXPECT_EQ(1, node.size());
EXPECT_EQ(node, node[node]);
EXPECT_EQ(node, node[node][node]);
EXPECT_EQ(node[node], node[node][node]);
}
TEST(NodeTest, TempMapVariable) {
Node node;
Node tmp = node["key"];
tmp = "value";
EXPECT_TRUE(node.IsMap());
EXPECT_EQ(1, node.size());
EXPECT_EQ("value", node["key"].as<std::string>());
}
TEST(NodeTest, TempMapVariableAlias) {
Node node;
Node tmp = node["key"];
tmp = node["other"];
node["other"] = "value";
EXPECT_TRUE(node.IsMap());
EXPECT_EQ(2, node.size());
EXPECT_EQ("value", node["key"].as<std::string>());
EXPECT_EQ("value", node["other"].as<std::string>());
EXPECT_EQ(node["key"], node["other"]);
}
TEST(NodeTest, Bool) {
Node node;
node[true] = false;
EXPECT_TRUE(node.IsMap());
EXPECT_EQ(false, node[true].as<bool>());
}
TEST(NodeTest, AutoBoolConversion) {
#ifdef _MSC_VER
#pragma warning(disable : 4800)
#endif
Node node;
node["foo"] = "bar";
EXPECT_TRUE(static_cast<bool>(node["foo"]));
EXPECT_TRUE(!node["monkey"]);
EXPECT_TRUE(!!node["foo"]);
}
TEST(NodeTest, FloatingPrecision) {
const double x = 0.123456789;
Node node = Node(x);
EXPECT_EQ(x, node.as<double>());
}
TEST(NodeTest, SpaceChar) {
Node node = Node(' ');
EXPECT_EQ(' ', node.as<char>());
}
TEST(NodeTest, CloneNull) {
Node node;
Node clone = Clone(node);
EXPECT_EQ(NodeType::Null, clone.Type());
}
TEST(NodeTest, KeyNodeExitsScope) {
Node node;
{
Node temp("Hello, world");
node[temp] = 0;
}
for (Node::const_iterator it = node.begin(); it != node.end(); ++it) {
(void)it;
}
}
TEST(NodeTest, DefaultNodeStyle) {
Node node;
EXPECT_EQ(EmitterStyle::Default, node.Style());
}
TEST(NodeTest, AccessNonexistentKeyOnConstNode) {
YAML::Node node;
node["3"] = "4";
const YAML::Node& other = node;
ASSERT_FALSE(other["5"]);
}
class NodeEmitterTest : public ::testing::Test {
protected:
void ExpectOutput(const std::string& output, const Node& node) {
Emitter emitter;
emitter << node;
ASSERT_TRUE(emitter.good());
EXPECT_EQ(output, emitter.c_str());
}
void ExpectAnyOutput(const Node& node, const std::string& output1,
const std::string& output2) {
Emitter emitter;
emitter << node;
ASSERT_TRUE(emitter.good());
EXPECT_THAT(emitter.c_str(), AnyOf(Eq(output1), Eq(output2)));
}
};
TEST_F(NodeEmitterTest, SimpleFlowSeqNode) {
Node node;
node.SetStyle(EmitterStyle::Flow);
node.push_back(1.01);
node.push_back(2.01);
node.push_back(3.01);
ExpectOutput("[1.01, 2.01, 3.01]", node);
}
TEST_F(NodeEmitterTest, NestFlowSeqNode) {
Node node, cell0, cell1;
cell0.push_back(1.01);
cell0.push_back(2.01);
cell0.push_back(3.01);
cell1.push_back(4.01);
cell1.push_back(5.01);
cell1.push_back(6.01);
node.SetStyle(EmitterStyle::Flow);
node.push_back(cell0);
node.push_back(cell1);
ExpectOutput("[[1.01, 2.01, 3.01], [4.01, 5.01, 6.01]]", node);
}
TEST_F(NodeEmitterTest, MixBlockFlowSeqNode) {
Node node, cell0, cell1;
cell0.SetStyle(EmitterStyle::Flow);
cell0.push_back(1.01);
cell0.push_back(2.01);
cell0.push_back(3.01);
cell1.push_back(4.01);
cell1.push_back(5.01);
cell1.push_back(6.01);
node.SetStyle(EmitterStyle::Block);
node.push_back(cell0);
node.push_back(cell1);
ExpectOutput("- [1.01, 2.01, 3.01]\n-\n - 4.01\n - 5.01\n - 6.01", node);
}
TEST_F(NodeEmitterTest, NestBlockFlowMapListNode) {
Node node, mapNode, blockNode;
node.push_back(1.01);
node.push_back(2.01);
node.push_back(3.01);
mapNode.SetStyle(EmitterStyle::Flow);
mapNode["position"] = node;
blockNode.push_back(1.01);
blockNode.push_back(mapNode);
ExpectOutput("- 1.01\n- {position: [1.01, 2.01, 3.01]}", blockNode);
}
TEST_F(NodeEmitterTest, NestBlockMixMapListNode) {
Node node, mapNode, blockNode;
node.push_back(1.01);
node.push_back(2.01);
node.push_back(3.01);
mapNode.SetStyle(EmitterStyle::Flow);
mapNode["position"] = node;
blockNode["scalar"] = 1.01;
blockNode["object"] = mapNode;
ExpectAnyOutput(blockNode,
"scalar: 1.01\nobject: {position: [1.01, 2.01, 3.01]}",
"object: {position: [1.01, 2.01, 3.01]}\nscalar: 1.01");
}
TEST_F(NodeEmitterTest, NestBlockMapListNode) {
Node node, mapNode;
node.push_back(1.01);
node.push_back(2.01);
node.push_back(3.01);
mapNode.SetStyle(EmitterStyle::Block);
mapNode["position"] = node;
ExpectOutput("position:\n - 1.01\n - 2.01\n - 3.01", mapNode);
}
TEST_F(NodeEmitterTest, NestFlowMapListNode) {
Node node, mapNode;
node.push_back(1.01);
node.push_back(2.01);
node.push_back(3.01);
mapNode.SetStyle(EmitterStyle::Flow);
mapNode["position"] = node;
ExpectOutput("{position: [1.01, 2.01, 3.01]}", mapNode);
}
}
}