|
22 | 22 | #include <cfloat> |
23 | 23 | #include <cinttypes> |
24 | 24 | #include <climits> |
| 25 | +#include <clocale> |
25 | 26 | #include <cmath> |
26 | 27 | #include <cstddef> |
27 | 28 | #include <cstdint> |
|
39 | 40 |
|
40 | 41 | #include "gmock/gmock.h" |
41 | 42 | #include "gtest/gtest.h" |
| 43 | +#include "absl/cleanup/cleanup.h" |
42 | 44 | #include "absl/log/log.h" |
43 | 45 | #include "absl/numeric/int128.h" |
44 | 46 | #include "absl/random/random.h" |
@@ -1717,6 +1719,37 @@ class SimpleDtoaTest : public testing::Test { |
1717 | 1719 | fenv_t fp_env_; |
1718 | 1720 | }; |
1719 | 1721 |
|
| 1722 | +TEST(SimpleDtoa, HighPrecisionIsLocaleIndependent) { |
| 1723 | + // absl::HighPrecision(double) routes through RoundTripDoubleToBuffer(), which |
| 1724 | + // used to leak the global C locale's radix character (e.g. ',' under de_DE) |
| 1725 | + // into its output. HighPrecision() promises a value that SimpleAtod() reads |
| 1726 | + // back exactly, and SimpleAtod() only accepts '.', so the radix must stay '.' |
| 1727 | + // regardless of the active locale. |
| 1728 | + std::string old_locale = setlocale(LC_NUMERIC, nullptr); |
| 1729 | + auto restore_locale = |
| 1730 | + absl::MakeCleanup([&] { setlocale(LC_NUMERIC, old_locale.c_str()); }); |
| 1731 | + const char* comma_locales[] = {"de_DE.UTF-8", "de_DE", "fr_FR.UTF-8", "fr_FR", |
| 1732 | + "nl_NL.UTF-8"}; |
| 1733 | + bool changed = false; |
| 1734 | + for (const char* loc : comma_locales) { |
| 1735 | + if (setlocale(LC_NUMERIC, loc) != nullptr) { |
| 1736 | + changed = true; |
| 1737 | + break; |
| 1738 | + } |
| 1739 | + } |
| 1740 | + if (!changed) { |
| 1741 | + GTEST_SKIP() << "No comma-radix locale available on this system."; |
| 1742 | + } |
| 1743 | + EXPECT_EQ(absl::StrCat(absl::HighPrecision(0.5)), "0.5"); |
| 1744 | + EXPECT_EQ(absl::StrCat(absl::HighPrecision(-1.25)), "-1.25"); |
| 1745 | + EXPECT_EQ(absl::StrCat(absl::HighPrecision(3.14159265358979)), |
| 1746 | + "3.14159265358979"); |
| 1747 | + double parsed = 0; |
| 1748 | + EXPECT_TRUE( |
| 1749 | + absl::SimpleAtod(absl::StrCat(absl::HighPrecision(0.1)), &parsed)); |
| 1750 | + EXPECT_EQ(parsed, 0.1); |
| 1751 | +} |
| 1752 | + |
1720 | 1753 | // Run the given runnable functor for "cases" test cases, chosen over the |
1721 | 1754 | // available range of float. pi and e and 1/e are seeded, and then all |
1722 | 1755 | // available integer powers of 2 and 10 are multiplied against them. In |
|
0 commit comments