diff --git a/tests/unit/util.cpp b/tests/unit/util.cpp new file mode 100644 index 000000000..bbe3855b0 --- /dev/null +++ b/tests/unit/util.cpp @@ -0,0 +1,196 @@ +#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; + + 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 ((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 ((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)); +} + +} diff --git a/tests/unit/util.h b/tests/unit/util.h index c95def92c..5629a65e8 100644 --- a/tests/unit/util.h +++ b/tests/unit/util.h @@ -16,69 +16,38 @@ #include "common/common_pch.h" -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "gtest/gtest.h" +#include "common/strings/formatting.h" + +#define ASSERT_EBML_EQ(a, b) ASSERT_PRED_FORMAT2(EbmlEquals, (a), (b)) +#define EXPECT_EBML_EQ(a, b) EXPECT_PRED_FORMAT2(EbmlEquals, (a), (b)) namespace mtxut { using namespace libebml; -void -dump(EbmlElement *element, - bool with_values = false, - unsigned int level = 0) { - std::string indent_str, value_str; - size_t i; +void dump(EbmlElement *element, bool with_values = false, unsigned int level = 0); - for (i = 1; i <= level; ++i) - indent_str += " "; +::testing::AssertionResult EbmlEquals(char const *a_expr, char const *b_expr, EbmlElement &a, EbmlElement &b); - if (with_values) { - if (dynamic_cast(element)) - value_str = to_string(uint64(*static_cast(element))); +class ebml_equals_c { +private: + std::vector m_path; + std::string m_error; - else if (dynamic_cast(element)) - value_str = to_string(int64(*static_cast(element))); +public: + ebml_equals_c(); - else if (dynamic_cast(element)) - value_str = to_string(double(*static_cast(element))); + bool compare_impl(EbmlElement &a, EbmlElement &b); + std::string get_error() const; + bool set_error(std::string const &error, EbmlElement *cmp = nullptr); + bool set_error(boost::format const &error, EbmlElement *cmp = nullptr); - else if (dynamic_cast(element)) - value_str = UTFstring_to_cstrutf8(UTFstring(*static_cast(element))); - - 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); -} +public: + static bool check(EbmlElement &a, EbmlElement &b, std::string &error); +}; }