#include "./test_lib/test_case.hpp" #ifndef RYML_SINGLE_HEADER #include "c4/yml/common.hpp" #include "c4/yml/error.def.hpp" #include "c4/format.hpp" #include "c4/span.hpp" #include "c4/yml/std/std.hpp" #include "c4/yml/detail/print.hpp" #include "c4/yml/detail/checks.hpp" #endif #include #ifdef C4_EXCEPTIONS #include #else #include #endif #if defined(_MSC_VER) # pragma warning(push) #elif defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wold-style-cast" #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wuseless-cast" # pragma GCC diagnostic ignored "-Wold-style-cast" # if __GNUC__ >= 6 # pragma GCC diagnostic ignored "-Wnull-dereference" # endif # if __GNUC__ >= 7 # pragma GCC diagnostic ignored "-Wstringop-overflow" # endif #endif namespace c4 { namespace yml { id_type _num_leaves(Tree const& t, id_type node) { id_type count = 0; for(id_type ch = t.first_child(node); ch != NONE; ch = t.next_sibling(ch)) count += _num_leaves(t, ch); return count; } void test_compare(Tree const& actual, Tree const& expected, const char *actual_name, const char *expected_name, type_bits cmp_mask) { ASSERT_EQ(actual.empty(), expected.empty()); if(actual.empty() || expected.empty()) return; EXPECT_EQ(actual.size(), expected.size()); EXPECT_EQ(_num_leaves(actual, actual.root_id()), _num_leaves(expected, expected.root_id())); test_compare(actual, actual.root_id(), expected, expected.root_id(), 0, actual_name, expected_name, cmp_mask); } void test_compare(Tree const& actual, id_type node_actual, Tree const& expected, id_type node_expected, id_type depth, const char *actual_name, const char *expected_name, type_bits cmp_mask) { RYML_TRACE_FMT("{}[{}] vs {}[{}]. depth={}", actual_name, node_actual, expected_name, node_expected, depth); ASSERT_NE(node_actual, (id_type)NONE); ASSERT_NE(node_expected, (id_type)NONE); ASSERT_LT(node_actual, actual.capacity()); ASSERT_LT(node_expected, expected.capacity()); NodeType type_actual = actual.type(node_actual) & cmp_mask; NodeType type_expected = expected.type(node_expected) & cmp_mask; RYML_COMPARE_NODE_TYPE(type_actual, type_expected, ==, EQ); EXPECT_EQ(actual.has_key(node_actual), expected.has_key(node_expected)); if(actual.has_key(node_actual) && expected.has_key(node_expected)) { EXPECT_EQ(actual.key(node_actual), expected.key(node_expected)); } EXPECT_EQ(actual.has_val(node_actual), expected.has_val(node_expected)); if(actual.has_val(node_actual) && expected.has_val(node_expected)) { EXPECT_EQ(actual.val(node_actual), expected.val(node_expected)); } EXPECT_EQ(actual.has_key_tag(node_actual), expected.has_key_tag(node_expected)); if(actual.has_key_tag(node_actual) && expected.has_key_tag(node_expected)) { EXPECT_EQ(actual.key_tag(node_actual), expected.key_tag(node_expected)); } EXPECT_EQ(actual.has_val_tag(node_actual), expected.has_val_tag(node_expected)); if(actual.has_val_tag(node_actual) && expected.has_val_tag(node_expected)) { auto filtered = [](csubstr tag) { if(tag.begins_with("!')) return tag.offs(3, 1); return tag; }; csubstr actual_tag = filtered(actual.val_tag(node_actual)); csubstr expected_tag = filtered(actual.val_tag(node_expected)); EXPECT_EQ(actual_tag, expected_tag); } EXPECT_EQ(actual.has_key_anchor(node_actual), expected.has_key_anchor(node_expected)); if(actual.has_key_anchor(node_actual) && expected.has_key_anchor(node_expected)) { EXPECT_EQ(actual.key_anchor(node_actual), expected.key_anchor(node_expected)); } EXPECT_EQ(actual.has_val_anchor(node_actual), expected.has_val_anchor(node_expected)); if(actual.has_val_anchor(node_actual) && expected.has_val_anchor(node_expected)) { EXPECT_EQ(actual.val_anchor(node_actual), expected.val_anchor(node_expected)); } EXPECT_EQ(actual.num_children(node_actual), expected.num_children(node_expected)); for(id_type ia = actual.first_child(node_actual), ib = expected.first_child(node_expected); ia != NONE && ib != NONE; ia = actual.next_sibling(ia), ib = expected.next_sibling(ib)) { test_compare(actual, ia, expected, ib, depth+1, actual_name, expected_name); } } void test_arena_not_shared(Tree const& a, Tree const& b) { for(NodeData const* n = a.m_buf, *e = a.m_buf + a.m_cap; n != e; ++n) { EXPECT_FALSE(b.in_arena(n->m_key.scalar)) << n - a.m_buf; EXPECT_FALSE(b.in_arena(n->m_key.tag )) << n - a.m_buf; EXPECT_FALSE(b.in_arena(n->m_key.anchor)) << n - a.m_buf; EXPECT_FALSE(b.in_arena(n->m_val.scalar)) << n - a.m_buf; EXPECT_FALSE(b.in_arena(n->m_val.tag )) << n - a.m_buf; EXPECT_FALSE(b.in_arena(n->m_val.anchor)) << n - a.m_buf; } for(NodeData const* n = b.m_buf, *e = b.m_buf + b.m_cap; n != e; ++n) { EXPECT_FALSE(a.in_arena(n->m_key.scalar)) << n - b.m_buf; EXPECT_FALSE(a.in_arena(n->m_key.tag )) << n - b.m_buf; EXPECT_FALSE(a.in_arena(n->m_key.anchor)) << n - b.m_buf; EXPECT_FALSE(a.in_arena(n->m_val.scalar)) << n - b.m_buf; EXPECT_FALSE(a.in_arena(n->m_val.tag )) << n - b.m_buf; EXPECT_FALSE(a.in_arena(n->m_val.anchor)) << n - b.m_buf; } for(TagDirective const& td : a.m_tag_directives) { EXPECT_FALSE(b.in_arena(td.handle)); EXPECT_FALSE(b.in_arena(td.prefix)); } for(TagDirective const& td : b.m_tag_directives) { EXPECT_FALSE(a.in_arena(td.handle)); EXPECT_FALSE(a.in_arena(td.prefix)); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ensure coverage of the default callback report #ifndef RYML_NO_DEFAULT_CALLBACKS extern void report_error_parse_impl(csubstr msg, Location loc, FILE *file); #endif std::string format_error_basic(csubstr msg, ErrorDataBasic const& errdata) { std::string out; err_basic_format([&](csubstr s){ out.append(s.str, s.len); }, msg, errdata); return out; } std::string format_error_parse(csubstr msg, ErrorDataParse const& errdata) { std::string out; err_parse_format([&](csubstr s){ out.append(s.str, s.len); }, msg, errdata); return out; } std::string format_error_visit(csubstr msg, ErrorDataVisit const& errdata) { std::string out; err_visit_format([&](csubstr s){ out.append(s.str, s.len); }, msg, errdata); return out; } struct ExpectedErrorBasic C4_IF_EXCEPTIONS_( : public std::exception, ) { std::string smsg; C4_IF_EXCEPTIONS_(const char *what() const noexcept override { return smsg.c_str(); }, ) ExpectedErrorBasic() = default; ExpectedErrorBasic(csubstr msg, ErrorDataBasic const& errdata_) : C4_IF_EXCEPTIONS_(std::exception() C4_COMMA,) smsg(format_error_basic(msg, errdata_)) { } ExpectedErrorBasic(std::string s) : C4_IF_EXCEPTIONS_(std::exception() C4_COMMA,) smsg(std::move(s)) { } }; struct ExpectedErrorParse : public ExpectedErrorBasic { ErrorDataParse errdata; ExpectedErrorParse() = default; ExpectedErrorParse(csubstr msg, ErrorDataParse const& errdata_) : ExpectedErrorBasic(format_error_parse(msg, errdata_)) , errdata(errdata_) { } }; struct ExpectedErrorVisit : public ExpectedErrorBasic { ErrorDataVisit errdata; ExpectedErrorVisit() = default; ExpectedErrorVisit(csubstr msg, ErrorDataVisit const& errdata_) : ExpectedErrorBasic(format_error_visit(msg, errdata_)) , errdata(errdata_) { } }; //----------------------------------------------------------------------------- C4_IF_EXCEPTIONS_( , std::jmp_buf s_jmp_env_expect_error; ExpectedErrorBasic s_jmp_err_basic = {}; ExpectedErrorParse s_jmp_err_parse = {}; ExpectedErrorVisit s_jmp_err_visit = {}; ) ExpectError::ExpectError(Tree *tree, Location loc) : m_got_an_error(false) , m_tree(tree) , m_glob_prev(get_callbacks()) , m_tree_prev(tree ? tree->callbacks() : m_glob_prev) , expected_location(loc) { auto errb = [](csubstr msg, ErrorDataBasic const& errdata, void *this_) { _c4dbgp("called basic error callback!"); ((ExpectError*)this_)->m_got_an_error = true; // assign in here to ensure the exception was thrown here C4_IF_EXCEPTIONS( throw ExpectedErrorBasic(msg, errdata); , s_jmp_err_basic = ExpectedErrorBasic(msg, errdata); std::longjmp(s_jmp_env_expect_error, 1); ); C4_UNREACHABLE_AFTER_ERR(); }; auto errp = [](csubstr msg, ErrorDataParse const& errdata, void *this_) { _c4dbgpf("called parse error callback! (withlocation={})", bool(errdata.ymlloc)); ((ExpectError*)this_)->m_got_an_error = true; // assign in here to ensure the exception was thrown here C4_IF_EXCEPTIONS( throw ExpectedErrorParse(msg, errdata); , s_jmp_err_parse = ExpectedErrorParse(msg, errdata); std::longjmp(s_jmp_env_expect_error, 1); ); C4_UNREACHABLE_AFTER_ERR(); }; auto errv = [](csubstr msg, ErrorDataVisit const& errdata, void *this_) { _c4dbgp("called visit error callback!"); ((ExpectError*)this_)->m_got_an_error = true; // assign in here to ensure the exception was thrown here C4_IF_EXCEPTIONS( throw ExpectedErrorVisit(msg, errdata); , s_jmp_err_visit = ExpectedErrorVisit(msg, errdata); std::longjmp(s_jmp_env_expect_error, 1); ); C4_UNREACHABLE_AFTER_ERR(); }; c4::yml::Callbacks tcb; c4::yml::Callbacks gcb; tcb.set_user_data((void*)this).set_error_basic(errb).set_error_parse(errp).set_error_visit(errv); gcb.set_user_data((void*)this).set_error_basic(errb).set_error_parse(errp).set_error_visit(errv); if(tree) { _c4dbgpf("setting error callback: tree err={}", c4::fmt::hex((void const*)&errp)); tree->callbacks(tcb); EXPECT_EQ(tree->callbacks().m_error_basic, errb); EXPECT_EQ(tree->callbacks().m_error_parse, errp); EXPECT_EQ(tree->callbacks().m_error_visit, errv); } _c4dbgpf("setting error callback: global err={}", c4::fmt::hex((void const*)&errp)); set_callbacks(gcb); EXPECT_EQ(get_callbacks().m_error_basic, errb); EXPECT_EQ(get_callbacks().m_error_parse, errp); EXPECT_EQ(get_callbacks().m_error_visit, errv); } ExpectError::~ExpectError() { if(m_tree) { _c4dbgp("resetting error callback: tree"); m_tree->callbacks(m_tree_prev); } _c4dbgp("resetting error callback: global"); set_callbacks(m_tree_prev); } void ExpectError::check_success(Tree *tree, fntestref fn) { Location expected_location = {}; auto context = ExpectError(tree, expected_location); C4_IF_EXCEPTIONS_(try, if(setjmp(s_jmp_env_expect_error) == 0)) { _c4dbgp("check expected success"); fn(); _c4dbgp("check expected success: success!"); } C4_IF_EXCEPTIONS_(catch(ExpectedErrorParse const&), else) { FAIL() << "check expected success: failed!"; } ASSERT_FALSE(context.m_got_an_error); } void ExpectError::check_error_basic(Tree const* tree, fntestref fn) { check_error_basic(const_cast(tree), fn); } void ExpectError::check_error_parse(Tree const* tree, fntestref fn, Location const& expected_location) { check_error_parse(const_cast(tree), fn, expected_location); } void ExpectError::check_error_visit(Tree const* tree, fntestref fn, id_type expected_id) { check_error_visit(const_cast(tree), fn, expected_id); } void ExpectError::check_error_basic(Tree *tree, fntestref fn) { auto context = ExpectError(tree); C4_IF_EXCEPTIONS_(try, if(setjmp(s_jmp_env_expect_error) == 0)) { _c4dbgp("check expected basic error"); fn(); _c4dbgp("check expected basic error: failed!"); } C4_IF_EXCEPTIONS_(catch(ExpectedErrorBasic const& e), else) { C4_IF_EXCEPTIONS_( , ExpectedErrorBasic const& e = s_jmp_err_basic); (void)e; #if defined(RYML_DBG) std::cout << "---------------\n"; std::cout << "got an expected parse error:\n" << e.what() << "\n"; std::cout << "---------------\n"; #endif } C4_IF_EXCEPTIONS_(catch(...) { _c4dbgp("---------------\n" "got an unexpected exception!\n" "---------------\n"); }, ) EXPECT_TRUE(context.m_got_an_error); } void ExpectError::check_error_parse(Tree *tree, fntestref fn, Location const& expected_location) { ExpectError context(tree, expected_location); C4_IF_EXCEPTIONS_(try, if(setjmp(s_jmp_env_expect_error) == 0)) { _c4dbgp("check expected parse error"); fn(); _c4dbgp("check expected parse error: failed!"); } C4_IF_EXCEPTIONS_(catch(ExpectedErrorParse const& e), else) { C4_IF_EXCEPTIONS_( , ExpectedErrorParse const& e = s_jmp_err_parse); (void)e; #if defined(RYML_DBG) std::cout << "---------------\n"; std::cout << "got an expected parse error:\n" << e.what() << "\n"; std::cout << "---------------\n"; #endif if(expected_location) { _c4dbgp("checking expected location..."); EXPECT_EQ(static_cast(e.errdata.ymlloc), static_cast(context.expected_location)); if(context.expected_location.line != npos) { EXPECT_EQ(e.errdata.ymlloc.line, context.expected_location.line); } if(context.expected_location.col != npos) { EXPECT_EQ(e.errdata.ymlloc.col, context.expected_location.col); } if(context.expected_location.offset != npos) { EXPECT_EQ(e.errdata.ymlloc.offset, context.expected_location.offset); } } } C4_IF_EXCEPTIONS_(catch(...) { _c4dbgp("---------------\n" "got an unexpected exception!\n" "---------------\n"); }, ) EXPECT_TRUE(context.m_got_an_error); } void ExpectError::check_error_visit(Tree *tree, fntestref fn, id_type id) { auto context = ExpectError(tree); C4_IF_EXCEPTIONS_(try, if(setjmp(s_jmp_env_expect_error) == 0)) { _c4dbgp("check expected visit error"); fn(); _c4dbgp("check expected visit error: failed!"); } C4_IF_EXCEPTIONS_(catch(ExpectedErrorVisit const& e), else) { C4_IF_EXCEPTIONS_( , ExpectedErrorVisit const& e = s_jmp_err_visit); (void)e; #if defined(RYML_DBG) std::cout << "---------------\n"; std::cout << "got an expected visit error:\n" << e.what() << "\n"; std::cout << "---------------\n"; #endif EXPECT_EQ(e.errdata.tree, tree); if(id != npos) { EXPECT_EQ(e.errdata.node, id); } } C4_IF_EXCEPTIONS_(catch(std::exception const& exc) { std::cout << "---------------\n"; std::cout << "got an unexpected exception!:\n" << exc.what() << "\n"; std::cout << "---------------\n"; }, ) C4_IF_EXCEPTIONS_(catch(...) { std::cout << "---------------\n"; std::cout << "got an unexpected exception!\n"; std::cout << "---------------\n"; }, ) EXPECT_TRUE(context.m_got_an_error); } void ExpectError::check_assert_basic(Tree *tree, fntestref fn) { #if RYML_USE_ASSERT ExpectError::check_error_basic(tree, fn); #else C4_UNUSED(tree); C4_UNUSED(fn); #endif } void ExpectError::check_assert_parse(Tree *tree, fntestref fn, Location const& expected_location) { #if RYML_USE_ASSERT ExpectError::check_error_parse(tree, fn, expected_location); #else C4_UNUSED(tree); C4_UNUSED(fn); C4_UNUSED(expected_location); #endif } void ExpectError::check_assert_visit(Tree *tree, fntestref fn, id_type id) { #if RYML_USE_ASSERT ExpectError::check_error_visit(tree, fn, id); #else C4_UNUSED(tree); C4_UNUSED(fn); C4_UNUSED(id); #endif } //----------------------------------------------------------------------------- void print_path(ConstNodeRef const& n) { size_t len = 0; char buf[1024]; ConstNodeRef p = n; while(p.readable()) { if(p.has_key()) { len += 1 + p.key().len; } else { int ret = snprintf(buf, sizeof(buf), "/%zu", p.has_parent() ? (size_t)p.parent().child_pos(p) : (size_t)0); _RYML_ASSERT_BASIC(ret >= 0); len += static_cast(ret); } p = p.parent(); }; C4_ASSERT(len < sizeof(buf)); size_t pos = len; p = n; while(p.readable()) { if(p.has_key()) { size_t tl = p.key().len; int ret = snprintf(buf + pos - tl, tl, "%.*s", (int)tl, p.key().str); _RYML_ASSERT_BASIC(ret >= 0); pos -= static_cast(ret); } else if(p.has_parent()) { pos = (size_t)p.parent().child_pos(p); int ret = snprintf(buf, 0, "/%zu", pos); _RYML_ASSERT_BASIC(ret >= 0); size_t tl = static_cast(ret); _RYML_ASSERT_BASIC(pos >= tl); ret = snprintf(buf + static_cast(pos - tl), tl, "/%zu", pos); _RYML_ASSERT_BASIC(ret >= 0); pos -= static_cast(ret); } p = p.parent(); }; printf("%.*s", (int)len, buf); } void print_test_node(TestCaseNode const& p, int level) { printf("%*s%p", (2*level), "", (void const*)&p); if( ! p.parent) { printf(" [ROOT]"); } printf(" %s:", NodeType::type_str(p.type)); if(p.has_key()) { const char code = _scalar_code_key(p.type); if(p.has_key_anchor()) { csubstr ka = p.key_anchor.str; printf(" &%.*s", (int)ka.len, ka.str); } if(p.key_tag.empty()) { csubstr v = p.key; printf(" %c%.*s%c", code, (int)v.len, v.str, code); } else { csubstr vt = p.key_tag; csubstr v = p.key; printf(" %.*s %c%.*s%c'", (int)vt.len, vt.str, code, (int)v.len, v.str, code); } } if(p.has_val()) { const char code = _scalar_code_val(p.type); if(p.val_tag.empty()) { csubstr v = p.val; printf(" %c%.*s%c", code, (int)v.len, v.str, code); } else { csubstr vt = p.val_tag; csubstr v = p.val; printf(" %.*s%c%.*s%c", (int)vt.len, vt.str, code, (int)v.len, v.str, code); } } else { if( ! p.val_tag.empty()) { csubstr vt = p.val_tag; printf(" %.*s", (int)vt.len, vt.str); } } if(p.has_val_anchor()) { auto &a = p.val_anchor.str; printf(" valanchor='&%.*s'", (int)a.len, a.str); } printf(" (%zd sibs)", p.parent ? p.parent->children.size() : 0); if(p.is_container()) { printf(" %zd children:", p.children.size()); } printf("\n"); } void print_test_tree(TestCaseNode const& p, int level) { print_test_node(p, level); for(auto const& ch : p.children) print_test_tree(ch, level+1); } void print_test_tree(const char *message, TestCaseNode const& t) { printf("--------------------------------------\n"); if(message != nullptr) printf("%s:\n", message); print_test_tree(t, 0); printf("#nodes: %zu\n", (size_t)t.reccount()); printf("--------------------------------------\n"); } void test_invariants(ConstNodeRef const& n) { SCOPED_TRACE(n.id()); if(n.is_root()) { EXPECT_FALSE(n.has_other_siblings()); } // vals cannot be containers if( ! n.empty() && ! n.is_doc()) { EXPECT_NE(n.has_val(), n.is_container()); } if(n.has_children()) { EXPECT_TRUE(n.is_container()); EXPECT_FALSE(n.is_val()); } // check sibling reciprocity for(ConstNodeRef s : n.siblings()) { EXPECT_TRUE(n.has_sibling(s)); EXPECT_TRUE(s.has_sibling(n)); if(n.has_key() && s.has_key()) { EXPECT_TRUE(n.has_sibling(s.key())); EXPECT_TRUE(s.has_sibling(n.key())); } EXPECT_EQ(s.parent().get(), n.parent().get()); } // check parent/child reciprocity if(n.parent().readable()) { EXPECT_EQ(n.parent().num_children() > 1, n.has_other_siblings()); EXPECT_TRUE(n.parent().has_child(n)); EXPECT_EQ(n.parent().num_children(), n.num_siblings()); EXPECT_EQ(n.parent().num_children(), n.num_other_siblings()+id_type(1)); // doc parent must be a seq and a stream if(n.is_doc()) { EXPECT_TRUE(n.parent().is_seq()); EXPECT_TRUE(n.parent().is_stream()); } } else { EXPECT_TRUE(n.is_root()); } if(n.is_seq()) { EXPECT_TRUE(n.is_container()); EXPECT_FALSE(n.is_map()); for(ConstNodeRef ch : n.children()) { EXPECT_FALSE(ch.is_keyval()); EXPECT_FALSE(ch.has_key()); } } if(n.is_map()) { EXPECT_TRUE(n.is_container()); EXPECT_FALSE(n.is_seq()); for(ConstNodeRef ch : n.children()) { if(ch.type() != NOTYPE) { EXPECT_TRUE(ch.has_key()); } } } if(n.has_key_anchor()) { EXPECT_FALSE(n.key_anchor().empty()); EXPECT_FALSE(n.is_key_ref()); } if(n.has_val_anchor()) { EXPECT_FALSE(n.val_anchor().empty()); EXPECT_FALSE(n.is_val_ref()); } if(n.is_key_ref()) { EXPECT_FALSE(n.key_ref().empty()); EXPECT_FALSE(n.has_key_anchor()); } if(n.is_val_ref()) { EXPECT_FALSE(n.val_ref().empty()); EXPECT_FALSE(n.has_val_anchor()); } if(n.has_key()) { if(n.is_key_quoted()) { EXPECT_FALSE(n.key_is_null()); } if(n.key_is_null()) { EXPECT_FALSE(n.is_key_quoted()); } } if(n.has_val() && n.is_val_quoted()) { if(n.is_val_quoted()) { EXPECT_FALSE(n.val_is_null()); } if(n.val_is_null()) { EXPECT_FALSE(n.is_val_quoted()); } } // ... add more tests here // now recurse into the children for(ConstNodeRef ch : n.children()) { test_invariants(ch); } #undef _MORE_INFO } static size_t test_tree_invariants(ConstNodeRef const& n) { ConstNodeRef parent = n.parent(); if(n.get()->m_prev_sibling == NONE) { if(parent.readable()) { EXPECT_EQ(parent.first_child().get(), n.get()); EXPECT_EQ(parent.first_child().id(), n.id()); } } if(n.get()->m_next_sibling == NONE) { if(parent.readable()) { EXPECT_EQ(parent.last_child().get(), n.get()); EXPECT_EQ(parent.last_child().id(), n.id()); } } if(!parent.readable()) { EXPECT_TRUE(n.is_root()); EXPECT_EQ(n.prev_sibling().get(), nullptr); EXPECT_EQ(n.next_sibling().get(), nullptr); } size_t count = 1, num = 0; for(ConstNodeRef ch : n.children()) { EXPECT_NE(ch.id(), n.id()); count += test_tree_invariants(ch); ++num; } EXPECT_EQ(num, n.num_children()); return count; } void test_invariants(Tree const& t) { SCOPED_TRACE("tree invariants"); ASSERT_LE(t.size(), t.capacity()); EXPECT_EQ(t.size() + t.slack(), t.capacity()); ASSERT_LE(t.arena_size(), t.arena_capacity()); ASSERT_LE(t.arena_slack(), t.arena_capacity()); EXPECT_EQ(t.arena_size() + t.arena_slack(), t.arena_capacity()); if(t.empty()) return; size_t count = test_tree_invariants(t.rootref()); EXPECT_EQ(count, t.size()); check_invariants(t); test_invariants(t.rootref()); if(!testing::UnitTest::GetInstance()->current_test_info()->result()->Passed()) { print_tree(t); } return; #if 0 == 1 for(size_t i = 0; i < t.m_size; ++i) { auto n = t.get(i); if(n->m_prev_sibling == NONE) { EXPECT_TRUE(i == t.m_head || i == t.m_free_head); } if(n->m_next_sibling == NONE) { EXPECT_TRUE(i == t.m_tail || i == t.m_free_tail); } } std::vector touched(t.capacity()); for(size_t i = t.m_head; i != NONE; i = t.get(i)->m_next_sibling) touched[i] = true; size_t size = 0; for(bool v : touched) size += v; EXPECT_EQ(size, t.size()); touched.clear(); touched.resize(t.capacity()); for(size_t i = t.m_free_head; i != NONE; i = t.get(i)->m_next_sibling) { touched[i] = true; } size_t slack = 0; for(auto v : touched) { slack += v; } EXPECT_EQ(slack, t.slack()); EXPECT_EQ(size+slack, t.capacity()); // there are more checks to be done #endif } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- CaseData* get_data(csubstr name) { static std::map m; auto it = m.find(name); CaseData *cd; if(it == m.end()) { cd = &m[name]; Case const* c = get_case(name); _RYML_CHECK_BASIC(c->src.find("\n\r") == csubstr::npos); { std::string tmp; replace_all("\r", "", c->src, &tmp); cd->unix_style.assign(to_csubstr(tmp)); cd->unix_style_json.assign(to_csubstr(tmp)); } { std::string tmp; replace_all("\n", "\r\n", cd->unix_style.src, &tmp); cd->windows_style.assign(to_csubstr(tmp)); cd->windows_style_json.assign(to_csubstr(tmp)); } } else { cd = &it->second; } return cd; } } // namespace yml } // namespace c4 #if defined(_MSC_VER) # pragma warning(pop) #elif defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) # pragma GCC diagnostic pop #endif