diff options
author | Vincent Ambo <mail@tazj.in> | 2022-02-07T23·05+0300 |
---|---|---|
committer | clbot <clbot@tvl.fyi> | 2022-02-07T23·09+0000 |
commit | 5aa5d282eac56a21e74611c1cdbaa97bb5db2dca (patch) | |
tree | 8cc5dce8157a1470ff76719dd15d65f648a05522 /third_party/abseil_cpp/absl/strings/internal/str_format/convert_test.cc | |
parent | a25675804c4f429fab5ee5201fe25e89865dfd13 (diff) |
chore(3p/abseil_cpp): unvendor abseil_cpp r/3786
we weren't actually using these sources anymore, okay? Change-Id: If701571d9716de308d3512e1eb22c35db0877a66 Reviewed-on: https://cl.tvl.fyi/c/depot/+/5248 Tested-by: BuildkiteCI Reviewed-by: grfn <grfn@gws.fyi> Autosubmit: tazjin <tazjin@tvl.su>
Diffstat (limited to 'third_party/abseil_cpp/absl/strings/internal/str_format/convert_test.cc')
-rw-r--r-- | third_party/abseil_cpp/absl/strings/internal/str_format/convert_test.cc | 1242 |
1 files changed, 0 insertions, 1242 deletions
diff --git a/third_party/abseil_cpp/absl/strings/internal/str_format/convert_test.cc b/third_party/abseil_cpp/absl/strings/internal/str_format/convert_test.cc deleted file mode 100644 index 375db0a0592c..000000000000 --- a/third_party/abseil_cpp/absl/strings/internal/str_format/convert_test.cc +++ /dev/null @@ -1,1242 +0,0 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include <errno.h> -#include <stdarg.h> -#include <stdio.h> - -#include <cctype> -#include <cmath> -#include <limits> -#include <string> -#include <thread> // NOLINT - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/strings/internal/str_format/bind.h" -#include "absl/strings/match.h" -#include "absl/types/optional.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace str_format_internal { -namespace { - -struct NativePrintfTraits { - bool hex_float_has_glibc_rounding; - bool hex_float_prefers_denormal_repr; - bool hex_float_uses_minimal_precision_when_not_specified; - bool hex_float_optimizes_leading_digit_bit_count; -}; - -template <typename T, size_t N> -size_t ArraySize(T (&)[N]) { - return N; -} - -std::string LengthModFor(float) { return ""; } -std::string LengthModFor(double) { return ""; } -std::string LengthModFor(long double) { return "L"; } -std::string LengthModFor(char) { return "hh"; } -std::string LengthModFor(signed char) { return "hh"; } -std::string LengthModFor(unsigned char) { return "hh"; } -std::string LengthModFor(short) { return "h"; } // NOLINT -std::string LengthModFor(unsigned short) { return "h"; } // NOLINT -std::string LengthModFor(int) { return ""; } -std::string LengthModFor(unsigned) { return ""; } -std::string LengthModFor(long) { return "l"; } // NOLINT -std::string LengthModFor(unsigned long) { return "l"; } // NOLINT -std::string LengthModFor(long long) { return "ll"; } // NOLINT -std::string LengthModFor(unsigned long long) { return "ll"; } // NOLINT - -std::string EscCharImpl(int v) { - if (std::isprint(static_cast<unsigned char>(v))) { - return std::string(1, static_cast<char>(v)); - } - char buf[64]; - int n = snprintf(buf, sizeof(buf), "\\%#.2x", - static_cast<unsigned>(v & 0xff)); - assert(n > 0 && n < sizeof(buf)); - return std::string(buf, n); -} - -std::string Esc(char v) { return EscCharImpl(v); } -std::string Esc(signed char v) { return EscCharImpl(v); } -std::string Esc(unsigned char v) { return EscCharImpl(v); } - -template <typename T> -std::string Esc(const T &v) { - std::ostringstream oss; - oss << v; - return oss.str(); -} - -void StrAppendV(std::string *dst, const char *format, va_list ap) { - // First try with a small fixed size buffer - static const int kSpaceLength = 1024; - char space[kSpaceLength]; - - // It's possible for methods that use a va_list to invalidate - // the data in it upon use. The fix is to make a copy - // of the structure before using it and use that copy instead. - va_list backup_ap; - va_copy(backup_ap, ap); - int result = vsnprintf(space, kSpaceLength, format, backup_ap); - va_end(backup_ap); - if (result < kSpaceLength) { - if (result >= 0) { - // Normal case -- everything fit. - dst->append(space, result); - return; - } - if (result < 0) { - // Just an error. - return; - } - } - - // Increase the buffer size to the size requested by vsnprintf, - // plus one for the closing \0. - int length = result + 1; - char *buf = new char[length]; - - // Restore the va_list before we use it again - va_copy(backup_ap, ap); - result = vsnprintf(buf, length, format, backup_ap); - va_end(backup_ap); - - if (result >= 0 && result < length) { - // It fit - dst->append(buf, result); - } - delete[] buf; -} - -void StrAppend(std::string *out, const char *format, ...) { - va_list ap; - va_start(ap, format); - StrAppendV(out, format, ap); - va_end(ap); -} - -std::string StrPrint(const char *format, ...) { - va_list ap; - va_start(ap, format); - std::string result; - StrAppendV(&result, format, ap); - va_end(ap); - return result; -} - -NativePrintfTraits VerifyNativeImplementationImpl() { - NativePrintfTraits result; - - // >>> hex_float_has_glibc_rounding. To have glibc's rounding behavior we need - // to meet three requirements: - // - // - The threshold for rounding up is 8 (for e.g. MSVC uses 9). - // - If the digits lower than than the 8 are non-zero then we round up. - // - If the digits lower than the 8 are all zero then we round toward even. - // - // The numbers below represent all the cases covering {below,at,above} the - // threshold (8) with both {zero,non-zero} lower bits and both {even,odd} - // preceding digits. - const double d0079 = 65657.0; // 0x1.0079p+16 - const double d0179 = 65913.0; // 0x1.0179p+16 - const double d0080 = 65664.0; // 0x1.0080p+16 - const double d0180 = 65920.0; // 0x1.0180p+16 - const double d0081 = 65665.0; // 0x1.0081p+16 - const double d0181 = 65921.0; // 0x1.0181p+16 - result.hex_float_has_glibc_rounding = - StartsWith(StrPrint("%.2a", d0079), "0x1.00") && - StartsWith(StrPrint("%.2a", d0179), "0x1.01") && - StartsWith(StrPrint("%.2a", d0080), "0x1.00") && - StartsWith(StrPrint("%.2a", d0180), "0x1.02") && - StartsWith(StrPrint("%.2a", d0081), "0x1.01") && - StartsWith(StrPrint("%.2a", d0181), "0x1.02"); - - // >>> hex_float_prefers_denormal_repr. Formatting `denormal` on glibc yields - // "0x0.0000000000001p-1022", whereas on std libs that don't use denormal - // representation it would either be 0x1p-1074 or 0x1.0000000000000-1074. - const double denormal = std::numeric_limits<double>::denorm_min(); - result.hex_float_prefers_denormal_repr = - StartsWith(StrPrint("%a", denormal), "0x0.0000000000001"); - - // >>> hex_float_uses_minimal_precision_when_not_specified. Some (non-glibc) - // libs will format the following as "0x1.0079000000000p+16". - result.hex_float_uses_minimal_precision_when_not_specified = - (StrPrint("%a", d0079) == "0x1.0079p+16"); - - // >>> hex_float_optimizes_leading_digit_bit_count. The number 1.5, when - // formatted by glibc should yield "0x1.8p+0" for `double` and "0xcp-3" for - // `long double`, i.e., number of bits in the leading digit is adapted to the - // number of bits in the mantissa. - const double d_15 = 1.5; - const long double ld_15 = 1.5; - result.hex_float_optimizes_leading_digit_bit_count = - StartsWith(StrPrint("%a", d_15), "0x1.8") && - StartsWith(StrPrint("%La", ld_15), "0xc"); - - return result; -} - -const NativePrintfTraits &VerifyNativeImplementation() { - static NativePrintfTraits native_traits = VerifyNativeImplementationImpl(); - return native_traits; -} - -class FormatConvertTest : public ::testing::Test { }; - -template <typename T> -void TestStringConvert(const T& str) { - const FormatArgImpl args[] = {FormatArgImpl(str)}; - struct Expectation { - const char *out; - const char *fmt; - }; - const Expectation kExpect[] = { - {"hello", "%1$s" }, - {"", "%1$.s" }, - {"", "%1$.0s" }, - {"h", "%1$.1s" }, - {"he", "%1$.2s" }, - {"hello", "%1$.10s" }, - {" hello", "%1$6s" }, - {" he", "%1$5.2s" }, - {"he ", "%1$-5.2s" }, - {"hello ", "%1$-6.10s" }, - }; - for (const Expectation &e : kExpect) { - UntypedFormatSpecImpl format(e.fmt); - EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))); - } -} - -TEST_F(FormatConvertTest, BasicString) { - TestStringConvert("hello"); // As char array. - TestStringConvert(static_cast<const char*>("hello")); - TestStringConvert(std::string("hello")); - TestStringConvert(string_view("hello")); -} - -TEST_F(FormatConvertTest, NullString) { - const char* p = nullptr; - UntypedFormatSpecImpl format("%s"); - EXPECT_EQ("", FormatPack(format, {FormatArgImpl(p)})); -} - -TEST_F(FormatConvertTest, StringPrecision) { - // We cap at the precision. - char c = 'a'; - const char* p = &c; - UntypedFormatSpecImpl format("%.1s"); - EXPECT_EQ("a", FormatPack(format, {FormatArgImpl(p)})); - - // We cap at the NUL-terminator. - p = "ABC"; - UntypedFormatSpecImpl format2("%.10s"); - EXPECT_EQ("ABC", FormatPack(format2, {FormatArgImpl(p)})); -} - -// Pointer formatting is implementation defined. This checks that the argument -// can be matched to `ptr`. -MATCHER_P(MatchesPointerString, ptr, "") { - if (ptr == nullptr && arg == "(nil)") { - return true; - } - void* parsed = nullptr; - if (sscanf(arg.c_str(), "%p", &parsed) != 1) { - ABSL_RAW_LOG(FATAL, "Could not parse %s", arg.c_str()); - } - return ptr == parsed; -} - -TEST_F(FormatConvertTest, Pointer) { - static int x = 0; - const int *xp = &x; - char c = 'h'; - char *mcp = &c; - const char *cp = "hi"; - const char *cnil = nullptr; - const int *inil = nullptr; - using VoidF = void (*)(); - VoidF fp = [] {}, fnil = nullptr; - volatile char vc; - volatile char *vcp = &vc; - volatile char *vcnil = nullptr; - const FormatArgImpl args_array[] = { - FormatArgImpl(xp), FormatArgImpl(cp), FormatArgImpl(inil), - FormatArgImpl(cnil), FormatArgImpl(mcp), FormatArgImpl(fp), - FormatArgImpl(fnil), FormatArgImpl(vcp), FormatArgImpl(vcnil), - }; - auto args = absl::MakeConstSpan(args_array); - - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%p"), args), - MatchesPointerString(&x)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%20p"), args), - MatchesPointerString(&x)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.1p"), args), - MatchesPointerString(&x)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args), - MatchesPointerString(&x)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%30.20p"), args), - MatchesPointerString(&x)); - - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-p"), args), - MatchesPointerString(&x)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-20p"), args), - MatchesPointerString(&x)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-.1p"), args), - MatchesPointerString(&x)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args), - MatchesPointerString(&x)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-30.20p"), args), - MatchesPointerString(&x)); - - // const char* - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%2$p"), args), - MatchesPointerString(cp)); - // null const int* - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%3$p"), args), - MatchesPointerString(nullptr)); - // null const char* - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%4$p"), args), - MatchesPointerString(nullptr)); - // nonconst char* - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%5$p"), args), - MatchesPointerString(mcp)); - - // function pointers - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%6$p"), args), - MatchesPointerString(reinterpret_cast<const void*>(fp))); - EXPECT_THAT( - FormatPack(UntypedFormatSpecImpl("%8$p"), args), - MatchesPointerString(reinterpret_cast<volatile const void *>(vcp))); - - // null function pointers - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%7$p"), args), - MatchesPointerString(nullptr)); - EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%9$p"), args), - MatchesPointerString(nullptr)); -} - -struct Cardinal { - enum Pos { k1 = 1, k2 = 2, k3 = 3 }; - enum Neg { kM1 = -1, kM2 = -2, kM3 = -3 }; -}; - -TEST_F(FormatConvertTest, Enum) { - const Cardinal::Pos k3 = Cardinal::k3; - const Cardinal::Neg km3 = Cardinal::kM3; - const FormatArgImpl args[] = {FormatArgImpl(k3), FormatArgImpl(km3)}; - UntypedFormatSpecImpl format("%1$d"); - UntypedFormatSpecImpl format2("%2$d"); - EXPECT_EQ("3", FormatPack(format, absl::MakeSpan(args))); - EXPECT_EQ("-3", FormatPack(format2, absl::MakeSpan(args))); -} - -template <typename T> -class TypedFormatConvertTest : public FormatConvertTest { }; - -TYPED_TEST_SUITE_P(TypedFormatConvertTest); - -std::vector<std::string> AllFlagCombinations() { - const char kFlags[] = {'-', '#', '0', '+', ' '}; - std::vector<std::string> result; - for (size_t fsi = 0; fsi < (1ull << ArraySize(kFlags)); ++fsi) { - std::string flag_set; - for (size_t fi = 0; fi < ArraySize(kFlags); ++fi) - if (fsi & (1ull << fi)) - flag_set += kFlags[fi]; - result.push_back(flag_set); - } - return result; -} - -TYPED_TEST_P(TypedFormatConvertTest, AllIntsWithFlags) { - typedef TypeParam T; - typedef typename std::make_unsigned<T>::type UnsignedT; - using remove_volatile_t = typename std::remove_volatile<T>::type; - const T kMin = std::numeric_limits<remove_volatile_t>::min(); - const T kMax = std::numeric_limits<remove_volatile_t>::max(); - const T kVals[] = { - remove_volatile_t(1), - remove_volatile_t(2), - remove_volatile_t(3), - remove_volatile_t(123), - remove_volatile_t(-1), - remove_volatile_t(-2), - remove_volatile_t(-3), - remove_volatile_t(-123), - remove_volatile_t(0), - kMax - remove_volatile_t(1), - kMax, - kMin + remove_volatile_t(1), - kMin, - }; - const char kConvChars[] = {'d', 'i', 'u', 'o', 'x', 'X'}; - const std::string kWid[] = {"", "4", "10"}; - const std::string kPrec[] = {"", ".", ".0", ".4", ".10"}; - - const std::vector<std::string> flag_sets = AllFlagCombinations(); - - for (size_t vi = 0; vi < ArraySize(kVals); ++vi) { - const T val = kVals[vi]; - SCOPED_TRACE(Esc(val)); - const FormatArgImpl args[] = {FormatArgImpl(val)}; - for (size_t ci = 0; ci < ArraySize(kConvChars); ++ci) { - const char conv_char = kConvChars[ci]; - for (size_t fsi = 0; fsi < flag_sets.size(); ++fsi) { - const std::string &flag_set = flag_sets[fsi]; - for (size_t wi = 0; wi < ArraySize(kWid); ++wi) { - const std::string &wid = kWid[wi]; - for (size_t pi = 0; pi < ArraySize(kPrec); ++pi) { - const std::string &prec = kPrec[pi]; - - const bool is_signed_conv = (conv_char == 'd' || conv_char == 'i'); - const bool is_unsigned_to_signed = - !std::is_signed<T>::value && is_signed_conv; - // Don't consider sign-related flags '+' and ' ' when doing - // unsigned to signed conversions. - if (is_unsigned_to_signed && - flag_set.find_first_of("+ ") != std::string::npos) { - continue; - } - - std::string new_fmt("%"); - new_fmt += flag_set; - new_fmt += wid; - new_fmt += prec; - // old and new always agree up to here. - std::string old_fmt = new_fmt; - new_fmt += conv_char; - std::string old_result; - if (is_unsigned_to_signed) { - // don't expect agreement on unsigned formatted as signed, - // as printf can't do that conversion properly. For those - // cases, we do expect agreement with printf with a "%u" - // and the unsigned equivalent of 'val'. - UnsignedT uval = val; - old_fmt += LengthModFor(uval); - old_fmt += "u"; - old_result = StrPrint(old_fmt.c_str(), uval); - } else { - old_fmt += LengthModFor(val); - old_fmt += conv_char; - old_result = StrPrint(old_fmt.c_str(), val); - } - - SCOPED_TRACE(std::string() + " old_fmt: \"" + old_fmt + - "\"'" - " new_fmt: \"" + - new_fmt + "\""); - UntypedFormatSpecImpl format(new_fmt); - EXPECT_EQ(old_result, FormatPack(format, absl::MakeSpan(args))); - } - } - } - } - } -} - -TYPED_TEST_P(TypedFormatConvertTest, Char) { - typedef TypeParam T; - using remove_volatile_t = typename std::remove_volatile<T>::type; - static const T kMin = std::numeric_limits<remove_volatile_t>::min(); - static const T kMax = std::numeric_limits<remove_volatile_t>::max(); - T kVals[] = { - remove_volatile_t(1), remove_volatile_t(2), remove_volatile_t(10), - remove_volatile_t(-1), remove_volatile_t(-2), remove_volatile_t(-10), - remove_volatile_t(0), - kMin + remove_volatile_t(1), kMin, - kMax - remove_volatile_t(1), kMax - }; - for (const T &c : kVals) { - const FormatArgImpl args[] = {FormatArgImpl(c)}; - UntypedFormatSpecImpl format("%c"); - EXPECT_EQ(StrPrint("%c", c), FormatPack(format, absl::MakeSpan(args))); - } -} - -REGISTER_TYPED_TEST_CASE_P(TypedFormatConvertTest, AllIntsWithFlags, Char); - -typedef ::testing::Types< - int, unsigned, volatile int, - short, unsigned short, - long, unsigned long, - long long, unsigned long long, - signed char, unsigned char, char> - AllIntTypes; -INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes, - TypedFormatConvertTest, AllIntTypes); -TEST_F(FormatConvertTest, VectorBool) { - // Make sure vector<bool>'s values behave as bools. - std::vector<bool> v = {true, false}; - const std::vector<bool> cv = {true, false}; - EXPECT_EQ("1,0,1,0", - FormatPack(UntypedFormatSpecImpl("%d,%d,%d,%d"), - absl::Span<const FormatArgImpl>( - {FormatArgImpl(v[0]), FormatArgImpl(v[1]), - FormatArgImpl(cv[0]), FormatArgImpl(cv[1])}))); -} - - -TEST_F(FormatConvertTest, Int128) { - absl::int128 positive = static_cast<absl::int128>(0x1234567890abcdef) * 1979; - absl::int128 negative = -positive; - absl::int128 max = absl::Int128Max(), min = absl::Int128Min(); - const FormatArgImpl args[] = {FormatArgImpl(positive), - FormatArgImpl(negative), FormatArgImpl(max), - FormatArgImpl(min)}; - - struct Case { - const char* format; - const char* expected; - } cases[] = { - {"%1$d", "2595989796776606496405"}, - {"%1$30d", " 2595989796776606496405"}, - {"%1$-30d", "2595989796776606496405 "}, - {"%1$u", "2595989796776606496405"}, - {"%1$x", "8cba9876066020f695"}, - {"%2$d", "-2595989796776606496405"}, - {"%2$30d", " -2595989796776606496405"}, - {"%2$-30d", "-2595989796776606496405 "}, - {"%2$u", "340282366920938460867384810655161715051"}, - {"%2$x", "ffffffffffffff73456789f99fdf096b"}, - {"%3$d", "170141183460469231731687303715884105727"}, - {"%3$u", "170141183460469231731687303715884105727"}, - {"%3$x", "7fffffffffffffffffffffffffffffff"}, - {"%4$d", "-170141183460469231731687303715884105728"}, - {"%4$x", "80000000000000000000000000000000"}, - }; - - for (auto c : cases) { - UntypedFormatSpecImpl format(c.format); - EXPECT_EQ(c.expected, FormatPack(format, absl::MakeSpan(args))); - } -} - -TEST_F(FormatConvertTest, Uint128) { - absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979; - absl::uint128 max = absl::Uint128Max(); - const FormatArgImpl args[] = {FormatArgImpl(v), FormatArgImpl(max)}; - - struct Case { - const char* format; - const char* expected; - } cases[] = { - {"%1$d", "2595989796776606496405"}, - {"%1$30d", " 2595989796776606496405"}, - {"%1$-30d", "2595989796776606496405 "}, - {"%1$u", "2595989796776606496405"}, - {"%1$x", "8cba9876066020f695"}, - {"%2$d", "340282366920938463463374607431768211455"}, - {"%2$u", "340282366920938463463374607431768211455"}, - {"%2$x", "ffffffffffffffffffffffffffffffff"}, - }; - - for (auto c : cases) { - UntypedFormatSpecImpl format(c.format); - EXPECT_EQ(c.expected, FormatPack(format, absl::MakeSpan(args))); - } -} - -template <typename Floating> -void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats) { - const NativePrintfTraits &native_traits = VerifyNativeImplementation(); - // Reserve the space to ensure we don't allocate memory in the output itself. - std::string str_format_result; - str_format_result.reserve(1 << 20); - std::string string_printf_result; - string_printf_result.reserve(1 << 20); - - const char *const kFormats[] = { - "%", "%.3", "%8.5", "%500", "%.5000", "%.60", "%.30", "%03", - "%+", "% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"}; - - for (const char *fmt : kFormats) { - for (char f : {'f', 'F', // - 'g', 'G', // - 'a', 'A', // - 'e', 'E'}) { - std::string fmt_str = std::string(fmt) + f; - - if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' && - f != 'a' && f != 'A') { - // This particular test takes way too long with snprintf. - // Disable for the case we are not implementing natively. - continue; - } - - if ((f == 'a' || f == 'A') && - !native_traits.hex_float_has_glibc_rounding) { - continue; - } - - for (Floating d : floats) { - if (!native_traits.hex_float_prefers_denormal_repr && - (f == 'a' || f == 'A') && std::fpclassify(d) == FP_SUBNORMAL) { - continue; - } - int i = -10; - FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)}; - UntypedFormatSpecImpl format(fmt_str); - - string_printf_result.clear(); - StrAppend(&string_printf_result, fmt_str.c_str(), d, i); - str_format_result.clear(); - - { - AppendPack(&str_format_result, format, absl::MakeSpan(args)); - } - - if (string_printf_result != str_format_result) { - // We use ASSERT_EQ here because failures are usually correlated and a - // bug would print way too many failed expectations causing the test - // to time out. - ASSERT_EQ(string_printf_result, str_format_result) - << fmt_str << " " << StrPrint("%.18g", d) << " " - << StrPrint("%a", d) << " " << StrPrint("%.50f", d); - } - } - } - } -} - -TEST_F(FormatConvertTest, Float) { -#ifdef _MSC_VER - // MSVC has a different rounding policy than us so we can't test our - // implementation against the native one there. - return; -#endif // _MSC_VER - - std::vector<float> floats = {0.0f, - -0.0f, - .9999999f, - 9999999.f, - std::numeric_limits<float>::max(), - -std::numeric_limits<float>::max(), - std::numeric_limits<float>::min(), - -std::numeric_limits<float>::min(), - std::numeric_limits<float>::lowest(), - -std::numeric_limits<float>::lowest(), - std::numeric_limits<float>::epsilon(), - std::numeric_limits<float>::epsilon() + 1.0f, - std::numeric_limits<float>::infinity(), - -std::numeric_limits<float>::infinity()}; - - // Some regression tests. - floats.push_back(0.999999989f); - - if (std::numeric_limits<float>::has_denorm != std::denorm_absent) { - floats.push_back(std::numeric_limits<float>::denorm_min()); - floats.push_back(-std::numeric_limits<float>::denorm_min()); - } - - for (float base : - {1.f, 12.f, 123.f, 1234.f, 12345.f, 123456.f, 1234567.f, 12345678.f, - 123456789.f, 1234567890.f, 12345678901.f, 12345678.f, 12345678.f}) { - for (int exp = -123; exp <= 123; ++exp) { - for (int sign : {1, -1}) { - floats.push_back(sign * std::ldexp(base, exp)); - } - } - } - - for (int exp = -300; exp <= 300; ++exp) { - const float all_ones_mantissa = 0xffffff; - floats.push_back(std::ldexp(all_ones_mantissa, exp)); - } - - // Remove duplicates to speed up the logic below. - std::sort(floats.begin(), floats.end()); - floats.erase(std::unique(floats.begin(), floats.end()), floats.end()); - -#ifndef __APPLE__ - // Apple formats NaN differently (+nan) vs. (nan) - floats.push_back(std::nan("")); -#endif - - TestWithMultipleFormatsHelper(floats); -} - -TEST_F(FormatConvertTest, Double) { -#ifdef _MSC_VER - // MSVC has a different rounding policy than us so we can't test our - // implementation against the native one there. - return; -#endif // _MSC_VER - - std::vector<double> doubles = {0.0, - -0.0, - .99999999999999, - 99999999999999., - std::numeric_limits<double>::max(), - -std::numeric_limits<double>::max(), - std::numeric_limits<double>::min(), - -std::numeric_limits<double>::min(), - std::numeric_limits<double>::lowest(), - -std::numeric_limits<double>::lowest(), - std::numeric_limits<double>::epsilon(), - std::numeric_limits<double>::epsilon() + 1, - std::numeric_limits<double>::infinity(), - -std::numeric_limits<double>::infinity()}; - - // Some regression tests. - doubles.push_back(0.99999999999999989); - - if (std::numeric_limits<double>::has_denorm != std::denorm_absent) { - doubles.push_back(std::numeric_limits<double>::denorm_min()); - doubles.push_back(-std::numeric_limits<double>::denorm_min()); - } - - for (double base : - {1., 12., 123., 1234., 12345., 123456., 1234567., 12345678., 123456789., - 1234567890., 12345678901., 123456789012., 1234567890123.}) { - for (int exp = -123; exp <= 123; ++exp) { - for (int sign : {1, -1}) { - doubles.push_back(sign * std::ldexp(base, exp)); - } - } - } - - // Workaround libc bug. - // https://sourceware.org/bugzilla/show_bug.cgi?id=22142 - const bool gcc_bug_22142 = - StrPrint("%f", std::numeric_limits<double>::max()) != - "1797693134862315708145274237317043567980705675258449965989174768031" - "5726078002853876058955863276687817154045895351438246423432132688946" - "4182768467546703537516986049910576551282076245490090389328944075868" - "5084551339423045832369032229481658085593321233482747978262041447231" - "68738177180919299881250404026184124858368.000000"; - - if (!gcc_bug_22142) { - for (int exp = -300; exp <= 300; ++exp) { - const double all_ones_mantissa = 0x1fffffffffffff; - doubles.push_back(std::ldexp(all_ones_mantissa, exp)); - } - } - - if (gcc_bug_22142) { - for (auto &d : doubles) { - using L = std::numeric_limits<double>; - double d2 = std::abs(d); - if (d2 == L::max() || d2 == L::min() || d2 == L::denorm_min()) { - d = 0; - } - } - } - - // Remove duplicates to speed up the logic below. - std::sort(doubles.begin(), doubles.end()); - doubles.erase(std::unique(doubles.begin(), doubles.end()), doubles.end()); - -#ifndef __APPLE__ - // Apple formats NaN differently (+nan) vs. (nan) - doubles.push_back(std::nan("")); -#endif - - TestWithMultipleFormatsHelper(doubles); -} - -TEST_F(FormatConvertTest, DoubleRound) { - std::string s; - const auto format = [&](const char *fmt, double d) -> std::string & { - s.clear(); - FormatArgImpl args[1] = {FormatArgImpl(d)}; - AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args)); -#if !defined(_MSC_VER) - // MSVC has a different rounding policy than us so we can't test our - // implementation against the native one there. - EXPECT_EQ(StrPrint(fmt, d), s); -#endif // _MSC_VER - - return s; - }; - // All of these values have to be exactly represented. - // Otherwise we might not be testing what we think we are testing. - - // These values can fit in a 64bit "fast" representation. - const double exact_value = 0.00000000000005684341886080801486968994140625; - assert(exact_value == std::pow(2, -44)); - // Round up at a 5xx. - EXPECT_EQ(format("%.13f", exact_value), "0.0000000000001"); - // Round up at a >5 - EXPECT_EQ(format("%.14f", exact_value), "0.00000000000006"); - // Round down at a <5 - EXPECT_EQ(format("%.16f", exact_value), "0.0000000000000568"); - // Nine handling - EXPECT_EQ(format("%.35f", exact_value), - "0.00000000000005684341886080801486969"); - EXPECT_EQ(format("%.36f", exact_value), - "0.000000000000056843418860808014869690"); - // Round down the last nine. - EXPECT_EQ(format("%.37f", exact_value), - "0.0000000000000568434188608080148696899"); - EXPECT_EQ(format("%.10f", 0.000003814697265625), "0.0000038147"); - // Round up the last nine - EXPECT_EQ(format("%.11f", 0.000003814697265625), "0.00000381470"); - EXPECT_EQ(format("%.12f", 0.000003814697265625), "0.000003814697"); - - // Round to even (down) - EXPECT_EQ(format("%.43f", exact_value), - "0.0000000000000568434188608080148696899414062"); - // Exact - EXPECT_EQ(format("%.44f", exact_value), - "0.00000000000005684341886080801486968994140625"); - // Round to even (up), let make the last digits 75 instead of 25 - EXPECT_EQ(format("%.43f", exact_value + std::pow(2, -43)), - "0.0000000000001705302565824240446090698242188"); - // Exact, just to check. - EXPECT_EQ(format("%.44f", exact_value + std::pow(2, -43)), - "0.00000000000017053025658242404460906982421875"); - - // This value has to be small enough that it won't fit in the uint128 - // representation for printing. - const double small_exact_value = - 0.000000000000000000000000000000000000752316384526264005099991383822237233803945956334136013765601092018187046051025390625; // NOLINT - assert(small_exact_value == std::pow(2, -120)); - // Round up at a 5xx. - EXPECT_EQ(format("%.37f", small_exact_value), - "0.0000000000000000000000000000000000008"); - // Round down at a <5 - EXPECT_EQ(format("%.38f", small_exact_value), - "0.00000000000000000000000000000000000075"); - // Round up at a >5 - EXPECT_EQ(format("%.41f", small_exact_value), - "0.00000000000000000000000000000000000075232"); - // Nine handling - EXPECT_EQ(format("%.55f", small_exact_value), - "0.0000000000000000000000000000000000007523163845262640051"); - EXPECT_EQ(format("%.56f", small_exact_value), - "0.00000000000000000000000000000000000075231638452626400510"); - EXPECT_EQ(format("%.57f", small_exact_value), - "0.000000000000000000000000000000000000752316384526264005100"); - EXPECT_EQ(format("%.58f", small_exact_value), - "0.0000000000000000000000000000000000007523163845262640051000"); - // Round down the last nine - EXPECT_EQ(format("%.59f", small_exact_value), - "0.00000000000000000000000000000000000075231638452626400509999"); - // Round up the last nine - EXPECT_EQ(format("%.79f", small_exact_value), - "0.000000000000000000000000000000000000" - "7523163845262640050999913838222372338039460"); - - // Round to even (down) - EXPECT_EQ(format("%.119f", small_exact_value), - "0.000000000000000000000000000000000000" - "75231638452626400509999138382223723380" - "394595633413601376560109201818704605102539062"); - // Exact - EXPECT_EQ(format("%.120f", small_exact_value), - "0.000000000000000000000000000000000000" - "75231638452626400509999138382223723380" - "3945956334136013765601092018187046051025390625"); - // Round to even (up), let make the last digits 75 instead of 25 - EXPECT_EQ(format("%.119f", small_exact_value + std::pow(2, -119)), - "0.000000000000000000000000000000000002" - "25694915357879201529997415146671170141" - "183786900240804129680327605456113815307617188"); - // Exact, just to check. - EXPECT_EQ(format("%.120f", small_exact_value + std::pow(2, -119)), - "0.000000000000000000000000000000000002" - "25694915357879201529997415146671170141" - "1837869002408041296803276054561138153076171875"); -} - -TEST_F(FormatConvertTest, DoubleRoundA) { - const NativePrintfTraits &native_traits = VerifyNativeImplementation(); - std::string s; - const auto format = [&](const char *fmt, double d) -> std::string & { - s.clear(); - FormatArgImpl args[1] = {FormatArgImpl(d)}; - AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args)); - if (native_traits.hex_float_has_glibc_rounding) { - EXPECT_EQ(StrPrint(fmt, d), s); - } - return s; - }; - - // 0x1.00018000p+100 - const double on_boundary_odd = 1267679614447900152596896153600.0; - EXPECT_EQ(format("%.0a", on_boundary_odd), "0x1p+100"); - EXPECT_EQ(format("%.1a", on_boundary_odd), "0x1.0p+100"); - EXPECT_EQ(format("%.2a", on_boundary_odd), "0x1.00p+100"); - EXPECT_EQ(format("%.3a", on_boundary_odd), "0x1.000p+100"); - EXPECT_EQ(format("%.4a", on_boundary_odd), "0x1.0002p+100"); // round - EXPECT_EQ(format("%.5a", on_boundary_odd), "0x1.00018p+100"); - EXPECT_EQ(format("%.6a", on_boundary_odd), "0x1.000180p+100"); - - // 0x1.00028000p-2 - const double on_boundary_even = 0.250009536743164062500; - EXPECT_EQ(format("%.0a", on_boundary_even), "0x1p-2"); - EXPECT_EQ(format("%.1a", on_boundary_even), "0x1.0p-2"); - EXPECT_EQ(format("%.2a", on_boundary_even), "0x1.00p-2"); - EXPECT_EQ(format("%.3a", on_boundary_even), "0x1.000p-2"); - EXPECT_EQ(format("%.4a", on_boundary_even), "0x1.0002p-2"); // no round - EXPECT_EQ(format("%.5a", on_boundary_even), "0x1.00028p-2"); - EXPECT_EQ(format("%.6a", on_boundary_even), "0x1.000280p-2"); - - // 0x1.00018001p+1 - const double slightly_over = 2.00004577683284878730773925781250; - EXPECT_EQ(format("%.0a", slightly_over), "0x1p+1"); - EXPECT_EQ(format("%.1a", slightly_over), "0x1.0p+1"); - EXPECT_EQ(format("%.2a", slightly_over), "0x1.00p+1"); - EXPECT_EQ(format("%.3a", slightly_over), "0x1.000p+1"); - EXPECT_EQ(format("%.4a", slightly_over), "0x1.0002p+1"); - EXPECT_EQ(format("%.5a", slightly_over), "0x1.00018p+1"); - EXPECT_EQ(format("%.6a", slightly_over), "0x1.000180p+1"); - - // 0x1.00017fffp+0 - const double slightly_under = 1.000022887950763106346130371093750; - EXPECT_EQ(format("%.0a", slightly_under), "0x1p+0"); - EXPECT_EQ(format("%.1a", slightly_under), "0x1.0p+0"); - EXPECT_EQ(format("%.2a", slightly_under), "0x1.00p+0"); - EXPECT_EQ(format("%.3a", slightly_under), "0x1.000p+0"); - EXPECT_EQ(format("%.4a", slightly_under), "0x1.0001p+0"); - EXPECT_EQ(format("%.5a", slightly_under), "0x1.00018p+0"); - EXPECT_EQ(format("%.6a", slightly_under), "0x1.000180p+0"); - EXPECT_EQ(format("%.7a", slightly_under), "0x1.0001800p+0"); - - // 0x1.1b3829ac28058p+3 - const double hex_value = 8.85060580848964661981881363317370414733886718750; - EXPECT_EQ(format("%.0a", hex_value), "0x1p+3"); - EXPECT_EQ(format("%.1a", hex_value), "0x1.2p+3"); - EXPECT_EQ(format("%.2a", hex_value), "0x1.1bp+3"); - EXPECT_EQ(format("%.3a", hex_value), "0x1.1b4p+3"); - EXPECT_EQ(format("%.4a", hex_value), "0x1.1b38p+3"); - EXPECT_EQ(format("%.5a", hex_value), "0x1.1b383p+3"); - EXPECT_EQ(format("%.6a", hex_value), "0x1.1b382ap+3"); - EXPECT_EQ(format("%.7a", hex_value), "0x1.1b3829bp+3"); - EXPECT_EQ(format("%.8a", hex_value), "0x1.1b3829acp+3"); - EXPECT_EQ(format("%.9a", hex_value), "0x1.1b3829ac3p+3"); - EXPECT_EQ(format("%.10a", hex_value), "0x1.1b3829ac28p+3"); - EXPECT_EQ(format("%.11a", hex_value), "0x1.1b3829ac280p+3"); - EXPECT_EQ(format("%.12a", hex_value), "0x1.1b3829ac2806p+3"); - EXPECT_EQ(format("%.13a", hex_value), "0x1.1b3829ac28058p+3"); - EXPECT_EQ(format("%.14a", hex_value), "0x1.1b3829ac280580p+3"); - EXPECT_EQ(format("%.15a", hex_value), "0x1.1b3829ac2805800p+3"); - EXPECT_EQ(format("%.16a", hex_value), "0x1.1b3829ac28058000p+3"); - EXPECT_EQ(format("%.17a", hex_value), "0x1.1b3829ac280580000p+3"); - EXPECT_EQ(format("%.18a", hex_value), "0x1.1b3829ac2805800000p+3"); - EXPECT_EQ(format("%.19a", hex_value), "0x1.1b3829ac28058000000p+3"); - EXPECT_EQ(format("%.20a", hex_value), "0x1.1b3829ac280580000000p+3"); - EXPECT_EQ(format("%.21a", hex_value), "0x1.1b3829ac2805800000000p+3"); - - // 0x1.0818283848586p+3 - const double hex_value2 = 8.2529488658208371987257123691961169242858886718750; - EXPECT_EQ(format("%.0a", hex_value2), "0x1p+3"); - EXPECT_EQ(format("%.1a", hex_value2), "0x1.1p+3"); - EXPECT_EQ(format("%.2a", hex_value2), "0x1.08p+3"); - EXPECT_EQ(format("%.3a", hex_value2), "0x1.082p+3"); - EXPECT_EQ(format("%.4a", hex_value2), "0x1.0818p+3"); - EXPECT_EQ(format("%.5a", hex_value2), "0x1.08183p+3"); - EXPECT_EQ(format("%.6a", hex_value2), "0x1.081828p+3"); - EXPECT_EQ(format("%.7a", hex_value2), "0x1.0818284p+3"); - EXPECT_EQ(format("%.8a", hex_value2), "0x1.08182838p+3"); - EXPECT_EQ(format("%.9a", hex_value2), "0x1.081828385p+3"); - EXPECT_EQ(format("%.10a", hex_value2), "0x1.0818283848p+3"); - EXPECT_EQ(format("%.11a", hex_value2), "0x1.08182838486p+3"); - EXPECT_EQ(format("%.12a", hex_value2), "0x1.081828384858p+3"); - EXPECT_EQ(format("%.13a", hex_value2), "0x1.0818283848586p+3"); - EXPECT_EQ(format("%.14a", hex_value2), "0x1.08182838485860p+3"); - EXPECT_EQ(format("%.15a", hex_value2), "0x1.081828384858600p+3"); - EXPECT_EQ(format("%.16a", hex_value2), "0x1.0818283848586000p+3"); - EXPECT_EQ(format("%.17a", hex_value2), "0x1.08182838485860000p+3"); - EXPECT_EQ(format("%.18a", hex_value2), "0x1.081828384858600000p+3"); - EXPECT_EQ(format("%.19a", hex_value2), "0x1.0818283848586000000p+3"); - EXPECT_EQ(format("%.20a", hex_value2), "0x1.08182838485860000000p+3"); - EXPECT_EQ(format("%.21a", hex_value2), "0x1.081828384858600000000p+3"); -} - -TEST_F(FormatConvertTest, LongDoubleRoundA) { - if (std::numeric_limits<long double>::digits % 4 != 0) { - // This test doesn't really make sense to run on platforms where a long - // double has a different mantissa size (mod 4) than Prod, since then the - // leading digit will be formatted differently. - return; - } - const NativePrintfTraits &native_traits = VerifyNativeImplementation(); - std::string s; - const auto format = [&](const char *fmt, long double d) -> std::string & { - s.clear(); - FormatArgImpl args[1] = {FormatArgImpl(d)}; - AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args)); - if (native_traits.hex_float_has_glibc_rounding && - native_traits.hex_float_optimizes_leading_digit_bit_count) { - EXPECT_EQ(StrPrint(fmt, d), s); - } - return s; - }; - - // 0x8.8p+4 - const long double on_boundary_even = 136.0; - EXPECT_EQ(format("%.0La", on_boundary_even), "0x8p+4"); - EXPECT_EQ(format("%.1La", on_boundary_even), "0x8.8p+4"); - EXPECT_EQ(format("%.2La", on_boundary_even), "0x8.80p+4"); - EXPECT_EQ(format("%.3La", on_boundary_even), "0x8.800p+4"); - EXPECT_EQ(format("%.4La", on_boundary_even), "0x8.8000p+4"); - EXPECT_EQ(format("%.5La", on_boundary_even), "0x8.80000p+4"); - EXPECT_EQ(format("%.6La", on_boundary_even), "0x8.800000p+4"); - - // 0x9.8p+4 - const long double on_boundary_odd = 152.0; - EXPECT_EQ(format("%.0La", on_boundary_odd), "0xap+4"); - EXPECT_EQ(format("%.1La", on_boundary_odd), "0x9.8p+4"); - EXPECT_EQ(format("%.2La", on_boundary_odd), "0x9.80p+4"); - EXPECT_EQ(format("%.3La", on_boundary_odd), "0x9.800p+4"); - EXPECT_EQ(format("%.4La", on_boundary_odd), "0x9.8000p+4"); - EXPECT_EQ(format("%.5La", on_boundary_odd), "0x9.80000p+4"); - EXPECT_EQ(format("%.6La", on_boundary_odd), "0x9.800000p+4"); - - // 0x8.80001p+24 - const long double slightly_over = 142606352.0; - EXPECT_EQ(format("%.0La", slightly_over), "0x9p+24"); - EXPECT_EQ(format("%.1La", slightly_over), "0x8.8p+24"); - EXPECT_EQ(format("%.2La", slightly_over), "0x8.80p+24"); - EXPECT_EQ(format("%.3La", slightly_over), "0x8.800p+24"); - EXPECT_EQ(format("%.4La", slightly_over), "0x8.8000p+24"); - EXPECT_EQ(format("%.5La", slightly_over), "0x8.80001p+24"); - EXPECT_EQ(format("%.6La", slightly_over), "0x8.800010p+24"); - - // 0x8.7ffffp+24 - const long double slightly_under = 142606320.0; - EXPECT_EQ(format("%.0La", slightly_under), "0x8p+24"); - EXPECT_EQ(format("%.1La", slightly_under), "0x8.8p+24"); - EXPECT_EQ(format("%.2La", slightly_under), "0x8.80p+24"); - EXPECT_EQ(format("%.3La", slightly_under), "0x8.800p+24"); - EXPECT_EQ(format("%.4La", slightly_under), "0x8.8000p+24"); - EXPECT_EQ(format("%.5La", slightly_under), "0x8.7ffffp+24"); - EXPECT_EQ(format("%.6La", slightly_under), "0x8.7ffff0p+24"); - EXPECT_EQ(format("%.7La", slightly_under), "0x8.7ffff00p+24"); - - // 0xc.0828384858688000p+128 - const long double eights = 4094231060438608800781871108094404067328.0; - EXPECT_EQ(format("%.0La", eights), "0xcp+128"); - EXPECT_EQ(format("%.1La", eights), "0xc.1p+128"); - EXPECT_EQ(format("%.2La", eights), "0xc.08p+128"); - EXPECT_EQ(format("%.3La", eights), "0xc.083p+128"); - EXPECT_EQ(format("%.4La", eights), "0xc.0828p+128"); - EXPECT_EQ(format("%.5La", eights), "0xc.08284p+128"); - EXPECT_EQ(format("%.6La", eights), "0xc.082838p+128"); - EXPECT_EQ(format("%.7La", eights), "0xc.0828385p+128"); - EXPECT_EQ(format("%.8La", eights), "0xc.08283848p+128"); - EXPECT_EQ(format("%.9La", eights), "0xc.082838486p+128"); - EXPECT_EQ(format("%.10La", eights), "0xc.0828384858p+128"); - EXPECT_EQ(format("%.11La", eights), "0xc.08283848587p+128"); - EXPECT_EQ(format("%.12La", eights), "0xc.082838485868p+128"); - EXPECT_EQ(format("%.13La", eights), "0xc.0828384858688p+128"); - EXPECT_EQ(format("%.14La", eights), "0xc.08283848586880p+128"); - EXPECT_EQ(format("%.15La", eights), "0xc.082838485868800p+128"); - EXPECT_EQ(format("%.16La", eights), "0xc.0828384858688000p+128"); -} - -// We don't actually store the results. This is just to exercise the rest of the -// machinery. -struct NullSink { - friend void AbslFormatFlush(NullSink *sink, string_view str) {} -}; - -template <typename... T> -bool FormatWithNullSink(absl::string_view fmt, const T &... a) { - NullSink sink; - FormatArgImpl args[] = {FormatArgImpl(a)...}; - return FormatUntyped(&sink, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args)); -} - -TEST_F(FormatConvertTest, ExtremeWidthPrecision) { - for (const char *fmt : {"f"}) { - for (double d : {1e-100, 1.0, 1e100}) { - constexpr int max = std::numeric_limits<int>::max(); - EXPECT_TRUE(FormatWithNullSink(std::string("%.*") + fmt, max, d)); - EXPECT_TRUE(FormatWithNullSink(std::string("%1.*") + fmt, max, d)); - EXPECT_TRUE(FormatWithNullSink(std::string("%*") + fmt, max, d)); - EXPECT_TRUE(FormatWithNullSink(std::string("%*.*") + fmt, max, max, d)); - } - } -} - -TEST_F(FormatConvertTest, LongDouble) { -#ifdef _MSC_VER - // MSVC has a different rounding policy than us so we can't test our - // implementation against the native one there. - return; -#endif // _MSC_VER - const NativePrintfTraits &native_traits = VerifyNativeImplementation(); - const char *const kFormats[] = {"%", "%.3", "%8.5", "%9", "%.5000", - "%.60", "%+", "% ", "%-10"}; - - std::vector<long double> doubles = { - 0.0, - -0.0, - std::numeric_limits<long double>::max(), - -std::numeric_limits<long double>::max(), - std::numeric_limits<long double>::min(), - -std::numeric_limits<long double>::min(), - std::numeric_limits<long double>::infinity(), - -std::numeric_limits<long double>::infinity()}; - - for (long double base : {1.L, 12.L, 123.L, 1234.L, 12345.L, 123456.L, - 1234567.L, 12345678.L, 123456789.L, 1234567890.L, - 12345678901.L, 123456789012.L, 1234567890123.L, - // This value is not representable in double, but it - // is in long double that uses the extended format. - // This is to verify that we are not truncating the - // value mistakenly through a double. - 10000000000000000.25L}) { - for (int exp : {-1000, -500, 0, 500, 1000}) { - for (int sign : {1, -1}) { - doubles.push_back(sign * std::ldexp(base, exp)); - doubles.push_back(sign / std::ldexp(base, exp)); - } - } - } - - // Regression tests - // - // Using a string literal because not all platforms support hex literals or it - // might be out of range. - doubles.push_back(std::strtold("-0xf.ffffffb5feafffbp-16324L", nullptr)); - - for (const char *fmt : kFormats) { - for (char f : {'f', 'F', // - 'g', 'G', // - 'a', 'A', // - 'e', 'E'}) { - std::string fmt_str = std::string(fmt) + 'L' + f; - - if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' && - f != 'a' && f != 'A') { - // This particular test takes way too long with snprintf. - // Disable for the case we are not implementing natively. - continue; - } - - if (f == 'a' || f == 'A') { - if (!native_traits.hex_float_has_glibc_rounding || - !native_traits.hex_float_optimizes_leading_digit_bit_count) { - continue; - } - } - - for (auto d : doubles) { - FormatArgImpl arg(d); - UntypedFormatSpecImpl format(fmt_str); - // We use ASSERT_EQ here because failures are usually correlated and a - // bug would print way too many failed expectations causing the test to - // time out. - ASSERT_EQ(StrPrint(fmt_str.c_str(), d), FormatPack(format, {&arg, 1})) - << fmt_str << " " << StrPrint("%.18Lg", d) << " " - << StrPrint("%La", d) << " " << StrPrint("%.1080Lf", d); - } - } - } -} - -TEST_F(FormatConvertTest, IntAsDouble) { - const NativePrintfTraits &native_traits = VerifyNativeImplementation(); - const int kMin = std::numeric_limits<int>::min(); - const int kMax = std::numeric_limits<int>::max(); - const int ia[] = { - 1, 2, 3, 123, - -1, -2, -3, -123, - 0, kMax - 1, kMax, kMin + 1, kMin }; - for (const int fx : ia) { - SCOPED_TRACE(fx); - const FormatArgImpl args[] = {FormatArgImpl(fx)}; - struct Expectation { - int line; - std::string out; - const char *fmt; - }; - const double dx = static_cast<double>(fx); - std::vector<Expectation> expect = { - {__LINE__, StrPrint("%f", dx), "%f"}, - {__LINE__, StrPrint("%12f", dx), "%12f"}, - {__LINE__, StrPrint("%.12f", dx), "%.12f"}, - {__LINE__, StrPrint("%.12a", dx), "%.12a"}, - }; - if (native_traits.hex_float_uses_minimal_precision_when_not_specified) { - Expectation ex = {__LINE__, StrPrint("%12a", dx), "%12a"}; - expect.push_back(ex); - } - for (const Expectation &e : expect) { - SCOPED_TRACE(e.line); - SCOPED_TRACE(e.fmt); - UntypedFormatSpecImpl format(e.fmt); - EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))); - } - } -} - -template <typename T> -bool FormatFails(const char* test_format, T value) { - std::string format_string = std::string("<<") + test_format + ">>"; - UntypedFormatSpecImpl format(format_string); - - int one = 1; - const FormatArgImpl args[] = {FormatArgImpl(value), FormatArgImpl(one)}; - EXPECT_EQ(FormatPack(format, absl::MakeSpan(args)), "") - << "format=" << test_format << " value=" << value; - return FormatPack(format, absl::MakeSpan(args)).empty(); -} - -TEST_F(FormatConvertTest, ExpectedFailures) { - // Int input - EXPECT_TRUE(FormatFails("%p", 1)); - EXPECT_TRUE(FormatFails("%s", 1)); - EXPECT_TRUE(FormatFails("%n", 1)); - - // Double input - EXPECT_TRUE(FormatFails("%p", 1.)); - EXPECT_TRUE(FormatFails("%s", 1.)); - EXPECT_TRUE(FormatFails("%n", 1.)); - EXPECT_TRUE(FormatFails("%c", 1.)); - EXPECT_TRUE(FormatFails("%d", 1.)); - EXPECT_TRUE(FormatFails("%x", 1.)); - EXPECT_TRUE(FormatFails("%*d", 1.)); - - // String input - EXPECT_TRUE(FormatFails("%n", "")); - EXPECT_TRUE(FormatFails("%c", "")); - EXPECT_TRUE(FormatFails("%d", "")); - EXPECT_TRUE(FormatFails("%x", "")); - EXPECT_TRUE(FormatFails("%f", "")); - EXPECT_TRUE(FormatFails("%*d", "")); -} - -// Sanity check to make sure that we are testing what we think we're testing on -// e.g. the x86_64+glibc platform. -TEST_F(FormatConvertTest, GlibcHasCorrectTraits) { -#if !defined(__GLIBC__) || !defined(__x86_64__) - return; -#endif - const NativePrintfTraits &native_traits = VerifyNativeImplementation(); - // If one of the following tests break then it is either because the above PP - // macro guards failed to exclude a new platform (likely) or because something - // has changed in the implemention of glibc sprintf float formatting behavior. - // If the latter, then the code that computes these flags needs to be - // revisited and/or possibly the StrFormat implementation. - EXPECT_TRUE(native_traits.hex_float_has_glibc_rounding); - EXPECT_TRUE(native_traits.hex_float_prefers_denormal_repr); - EXPECT_TRUE( - native_traits.hex_float_uses_minimal_precision_when_not_specified); - EXPECT_TRUE(native_traits.hex_float_optimizes_leading_digit_bit_count); -} - -} // namespace -} // namespace str_format_internal -ABSL_NAMESPACE_END -} // namespace absl |