#include #include #include #include #include #include #include #include #include "libslic3r/LocalesUtils.hpp" using namespace Slic3r; namespace { // Switches this thread's numeric locale to one whose decimal separator is a comma, // when the system has one installed. struct CommaNumericLocale { #ifdef _WIN32 bool apply() { for (const char* name : { "de-DE", "German_Germany.1252" }) if (std::setlocale(LC_NUMERIC, name) != nullptr) return true; return false; } #else locale_t locale { (locale_t) 0 }; bool apply() { for (const char* name : { "de_DE.UTF-8", "de_DE.utf8", "de_DE" }) if ((locale = newlocale(LC_NUMERIC_MASK, name, (locale_t) 0)) != (locale_t) 0) { uselocale(locale); return true; } return false; } // Freed once the setters around apply() have put the thread's own locale back. ~CommaNumericLocale() { if (locale != (locale_t) 0) freelocale(locale); } #endif }; } // namespace TEST_CASE("a setter nested in another leaves the C locale in place for the outer one", "[LocalesUtils]") { CNumericLocalesSetter outer; { CNumericLocalesSetter inner; CHECK(is_decimal_separator_point()); } CHECK(is_decimal_separator_point()); } TEST_CASE("a setter nested in another sets C again when the locale changed between them", "[LocalesUtils]") { CommaNumericLocale comma; { CNumericLocalesSetter outer; if (! comma.apply()) SKIP("no locale with a comma decimal separator is installed"); REQUIRE_FALSE(is_decimal_separator_point()); { CNumericLocalesSetter inner; CHECK(is_decimal_separator_point()); } CHECK_FALSE(is_decimal_separator_point()); } } TEST_CASE("atof_decimal_point parses what atof parses in the C locale", "[LocalesUtils]") { const auto [text, value] = GENERATE(table({ { "5", 5. }, { " 12.5", 12.5 }, { "\t+3", 3. }, { "\r\n7", 7. }, { "-1.25", -1.25 }, { "1e2", 100. }, { ".5", 0.5 }, { "12.5;comment", 12.5 }, { "+-5", 0. }, { "", 0. }, { "abc", 0. }, })); INFO(text); CHECK_THAT(atof_decimal_point(text), Catch::Matchers::WithinAbs(value, 1e-12)); }