"vscode:/vscode.git/clone" did not exist on "6c569e58b0ca46dcbf7bbef821b1f4da8918f8fb"
Commit 0d32d19e authored by Jesse Beder's avatar Jesse Beder
Browse files

First pass at spearating out a 'core' library from the old api (default) branch

parent fca7b7e1
#ifndef CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
#include "yaml-cpp/null.h"
#include "yaml-cpp/traits.h"
#include <limits>
#include <string>
#include <sstream>
namespace YAML
{
// traits for conversion
template<typename T>
struct is_scalar_convertible { enum { value = is_numeric<T>::value }; };
template<> struct is_scalar_convertible<std::string> { enum { value = true }; };
template<> struct is_scalar_convertible<bool> { enum { value = true }; };
template<> struct is_scalar_convertible<_Null> { enum { value = true }; };
// actual conversion
inline bool Convert(const std::string& input, std::string& output) {
output = input;
return true;
}
YAML_CPP_API bool Convert(const std::string& input, bool& output);
YAML_CPP_API bool Convert(const std::string& input, _Null& output);
inline bool IsInfinity(const std::string& input) {
return input == ".inf" || input == ".Inf" || input == ".INF" || input == "+.inf" || input == "+.Inf" || input == "+.INF";
}
inline bool IsNegativeInfinity(const std::string& input) {
return input == "-.inf" || input == "-.Inf" || input == "-.INF";
}
inline bool IsNaN(const std::string& input) {
return input == ".nan" || input == ".NaN" || input == ".NAN";
}
template <typename T>
inline bool Convert(const std::string& input, T& output, typename enable_if<is_numeric<T> >::type * = 0) {
std::stringstream stream(input);
stream.unsetf(std::ios::dec);
if((stream >> output) && (stream >> std::ws).eof())
return true;
if(std::numeric_limits<T>::has_infinity) {
if(IsInfinity(input)) {
output = std::numeric_limits<T>::infinity();
return true;
} else if(IsNegativeInfinity(input)) {
output = -std::numeric_limits<T>::infinity();
return true;
}
}
if(std::numeric_limits<T>::has_quiet_NaN && IsNaN(input)) {
output = std::numeric_limits<T>::quiet_NaN();
return true;
}
return false;
}
}
#endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#ifndef ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
#include "yaml-cpp/dll.h"
#include <memory>
namespace YAML
{
class Node;
struct IterPriv;
class YAML_CPP_API Iterator
{
public:
Iterator();
Iterator(std::auto_ptr<IterPriv> pData);
Iterator(const Iterator& rhs);
~Iterator();
Iterator& operator = (const Iterator& rhs);
Iterator& operator ++ ();
Iterator operator ++ (int);
const Node& operator * () const;
const Node *operator -> () const;
const Node& first() const;
const Node& second() const;
friend YAML_CPP_API bool operator == (const Iterator& it, const Iterator& jt);
friend YAML_CPP_API bool operator != (const Iterator& it, const Iterator& jt);
private:
std::auto_ptr<IterPriv> m_pData;
};
}
#endif // ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#ifndef LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
namespace YAML
{
class Node;
struct ltnode {
bool operator()(const Node *pNode1, const Node *pNode2) const;
};
}
#endif // LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#ifndef NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
#include "yaml-cpp/dll.h"
#include "yaml-cpp/exceptions.h"
#include "yaml-cpp/mark.h"
#include "yaml-cpp/noncopyable.h"
#include "yaml-cpp/conversion.h"
#include "yaml-cpp/iterator.h"
#include "yaml-cpp/ltnode.h"
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <vector>
namespace YAML
{
class AliasManager;
class Content;
class NodeOwnership;
class Scanner;
class Emitter;
class EventHandler;
struct NodeType { enum value { Null, Scalar, Sequence, Map }; };
class YAML_CPP_API Node: private noncopyable
{
public:
friend class NodeOwnership;
friend class NodeBuilder;
Node();
~Node();
void Clear();
std::auto_ptr<Node> Clone() const;
void EmitEvents(EventHandler& eventHandler) const;
void EmitEvents(AliasManager& am, EventHandler& eventHandler) const;
NodeType::value Type() const { return m_type; }
bool IsAliased() const;
// file location of start of this node
const Mark GetMark() const { return m_mark; }
// accessors
Iterator begin() const;
Iterator end() const;
std::size_t size() const;
// extraction of scalars
bool GetScalar(std::string& s) const;
// we can specialize this for other values
template <typename T>
bool Read(T& value) const;
template <typename T>
const T to() const;
template <typename T>
friend YAML_CPP_API typename enable_if<is_scalar_convertible<T> >::type operator >> (const Node& node, T& value);
// retrieval for maps and sequences
template <typename T>
const Node *FindValue(const T& key) const;
template <typename T>
const Node& operator [] (const T& key) const;
// specific to maps
const Node *FindValue(const char *key) const;
const Node *FindValue(char *key) const;
const Node& operator [] (const char *key) const;
const Node& operator [] (char *key) const;
// for tags
const std::string& Tag() const { return m_tag; }
// emitting
friend YAML_CPP_API Emitter& operator << (Emitter& out, const Node& node);
// ordering
int Compare(const Node& rhs) const;
friend bool operator < (const Node& n1, const Node& n2);
private:
explicit Node(NodeOwnership& owner);
Node& CreateNode();
void Init(NodeType::value type, const Mark& mark, const std::string& tag);
void MarkAsAliased();
void SetScalarData(const std::string& data);
void Append(Node& node);
void Insert(Node& key, Node& value);
// helper for sequences
template <typename, bool> friend struct _FindFromNodeAtIndex;
const Node *FindAtIndex(std::size_t i) const;
// helper for maps
template <typename T>
const Node& GetValue(const T& key) const;
template <typename T>
const Node *FindValueForKey(const T& key) const;
private:
std::auto_ptr<NodeOwnership> m_pOwnership;
Mark m_mark;
std::string m_tag;
typedef std::vector<Node *> node_seq;
typedef std::map<Node *, Node *, ltnode> node_map;
NodeType::value m_type;
std::string m_scalarData;
node_seq m_seqData;
node_map m_mapData;
};
}
#include "yaml-cpp/nodeimpl.h"
#include "yaml-cpp/nodereadimpl.h"
#endif // NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#ifndef NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
#include "yaml-cpp/nodeutil.h"
#include <cassert>
namespace YAML
{
// implementation of templated things
template <typename T>
inline const T Node::to() const {
T value;
*this >> value;
return value;
}
template <typename T>
inline typename enable_if<is_scalar_convertible<T> >::type operator >> (const Node& node, T& value) {
if(!ConvertScalar(node, value))
throw InvalidScalar(node.m_mark);
}
template <typename T>
inline const Node *Node::FindValue(const T& key) const {
switch(m_type) {
case NodeType::Null:
case NodeType::Scalar:
throw BadDereference();
case NodeType::Sequence:
return FindFromNodeAtIndex(*this, key);
case NodeType::Map:
return FindValueForKey(key);
}
assert(false);
throw BadDereference();
}
template <typename T>
inline const Node *Node::FindValueForKey(const T& key) const {
for(Iterator it=begin();it!=end();++it) {
T t;
if(it.first().Read(t)) {
if(key == t)
return &it.second();
}
}
return 0;
}
template <typename T>
inline const Node& Node::GetValue(const T& key) const {
if(const Node *pValue = FindValue(key))
return *pValue;
throw MakeTypedKeyNotFound(m_mark, key);
}
template <typename T>
inline const Node& Node::operator [] (const T& key) const {
return GetValue(key);
}
inline const Node *Node::FindValue(const char *key) const {
return FindValue(std::string(key));
}
inline const Node *Node::FindValue(char *key) const {
return FindValue(std::string(key));
}
inline const Node& Node::operator [] (const char *key) const {
return GetValue(std::string(key));
}
inline const Node& Node::operator [] (char *key) const {
return GetValue(std::string(key));
}
}
#endif // NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#ifndef NODEREADIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODEREADIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
namespace YAML
{
// implementation for Node::Read
// (the goal is to call ConvertScalar if we can, and fall back to operator >> if not)
// thanks to litb from stackoverflow.com
// http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390
// Note: this doesn't work on gcc 3.2, but does on gcc 3.4 and above. I'm not sure about 3.3.
#if __GNUC__ && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3))
// trick doesn't work? Just fall back to ConvertScalar.
// This means that we can't use any user-defined types as keys in a map
template <typename T>
inline bool Node::Read(T& value) const {
return ConvertScalar(*this, value);
}
#else
// usual case: the trick!
template<bool>
struct read_impl;
// ConvertScalar available
template<>
struct read_impl<true> {
template<typename T>
static bool read(const Node& node, T& value) {
return ConvertScalar(node, value);
}
};
// ConvertScalar not available
template<>
struct read_impl<false> {
template<typename T>
static bool read(const Node& node, T& value) {
try {
node >> value;
} catch(const Exception&) {
return false;
}
return true;
}
};
namespace fallback {
// sizeof > 1
struct flag { char c[2]; };
flag Convert(...);
int operator,(flag, flag);
template<typename T>
char operator,(flag, T const&);
char operator,(int, flag);
int operator,(char, flag);
}
template <typename T>
inline bool Node::Read(T& value) const {
using namespace fallback;
return read_impl<sizeof (fallback::flag(), Convert(std::string(), value), fallback::flag()) != 1>::read(*this, value);
}
#endif // done with trick
// the main conversion function
template <typename T>
inline bool ConvertScalar(const Node& node, T& value) {
std::string scalar;
if(!node.GetScalar(scalar))
return false;
return Convert(scalar, value);
}
}
#endif // NODEREADIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#ifndef NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
namespace YAML
{
template <typename T, typename U>
struct is_same_type {
enum { value = false };
};
template <typename T>
struct is_same_type<T, T> {
enum { value = true };
};
template <typename T, bool check>
struct is_index_type_with_check {
enum { value = false };
};
template <> struct is_index_type_with_check<std::size_t, false> { enum { value = true }; };
#define MAKE_INDEX_TYPE(Type) \
template <> struct is_index_type_with_check<Type, is_same_type<Type, std::size_t>::value> { enum { value = true }; }
MAKE_INDEX_TYPE(int);
MAKE_INDEX_TYPE(unsigned);
MAKE_INDEX_TYPE(short);
MAKE_INDEX_TYPE(unsigned short);
MAKE_INDEX_TYPE(long);
MAKE_INDEX_TYPE(unsigned long);
#undef MAKE_INDEX_TYPE
template <typename T>
struct is_index_type: public is_index_type_with_check<T, false> {};
// messing around with template stuff to get the right overload for operator [] for a sequence
template <typename T, bool b>
struct _FindFromNodeAtIndex {
const Node *pRet;
_FindFromNodeAtIndex(const Node&, const T&): pRet(0) {}
};
template <typename T>
struct _FindFromNodeAtIndex<T, true> {
const Node *pRet;
_FindFromNodeAtIndex(const Node& node, const T& key): pRet(node.FindAtIndex(static_cast<std::size_t>(key))) {}
};
template <typename T>
inline const Node *FindFromNodeAtIndex(const Node& node, const T& key) {
return _FindFromNodeAtIndex<T, is_index_type<T>::value>(node, key).pRet;
}
}
#endif // NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "yaml-cpp/aliasmanager.h"
#include "yaml-cpp/node.h"
#include <cassert>
#include <sstream>
namespace YAML
{
AliasManager::AliasManager(): m_curAnchor(0)
{
}
void AliasManager::RegisterReference(const Node& node)
{
m_anchorByIdentity.insert(std::make_pair(&node, _CreateNewAnchor()));
}
anchor_t AliasManager::LookupAnchor(const Node& node) const
{
AnchorByIdentity::const_iterator it = m_anchorByIdentity.find(&node);
if(it == m_anchorByIdentity.end())
return 0;
return it->second;
}
anchor_t AliasManager::_CreateNewAnchor()
{
return ++m_curAnchor;
}
}
#include "yaml-cpp/conversion.h"
#include <algorithm>
////////////////////////////////////////////////////////////////
// Specializations for converting a string to specific types
namespace
{
// we're not gonna mess with the mess that is all the isupper/etc. functions
bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; }
bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; }
char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; }
std::string tolower(const std::string& str)
{
std::string s(str);
std::transform(s.begin(), s.end(), s.begin(), ToLower);
return s;
}
template <typename T>
bool IsEntirely(const std::string& str, T func)
{
for(std::size_t i=0;i<str.size();i++)
if(!func(str[i]))
return false;
return true;
}
// IsFlexibleCase
// . Returns true if 'str' is:
// . UPPERCASE
// . lowercase
// . Capitalized
bool IsFlexibleCase(const std::string& str)
{
if(str.empty())
return true;
if(IsEntirely(str, IsLower))
return true;
bool firstcaps = IsUpper(str[0]);
std::string rest = str.substr(1);
return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper));
}
}
namespace YAML
{
bool Convert(const std::string& input, bool& b)
{
// we can't use iostream bool extraction operators as they don't
// recognize all possible values in the table below (taken from
// http://yaml.org/type/bool.html)
static const struct {
std::string truename, falsename;
} names[] = {
{ "y", "n" },
{ "yes", "no" },
{ "true", "false" },
{ "on", "off" },
};
if(!IsFlexibleCase(input))
return false;
for(unsigned i=0;i<sizeof(names)/sizeof(names[0]);i++) {
if(names[i].truename == tolower(input)) {
b = true;
return true;
}
if(names[i].falsename == tolower(input)) {
b = false;
return true;
}
}
return false;
}
bool Convert(const std::string& input, _Null& /*output*/)
{
return input.empty() || input == "~" || input == "null" || input == "Null" || input == "NULL";
}
}
#include "yaml-cpp/node.h"
#include "yaml-cpp/exceptions.h"
#include "iterpriv.h"
namespace YAML
{
Iterator::Iterator(): m_pData(new IterPriv)
{
}
Iterator::Iterator(std::auto_ptr<IterPriv> pData): m_pData(pData)
{
}
Iterator::Iterator(const Iterator& rhs): m_pData(new IterPriv(*rhs.m_pData))
{
}
Iterator& Iterator::operator = (const Iterator& rhs)
{
if(this == &rhs)
return *this;
m_pData.reset(new IterPriv(*rhs.m_pData));
return *this;
}
Iterator::~Iterator()
{
}
Iterator& Iterator::operator ++ ()
{
if(m_pData->type == IterPriv::IT_SEQ)
++m_pData->seqIter;
else if(m_pData->type == IterPriv::IT_MAP)
++m_pData->mapIter;
return *this;
}
Iterator Iterator::operator ++ (int)
{
Iterator temp = *this;
if(m_pData->type == IterPriv::IT_SEQ)
++m_pData->seqIter;
else if(m_pData->type == IterPriv::IT_MAP)
++m_pData->mapIter;
return temp;
}
const Node& Iterator::operator * () const
{
if(m_pData->type == IterPriv::IT_SEQ)
return **m_pData->seqIter;
throw BadDereference();
}
const Node *Iterator::operator -> () const
{
if(m_pData->type == IterPriv::IT_SEQ)
return *m_pData->seqIter;
throw BadDereference();
}
const Node& Iterator::first() const
{
if(m_pData->type == IterPriv::IT_MAP)
return *m_pData->mapIter->first;
throw BadDereference();
}
const Node& Iterator::second() const
{
if(m_pData->type == IterPriv::IT_MAP)
return *m_pData->mapIter->second;
throw BadDereference();
}
bool operator == (const Iterator& it, const Iterator& jt)
{
if(it.m_pData->type != jt.m_pData->type)
return false;
if(it.m_pData->type == IterPriv::IT_SEQ)
return it.m_pData->seqIter == jt.m_pData->seqIter;
else if(it.m_pData->type == IterPriv::IT_MAP)
return it.m_pData->mapIter == jt.m_pData->mapIter;
return true;
}
bool operator != (const Iterator& it, const Iterator& jt)
{
return !(it == jt);
}
}
#ifndef ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
#include "yaml-cpp/ltnode.h"
#include <vector>
#include <map>
namespace YAML
{
class Node;
// IterPriv
// . The implementation for iterators - essentially a union of sequence and map iterators.
struct IterPriv
{
IterPriv(): type(IT_NONE) {}
IterPriv(std::vector <Node *>::const_iterator it): type(IT_SEQ), seqIter(it) {}
IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it): type(IT_MAP), mapIter(it) {}
enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP };
ITER_TYPE type;
std::vector <Node *>::const_iterator seqIter;
std::map <Node *, Node *, ltnode>::const_iterator mapIter;
};
}
#endif // ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "yaml-cpp/node.h"
#include "yaml-cpp/aliasmanager.h"
#include "yaml-cpp/emitfromevents.h"
#include "yaml-cpp/emitter.h"
#include "yaml-cpp/eventhandler.h"
#include "iterpriv.h"
#include "nodebuilder.h"
#include "nodeownership.h"
#include "scanner.h"
#include "tag.h"
#include "token.h"
#include <cassert>
#include <stdexcept>
namespace YAML
{
bool ltnode::operator()(const Node *pNode1, const Node *pNode2) const {
return *pNode1 < *pNode2;
}
Node::Node(): m_pOwnership(new NodeOwnership), m_type(NodeType::Null)
{
}
Node::Node(NodeOwnership& owner): m_pOwnership(new NodeOwnership(&owner)), m_type(NodeType::Null)
{
}
Node::~Node()
{
Clear();
}
void Node::Clear()
{
m_pOwnership.reset(new NodeOwnership);
m_type = NodeType::Null;
m_tag.clear();
m_scalarData.clear();
m_seqData.clear();
m_mapData.clear();
}
bool Node::IsAliased() const
{
return m_pOwnership->IsAliased(*this);
}
Node& Node::CreateNode()
{
return m_pOwnership->Create();
}
std::auto_ptr<Node> Node::Clone() const
{
std::auto_ptr<Node> pNode(new Node);
NodeBuilder nodeBuilder(*pNode);
EmitEvents(nodeBuilder);
return pNode;
}
void Node::EmitEvents(EventHandler& eventHandler) const
{
eventHandler.OnDocumentStart(m_mark);
AliasManager am;
EmitEvents(am, eventHandler);
eventHandler.OnDocumentEnd();
}
void Node::EmitEvents(AliasManager& am, EventHandler& eventHandler) const
{
anchor_t anchor = NullAnchor;
if(IsAliased()) {
anchor = am.LookupAnchor(*this);
if(anchor) {
eventHandler.OnAlias(m_mark, anchor);
return;
}
am.RegisterReference(*this);
anchor = am.LookupAnchor(*this);
}
switch(m_type) {
case NodeType::Null:
eventHandler.OnNull(m_mark, anchor);
break;
case NodeType::Scalar:
eventHandler.OnScalar(m_mark, m_tag, anchor, m_scalarData);
break;
case NodeType::Sequence:
eventHandler.OnSequenceStart(m_mark, m_tag, anchor);
for(std::size_t i=0;i<m_seqData.size();i++)
m_seqData[i]->EmitEvents(am, eventHandler);
eventHandler.OnSequenceEnd();
break;
case NodeType::Map:
eventHandler.OnMapStart(m_mark, m_tag, anchor);
for(node_map::const_iterator it=m_mapData.begin();it!=m_mapData.end();++it) {
it->first->EmitEvents(am, eventHandler);
it->second->EmitEvents(am, eventHandler);
}
eventHandler.OnMapEnd();
break;
}
}
void Node::Init(NodeType::value type, const Mark& mark, const std::string& tag)
{
Clear();
m_mark = mark;
m_type = type;
m_tag = tag;
}
void Node::MarkAsAliased()
{
m_pOwnership->MarkAsAliased(*this);
}
void Node::SetScalarData(const std::string& data)
{
assert(m_type == NodeType::Scalar); // TODO: throw?
m_scalarData = data;
}
void Node::Append(Node& node)
{
assert(m_type == NodeType::Sequence); // TODO: throw?
m_seqData.push_back(&node);
}
void Node::Insert(Node& key, Node& value)
{
assert(m_type == NodeType::Map); // TODO: throw?
m_mapData[&key] = &value;
}
// begin
// Returns an iterator to the beginning of this (sequence or map).
Iterator Node::begin() const
{
switch(m_type) {
case NodeType::Null:
case NodeType::Scalar:
return Iterator();
case NodeType::Sequence:
return Iterator(std::auto_ptr<IterPriv>(new IterPriv(m_seqData.begin())));
case NodeType::Map:
return Iterator(std::auto_ptr<IterPriv>(new IterPriv(m_mapData.begin())));
}
assert(false);
return Iterator();
}
// end
// . Returns an iterator to the end of this (sequence or map).
Iterator Node::end() const
{
switch(m_type) {
case NodeType::Null:
case NodeType::Scalar:
return Iterator();
case NodeType::Sequence:
return Iterator(std::auto_ptr<IterPriv>(new IterPriv(m_seqData.end())));
case NodeType::Map:
return Iterator(std::auto_ptr<IterPriv>(new IterPriv(m_mapData.end())));
}
assert(false);
return Iterator();
}
// size
// . Returns the size of a sequence or map node
// . Otherwise, returns zero.
std::size_t Node::size() const
{
switch(m_type) {
case NodeType::Null:
case NodeType::Scalar:
return 0;
case NodeType::Sequence:
return m_seqData.size();
case NodeType::Map:
return m_mapData.size();
}
assert(false);
return 0;
}
const Node *Node::FindAtIndex(std::size_t i) const
{
if(m_type == NodeType::Sequence)
return m_seqData[i];
return 0;
}
bool Node::GetScalar(std::string& s) const
{
switch(m_type) {
case NodeType::Null:
s = "~";
return true;
case NodeType::Scalar:
s = m_scalarData;
return true;
case NodeType::Sequence:
case NodeType::Map:
return false;
}
assert(false);
return false;
}
Emitter& operator << (Emitter& out, const Node& node)
{
EmitFromEvents emitFromEvents(out);
node.EmitEvents(emitFromEvents);
return out;
}
int Node::Compare(const Node& rhs) const
{
if(m_type != rhs.m_type)
return rhs.m_type - m_type;
switch(m_type) {
case NodeType::Null:
return 0;
case NodeType::Scalar:
return m_scalarData.compare(rhs.m_scalarData);
case NodeType::Sequence:
if(m_seqData.size() < rhs.m_seqData.size())
return 1;
else if(m_seqData.size() > rhs.m_seqData.size())
return -1;
for(std::size_t i=0;i<m_seqData.size();i++)
if(int cmp = m_seqData[i]->Compare(*rhs.m_seqData[i]))
return cmp;
return 0;
case NodeType::Map:
if(m_mapData.size() < rhs.m_mapData.size())
return 1;
else if(m_mapData.size() > rhs.m_mapData.size())
return -1;
node_map::const_iterator it = m_mapData.begin();
node_map::const_iterator jt = rhs.m_mapData.begin();
for(;it!=m_mapData.end() && jt!=rhs.m_mapData.end();it++, jt++) {
if(int cmp = it->first->Compare(*jt->first))
return cmp;
if(int cmp = it->second->Compare(*jt->second))
return cmp;
}
return 0;
}
assert(false);
return 0;
}
bool operator < (const Node& n1, const Node& n2)
{
return n1.Compare(n2) < 0;
}
}
#include "nodebuilder.h"
#include "yaml-cpp/mark.h"
#include "yaml-cpp/node.h"
#include <cassert>
namespace YAML
{
NodeBuilder::NodeBuilder(Node& root): m_root(root), m_initializedRoot(false), m_finished(false)
{
m_root.Clear();
m_anchors.push_back(0); // since the anchors start at 1
}
NodeBuilder::~NodeBuilder()
{
}
void NodeBuilder::OnDocumentStart(const Mark&)
{
}
void NodeBuilder::OnDocumentEnd()
{
assert(m_finished);
}
void NodeBuilder::OnNull(const Mark& mark, anchor_t anchor)
{
Node& node = Push(anchor);
node.Init(NodeType::Null, mark, "");
Pop();
}
void NodeBuilder::OnAlias(const Mark& /*mark*/, anchor_t anchor)
{
Node& node = *m_anchors[anchor];
Insert(node);
node.MarkAsAliased();
}
void NodeBuilder::OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value)
{
Node& node = Push(anchor);
node.Init(NodeType::Scalar, mark, tag);
node.SetScalarData(value);
Pop();
}
void NodeBuilder::OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor)
{
Node& node = Push(anchor);
node.Init(NodeType::Sequence, mark, tag);
}
void NodeBuilder::OnSequenceEnd()
{
Pop();
}
void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor)
{
Node& node = Push(anchor);
node.Init(NodeType::Map, mark, tag);
m_didPushKey.push(false);
}
void NodeBuilder::OnMapEnd()
{
m_didPushKey.pop();
Pop();
}
Node& NodeBuilder::Push(anchor_t anchor)
{
Node& node = Push();
RegisterAnchor(anchor, node);
return node;
}
Node& NodeBuilder::Push()
{
if(!m_initializedRoot) {
m_initializedRoot = true;
return m_root;
}
Node& node = m_root.CreateNode();
m_stack.push(&node);
return node;
}
Node& NodeBuilder::Top()
{
return m_stack.empty() ? m_root : *m_stack.top();
}
void NodeBuilder::Pop()
{
assert(!m_finished);
if(m_stack.empty()) {
m_finished = true;
return;
}
Node& node = *m_stack.top();
m_stack.pop();
Insert(node);
}
void NodeBuilder::Insert(Node& node)
{
Node& curTop = Top();
switch(curTop.Type()) {
case NodeType::Null:
case NodeType::Scalar:
assert(false);
break;
case NodeType::Sequence:
curTop.Append(node);
break;
case NodeType::Map:
assert(!m_didPushKey.empty());
if(m_didPushKey.top()) {
assert(!m_pendingKeys.empty());
Node& key = *m_pendingKeys.top();
m_pendingKeys.pop();
curTop.Insert(key, node);
m_didPushKey.top() = false;
} else {
m_pendingKeys.push(&node);
m_didPushKey.top() = true;
}
break;
}
}
void NodeBuilder::RegisterAnchor(anchor_t anchor, Node& node)
{
if(anchor) {
assert(anchor == m_anchors.size());
m_anchors.push_back(&node);
}
}
}
#ifndef NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
#include "yaml-cpp/eventhandler.h"
#include <map>
#include <memory>
#include <stack>
#include <vector>
namespace YAML
{
class Node;
class NodeBuilder: public EventHandler
{
public:
explicit NodeBuilder(Node& root);
virtual ~NodeBuilder();
virtual void OnDocumentStart(const Mark& mark);
virtual void OnDocumentEnd();
virtual void OnNull(const Mark& mark, anchor_t anchor);
virtual void OnAlias(const Mark& mark, anchor_t anchor);
virtual void OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value);
virtual void OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor);
virtual void OnSequenceEnd();
virtual void OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor);
virtual void OnMapEnd();
private:
Node& Push(anchor_t anchor);
Node& Push();
Node& Top();
void Pop();
void Insert(Node& node);
void RegisterAnchor(anchor_t anchor, Node& node);
private:
Node& m_root;
bool m_initializedRoot;
bool m_finished;
std::stack<Node *> m_stack;
std::stack<Node *> m_pendingKeys;
std::stack<bool> m_didPushKey;
typedef std::vector<Node *> Anchors;
Anchors m_anchors;
};
}
#endif // NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "nodeownership.h"
#include "yaml-cpp/node.h"
namespace YAML
{
NodeOwnership::NodeOwnership(NodeOwnership *pOwner): m_pOwner(pOwner)
{
if(!m_pOwner)
m_pOwner = this;
}
NodeOwnership::~NodeOwnership()
{
}
Node& NodeOwnership::_Create()
{
m_nodes.push_back(std::auto_ptr<Node>(new Node));
return m_nodes.back();
}
void NodeOwnership::_MarkAsAliased(const Node& node)
{
m_aliasedNodes.insert(&node);
}
bool NodeOwnership::_IsAliased(const Node& node) const
{
return m_aliasedNodes.count(&node) > 0;
}
}
#ifndef NODE_OWNERSHIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODE_OWNERSHIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif
#include "yaml-cpp/noncopyable.h"
#include "ptr_vector.h"
#include <set>
namespace YAML
{
class Node;
class NodeOwnership: private noncopyable
{
public:
explicit NodeOwnership(NodeOwnership *pOwner = 0);
~NodeOwnership();
Node& Create() { return m_pOwner->_Create(); }
void MarkAsAliased(const Node& node) { m_pOwner->_MarkAsAliased(node); }
bool IsAliased(const Node& node) const { return m_pOwner->_IsAliased(node); }
private:
Node& _Create();
void _MarkAsAliased(const Node& node);
bool _IsAliased(const Node& node) const;
private:
ptr_vector<Node> m_nodes;
std::set<const Node *> m_aliasedNodes;
NodeOwnership *m_pOwner;
};
}
#endif // NODE_OWNERSHIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "tests.h"
#include "yaml-cpp/yaml.h"
#include <sstream>
#include <algorithm>
#include <iostream>
namespace Test
{
namespace Parser {
void SimpleScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar = "Hello, World!";
desiredOutput = "Hello, World!";
}
void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar =
"normal scalar, but\n"
"over several lines";
desiredOutput = "normal scalar, but over several lines";
}
void LiteralScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar =
"|\n"
" literal scalar - so we can draw ASCII:\n"
" \n"
" - -\n"
" | - |\n"
" -----\n";
desiredOutput =
"literal scalar - so we can draw ASCII:\n"
"\n"
" - -\n"
" | - |\n"
" -----\n";
}
void FoldedScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar =
">\n"
" and a folded scalar... so we\n"
" can just keep writing various\n"
" things. And if we want to keep indentation:\n"
" \n"
" we just indent a little\n"
" see, this stays indented";
desiredOutput =
"and a folded scalar... so we"
" can just keep writing various"
" things. And if we want to keep indentation:\n"
"\n"
" we just indent a little\n"
" see, this stays indented";
}
void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar =
">-\n"
" Here's a folded scalar\n"
" that gets chomped.";
desiredOutput =
"Here's a folded scalar"
" that gets chomped.";
}
void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar =
"|-\n"
" Here's a literal scalar\n"
" that gets chomped.";
desiredOutput =
"Here's a literal scalar\n"
"that gets chomped.";
}
void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar =
">2\n"
" Here's a folded scalar\n"
" that starts with some indentation.";
desiredOutput =
" Here's a folded scalar\n"
"that starts with some indentation.";
}
void ColonScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar = "::vector";
desiredOutput = "::vector";
}
void QuotedScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar = "\": - ()\"";
desiredOutput = ": - ()";
}
void CommaScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar = "Up, up, and away!";
desiredOutput = "Up, up, and away!";
}
void DashScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar = "-123";
desiredOutput = "-123";
}
void URLScalar(std::string& inputScalar, std::string& desiredOutput)
{
inputScalar = "http://example.com/foo#bar";
desiredOutput = "http://example.com/foo#bar";
}
bool SimpleSeq()
{
std::string input =
"- eggs\n"
"- bread\n"
"- milk";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
if(doc[0].to<std::string>() != "eggs")
return false;
if(doc[1].to<std::string>() != "bread")
return false;
if(doc[2].to<std::string>() != "milk")
return false;
return true;
}
bool SimpleMap()
{
std::string input =
"name: Prince Fielder\n"
"position: 1B\n"
"bats: L";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc["name"] >> output;
if(output != "Prince Fielder")
return false;
doc["position"] >> output;
if(output != "1B")
return false;
doc["bats"] >> output;
if(output != "L")
return false;
return true;
}
bool FlowSeq()
{
std::string input = "[ 2 , 3, 5 , 7, 11]";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
int output;
doc[0] >> output;
if(output != 2)
return false;
doc[1] >> output;
if(output != 3)
return false;
doc[2] >> output;
if(output != 5)
return false;
doc[3] >> output;
if(output != 7)
return false;
doc[4] >> output;
if(output != 11)
return false;
return true;
}
bool FlowMap()
{
std::string input = "{hr: 65, avg: 0.278}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc["hr"] >> output;
if(output != "65")
return false;
doc["avg"] >> output;
if(output != "0.278")
return false;
return true;
}
bool FlowMapWithOmittedKey()
{
std::string input = "{: omitted key}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc[YAML::Null] >> output;
if(output != "omitted key")
return false;
return true;
}
bool FlowMapWithOmittedValue()
{
std::string input = "{a: b, c:, d:}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc["a"] >> output;
if(output != "b")
return false;
if(!IsNull(doc["c"]))
return false;
if(!IsNull(doc["d"]))
return false;
return true;
}
bool FlowMapWithSoloEntry()
{
std::string input = "{a: b, c, d: e}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc["a"] >> output;
if(output != "b")
return false;
if(!IsNull(doc["c"]))
return false;
doc["d"] >> output;
if(output != "e")
return false;
return true;
}
bool FlowMapEndingWithSoloEntry()
{
std::string input = "{a: b, c}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc["a"] >> output;
if(output != "b")
return false;
if(!IsNull(doc["c"]))
return false;
return true;
}
bool QuotedSimpleKeys()
{
std::string KeyValue[3] = { "\"double\": double\n", "'single': single\n", "plain: plain\n" };
int perm[3] = { 0, 1, 2 };
do {
std::string input = KeyValue[perm[0]] + KeyValue[perm[1]] + KeyValue[perm[2]];
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc["double"] >> output;
if(output != "double")
return false;
doc["single"] >> output;
if(output != "single")
return false;
doc["plain"] >> output;
if(output != "plain")
return false;
} while(std::next_permutation(perm, perm + 3));
return true;
}
bool CompressedMapAndSeq()
{
std::string input = "key:\n- one\n- two";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
const YAML::Node& seq = doc["key"];
if(seq.size() != 2)
return false;
std::string output;
seq[0] >> output;
if(output != "one")
return false;
seq[1] >> output;
if(output != "two")
return false;
return true;
}
bool NullBlockSeqEntry()
{
std::string input = "- hello\n-\n- world";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc[0] >> output;
if(output != "hello")
return false;
if(!IsNull(doc[1]))
return false;
doc[2] >> output;
if(output != "world")
return false;
return true;
}
bool NullBlockMapKey()
{
std::string input = ": empty key";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc[YAML::Null] >> output;
if(output != "empty key")
return false;
return true;
}
bool NullBlockMapValue()
{
std::string input = "empty value:";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(!IsNull(doc["empty value"]))
return false;
return true;
}
bool SimpleAlias()
{
std::string input = "- &alias test\n- *alias";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc[0] >> output;
if(output != "test")
return false;
doc[1] >> output;
if(output != "test")
return false;
if(doc.size() != 2)
return false;
return true;
}
bool AliasWithNull()
{
std::string input = "- &alias\n- *alias";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(!IsNull(doc[0]))
return false;
if(!IsNull(doc[1]))
return false;
if(doc.size() != 2)
return false;
return true;
}
bool AnchorInSimpleKey()
{
std::string input = "- &a b: c\n- *a";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
std::string output;
doc[0]["b"] >> output;
if(output != "c")
return false;
doc[1] >> output;
if(output != "b")
return false;
return true;
}
bool AliasAsSimpleKey()
{
std::string input = "- &a b\n- *a : c";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
std::string output;
doc[0] >> output;
if(output != "b")
return false;
doc[1]["b"] >> output;
if(output != "c")
return false;
return true;
}
bool ExplicitDoc()
{
std::string input = "---\n- one\n- two";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
std::string output;
doc[0] >> output;
if(output != "one")
return false;
doc[1] >> output;
if(output != "two")
return false;
return true;
}
bool MultipleDocs()
{
std::string input = "---\nname: doc1\n---\nname: doc2";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::string output;
doc["name"] >> output;
if(output != "doc1")
return false;
if(!parser)
return false;
parser.GetNextDocument(doc);
doc["name"] >> output;
if(output != "doc2")
return false;
return true;
}
bool ExplicitEndDoc()
{
std::string input = "- one\n- two\n...\n...";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
std::string output;
doc[0] >> output;
if(output != "one")
return false;
doc[1] >> output;
if(output != "two")
return false;
return true;
}
bool MultipleDocsWithSomeExplicitIndicators()
{
std::string input =
"- one\n- two\n...\n"
"---\nkey: value\n...\n...\n"
"- three\n- four\n"
"---\nkey: value";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
std::string output;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
doc[0] >> output;
if(output != "one")
return false;
doc[1] >> output;
if(output != "two")
return false;
parser.GetNextDocument(doc);
doc["key"] >> output;
if(output != "value")
return false;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
doc[0] >> output;
if(output != "three")
return false;
doc[1] >> output;
if(output != "four")
return false;
parser.GetNextDocument(doc);
doc["key"] >> output;
if(output != "value")
return false;
return true;
}
bool BlockKeyWithNullValue()
{
std::string input =
"key:\n"
"just a key: value";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
if(!IsNull(doc["key"]))
return false;
if(doc["just a key"].to<std::string>() != "value")
return false;
return true;
}
bool Bases()
{
std::string input =
"- 15\n"
"- 0x10\n"
"- 030\n"
"- 0xffffffff\n";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 4)
return false;
if(doc[0].to<int>() != 15)
return false;
if(doc[1].to<int>() != 0x10)
return false;
if(doc[2].to<int>() != 030)
return false;
if(doc[3].to<unsigned>() != 0xffffffff)
return false;
return true;
}
bool KeyNotFound()
{
std::string input = "key: value";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
try {
doc["bad key"];
} catch(const YAML::Exception& e) {
if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": bad key")
throw;
}
try {
doc[5];
} catch(const YAML::Exception& e) {
if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": 5")
throw;
}
try {
doc[2.5];
} catch(const YAML::Exception& e) {
if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": 2.5")
throw;
}
return true;
}
bool DuplicateKey()
{
std::string input = "{a: 1, b: 2, c: 3, a: 4}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc["a"].to<int>() != 4)
return false;
if(doc["b"].to<int>() != 2)
return false;
if(doc["c"].to<int>() != 3)
return false;
return true;
}
void PrepareNodeForTagExam(YAML::Node& doc, const std::string& input)
{
std::stringstream stream(input);
YAML::Parser parser(stream);
parser.GetNextDocument(doc);
}
struct TagMismatch: public std::exception {
TagMismatch(const std::string& actualTag, const std::string& expectedTag) {
std::stringstream output;
output << "Tag has value \"" << actualTag << "\" but \"" << expectedTag << "\" was expected";
what_ = output.str();
}
virtual ~TagMismatch() throw() {}
virtual const char *what() const throw() { return what_.c_str(); }
private:
std::string what_;
};
bool ExpectedTagValue(YAML::Node& node, const char* tag)
{
if(node.Tag() == tag)
return true;
throw TagMismatch(node.Tag(), tag);
}
bool DefaultPlainScalarTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- 12");
return ExpectedTagValue(node, "?");
}
bool DefaultSingleQuotedScalarTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- '12'");
return ExpectedTagValue(node, "!");
}
bool ExplicitNonSpecificPlainScalarTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- ! 12");
return ExpectedTagValue(node, "!");
}
bool BasicLocalTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- !foo 12");
return ExpectedTagValue(node, "!foo");
}
bool VerbatimLocalTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- !<!foo> 12");
return ExpectedTagValue(node, "!foo");
}
bool StandardShortcutTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- !!int 12");
return ExpectedTagValue(node, "tag:yaml.org,2002:int");
}
bool VerbatimURITag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- !<tag:yaml.org,2002:int> 12");
return ExpectedTagValue(node, "tag:yaml.org,2002:int");
}
bool DefaultSequenceTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- [12]");
return ExpectedTagValue(node, "?");
}
bool ExplicitNonSpecificSequenceTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- ! [12]");
return ExpectedTagValue(node, "!");
}
bool Infinity()
{
std::string input =
"- .inf\n"
"- .Inf\n"
"- .INF\n"
"- +.inf\n"
"- +.Inf\n"
"- +.INF\n"
"- -.inf\n"
"- -.Inf\n"
"- -.INF\n";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
for(unsigned i=0;i<doc.size();i++)
if(doc[i].to<double>() != (i < 6 ? +1 : -1) * std::numeric_limits<double>::infinity())
return false;
for(unsigned i=0;i<doc.size();i++)
if(doc[i].to<long double>() != (i < 6 ? +1 : -1) * std::numeric_limits<long double>::infinity())
return false;
for(unsigned i=0;i<doc.size();i++)
if(doc[i].to<float>() != (i < 6 ? +1 : -1) * std::numeric_limits<float>::infinity())
return false;
return true;
}
bool NaN()
{
std::string input =
"- .nan\n"
"- .NaN\n"
"- .NAN\n";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
for(unsigned i=0;i<doc.size();i++) {
double d;
doc[i] >> d;
if(d == d)
return false;
}
for(unsigned i=0;i<doc.size();i++) {
long double d;
doc[i] >> d;
if(d == d)
return false;
}
for(unsigned i=0;i<doc.size();i++) {
float d;
doc[i] >> d;
if(d == d)
return false;
}
return true;
}
bool NonConstKey()
{
std::string input = "{a: 1}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
std::vector<char> key(2);
key[0] = 'a';
key[1] = '\0';
if(doc[&key[0]].to<int>() != 1)
return false;
return true;
}
bool SingleChar()
{
std::string input = "5";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
return doc.to<int>() == 5;
}
bool QuotedNewline()
{
std::string input = "foo: \"\\n\"";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
return doc["foo"].to<std::string>() == "\n";
}
bool DoubleAsInt()
{
std::string input = "1.5";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
try {
doc.to<int>();
} catch(const YAML::InvalidScalar& e) {
return true;
}
return false;
}
bool Binary()
{
std::string input = "[!!binary \"SGVsbG8sIFdvcmxkIQ==\", !!binary \"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4K\"]";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc[0].to<YAML::Binary>() != YAML::Binary(reinterpret_cast<const unsigned char*>("Hello, World!"), 13))
return false;
if(doc[1].to<YAML::Binary>() != YAML::Binary(reinterpret_cast<const unsigned char*>("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))
return false;
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.what();
}
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.what();
} catch(const Parser::TagMismatch& e) {
ok = false;
error = e.what();
}
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<char>(static_cast<unsigned char>(static_cast<unsigned int>(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<std::string>& entries() {return m_entries;}
private:
std::stringstream m_yaml;
std::vector<std::string> 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<std::string>::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);
RunParserTest(&Parser::BlockKeyWithNullValue, "block key with null value", passed, total);
RunParserTest(&Parser::Bases, "bases", passed, total);
RunParserTest(&Parser::KeyNotFound, "key not found", passed, total);
RunParserTest(&Parser::DuplicateKey, "duplicate key", passed, total);
RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total);
RunParserTest(&Parser::DefaultSingleQuotedScalarTag, "default single-quoted scalar tag", passed, total);
RunParserTest(&Parser::ExplicitNonSpecificPlainScalarTag, "explicit, non-specific plain scalar tag", passed, total);
RunParserTest(&Parser::BasicLocalTag, "basic local tag", passed, total);
RunParserTest(&Parser::VerbatimLocalTag, "verbatim local tag", passed, total);
RunParserTest(&Parser::StandardShortcutTag, "standard shortcut tag", passed, total);
RunParserTest(&Parser::VerbatimURITag, "verbatim URI tag", passed, total);
RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total);
RunParserTest(&Parser::DefaultSequenceTag, "default sequence tag", passed, total);
RunParserTest(&Parser::ExplicitNonSpecificSequenceTag, "explicit, non-specific sequence tag", passed, total);
RunParserTest(&Parser::Infinity, "infinity", passed, total);
RunParserTest(&Parser::NaN, "NaN", passed, total);
RunParserTest(&Parser::NonConstKey, "non const key", passed, total);
RunParserTest(&Parser::SingleChar, "single char", passed, total);
RunParserTest(&Parser::QuotedNewline, "quoted newline", passed, total);
RunParserTest(&Parser::DoubleAsInt, "double as int", passed, total);
RunParserTest(&Parser::Binary, "binary", 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;
}
}
#include "spectests.h"
#include "specexamples.h"
#include "yaml-cpp/yaml.h"
#include <fstream>
#include <sstream>
#include <vector>
#include <iostream>
#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false)
#define PARSE(doc, input) \
std::stringstream stream(input);\
YAML::Parser parser(stream);\
YAML::Node doc;\
parser.GetNextDocument(doc)
#define PARSE_NEXT(doc) parser.GetNextDocument(doc)
namespace Test {
namespace Spec {
// 2.1
TEST SeqScalars() {
PARSE(doc, ex2_1);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].to<std::string>() == "Mark McGwire");
YAML_ASSERT(doc[1].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc[2].to<std::string>() == "Ken Griffey");
return true;
}
// 2.2
TEST MappingScalarsToScalars() {
PARSE(doc, ex2_2);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["hr"].to<std::string>() == "65");
YAML_ASSERT(doc["avg"].to<std::string>() == "0.278");
YAML_ASSERT(doc["rbi"].to<std::string>() == "147");
return true;
}
// 2.3
TEST MappingScalarsToSequences() {
PARSE(doc, ex2_3);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["american"].size() == 3);
YAML_ASSERT(doc["american"][0].to<std::string>() == "Boston Red Sox");
YAML_ASSERT(doc["american"][1].to<std::string>() == "Detroit Tigers");
YAML_ASSERT(doc["american"][2].to<std::string>() == "New York Yankees");
YAML_ASSERT(doc["national"].size() == 3);
YAML_ASSERT(doc["national"][0].to<std::string>() == "New York Mets");
YAML_ASSERT(doc["national"][1].to<std::string>() == "Chicago Cubs");
YAML_ASSERT(doc["national"][2].to<std::string>() == "Atlanta Braves");
return true;
}
// 2.4
TEST SequenceOfMappings()
{
PARSE(doc, ex2_4);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[0].size() == 3);
YAML_ASSERT(doc[0]["name"].to<std::string>() == "Mark McGwire");
YAML_ASSERT(doc[0]["hr"].to<std::string>() == "65");
YAML_ASSERT(doc[0]["avg"].to<std::string>() == "0.278");
YAML_ASSERT(doc[1].size() == 3);
YAML_ASSERT(doc[1]["name"].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc[1]["hr"].to<std::string>() == "63");
YAML_ASSERT(doc[1]["avg"].to<std::string>() == "0.288");
return true;
}
// 2.5
TEST SequenceOfSequences()
{
PARSE(doc, ex2_5);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].size() == 3);
YAML_ASSERT(doc[0][0].to<std::string>() == "name");
YAML_ASSERT(doc[0][1].to<std::string>() == "hr");
YAML_ASSERT(doc[0][2].to<std::string>() == "avg");
YAML_ASSERT(doc[1].size() == 3);
YAML_ASSERT(doc[1][0].to<std::string>() == "Mark McGwire");
YAML_ASSERT(doc[1][1].to<std::string>() == "65");
YAML_ASSERT(doc[1][2].to<std::string>() == "0.278");
YAML_ASSERT(doc[2].size() == 3);
YAML_ASSERT(doc[2][0].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc[2][1].to<std::string>() == "63");
YAML_ASSERT(doc[2][2].to<std::string>() == "0.288");
return true;
}
// 2.6
TEST MappingOfMappings()
{
PARSE(doc, ex2_6);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["Mark McGwire"].size() == 2);
YAML_ASSERT(doc["Mark McGwire"]["hr"].to<std::string>() == "65");
YAML_ASSERT(doc["Mark McGwire"]["avg"].to<std::string>() == "0.278");
YAML_ASSERT(doc["Sammy Sosa"].size() == 2);
YAML_ASSERT(doc["Sammy Sosa"]["hr"].to<std::string>() == "63");
YAML_ASSERT(doc["Sammy Sosa"]["avg"].to<std::string>() == "0.288");
return true;
}
// 2.7
TEST TwoDocumentsInAStream()
{
PARSE(doc, ex2_7);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].to<std::string>() == "Mark McGwire");
YAML_ASSERT(doc[1].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc[2].to<std::string>() == "Ken Griffey");
PARSE_NEXT(doc);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[0].to<std::string>() == "Chicago Cubs");
YAML_ASSERT(doc[1].to<std::string>() == "St Louis Cardinals");
return true;
}
// 2.8
TEST PlayByPlayFeed()
{
PARSE(doc, ex2_8);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["time"].to<std::string>() == "20:03:20");
YAML_ASSERT(doc["player"].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc["action"].to<std::string>() == "strike (miss)");
PARSE_NEXT(doc);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["time"].to<std::string>() == "20:03:47");
YAML_ASSERT(doc["player"].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc["action"].to<std::string>() == "grand slam");
return true;
}
// 2.9
TEST SingleDocumentWithTwoComments()
{
PARSE(doc, ex2_9);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["hr"].size() == 2);
YAML_ASSERT(doc["hr"][0].to<std::string>() == "Mark McGwire");
YAML_ASSERT(doc["hr"][1].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc["rbi"].size() == 2);
YAML_ASSERT(doc["rbi"][0].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc["rbi"][1].to<std::string>() == "Ken Griffey");
return true;
}
// 2.10
TEST SimpleAnchor()
{
PARSE(doc, ex2_10);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["hr"].size() == 2);
YAML_ASSERT(doc["hr"][0].to<std::string>() == "Mark McGwire");
YAML_ASSERT(doc["hr"][1].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc["rbi"].size() == 2);
YAML_ASSERT(doc["rbi"][0].to<std::string>() == "Sammy Sosa");
YAML_ASSERT(doc["rbi"][1].to<std::string>() == "Ken Griffey");
return true;
}
struct Pair {
Pair() {}
Pair(const std::string& f, const std::string& s): first(f), second(s) {}
std::string first, second;
};
bool operator == (const Pair& p, const Pair& q) {
return p.first == q.first && p.second == q.second;
}
void operator >> (const YAML::Node& node, Pair& p) {
node[0] >> p.first;
node[1] >> p.second;
}
// 2.11
TEST MappingBetweenSequences()
{
PARSE(doc, ex2_11);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")].size() == 1);
YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")][0].to<std::string>() == "2001-07-23");
YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")].size() == 3);
YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][0].to<std::string>() == "2001-07-02");
YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][1].to<std::string>() == "2001-08-12");
YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][2].to<std::string>() == "2001-08-14");
return true;
}
// 2.12
TEST CompactNestedMapping()
{
PARSE(doc, ex2_12);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0]["item"].to<std::string>() == "Super Hoop");
YAML_ASSERT(doc[0]["quantity"].to<int>() == 1);
YAML_ASSERT(doc[1].size() == 2);
YAML_ASSERT(doc[1]["item"].to<std::string>() == "Basketball");
YAML_ASSERT(doc[1]["quantity"].to<int>() == 4);
YAML_ASSERT(doc[2].size() == 2);
YAML_ASSERT(doc[2]["item"].to<std::string>() == "Big Shoes");
YAML_ASSERT(doc[2]["quantity"].to<int>() == 1);
return true;
}
// 2.13
TEST InLiteralsNewlinesArePreserved()
{
PARSE(doc, ex2_13);
YAML_ASSERT(doc.to<std::string>() ==
"\\//||\\/||\n"
"// || ||__");
return true;
}
// 2.14
TEST InFoldedScalarsNewlinesBecomeSpaces()
{
PARSE(doc, ex2_14);
YAML_ASSERT(doc.to<std::string>() == "Mark McGwire's year was crippled by a knee injury.");
return true;
}
// 2.15
TEST FoldedNewlinesArePreservedForMoreIndentedAndBlankLines()
{
PARSE(doc, ex2_15);
YAML_ASSERT(doc.to<std::string>() ==
"Sammy Sosa completed another fine season with great stats.\n\n"
" 63 Home Runs\n"
" 0.288 Batting Average\n\n"
"What a year!");
return true;
}
// 2.16
TEST IndentationDeterminesScope()
{
PARSE(doc, ex2_16);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["name"].to<std::string>() == "Mark McGwire");
YAML_ASSERT(doc["accomplishment"].to<std::string>() == "Mark set a major league home run record in 1998.\n");
YAML_ASSERT(doc["stats"].to<std::string>() == "65 Home Runs\n0.278 Batting Average\n");
return true;
}
// 2.17
TEST QuotedScalars()
{
PARSE(doc, ex2_17);
YAML_ASSERT(doc.size() == 6);
YAML_ASSERT(doc["unicode"].to<std::string>() == "Sosa did fine.\xe2\x98\xba");
YAML_ASSERT(doc["control"].to<std::string>() == "\b1998\t1999\t2000\n");
YAML_ASSERT(doc["hex esc"].to<std::string>() == "\x0d\x0a is \r\n");
YAML_ASSERT(doc["single"].to<std::string>() == "\"Howdy!\" he cried.");
YAML_ASSERT(doc["quoted"].to<std::string>() == " # Not a 'comment'.");
YAML_ASSERT(doc["tie-fighter"].to<std::string>() == "|\\-*-/|");
return true;
}
// 2.18
TEST MultiLineFlowScalars()
{
PARSE(doc, ex2_18);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["plain"].to<std::string>() == "This unquoted scalar spans many lines.");
YAML_ASSERT(doc["quoted"].to<std::string>() == "So does this quoted scalar.\n");
return true;
}
// TODO: 2.19 - 2.22 schema tags
// 2.23
TEST VariousExplicitTags()
{
PARSE(doc, ex2_23);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["not-date"].Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc["not-date"].to<std::string>() == "2002-04-28");
YAML_ASSERT(doc["picture"].Tag() == "tag:yaml.org,2002:binary");
YAML_ASSERT(doc["picture"].to<std::string>() ==
"R0lGODlhDAAMAIQAAP//9/X\n"
"17unp5WZmZgAAAOfn515eXv\n"
"Pz7Y6OjuDg4J+fn5OTk6enp\n"
"56enmleECcgggoBADs=\n"
);
YAML_ASSERT(doc["application specific tag"].Tag() == "!something");
YAML_ASSERT(doc["application specific tag"].to<std::string>() ==
"The semantics of the tag\n"
"above may be different for\n"
"different documents."
);
return true;
}
// 2.24
TEST GlobalTags()
{
PARSE(doc, ex2_24);
YAML_ASSERT(doc.Tag() == "tag:clarkevans.com,2002:shape");
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].Tag() == "tag:clarkevans.com,2002:circle");
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0]["center"].size() == 2);
YAML_ASSERT(doc[0]["center"]["x"].to<int>() == 73);
YAML_ASSERT(doc[0]["center"]["y"].to<int>() == 129);
YAML_ASSERT(doc[0]["radius"].to<int>() == 7);
YAML_ASSERT(doc[1].Tag() == "tag:clarkevans.com,2002:line");
YAML_ASSERT(doc[1].size() == 2);
YAML_ASSERT(doc[1]["start"].size() == 2);
YAML_ASSERT(doc[1]["start"]["x"].to<int>() == 73);
YAML_ASSERT(doc[1]["start"]["y"].to<int>() == 129);
YAML_ASSERT(doc[1]["finish"].size() == 2);
YAML_ASSERT(doc[1]["finish"]["x"].to<int>() == 89);
YAML_ASSERT(doc[1]["finish"]["y"].to<int>() == 102);
YAML_ASSERT(doc[2].Tag() == "tag:clarkevans.com,2002:label");
YAML_ASSERT(doc[2].size() == 3);
YAML_ASSERT(doc[2]["start"].size() == 2);
YAML_ASSERT(doc[2]["start"]["x"].to<int>() == 73);
YAML_ASSERT(doc[2]["start"]["y"].to<int>() == 129);
YAML_ASSERT(doc[2]["color"].to<std::string>() == "0xFFEEBB");
YAML_ASSERT(doc[2]["text"].to<std::string>() == "Pretty vector drawing.");
return true;
}
// 2.25
TEST UnorderedSets()
{
PARSE(doc, ex2_25);
YAML_ASSERT(doc.Tag() == "tag:yaml.org,2002:set");
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(IsNull(doc["Mark McGwire"]));
YAML_ASSERT(IsNull(doc["Sammy Sosa"]));
YAML_ASSERT(IsNull(doc["Ken Griffey"]));
return true;
}
// 2.26
TEST OrderedMappings()
{
PARSE(doc, ex2_26);
YAML_ASSERT(doc.Tag() == "tag:yaml.org,2002:omap");
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0]["Mark McGwire"].to<int>() == 65);
YAML_ASSERT(doc[1].size() == 1);
YAML_ASSERT(doc[1]["Sammy Sosa"].to<int>() == 63);
YAML_ASSERT(doc[2].size() == 1);
YAML_ASSERT(doc[2]["Ken Griffey"].to<int>() == 58);
return true;
}
// 2.27
TEST Invoice()
{
PARSE(doc, ex2_27);
YAML_ASSERT(doc.Tag() == "tag:clarkevans.com,2002:invoice");
YAML_ASSERT(doc.size() == 8);
YAML_ASSERT(doc["invoice"].to<int>() == 34843);
YAML_ASSERT(doc["date"].to<std::string>() == "2001-01-23");
YAML_ASSERT(doc["bill-to"].size() == 3);
YAML_ASSERT(doc["bill-to"]["given"].to<std::string>() == "Chris");
YAML_ASSERT(doc["bill-to"]["family"].to<std::string>() == "Dumars");
YAML_ASSERT(doc["bill-to"]["address"].size() == 4);
YAML_ASSERT(doc["bill-to"]["address"]["lines"].to<std::string>() == "458 Walkman Dr.\nSuite #292\n");
YAML_ASSERT(doc["bill-to"]["address"]["city"].to<std::string>() == "Royal Oak");
YAML_ASSERT(doc["bill-to"]["address"]["state"].to<std::string>() == "MI");
YAML_ASSERT(doc["bill-to"]["address"]["postal"].to<std::string>() == "48046");
YAML_ASSERT(doc["ship-to"].size() == 3);
YAML_ASSERT(doc["ship-to"]["given"].to<std::string>() == "Chris");
YAML_ASSERT(doc["ship-to"]["family"].to<std::string>() == "Dumars");
YAML_ASSERT(doc["ship-to"]["address"].size() == 4);
YAML_ASSERT(doc["ship-to"]["address"]["lines"].to<std::string>() == "458 Walkman Dr.\nSuite #292\n");
YAML_ASSERT(doc["ship-to"]["address"]["city"].to<std::string>() == "Royal Oak");
YAML_ASSERT(doc["ship-to"]["address"]["state"].to<std::string>() == "MI");
YAML_ASSERT(doc["ship-to"]["address"]["postal"].to<std::string>() == "48046");
YAML_ASSERT(doc["product"].size() == 2);
YAML_ASSERT(doc["product"][0].size() == 4);
YAML_ASSERT(doc["product"][0]["sku"].to<std::string>() == "BL394D");
YAML_ASSERT(doc["product"][0]["quantity"].to<int>() == 4);
YAML_ASSERT(doc["product"][0]["description"].to<std::string>() == "Basketball");
YAML_ASSERT(doc["product"][0]["price"].to<std::string>() == "450.00");
YAML_ASSERT(doc["product"][1].size() == 4);
YAML_ASSERT(doc["product"][1]["sku"].to<std::string>() == "BL4438H");
YAML_ASSERT(doc["product"][1]["quantity"].to<int>() == 1);
YAML_ASSERT(doc["product"][1]["description"].to<std::string>() == "Super Hoop");
YAML_ASSERT(doc["product"][1]["price"].to<std::string>() == "2392.00");
YAML_ASSERT(doc["tax"].to<std::string>() == "251.42");
YAML_ASSERT(doc["total"].to<std::string>() == "4443.52");
YAML_ASSERT(doc["comments"].to<std::string>() == "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.");
return true;
}
// 2.28
TEST LogFile()
{
PARSE(doc, ex2_28);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["Time"].to<std::string>() == "2001-11-23 15:01:42 -5");
YAML_ASSERT(doc["User"].to<std::string>() == "ed");
YAML_ASSERT(doc["Warning"].to<std::string>() == "This is an error message for the log file");
PARSE_NEXT(doc);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["Time"].to<std::string>() == "2001-11-23 15:02:31 -5");
YAML_ASSERT(doc["User"].to<std::string>() == "ed");
YAML_ASSERT(doc["Warning"].to<std::string>() == "A slightly different error message.");
PARSE_NEXT(doc);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(doc["Date"].to<std::string>() == "2001-11-23 15:03:17 -5");
YAML_ASSERT(doc["User"].to<std::string>() == "ed");
YAML_ASSERT(doc["Fatal"].to<std::string>() == "Unknown variable \"bar\"");
YAML_ASSERT(doc["Stack"].size() == 2);
YAML_ASSERT(doc["Stack"][0].size() == 3);
YAML_ASSERT(doc["Stack"][0]["file"].to<std::string>() == "TopClass.py");
YAML_ASSERT(doc["Stack"][0]["line"].to<std::string>() == "23");
YAML_ASSERT(doc["Stack"][0]["code"].to<std::string>() == "x = MoreObject(\"345\\n\")\n");
YAML_ASSERT(doc["Stack"][1].size() == 3);
YAML_ASSERT(doc["Stack"][1]["file"].to<std::string>() == "MoreClass.py");
YAML_ASSERT(doc["Stack"][1]["line"].to<std::string>() == "58");
YAML_ASSERT(doc["Stack"][1]["code"].to<std::string>() == "foo = bar");
return true;
}
// TODO: 5.1 - 5.2 BOM
// 5.3
TEST BlockStructureIndicators()
{
PARSE(doc, ex5_3);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["sequence"].size() == 2);
YAML_ASSERT(doc["sequence"][0].to<std::string>() == "one");
YAML_ASSERT(doc["sequence"][1].to<std::string>() == "two");
YAML_ASSERT(doc["mapping"].size() == 2);
YAML_ASSERT(doc["mapping"]["sky"].to<std::string>() == "blue");
YAML_ASSERT(doc["mapping"]["sea"].to<std::string>() == "green");
return true;
}
// 5.4
TEST FlowStructureIndicators()
{
PARSE(doc, ex5_4);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["sequence"].size() == 2);
YAML_ASSERT(doc["sequence"][0].to<std::string>() == "one");
YAML_ASSERT(doc["sequence"][1].to<std::string>() == "two");
YAML_ASSERT(doc["mapping"].size() == 2);
YAML_ASSERT(doc["mapping"]["sky"].to<std::string>() == "blue");
YAML_ASSERT(doc["mapping"]["sea"].to<std::string>() == "green");
return true;
}
// 5.5
TEST CommentIndicator()
{
PARSE(doc, ex5_5);
YAML_ASSERT(doc.size() == 0);
return true;
}
// 5.6
TEST NodePropertyIndicators()
{
PARSE(doc, ex5_6);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["anchored"].to<std::string>() == "value"); // TODO: assert tag
YAML_ASSERT(doc["alias"].to<std::string>() == "value");
return true;
}
// 5.7
TEST BlockScalarIndicators()
{
PARSE(doc, ex5_7);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["literal"].to<std::string>() == "some\ntext\n");
YAML_ASSERT(doc["folded"].to<std::string>() == "some text\n");
return true;
}
// 5.8
TEST QuotedScalarIndicators()
{
PARSE(doc, ex5_8);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["single"].to<std::string>() == "text");
YAML_ASSERT(doc["double"].to<std::string>() == "text");
return true;
}
// TODO: 5.9 directive
// TODO: 5.10 reserved indicator
// 5.11
TEST LineBreakCharacters()
{
PARSE(doc, ex5_11);
YAML_ASSERT(doc.to<std::string>() == "Line break (no glyph)\nLine break (glyphed)\n");
return true;
}
// 5.12
TEST TabsAndSpaces()
{
PARSE(doc, ex5_12);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["quoted"].to<std::string>() == "Quoted\t");
YAML_ASSERT(doc["block"].to<std::string>() ==
"void main() {\n"
"\tprintf(\"Hello, world!\\n\");\n"
"}");
return true;
}
// 5.13
TEST EscapedCharacters()
{
PARSE(doc, ex5_13);
YAML_ASSERT(doc.to<std::string>() == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9 A A A");
return true;
}
// 5.14
TEST InvalidEscapedCharacters()
{
std::stringstream stream(ex5_14);
try {
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
} catch(const YAML::ParserException& e) {
YAML_ASSERT(e.msg == std::string(YAML::ErrorMsg::INVALID_ESCAPE) + "c");
return true;
}
return false;
}
// 6.1
TEST IndentationSpaces()
{
PARSE(doc, ex6_1);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["Not indented"].size() == 2);
YAML_ASSERT(doc["Not indented"]["By one space"].to<std::string>() == "By four\n spaces\n");
YAML_ASSERT(doc["Not indented"]["Flow style"].size() == 3);
YAML_ASSERT(doc["Not indented"]["Flow style"][0].to<std::string>() == "By two");
YAML_ASSERT(doc["Not indented"]["Flow style"][1].to<std::string>() == "Also by two");
YAML_ASSERT(doc["Not indented"]["Flow style"][2].to<std::string>() == "Still by two");
return true;
}
// 6.2
TEST IndentationIndicators()
{
PARSE(doc, ex6_2);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["a"].size() == 2);
YAML_ASSERT(doc["a"][0].to<std::string>() == "b");
YAML_ASSERT(doc["a"][1].size() == 2);
YAML_ASSERT(doc["a"][1][0].to<std::string>() == "c");
YAML_ASSERT(doc["a"][1][1].to<std::string>() == "d");
return true;
}
// 6.3
TEST SeparationSpaces()
{
PARSE(doc, ex6_3);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0]["foo"].to<std::string>() == "bar");
YAML_ASSERT(doc[1].size() == 2);
YAML_ASSERT(doc[1][0].to<std::string>() == "baz");
YAML_ASSERT(doc[1][1].to<std::string>() == "baz");
return true;
}
// 6.4
TEST LinePrefixes()
{
PARSE(doc, ex6_4);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["plain"].to<std::string>() == "text lines");
YAML_ASSERT(doc["quoted"].to<std::string>() == "text lines");
YAML_ASSERT(doc["block"].to<std::string>() == "text\n \tlines\n");
return true;
}
// 6.5
TEST EmptyLines()
{
PARSE(doc, ex6_5);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["Folding"].to<std::string>() == "Empty line\nas a line feed");
YAML_ASSERT(doc["Chomping"].to<std::string>() == "Clipped empty lines\n");
return true;
}
// 6.6
TEST LineFolding()
{
PARSE(doc, ex6_6);
YAML_ASSERT(doc.to<std::string>() == "trimmed\n\n\nas space");
return true;
}
// 6.7
TEST BlockFolding()
{
PARSE(doc, ex6_7);
YAML_ASSERT(doc.to<std::string>() == "foo \n\n\t bar\n\nbaz\n");
return true;
}
// 6.8
TEST FlowFolding()
{
PARSE(doc, ex6_8);
YAML_ASSERT(doc.to<std::string>() == " foo\nbar\nbaz ");
return true;
}
// 6.9
TEST SeparatedComment()
{
PARSE(doc, ex6_9);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["key"].to<std::string>() == "value");
return true;
}
// 6.10
TEST CommentLines()
{
PARSE(doc, ex6_10);
YAML_ASSERT(doc.size() == 0);
return true;
}
// 6.11
TEST MultiLineComments()
{
PARSE(doc, ex6_11);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["key"].to<std::string>() == "value");
return true;
}
struct StringMap {
typedef std::map<std::string, std::string> Map;
Map _;
};
bool operator == (const StringMap& m, const StringMap& n) {
return m._ == n._;
}
void operator >> (const YAML::Node& node, StringMap& m) {
m._.clear();
for(YAML::Iterator it=node.begin();it!=node.end();++it) {
std::string key = it.first().to<std::string>();
std::string value = it.second().to<std::string>();
m._[key] = value;
}
}
// 6.12
TEST SeparationSpacesII()
{
PARSE(doc, ex6_12);
std::map<std::string, std::string> key;
key["first"] = "Sammy";
key["last"] = "Sosa";
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc[key].size() == 2);
YAML_ASSERT(doc[key]["hr"].to<int>() == 65);
YAML_ASSERT(doc[key]["avg"].to<std::string>() == "0.278");
return true;
}
// 6.13
TEST ReservedDirectives()
{
PARSE(doc, ex6_13);
return true;
}
// 6.14
TEST YAMLDirective()
{
PARSE(doc, ex6_14);
return true;
}
// 6.15
TEST InvalidRepeatedYAMLDirective()
{
try {
PARSE(doc, ex6_15);
} catch(const YAML::ParserException& e) {
if(e.msg == YAML::ErrorMsg::REPEATED_YAML_DIRECTIVE)
return true;
throw;
}
return " No exception was thrown";
}
// 6.16
TEST TagDirective()
{
PARSE(doc, ex6_16);
YAML_ASSERT(doc.Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc.to<std::string>() == "foo");
return true;
}
// 6.17
TEST InvalidRepeatedTagDirective()
{
try {
PARSE(doc, ex6_17);
} catch(const YAML::ParserException& e) {
if(e.msg == YAML::ErrorMsg::REPEATED_TAG_DIRECTIVE)
return true;
throw;
}
return " No exception was thrown";
}
// 6.18
TEST PrimaryTagHandle()
{
PARSE(doc, ex6_18);
YAML_ASSERT(doc.Tag() == "!foo");
YAML_ASSERT(doc.to<std::string>() == "bar");
PARSE_NEXT(doc);
YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/foo");
YAML_ASSERT(doc.to<std::string>() == "bar");
return true;
}
// 6.19
TEST SecondaryTagHandle()
{
PARSE(doc, ex6_19);
YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/int");
YAML_ASSERT(doc.to<std::string>() == "1 - 3");
return true;
}
// 6.20
TEST TagHandles()
{
PARSE(doc, ex6_20);
YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/foo");
YAML_ASSERT(doc.to<std::string>() == "bar");
return true;
}
// 6.21
TEST LocalTagPrefix()
{
PARSE(doc, ex6_21);
YAML_ASSERT(doc.Tag() == "!my-light");
YAML_ASSERT(doc.to<std::string>() == "fluorescent");
PARSE_NEXT(doc);
YAML_ASSERT(doc.Tag() == "!my-light");
YAML_ASSERT(doc.to<std::string>() == "green");
return true;
}
// 6.22
TEST GlobalTagPrefix()
{
PARSE(doc, ex6_22);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc[0].Tag() == "tag:example.com,2000:app/foo");
YAML_ASSERT(doc[0].to<std::string>() == "bar");
return true;
}
// 6.23
TEST NodeProperties()
{
PARSE(doc, ex6_23);
YAML_ASSERT(doc.size() == 2);
for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
if(it.first().to<std::string>() == "foo") {
YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.second().Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.second().to<std::string>() == "bar");
} else if(it.first().to<std::string>() == "baz") {
YAML_ASSERT(it.second().to<std::string>() == "foo");
} else
return " unknown key";
}
return true;
}
// 6.24
TEST VerbatimTags()
{
PARSE(doc, ex6_24);
YAML_ASSERT(doc.size() == 1);
for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.first().to<std::string>() == "foo");
YAML_ASSERT(it.second().Tag() == "!bar");
YAML_ASSERT(it.second().to<std::string>() == "baz");
}
return true;
}
// 6.25
TEST InvalidVerbatimTags()
{
PARSE(doc, ex6_25);
return " not implemented yet"; // TODO: check tags (but we probably will say these are valid, I think)
}
// 6.26
TEST TagShorthands()
{
PARSE(doc, ex6_26);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].Tag() == "!local");
YAML_ASSERT(doc[0].to<std::string>() == "foo");
YAML_ASSERT(doc[1].Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc[1].to<std::string>() == "bar");
YAML_ASSERT(doc[2].Tag() == "tag:example.com,2000:app/tag%21");
YAML_ASSERT(doc[2].to<std::string>() == "baz");
return true;
}
// 6.27
TEST InvalidTagShorthands()
{
bool threw = false;
try {
PARSE(doc, ex6_27a);
} catch(const YAML::ParserException& e) {
threw = true;
if(e.msg != YAML::ErrorMsg::TAG_WITH_NO_SUFFIX)
throw;
}
if(!threw)
return " No exception was thrown for a tag with no suffix";
PARSE(doc, ex6_27b); // TODO: should we reject this one (since !h! is not declared)?
return " not implemented yet";
}
// 6.28
TEST NonSpecificTags()
{
PARSE(doc, ex6_28);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].to<std::string>() == "12"); // TODO: check tags. How?
YAML_ASSERT(doc[1].to<int>() == 12);
YAML_ASSERT(doc[2].to<std::string>() == "12");
return true;
}
// 6.29
TEST NodeAnchors()
{
PARSE(doc, ex6_29);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["First occurrence"].to<std::string>() == "Value");
YAML_ASSERT(doc["Second occurrence"].to<std::string>() == "Value");
return true;
}
// 7.1
TEST AliasNodes()
{
PARSE(doc, ex7_1);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(doc["First occurrence"].to<std::string>() == "Foo");
YAML_ASSERT(doc["Second occurrence"].to<std::string>() == "Foo");
YAML_ASSERT(doc["Override anchor"].to<std::string>() == "Bar");
YAML_ASSERT(doc["Reuse anchor"].to<std::string>() == "Bar");
return true;
}
// 7.2
TEST EmptyNodes()
{
PARSE(doc, ex7_2);
YAML_ASSERT(doc.size() == 2);
for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
if(it.first().to<std::string>() == "foo") {
YAML_ASSERT(it.second().Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.second().to<std::string>() == "");
} else if(it.first().to<std::string>() == "") {
YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.second().to<std::string>() == "bar");
} else
return " unexpected key";
}
return true;
}
// 7.3
TEST CompletelyEmptyNodes()
{
PARSE(doc, ex7_3);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(IsNull(doc["foo"]));
YAML_ASSERT(doc[YAML::Null].to<std::string>() == "bar");
return true;
}
// 7.4
TEST DoubleQuotedImplicitKeys()
{
PARSE(doc, ex7_4);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["implicit block key"].size() == 1);
YAML_ASSERT(doc["implicit block key"][0].size() == 1);
YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"].to<std::string>() == "value");
return true;
}
// 7.5
TEST DoubleQuotedLineBreaks()
{
PARSE(doc, ex7_5);
YAML_ASSERT(doc.to<std::string>() == "folded to a space,\nto a line feed, or \t \tnon-content");
return true;
}
// 7.6
TEST DoubleQuotedLines()
{
PARSE(doc, ex7_6);
YAML_ASSERT(doc.to<std::string>() == " 1st non-empty\n2nd non-empty 3rd non-empty ");
return true;
}
// 7.7
TEST SingleQuotedCharacters()
{
PARSE(doc, ex7_7);
YAML_ASSERT(doc.to<std::string>() == "here's to \"quotes\"");
return true;
}
// 7.8
TEST SingleQuotedImplicitKeys()
{
PARSE(doc, ex7_8);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["implicit block key"].size() == 1);
YAML_ASSERT(doc["implicit block key"][0].size() == 1);
YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"].to<std::string>() == "value");
return true;
}
// 7.9
TEST SingleQuotedLines()
{
PARSE(doc, ex7_9);
YAML_ASSERT(doc.to<std::string>() == " 1st non-empty\n2nd non-empty 3rd non-empty ");
return true;
}
// 7.10
TEST PlainCharacters()
{
PARSE(doc, ex7_10);
YAML_ASSERT(doc.size() == 6);
YAML_ASSERT(doc[0].to<std::string>() == "::vector");
YAML_ASSERT(doc[1].to<std::string>() == ": - ()");
YAML_ASSERT(doc[2].to<std::string>() == "Up, up, and away!");
YAML_ASSERT(doc[3].to<int>() == -123);
YAML_ASSERT(doc[4].to<std::string>() == "http://example.com/foo#bar");
YAML_ASSERT(doc[5].size() == 5);
YAML_ASSERT(doc[5][0].to<std::string>() == "::vector");
YAML_ASSERT(doc[5][1].to<std::string>() == ": - ()");
YAML_ASSERT(doc[5][2].to<std::string>() == "Up, up, and away!");
YAML_ASSERT(doc[5][3].to<int>() == -123);
YAML_ASSERT(doc[5][4].to<std::string>() == "http://example.com/foo#bar");
return true;
}
// 7.11
TEST PlainImplicitKeys()
{
PARSE(doc, ex7_11);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["implicit block key"].size() == 1);
YAML_ASSERT(doc["implicit block key"][0].size() == 1);
YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"].to<std::string>() == "value");
return true;
}
// 7.12
TEST PlainLines()
{
PARSE(doc, ex7_12);
YAML_ASSERT(doc.to<std::string>() == "1st non-empty\n2nd non-empty 3rd non-empty");
return true;
}
// 7.13
TEST FlowSequence()
{
PARSE(doc, ex7_13);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0][0].to<std::string>() == "one");
YAML_ASSERT(doc[0][1].to<std::string>() == "two");
YAML_ASSERT(doc[1].size() == 2);
YAML_ASSERT(doc[1][0].to<std::string>() == "three");
YAML_ASSERT(doc[1][1].to<std::string>() == "four");
return true;
}
// 7.14
TEST FlowSequenceEntries()
{
PARSE(doc, ex7_14);
YAML_ASSERT(doc.size() == 5);
YAML_ASSERT(doc[0].to<std::string>() == "double quoted");
YAML_ASSERT(doc[1].to<std::string>() == "single quoted");
YAML_ASSERT(doc[2].to<std::string>() == "plain text");
YAML_ASSERT(doc[3].size() == 1);
YAML_ASSERT(doc[3][0].to<std::string>() == "nested");
YAML_ASSERT(doc[4].size() == 1);
YAML_ASSERT(doc[4]["single"].to<std::string>() == "pair");
return true;
}
// 7.15
TEST FlowMappings()
{
PARSE(doc, ex7_15);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0]["one"].to<std::string>() == "two");
YAML_ASSERT(doc[0]["three"].to<std::string>() == "four");
YAML_ASSERT(doc[1].size() == 2);
YAML_ASSERT(doc[1]["five"].to<std::string>() == "six");
YAML_ASSERT(doc[1]["seven"].to<std::string>() == "eight");
return true;
}
// 7.16
TEST FlowMappingEntries()
{
PARSE(doc, ex7_16);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["explicit"].to<std::string>() == "entry");
YAML_ASSERT(doc["implicit"].to<std::string>() == "entry");
YAML_ASSERT(IsNull(doc[YAML::Null]));
return true;
}
// 7.17
TEST FlowMappingSeparateValues()
{
PARSE(doc, ex7_17);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(doc["unquoted"].to<std::string>() == "separate");
YAML_ASSERT(IsNull(doc["http://foo.com"]));
YAML_ASSERT(IsNull(doc["omitted value"]));
YAML_ASSERT(doc[YAML::Null].to<std::string>() == "omitted key");
return true;
}
// 7.18
TEST FlowMappingAdjacentValues()
{
PARSE(doc, ex7_18);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["adjacent"].to<std::string>() == "value");
YAML_ASSERT(doc["readable"].to<std::string>() == "value");
YAML_ASSERT(IsNull(doc["empty"]));
return true;
}
// 7.19
TEST SinglePairFlowMappings()
{
PARSE(doc, ex7_19);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0]["foo"].to<std::string>() == "bar");
return true;
}
// 7.20
TEST SinglePairExplicitEntry()
{
PARSE(doc, ex7_20);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0]["foo bar"].to<std::string>() == "baz");
return true;
}
// 7.21
TEST SinglePairImplicitEntries()
{
PARSE(doc, ex7_21);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0][0].size() == 1);
YAML_ASSERT(doc[0][0]["YAML"].to<std::string>() == "separate");
YAML_ASSERT(doc[1].size() == 1);
YAML_ASSERT(doc[1][0].size() == 1);
YAML_ASSERT(doc[1][0][YAML::Null].to<std::string>() == "empty key entry");
YAML_ASSERT(doc[2].size() == 1);
YAML_ASSERT(doc[2][0].size() == 1);
StringMap key;
key._["JSON"] = "like";
YAML_ASSERT(doc[2][0][key].to<std::string>() == "adjacent");
return true;
}
// 7.22
TEST InvalidImplicitKeys()
{
try {
PARSE(doc, ex7_22);
} catch(const YAML::Exception& e) {
if(e.msg == YAML::ErrorMsg::END_OF_SEQ_FLOW)
return true;
throw;
}
return " no exception thrown";
}
// 7.23
TEST FlowContent()
{
PARSE(doc, ex7_23);
YAML_ASSERT(doc.size() == 5);
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0][0].to<std::string>() == "a");
YAML_ASSERT(doc[0][1].to<std::string>() == "b");
YAML_ASSERT(doc[1].size() == 1);
YAML_ASSERT(doc[1]["a"].to<std::string>() == "b");
YAML_ASSERT(doc[2].to<std::string>() == "a");
YAML_ASSERT(doc[3].to<char>() == 'b');
YAML_ASSERT(doc[4].to<std::string>() == "c");
return true;
}
// 7.24
TEST FlowNodes()
{
PARSE(doc, ex7_24);
YAML_ASSERT(doc.size() == 5);
YAML_ASSERT(doc[0].Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc[0].to<std::string>() == "a");
YAML_ASSERT(doc[1].to<char>() == 'b');
YAML_ASSERT(doc[2].to<std::string>() == "c");
YAML_ASSERT(doc[3].to<std::string>() == "c");
YAML_ASSERT(doc[4].Tag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc[4].to<std::string>() == "");
return true;
}
// 8.1
TEST BlockScalarHeader()
{
PARSE(doc, ex8_1);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(doc[0].to<std::string>() == "literal\n");
YAML_ASSERT(doc[1].to<std::string>() == " folded\n");
YAML_ASSERT(doc[2].to<std::string>() == "keep\n\n");
YAML_ASSERT(doc[3].to<std::string>() == " strip");
return true;
}
// 8.2
TEST BlockIndentationHeader()
{
PARSE(doc, ex8_2);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(doc[0].to<std::string>() == "detected\n");
YAML_ASSERT(doc[1].to<std::string>() == "\n\n# detected\n");
YAML_ASSERT(doc[2].to<std::string>() == " explicit\n");
YAML_ASSERT(doc[3].to<std::string>() == "\t\ndetected\n");
return true;
}
// 8.3
TEST InvalidBlockScalarIndentationIndicators()
{
{
bool threw = false;
try {
PARSE(doc, ex8_3a);
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::END_OF_SEQ)
throw;
threw = true;
}
if(!threw)
return " no exception thrown for less indented auto-detecting indentation for a literal block scalar";
}
{
bool threw = false;
try {
PARSE(doc, ex8_3b);
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::END_OF_SEQ)
throw;
threw = true;
}
if(!threw)
return " no exception thrown for less indented auto-detecting indentation for a folded block scalar";
}
{
bool threw = false;
try {
PARSE(doc, ex8_3c);
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::END_OF_SEQ)
throw;
threw = true;
}
if(!threw)
return " no exception thrown for less indented explicit indentation for a literal block scalar";
}
return true;
}
// 8.4
TEST ChompingFinalLineBreak()
{
PARSE(doc, ex8_4);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["strip"].to<std::string>() == "text");
YAML_ASSERT(doc["clip"].to<std::string>() == "text\n");
YAML_ASSERT(doc["keep"].to<std::string>() == "text\n");
return true;
}
// 8.5
TEST ChompingTrailingLines()
{
PARSE(doc, ex8_5);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["strip"].to<std::string>() == "# text");
YAML_ASSERT(doc["clip"].to<std::string>() == "# text\n");
YAML_ASSERT(doc["keep"].to<std::string>() == "# text\n"); // Note: I believe this is a bug in the YAML spec - it should be "# text\n\n"
return true;
}
// 8.6
TEST EmptyScalarChomping()
{
PARSE(doc, ex8_6);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["strip"].to<std::string>() == "");
YAML_ASSERT(doc["clip"].to<std::string>() == "");
YAML_ASSERT(doc["keep"].to<std::string>() == "\n");
return true;
}
// 8.7
TEST LiteralScalar()
{
PARSE(doc, ex8_7);
YAML_ASSERT(doc.to<std::string>() == "literal\n\ttext\n");
return true;
}
// 8.8
TEST LiteralContent()
{
PARSE(doc, ex8_8);
YAML_ASSERT(doc.to<std::string>() == "\n\nliteral\n \n\ntext\n");
return true;
}
// 8.9
TEST FoldedScalar()
{
PARSE(doc, ex8_9);
YAML_ASSERT(doc.to<std::string>() == "folded text\n");
return true;
}
// 8.10
TEST FoldedLines()
{
PARSE(doc, ex8_10);
YAML_ASSERT(doc.to<std::string>() == "\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n");
return true;
}
// 8.11
TEST MoreIndentedLines()
{
return true; // same as 8.10
}
// 8.12
TEST EmptySeparationLines()
{
return true; // same as 8.10
}
// 8.13
TEST FinalEmptyLines()
{
return true; // same as 8.10
}
// 8.14
TEST BlockSequence()
{
PARSE(doc, ex8_14);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["block sequence"].size() == 2);
YAML_ASSERT(doc["block sequence"][0].to<std::string>() == "one");
YAML_ASSERT(doc["block sequence"][1].size() == 1);
YAML_ASSERT(doc["block sequence"][1]["two"].to<std::string>() == "three");
return true;
}
// 8.15
TEST BlockSequenceEntryTypes()
{
PARSE(doc, ex8_15);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(YAML::IsNull(doc[0]));
YAML_ASSERT(doc[1].to<std::string>() == "block node\n");
YAML_ASSERT(doc[2].size() == 2);
YAML_ASSERT(doc[2][0].to<std::string>() == "one");
YAML_ASSERT(doc[2][1].to<std::string>() == "two");
YAML_ASSERT(doc[3].size() == 1);
YAML_ASSERT(doc[3]["one"].to<std::string>() == "two");
return true;
}
// 8.16
TEST BlockMappings()
{
PARSE(doc, ex8_16);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc["block mapping"].size() == 1);
YAML_ASSERT(doc["block mapping"]["key"].to<std::string>() == "value");
return true;
}
// 8.17
TEST ExplicitBlockMappingEntries()
{
PARSE(doc, ex8_17);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(IsNull(doc["explicit key"]));
YAML_ASSERT(doc["block key\n"].size() == 2);
YAML_ASSERT(doc["block key\n"][0].to<std::string>() == "one");
YAML_ASSERT(doc["block key\n"][1].to<std::string>() == "two");
return true;
}
// 8.18
TEST ImplicitBlockMappingEntries()
{
PARSE(doc, ex8_18);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["plain key"].to<std::string>() == "in-line value");
YAML_ASSERT(IsNull(doc[YAML::Null]));
YAML_ASSERT(doc["quoted key"].size() == 1);
YAML_ASSERT(doc["quoted key"][0].to<std::string>() == "entry");
return true;
}
// 8.19
TEST CompactBlockMappings()
{
PARSE(doc, ex8_19);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0]["sun"].to<std::string>() == "yellow");
YAML_ASSERT(doc[1].size() == 1);
std::map<std::string, std::string> key;
key["earth"] = "blue";
YAML_ASSERT(doc[1][key].size() == 1);
YAML_ASSERT(doc[1][key]["moon"].to<std::string>() == "white");
return true;
}
// 8.20
TEST BlockNodeTypes()
{
PARSE(doc, ex8_20);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].to<std::string>() == "flow in block");
YAML_ASSERT(doc[1].to<std::string>() == "Block scalar\n");
YAML_ASSERT(doc[2].size() == 1);
YAML_ASSERT(doc[2]["foo"].to<std::string>() == "bar");
return true;
}
// 8.21
TEST BlockScalarNodes()
{
PARSE(doc, ex8_21);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["literal"].to<std::string>() == "value"); // Note: I believe this is a bug in the YAML spec - it should be "value\n"
YAML_ASSERT(doc["folded"].to<std::string>() == "value");
YAML_ASSERT(doc["folded"].Tag() == "!foo");
return true;
}
// 8.22
TEST BlockCollectionNodes()
{
PARSE(doc, ex8_22);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["sequence"].size() == 2);
YAML_ASSERT(doc["sequence"][0].to<std::string>() == "entry");
YAML_ASSERT(doc["sequence"][1].size() == 1);
YAML_ASSERT(doc["sequence"][1][0].to<std::string>() == "nested");
YAML_ASSERT(doc["mapping"].size() == 1);
YAML_ASSERT(doc["mapping"]["foo"].to<std::string>() == "bar");
return true;
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment