#include "common/common_pch.h" #include #include #include #include #include #include #include #include #include #include "common/strings/editing.h" #include "common/at_scope_exit.h" #include "tests/unit/util.h" namespace mtxut { void dump(EbmlElement *element, bool with_values, unsigned int level) { std::string indent_str, value_str; size_t i; for (i = 1; i <= level; ++i) indent_str += " "; if (with_values) { if (dynamic_cast(element)) value_str = to_string(uint64(*static_cast(element))); else if (dynamic_cast(element)) value_str = to_string(int64(*static_cast(element))); else if (dynamic_cast(element)) value_str = to_string(double(*static_cast(element))); else if (dynamic_cast(element)) value_str = UTFstring(*static_cast(element)).GetUTF8(); else if (dynamic_cast(element)) value_str = std::string(*static_cast(element)); else if (dynamic_cast(element)) value_str = to_string(static_cast(element)->GetEpochDate()); else value_str = (boost::format("(type: %1%)") % ( dynamic_cast(element) ? "binary" : dynamic_cast(element) ? "master" : dynamic_cast(element) ? "void" : "unknown")).str(); value_str = " " + value_str; } std::cout << indent_str << EBML_NAME(element) << value_str << std::endl; EbmlMaster *master = dynamic_cast(element); if (!master) return; for (auto el : *master) dump(el, with_values, level + 1); } // // ---------------------------------------------------------------------- // ::testing::AssertionResult EbmlEquals(char const *a_expr, char const *b_expr, EbmlElement &a, EbmlElement &b) { std::string error; if (ebml_equals_c::check(a, b, error)) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << a_expr << " and " << b_expr << " are not equal: " << error; } // // ---------------------------------------------------------------------- // ebml_equals_c::ebml_equals_c() { } std::string ebml_equals_c::get_error() const { return m_error; } bool ebml_equals_c::set_error(std::string const &error, EbmlElement *cmp) { auto full_path = m_path; if (cmp) full_path.push_back(EBML_NAME(cmp)); m_error = (boost::format("%1% path: %2%") % error % join(" -> ", full_path)).str(); return false; } bool ebml_equals_c::set_error(boost::format const &error, EbmlElement *cmp) { return set_error(error.str(), cmp); } bool ebml_equals_c::check(EbmlElement &a, EbmlElement &b, std::string &error) { ebml_equals_c checker; bool result = checker.compare_impl(a, b); error = checker.get_error(); return result; } bool ebml_equals_c::compare_impl(EbmlElement &a, EbmlElement &b) { if (&a == &b) return true; if (std::string{EBML_NAME(&a)} != std::string{EBML_NAME(&b)}) return set_error(boost::format("types are differing: %1% vs %2%") % EBML_NAME(&a) % EBML_NAME(&b)); EbmlUInteger *ui_a; EbmlSInteger *si_a; EbmlFloat *f_a; EbmlString *str_a; EbmlUnicodeString *ustr_a; EbmlMaster *m_a; EbmlDate *d_a; EbmlBinary *b_a; if ((ui_a = dynamic_cast(&a))) { auto val_b = uint64(*dynamic_cast(&b)); return uint64(*ui_a) == val_b ? true : set_error(boost::format("UInteger values differ: %1% vs %2%") % uint64(*ui_a) % val_b, &a); } else if ((si_a = dynamic_cast(&a))) { auto val_b = int64(*dynamic_cast(&b)); return int64(*si_a) == val_b ? true : set_error(boost::format("SInteger values differ: %1% vs %2%") % int64(*si_a) % val_b, &a); } else if ((d_a = dynamic_cast(&a))) { auto val_a = d_a->GetEpochDate(); auto val_b = dynamic_cast(&b)->GetEpochDate(); return val_a == val_b ? true : set_error(boost::format("Date values differ: %1% vs %2%") % val_a % val_b, &a); } else if ((f_a = dynamic_cast(&a))) { auto val_b = double(*dynamic_cast(&b)); return double(*f_a) == val_b ? true : set_error(boost::format("Float values differ: %1% vs %2%") % double(*f_a) % val_b, &a); } else if ((str_a = dynamic_cast(&a))) { auto val_b = std::string(*dynamic_cast(&b)); return std::string(*str_a) == val_b ? true : set_error(boost::format("String values differ: %1% vs %2%") % std::string(*str_a) % val_b, &a); } else if ((ustr_a = dynamic_cast(&a))) { auto val_a = UTFstring(*dynamic_cast(&a)).GetUTF8(); auto val_b = UTFstring(*dynamic_cast(&b)).GetUTF8(); return val_a == val_b ? true : set_error(boost::format("UnicodeString values differ: %1% vs %2%") % val_a % val_b, &a); } else if ((b_a = dynamic_cast(&a))) { auto b_b = dynamic_cast(&b); return *b_a == *b_b ? true : set_error(boost::format("Binary values differ; sizes %1% vs %2%") % b_a->GetSize() % b_b->GetSize(), &a); } else if ((m_a = dynamic_cast(&a))) { m_path.push_back(EBML_NAME(&a)); at_scope_exit_c popper{[&]() { m_path.pop_back(); }}; auto m_b = dynamic_cast(&b); for (int i = 0; i < std::min(m_a->ListSize(), m_b->ListSize()); ++i) if (!compare_impl(*(*m_a)[i], *(*m_b)[i])) return false; if (m_a->ListSize() == m_b->ListSize()) return true; std::string op; EbmlMaster *with_more, *with_less; if (m_a->ListSize() > m_b->ListSize()) { op = "more"; with_more = m_a; with_less = m_b; } else { op = "less"; with_less = m_a; with_more = m_b; } std::stringstream error{ (boost::format("LHS contains %1% elements than RHS (%2% vs %3%):") % op % m_a->ListSize() % m_b->ListSize()).str() }; for (auto i = with_less->ListSize(); i < with_more->ListSize(); ++i) error << " " << EBML_NAME((*with_more)[i]); return set_error(error.str()); } else return set_error(boost::format("unsupported types: %1% and %2%") % EBML_NAME(&a) % EBML_NAME(&b)); } }