summaryrefslogtreecommitdiff
path: root/absl/strings/numbers_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/numbers_test.cc')
-rw-r--r--absl/strings/numbers_test.cc110
1 files changed, 100 insertions, 10 deletions
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 77d7e783..68229b15 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -17,6 +17,7 @@
#include "absl/strings/numbers.h"
#include <sys/types.h>
+
#include <cfenv> // NOLINT(build/c++11)
#include <cinttypes>
#include <climits>
@@ -36,10 +37,11 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/internal/raw_logging.h"
-#include "absl/strings/str_cat.h"
-
+#include "absl/random/distributions.h"
+#include "absl/random/random.h"
#include "absl/strings/internal/numbers_test_common.h"
#include "absl/strings/internal/pow10_helper.h"
+#include "absl/strings/str_cat.h"
namespace {
@@ -204,6 +206,9 @@ void CheckHex64(uint64_t v) {
std::string actual = absl::StrCat(absl::Hex(v, absl::kZeroPad16));
snprintf(expected, sizeof(expected), "%016" PRIx64, static_cast<uint64_t>(v));
EXPECT_EQ(expected, actual) << " Input " << v;
+ actual = absl::StrCat(absl::Hex(v, absl::kSpacePad16));
+ snprintf(expected, sizeof(expected), "%16" PRIx64, static_cast<uint64_t>(v));
+ EXPECT_EQ(expected, actual) << " Input " << v;
}
TEST(Numbers, TestFastPrints) {
@@ -244,7 +249,9 @@ TEST(Numbers, TestFastPrints) {
template <typename int_type, typename in_val_type>
void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
- std::string s = absl::StrCat(in_value);
+ std::string s;
+ // uint128 can be streamed but not StrCat'd
+ absl::strings_internal::OStringStream(&s) << in_value;
int_type x = static_cast<int_type>(~exp_value);
EXPECT_TRUE(SimpleAtoi(s, &x))
<< "in_value=" << in_value << " s=" << s << " x=" << x;
@@ -320,6 +327,25 @@ TEST(NumbersTest, Atoi) {
VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint64_t>::max());
+ // SimpleAtoi(absl::string_view, absl::uint128)
+ VerifySimpleAtoiGood<absl::uint128>(0, 0);
+ VerifySimpleAtoiGood<absl::uint128>(42, 42);
+ VerifySimpleAtoiBad<absl::uint128>(-42);
+
+ VerifySimpleAtoiBad<absl::uint128>(std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int32_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint32_t>::max());
+ VerifySimpleAtoiBad<absl::uint128>(std::numeric_limits<int64_t>::min());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<int64_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<uint64_t>::max(),
+ std::numeric_limits<uint64_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(
+ std::numeric_limits<absl::uint128>::max(),
+ std::numeric_limits<absl::uint128>::max());
+
// Some other types
VerifySimpleAtoiGood<int>(-42, -42);
VerifySimpleAtoiGood<int32_t>(-42, -42);
@@ -652,6 +678,46 @@ TEST(stringtest, safe_strtou32_random) {
TEST(stringtest, safe_strtou64_random) {
test_random_integer_parse_base<uint64_t>(&safe_strtou64_base);
}
+TEST(stringtest, safe_strtou128_random) {
+ // random number generators don't work for uint128, and
+ // uint128 can be streamed but not StrCat'd, so this code must be custom
+ // implemented for uint128, but is generally the same as what's above.
+ // test_random_integer_parse_base<absl::uint128>(
+ // &absl::numbers_internal::safe_strtou128_base);
+ using RandomEngine = std::minstd_rand0;
+ using IntType = absl::uint128;
+ constexpr auto parse_func = &absl::numbers_internal::safe_strtou128_base;
+
+ std::random_device rd;
+ RandomEngine rng(rd());
+ std::uniform_int_distribution<uint64_t> random_uint64(
+ std::numeric_limits<uint64_t>::min());
+ std::uniform_int_distribution<int> random_base(2, 35);
+
+ for (size_t i = 0; i < kNumRandomTests; i++) {
+ IntType value = random_uint64(rng);
+ value = (value << 64) + random_uint64(rng);
+ int base = random_base(rng);
+ std::string str_value;
+ EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+ IntType parsed_value;
+
+ // Test successful parse
+ EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+ EXPECT_EQ(parsed_value, value);
+
+ // Test overflow
+ std::string s;
+ absl::strings_internal::OStringStream(&s)
+ << std::numeric_limits<IntType>::max() << value;
+ EXPECT_FALSE(parse_func(s, &parsed_value, base));
+
+ // Test underflow
+ s.clear();
+ absl::strings_internal::OStringStream(&s) << "-" << value;
+ EXPECT_FALSE(parse_func(s, &parsed_value, base));
+ }
+}
TEST(stringtest, safe_strtou32_base) {
for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {
@@ -713,11 +779,11 @@ TEST(stringtest, safe_strtou64_base_length_delimited) {
}
}
-// feenableexcept() and fedisableexcept() are missing on macOS, MSVC,
-// and WebAssembly.
-#if defined(_MSC_VER) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
-#define ABSL_MISSING_FEENABLEEXCEPT 1
-#define ABSL_MISSING_FEDISABLEEXCEPT 1
+// feenableexcept() and fedisableexcept() are extensions supported by some libc
+// implementations.
+#if defined(__GLIBC__) || defined(__BIONIC__)
+#define ABSL_HAVE_FEENABLEEXCEPT 1
+#define ABSL_HAVE_FEDISABLEEXCEPT 1
#endif
class SimpleDtoaTest : public testing::Test {
@@ -725,7 +791,7 @@ class SimpleDtoaTest : public testing::Test {
void SetUp() override {
// Store the current floating point env & clear away any pending exceptions.
feholdexcept(&fp_env_);
-#ifndef ABSL_MISSING_FEENABLEEXCEPT
+#ifdef ABSL_HAVE_FEENABLEEXCEPT
// Turn on floating point exceptions.
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
@@ -735,7 +801,7 @@ class SimpleDtoaTest : public testing::Test {
// Restore the floating point environment to the original state.
// In theory fedisableexcept is unnecessary; fesetenv will also do it.
// In practice, our toolchains have subtle bugs.
-#ifndef ABSL_MISSING_FEDISABLEEXCEPT
+#ifdef ABSL_HAVE_FEDISABLEEXCEPT
fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
fesetenv(&fp_env_);
@@ -1184,4 +1250,28 @@ TEST(StrToUint64Base, PrefixOnly) {
}
}
+void TestFastHexToBufferZeroPad16(uint64_t v) {
+ char buf[16];
+ auto digits = absl::numbers_internal::FastHexToBufferZeroPad16(v, buf);
+ absl::string_view res(buf, 16);
+ char buf2[17];
+ snprintf(buf2, sizeof(buf2), "%016" PRIx64, v);
+ EXPECT_EQ(res, buf2) << v;
+ size_t expected_digits = snprintf(buf2, sizeof(buf2), "%" PRIx64, v);
+ EXPECT_EQ(digits, expected_digits) << v;
+}
+
+TEST(FastHexToBufferZeroPad16, Smoke) {
+ TestFastHexToBufferZeroPad16(std::numeric_limits<uint64_t>::min());
+ TestFastHexToBufferZeroPad16(std::numeric_limits<uint64_t>::max());
+ TestFastHexToBufferZeroPad16(std::numeric_limits<int64_t>::min());
+ TestFastHexToBufferZeroPad16(std::numeric_limits<int64_t>::max());
+ absl::BitGen rng;
+ for (int i = 0; i < 100000; ++i) {
+ TestFastHexToBufferZeroPad16(
+ absl::LogUniform(rng, std::numeric_limits<uint64_t>::min(),
+ std::numeric_limits<uint64_t>::max()));
+ }
+}
+
} // namespace