diff --git a/test/boostLocale/test/unit_test.hpp b/test/boostLocale/test/unit_test.hpp index 953f414..cbfc8cd 100644 --- a/test/boostLocale/test/unit_test.hpp +++ b/test/boostLocale/test/unit_test.hpp @@ -10,6 +10,7 @@ #define BOOST_LOCALE_UNIT_TEST_HPP #include +#include #include #include #include @@ -33,8 +34,10 @@ namespace boost { namespace locale { namespace test { /// Name/path of current executable std::string exe_name; + class test_context; + struct test_result { - test_result() : error_counter(0), test_counter(0) + test_result() { #if defined(_MSC_VER) && (_MSC_VER > 1310) // disable message boxes on assert(), abort() @@ -46,8 +49,9 @@ namespace boost { namespace locale { namespace test { _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); #endif } - int error_counter; - int test_counter; + int error_counter = 0; + int test_counter = 0; + const test_context* context = nullptr; }; inline test_result& results() { @@ -55,9 +59,32 @@ namespace boost { namespace locale { namespace test { return instance; } + class test_context { + const test_context* oldCtx_; + const std::string msg_; + + public: + test_context(std::string ctx) : oldCtx_(results().context), msg_(std::move(ctx)) { results().context = this; } + ~test_context() { results().context = oldCtx_; } + friend std::ostream& operator<<(std::ostream& os, const test_context& c) + { + const test_context* current = &c; + os << "CONTEXT: "; + std::string indent = "\n\t"; + do { + os << indent << current->msg_; + indent += '\t'; + } while((current = current->oldCtx_) != nullptr); + return os; + } + }; + inline void report_error(const char* expr, const char* file, int line) { std::cerr << "Error at " << file << '#' << line << ": " << expr << std::endl; + const auto* context = results().context; + if(context) + std::cerr << ' ' << *context << std::endl; if(++boost::locale::test::results().error_counter > BOOST_LOCALE_ERROR_LIMIT) throw std::runtime_error("Error limits reached, stopping unit test"); } @@ -97,6 +124,10 @@ namespace boost { namespace locale { namespace test { BOOST_LOCALE_START_CONST_CONDITION \ } while(0) BOOST_LOCALE_END_CONST_CONDITION +#define TEST_CONTEXT(expr) \ + boost::locale::test::test_context BOOST_JOIN(test_context_, __COUNTER__)( \ + static_cast(std::stringstream{} << expr).str()) + void test_main(int argc, char** argv); int main(int argc, char** argv) diff --git a/test/test_catalog.cpp b/test/test_catalog.cpp index 6b884b9..bc06805 100644 --- a/test/test_catalog.cpp +++ b/test/test_catalog.cpp @@ -31,10 +31,8 @@ void test_plural_expr_rand(const T& ref, const char* expr) const auto n = getRandValue(minVal, maxVal); const auto result = ptr(n); const auto refResult = ref(n); - if(result != refResult) { - std::cerr << "Expression: " << expr << "; n=" << n << '\n'; // LCOV_EXCL_LINE - TEST_EQ(result, refResult); // LCOV_EXCL_LINE - } + TEST_CONTEXT("Expression: " << expr << "; n=" << n); + TEST_EQ(result, refResult); } } diff --git a/test/test_codecvt.cpp b/test/test_codecvt.cpp index 7df704d..504da43 100644 --- a/test/test_codecvt.cpp +++ b/test/test_codecvt.cpp @@ -53,10 +53,8 @@ void test_codecvt_in_n_m(const cvt_type& cvt, int n, int m) std::mbstate_t mb2 = mb; std::codecvt_base::result r = cvt.in(mb, from, end, from_next, to, to_end, to_next); - int count = cvt.length(mb2, from, end, to_end - to); + const int count = cvt.length(mb2, from, end, to_end - to); TEST_EQ(memcmp(&mb, &mb2, sizeof(mb)), 0); - if(count != from_next - from) - std::cout << count << " " << from_next - from << std::endl; // LCOV_EXCL_LINE TEST_EQ(count, from_next - from); if(r == cvt_type::partial) { diff --git a/test/test_encoding.cpp b/test/test_encoding.cpp index 4de7e61..7fb07c2 100644 --- a/test/test_encoding.cpp +++ b/test/test_encoding.cpp @@ -832,10 +832,9 @@ void test_simple_encodings() const auto encodings = get_simple_encodings(); for(auto it = encodings.begin(), end = encodings.end(); it != end; ++it) { TEST_EQ(normalize_encoding(*it), *it); // Must be normalized - const auto it2 = std::find(it + 1, end, *it); - TEST(it2 == end); - if(it2 != end) - std::cerr << "Duplicate entry: " << *it << '\n'; // LCOV_EXCL_LINE + TEST_CONTEXT("Entry: " << *it); + // Must be unique + TEST(std::find(it + 1, end, *it) == end); } const auto it = std::is_sorted_until(encodings.begin(), encodings.end()); TEST(it == encodings.end()); @@ -852,10 +851,9 @@ void test_win_codepages() auto is_same_win_codepage = [&it](const windows_encoding& rhs) -> bool { return it->codepage == rhs.codepage && std::strcmp(it->name, rhs.name) == 0; }; - const auto* it2 = std::find_if(it + 1, end, is_same_win_codepage); - TEST(it2 == end); - if(it2 != end) - std::cerr << "Duplicate entry: " << it->name << ':' << it->codepage << '\n'; // LCOV_EXCL_LINE + TEST_CONTEXT("Entry: " << it->name << ':' << it->codepage); + // Must be unique + TEST(std::find_if(it + 1, end, is_same_win_codepage) == end); } const auto cmp = [](const windows_encoding& rhs, const windows_encoding& lhs) -> bool { return rhs < lhs.name; }; const auto* it = std::is_sorted_until(all_windows_encodings, std::end(all_windows_encodings), cmp); diff --git a/test/test_formatting.cpp b/test/test_formatting.cpp index e2df2ad..41c30a0 100644 --- a/test/test_formatting.cpp +++ b/test/test_formatting.cpp @@ -300,6 +300,7 @@ void test_parse_fail_impl(std::basic_istringstream& ss, int line) #define TEST_MIN_MAX_POSIX(type) \ do { \ + TEST_CONTEXT(#type); \ const std::string minval = as_posix_string(std::numeric_limits::min()); \ const std::string maxval = as_posix_string(std::numeric_limits::max()); \ TEST_MIN_MAX_FMT(as::posix, type, minval, maxval); \ @@ -340,6 +341,7 @@ void test_as_posix(const std::string& e_charset = "UTF-8") localization_backend_manager::global(backend); for(const std::string name : {"en_US", "ru_RU", "de_DE"}) { const std::locale loc = boost::locale::generator{}(name + "." + e_charset); + TEST_CONTEXT("Locale " << (name + "." + e_charset)); TEST_MIN_MAX_POSIX(int16_t); TEST_MIN_MAX_POSIX(uint16_t);