tvl-depot/absl/strings/internal/str_format/convert_test.cc

591 lines
20 KiB
C++
Raw Normal View History

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
Export of internal Abseil changes. -- 5a5dba4252e764e6737070bf0a31074bf23a3b41 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 244898913 -- 3eb7d5b445ffbf08a104e39cd15aecf568417333 by Matt Calabrese <calabrese@google.com>: Introduce absl::is_trivially_move_constructible and absl::is_trivially_move_assignable, and update the absl::is_trivially_copy_constructible and absl::is_trivially_copy_assignable traits to use similar techniques (should now be closer to the standard behavior). PiperOrigin-RevId: 244859015 -- 7da05a24fa786cab3985de0c39a186d73dcbcfb5 by Abseil Team <absl-team@google.com>: Fix misspellings in comments in raw_hash_set.h. PiperOrigin-RevId: 244754700 -- 5c057be96048f21473d5ec45005ab4dcd8dd354f by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 244744239 -- 592394e3c2e98f1238d3fb6fcb0d20c3e3739ba9 by Derek Mauro <dmauro@google.com>: Limit the raw_hash_set prefetch test to x86-64. PiperOrigin-RevId: 244737534 -- 99ebe4e003633c8ff7838b035b31a827994879ef by Derek Mauro <dmauro@google.com>: Workaround warning 4091 in an MSVC header. PiperOrigin-RevId: 244701744 -- 0aa23f09a32efe7985ee55b0217190f08da42477 by Abseil Team <absl-team@google.com>: Fix comment typo. PiperOrigin-RevId: 244659371 -- c6cdb87e9f28062c8daa29b3d8d68182ecc16383 by Derek Mauro <dmauro@google.com>: Fix -Wundef warnings and support -Wundef. PiperOrigin-RevId: 244244968 -- 06b81245f7696b20c3c63b0618d33ac25e29cad6 by Abseil Team <absl-team@google.com>: Fix a typo in inlined_vector.h. PiperOrigin-RevId: 244230809 -- 94877a2125d2cfe837384240e4d6551f39d737e4 by Greg Falcon <gfalcon@google.com>: Fix sysinfo_test for emscripten. PiperOrigin-RevId: 244198804 -- ec7783531ef7f9df2da37d341d61f7cb2bf843f0 by Shaindel Schwartz <shaindel@google.com>: Import of CCTZ from GitHub. Fixes #291. PiperOrigin-RevId: 244184598 -- b652c14fa95ea206c217487ee713b11f5d1762b3 by Matt Calabrese <calabrese@google.com>: Emulate the `in_place_index` and `in_place_type` variable templates such that they are syntactically usable in C++11 with `any` and `variant`. Also pull in the variable templates from namespace std when available. The main observable differences here are: 1) The types of `in_place_index_t<I>` and `in_place_type_t<T>` become function pointer types rather than structs when using the implementation that is not an alias of the std equivalents. 2) The types of `in_place_index<I>` and `in_place_type<T>` are not directly `in_place_index_t<I>` and `in_place_type_t<T>`, but rather they become function types that decay to the corresponding function pointer types. 3) The default constructor for `in_place_index_t` and `in_place_type_t` instantiations is no longer explicit, but for these templates I think that's less important than for something like `in_place_t` since the _type_t and _index_t versions basically never have their template parameter non-deduced when participating in overload resolution with conflicting candidates. 4) While idiomatic usage of `in_place_type_t` and `in_place_index_t` with std::variant and std::any should not be affected, there is the possibility that strange, non-idiomatic uses may be affected in the wild. 5) Default construction (rather than value-initialization) leads to a default-constructed pointer. PiperOrigin-RevId: 244180003 -- b9ac5a96581837ffa24532117b7ea302a5569751 by Derek Mauro <dmauro@google.com>: Fix MSVC debug assertion. isprint is undefined for values not representable as unsigned char or EOF. PiperOrigin-RevId: 244083005 -- 41758be6137c2f25e84b50f23938e49484be2903 by Shaindel Schwartz <shaindel@google.com>: Update config settings for Apple platforms. PiperOrigin-RevId: 244040587 -- c90df6a26db94b0305a0c954455a621542a89d91 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 244024427 -- c71e9ceb89495354eca7d02bd905ffeaa9029aec by Derek Mauro <dmauro@google.com>: Adds missing ABSL_DEFAULT_COPTS and ABSL_TEST_COPTS to CMakeLists.txt Don't error on deprecated declarations in tests. It is completely reasonable to test that code marked deprecated still works. PiperOrigin-RevId: 244003941 -- e1326a96527a8ba9b8d120161545260da9c4562e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 243990623 -- 90b8e12934c7711e1bfcc0117d21288bf9220dee by Abseil Team <absl-team@google.com>: Add variation of absl::Base64Escape/WebSafeBase64Escape that directly returns its result. PiperOrigin-RevId: 243894308 -- 317fef3344481ebc5c35712d42f5d8a0fa64dff4 by Abseil Team <absl-team@google.com>: Enable raw logging in Emscripten builds. PiperOrigin-RevId: 243893705 GitOrigin-RevId: 5a5dba4252e764e6737070bf0a31074bf23a3b41 Change-Id: I19293aab73cc98d9e9bf6a9fdc30819764adb9db
2019-04-23 21:04:13 +02:00
#include <cctype>
#include <cmath>
#include <string>
#include "gtest/gtest.h"
#include "absl/strings/internal/str_format/bind.h"
namespace absl {
namespace str_format_internal {
namespace {
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) {
Export of internal Abseil changes. -- 5a5dba4252e764e6737070bf0a31074bf23a3b41 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 244898913 -- 3eb7d5b445ffbf08a104e39cd15aecf568417333 by Matt Calabrese <calabrese@google.com>: Introduce absl::is_trivially_move_constructible and absl::is_trivially_move_assignable, and update the absl::is_trivially_copy_constructible and absl::is_trivially_copy_assignable traits to use similar techniques (should now be closer to the standard behavior). PiperOrigin-RevId: 244859015 -- 7da05a24fa786cab3985de0c39a186d73dcbcfb5 by Abseil Team <absl-team@google.com>: Fix misspellings in comments in raw_hash_set.h. PiperOrigin-RevId: 244754700 -- 5c057be96048f21473d5ec45005ab4dcd8dd354f by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 244744239 -- 592394e3c2e98f1238d3fb6fcb0d20c3e3739ba9 by Derek Mauro <dmauro@google.com>: Limit the raw_hash_set prefetch test to x86-64. PiperOrigin-RevId: 244737534 -- 99ebe4e003633c8ff7838b035b31a827994879ef by Derek Mauro <dmauro@google.com>: Workaround warning 4091 in an MSVC header. PiperOrigin-RevId: 244701744 -- 0aa23f09a32efe7985ee55b0217190f08da42477 by Abseil Team <absl-team@google.com>: Fix comment typo. PiperOrigin-RevId: 244659371 -- c6cdb87e9f28062c8daa29b3d8d68182ecc16383 by Derek Mauro <dmauro@google.com>: Fix -Wundef warnings and support -Wundef. PiperOrigin-RevId: 244244968 -- 06b81245f7696b20c3c63b0618d33ac25e29cad6 by Abseil Team <absl-team@google.com>: Fix a typo in inlined_vector.h. PiperOrigin-RevId: 244230809 -- 94877a2125d2cfe837384240e4d6551f39d737e4 by Greg Falcon <gfalcon@google.com>: Fix sysinfo_test for emscripten. PiperOrigin-RevId: 244198804 -- ec7783531ef7f9df2da37d341d61f7cb2bf843f0 by Shaindel Schwartz <shaindel@google.com>: Import of CCTZ from GitHub. Fixes #291. PiperOrigin-RevId: 244184598 -- b652c14fa95ea206c217487ee713b11f5d1762b3 by Matt Calabrese <calabrese@google.com>: Emulate the `in_place_index` and `in_place_type` variable templates such that they are syntactically usable in C++11 with `any` and `variant`. Also pull in the variable templates from namespace std when available. The main observable differences here are: 1) The types of `in_place_index_t<I>` and `in_place_type_t<T>` become function pointer types rather than structs when using the implementation that is not an alias of the std equivalents. 2) The types of `in_place_index<I>` and `in_place_type<T>` are not directly `in_place_index_t<I>` and `in_place_type_t<T>`, but rather they become function types that decay to the corresponding function pointer types. 3) The default constructor for `in_place_index_t` and `in_place_type_t` instantiations is no longer explicit, but for these templates I think that's less important than for something like `in_place_t` since the _type_t and _index_t versions basically never have their template parameter non-deduced when participating in overload resolution with conflicting candidates. 4) While idiomatic usage of `in_place_type_t` and `in_place_index_t` with std::variant and std::any should not be affected, there is the possibility that strange, non-idiomatic uses may be affected in the wild. 5) Default construction (rather than value-initialization) leads to a default-constructed pointer. PiperOrigin-RevId: 244180003 -- b9ac5a96581837ffa24532117b7ea302a5569751 by Derek Mauro <dmauro@google.com>: Fix MSVC debug assertion. isprint is undefined for values not representable as unsigned char or EOF. PiperOrigin-RevId: 244083005 -- 41758be6137c2f25e84b50f23938e49484be2903 by Shaindel Schwartz <shaindel@google.com>: Update config settings for Apple platforms. PiperOrigin-RevId: 244040587 -- c90df6a26db94b0305a0c954455a621542a89d91 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 244024427 -- c71e9ceb89495354eca7d02bd905ffeaa9029aec by Derek Mauro <dmauro@google.com>: Adds missing ABSL_DEFAULT_COPTS and ABSL_TEST_COPTS to CMakeLists.txt Don't error on deprecated declarations in tests. It is completely reasonable to test that code marked deprecated still works. PiperOrigin-RevId: 244003941 -- e1326a96527a8ba9b8d120161545260da9c4562e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 243990623 -- 90b8e12934c7711e1bfcc0117d21288bf9220dee by Abseil Team <absl-team@google.com>: Add variation of absl::Base64Escape/WebSafeBase64Escape that directly returns its result. PiperOrigin-RevId: 243894308 -- 317fef3344481ebc5c35712d42f5d8a0fa64dff4 by Abseil Team <absl-team@google.com>: Enable raw logging in Emscripten builds. PiperOrigin-RevId: 243893705 GitOrigin-RevId: 5a5dba4252e764e6737070bf0a31074bf23a3b41 Change-Id: I19293aab73cc98d9e9bf6a9fdc30819764adb9db
2019-04-23 21:04:13 +02:00
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 StrAppend(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;
}
std::string StrPrint(const char *format, ...) {
va_list ap;
va_start(ap, format);
std::string result;
StrAppend(&result, format, ap);
va_end(ap);
return result;
}
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)}));
}
TEST_F(FormatConvertTest, Pointer) {
Export of internal Abseil changes. -- 5a5dba4252e764e6737070bf0a31074bf23a3b41 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 244898913 -- 3eb7d5b445ffbf08a104e39cd15aecf568417333 by Matt Calabrese <calabrese@google.com>: Introduce absl::is_trivially_move_constructible and absl::is_trivially_move_assignable, and update the absl::is_trivially_copy_constructible and absl::is_trivially_copy_assignable traits to use similar techniques (should now be closer to the standard behavior). PiperOrigin-RevId: 244859015 -- 7da05a24fa786cab3985de0c39a186d73dcbcfb5 by Abseil Team <absl-team@google.com>: Fix misspellings in comments in raw_hash_set.h. PiperOrigin-RevId: 244754700 -- 5c057be96048f21473d5ec45005ab4dcd8dd354f by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 244744239 -- 592394e3c2e98f1238d3fb6fcb0d20c3e3739ba9 by Derek Mauro <dmauro@google.com>: Limit the raw_hash_set prefetch test to x86-64. PiperOrigin-RevId: 244737534 -- 99ebe4e003633c8ff7838b035b31a827994879ef by Derek Mauro <dmauro@google.com>: Workaround warning 4091 in an MSVC header. PiperOrigin-RevId: 244701744 -- 0aa23f09a32efe7985ee55b0217190f08da42477 by Abseil Team <absl-team@google.com>: Fix comment typo. PiperOrigin-RevId: 244659371 -- c6cdb87e9f28062c8daa29b3d8d68182ecc16383 by Derek Mauro <dmauro@google.com>: Fix -Wundef warnings and support -Wundef. PiperOrigin-RevId: 244244968 -- 06b81245f7696b20c3c63b0618d33ac25e29cad6 by Abseil Team <absl-team@google.com>: Fix a typo in inlined_vector.h. PiperOrigin-RevId: 244230809 -- 94877a2125d2cfe837384240e4d6551f39d737e4 by Greg Falcon <gfalcon@google.com>: Fix sysinfo_test for emscripten. PiperOrigin-RevId: 244198804 -- ec7783531ef7f9df2da37d341d61f7cb2bf843f0 by Shaindel Schwartz <shaindel@google.com>: Import of CCTZ from GitHub. Fixes #291. PiperOrigin-RevId: 244184598 -- b652c14fa95ea206c217487ee713b11f5d1762b3 by Matt Calabrese <calabrese@google.com>: Emulate the `in_place_index` and `in_place_type` variable templates such that they are syntactically usable in C++11 with `any` and `variant`. Also pull in the variable templates from namespace std when available. The main observable differences here are: 1) The types of `in_place_index_t<I>` and `in_place_type_t<T>` become function pointer types rather than structs when using the implementation that is not an alias of the std equivalents. 2) The types of `in_place_index<I>` and `in_place_type<T>` are not directly `in_place_index_t<I>` and `in_place_type_t<T>`, but rather they become function types that decay to the corresponding function pointer types. 3) The default constructor for `in_place_index_t` and `in_place_type_t` instantiations is no longer explicit, but for these templates I think that's less important than for something like `in_place_t` since the _type_t and _index_t versions basically never have their template parameter non-deduced when participating in overload resolution with conflicting candidates. 4) While idiomatic usage of `in_place_type_t` and `in_place_index_t` with std::variant and std::any should not be affected, there is the possibility that strange, non-idiomatic uses may be affected in the wild. 5) Default construction (rather than value-initialization) leads to a default-constructed pointer. PiperOrigin-RevId: 244180003 -- b9ac5a96581837ffa24532117b7ea302a5569751 by Derek Mauro <dmauro@google.com>: Fix MSVC debug assertion. isprint is undefined for values not representable as unsigned char or EOF. PiperOrigin-RevId: 244083005 -- 41758be6137c2f25e84b50f23938e49484be2903 by Shaindel Schwartz <shaindel@google.com>: Update config settings for Apple platforms. PiperOrigin-RevId: 244040587 -- c90df6a26db94b0305a0c954455a621542a89d91 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 244024427 -- c71e9ceb89495354eca7d02bd905ffeaa9029aec by Derek Mauro <dmauro@google.com>: Adds missing ABSL_DEFAULT_COPTS and ABSL_TEST_COPTS to CMakeLists.txt Don't error on deprecated declarations in tests. It is completely reasonable to test that code marked deprecated still works. PiperOrigin-RevId: 244003941 -- e1326a96527a8ba9b8d120161545260da9c4562e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 243990623 -- 90b8e12934c7711e1bfcc0117d21288bf9220dee by Abseil Team <absl-team@google.com>: Add variation of absl::Base64Escape/WebSafeBase64Escape that directly returns its result. PiperOrigin-RevId: 243894308 -- 317fef3344481ebc5c35712d42f5d8a0fa64dff4 by Abseil Team <absl-team@google.com>: Enable raw logging in Emscripten builds. PiperOrigin-RevId: 243893705 GitOrigin-RevId: 5a5dba4252e764e6737070bf0a31074bf23a3b41 Change-Id: I19293aab73cc98d9e9bf6a9fdc30819764adb9db
2019-04-23 21:04:13 +02:00
#ifdef _MSC_VER
// MSVC's printf implementation prints pointers differently. We can't easily
// compare our implementation to theirs.
return;
#endif
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[] = {
FormatArgImpl(xp), FormatArgImpl(cp), FormatArgImpl(inil),
FormatArgImpl(cnil), FormatArgImpl(mcp), FormatArgImpl(fp),
FormatArgImpl(fnil), FormatArgImpl(vcp), FormatArgImpl(vcnil),
};
struct Expectation {
std::string out;
const char *fmt;
};
const Expectation kExpect[] = {
{StrPrint("%p", &x), "%p"},
{StrPrint("%20p", &x), "%20p"},
{StrPrint("%.1p", &x), "%.1p"},
{StrPrint("%.20p", &x), "%.20p"},
{StrPrint("%30.20p", &x), "%30.20p"},
{StrPrint("%-p", &x), "%-p"},
{StrPrint("%-20p", &x), "%-20p"},
{StrPrint("%-.1p", &x), "%-.1p"},
{StrPrint("%.20p", &x), "%.20p"},
{StrPrint("%-30.20p", &x), "%-30.20p"},
{StrPrint("%p", cp), "%2$p"}, // const char*
{"(nil)", "%3$p"}, // null const char *
{"(nil)", "%4$p"}, // null const int *
{StrPrint("%p", mcp), "%5$p"}, // nonconst char*
{StrPrint("%p", fp), "%6$p"}, // function pointer
{StrPrint("%p", vcp), "%8$p"}, // function pointer
#ifndef __APPLE__
// Apple's printf differs here (0x0 vs. nil)
{StrPrint("%p", fnil), "%7$p"}, // null function pointer
{StrPrint("%p", vcnil), "%9$p"}, // null function pointer
#endif
};
for (const Expectation &e : kExpect) {
UntypedFormatSpecImpl format(e.fmt);
EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))) << e.fmt;
}
}
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);
Export of internal Abseil changes. -- bdce7e57e9e886eff1114d0266781b443f7ec639 by Derek Mauro <dmauro@google.com>: Change {Get|Set}EnvironmentVariable to {Get|Set}EnvironmentVariableA for compatibility with /DUNICODE. PiperOrigin-RevId: 239229514 -- 2276ed502326a044a84060d34eb19d499e3a3be2 by Derek Mauro <dmauro@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 239228622 -- a462efb970ff43b08a362ef2343fb75ac1295a50 by Derek Mauro <dmauro@google.com>: Adding linking of CoreFoundation to CMakeLists in absl/time. Import https://github.com/abseil/abseil-cpp/pull/280. Fix #283 PiperOrigin-RevId: 239220785 -- fc23327b97f940c682aae1956cf7a1bf87f88c06 by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of gcc (8.3.0 today) with libstdc++ and bazel. PiperOrigin-RevId: 239220448 -- 418c08a8f6a53e63b84e39473035774417ca3aa7 by Derek Mauro <dmauro@google.com>: Disable part of the variant exeception safety test on move assignment when using versions of libstd++ that contain a bug. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c7 PiperOrigin-RevId: 239062455 -- 799722217aeda79679577843c91d5be62cbcbb42 by Matt Calabrese <calabrese@google.com>: Add internal-only IsSwappable traits corresponding to std::is_swappable and std::is_nothrow_swappable, which are used with the swap implementations of optional and variant. PiperOrigin-RevId: 239049448 -- aa46a036038a3de5c68ac5e5d3b4bf76f818d2ea by CJ Johnson <johnsoncj@google.com>: Make InlinedVectorStorage constructor explicit PiperOrigin-RevId: 239044361 -- 17949715b3aa21c794701f69f2154e91b6acabc3 by CJ Johnson <johnsoncj@google.com>: Add absl namesapce to internal/inlined_vector.h PiperOrigin-RevId: 239030789 -- 834628325953078cc08ed10d23bb8890e5bec897 by Derek Mauro <dmauro@google.com>: Add test script that uses Docker to build Abseil with gcc-4.8, libstdc++, and cmake. PiperOrigin-RevId: 239028433 -- 80fe24149ed73ed2ced995ad1e372fb060c60427 by CJ Johnson <johnsoncj@google.com>: Factors data members of InlinedVector into an impl type called InlinedVectorStorage so that (in future changes) the contents of a vector can be grouped together with a single pointer. PiperOrigin-RevId: 239021086 -- 585331436d5d4d79f845e45dcf79d918a0dc6169 by Derek Mauro <dmauro@google.com>: Add -Wno-missing-field-initializers to gcc compiler flags. gcc-4.x has spurious missing field initializer warnings. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750 PiperOrigin-RevId: 239017217 -- 94602fe4e33ee3a552a7f2939c0f57a992f55075 by Abseil Team <absl-team@google.com>: Formatting fixes. PiperOrigin-RevId: 238983038 -- a1c1b63c08505574e0a8c491561840cecb2bb93e by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of clang with libc++ and bazel. PiperOrigin-RevId: 238669118 -- e525f8d20bc2f79a0d69336b902f63858f3bff9d by Derek Mauro <dmauro@google.com>: Disable the test optionalTest.InPlaceTSFINAEBug until libc++ is updated. PiperOrigin-RevId: 238661703 -- f99a2a0b5ec424a059678f7f226600f137b4c74e by Derek Mauro <dmauro@google.com>: Correct the check for the FlatHashMap-Any test bug (list conditions instead of platforms when possible) PiperOrigin-RevId: 238653344 -- 777928035dbcbf39f361eb7d10dc3696822f692f by Jon Cohen <cohenjon@google.com>: Add install rules for Abseil CMake. These are attempted to be limited to in-project installation. This serves two purposes -- first it's morally the same as using Abseil in-source, except you don't have to rebuild us every time. Second, the presence of an install rule makes life massively simpler for package manager maintainers. Currently this doesn't install absl tests or testonly libraries. This can be added in a follow-up patch. Fixes #38, Fixes #80, Closes #182 PiperOrigin-RevId: 238645836 -- ded1c6ce697c191b7a6ff14572b3e6d183117b2c by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of clang with libstdc++ and bazel. PiperOrigin-RevId: 238517815 GitOrigin-RevId: bdce7e57e9e886eff1114d0266781b443f7ec639 Change-Id: I6f745869cb8ef63851891ccac05ae9a7dd241c4f
2019-03-19 19:14:01 +01:00
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, 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)));
}
}
TEST_F(FormatConvertTest, Float) {
Export of internal Abseil changes. -- 5a5dba4252e764e6737070bf0a31074bf23a3b41 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 244898913 -- 3eb7d5b445ffbf08a104e39cd15aecf568417333 by Matt Calabrese <calabrese@google.com>: Introduce absl::is_trivially_move_constructible and absl::is_trivially_move_assignable, and update the absl::is_trivially_copy_constructible and absl::is_trivially_copy_assignable traits to use similar techniques (should now be closer to the standard behavior). PiperOrigin-RevId: 244859015 -- 7da05a24fa786cab3985de0c39a186d73dcbcfb5 by Abseil Team <absl-team@google.com>: Fix misspellings in comments in raw_hash_set.h. PiperOrigin-RevId: 244754700 -- 5c057be96048f21473d5ec45005ab4dcd8dd354f by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 244744239 -- 592394e3c2e98f1238d3fb6fcb0d20c3e3739ba9 by Derek Mauro <dmauro@google.com>: Limit the raw_hash_set prefetch test to x86-64. PiperOrigin-RevId: 244737534 -- 99ebe4e003633c8ff7838b035b31a827994879ef by Derek Mauro <dmauro@google.com>: Workaround warning 4091 in an MSVC header. PiperOrigin-RevId: 244701744 -- 0aa23f09a32efe7985ee55b0217190f08da42477 by Abseil Team <absl-team@google.com>: Fix comment typo. PiperOrigin-RevId: 244659371 -- c6cdb87e9f28062c8daa29b3d8d68182ecc16383 by Derek Mauro <dmauro@google.com>: Fix -Wundef warnings and support -Wundef. PiperOrigin-RevId: 244244968 -- 06b81245f7696b20c3c63b0618d33ac25e29cad6 by Abseil Team <absl-team@google.com>: Fix a typo in inlined_vector.h. PiperOrigin-RevId: 244230809 -- 94877a2125d2cfe837384240e4d6551f39d737e4 by Greg Falcon <gfalcon@google.com>: Fix sysinfo_test for emscripten. PiperOrigin-RevId: 244198804 -- ec7783531ef7f9df2da37d341d61f7cb2bf843f0 by Shaindel Schwartz <shaindel@google.com>: Import of CCTZ from GitHub. Fixes #291. PiperOrigin-RevId: 244184598 -- b652c14fa95ea206c217487ee713b11f5d1762b3 by Matt Calabrese <calabrese@google.com>: Emulate the `in_place_index` and `in_place_type` variable templates such that they are syntactically usable in C++11 with `any` and `variant`. Also pull in the variable templates from namespace std when available. The main observable differences here are: 1) The types of `in_place_index_t<I>` and `in_place_type_t<T>` become function pointer types rather than structs when using the implementation that is not an alias of the std equivalents. 2) The types of `in_place_index<I>` and `in_place_type<T>` are not directly `in_place_index_t<I>` and `in_place_type_t<T>`, but rather they become function types that decay to the corresponding function pointer types. 3) The default constructor for `in_place_index_t` and `in_place_type_t` instantiations is no longer explicit, but for these templates I think that's less important than for something like `in_place_t` since the _type_t and _index_t versions basically never have their template parameter non-deduced when participating in overload resolution with conflicting candidates. 4) While idiomatic usage of `in_place_type_t` and `in_place_index_t` with std::variant and std::any should not be affected, there is the possibility that strange, non-idiomatic uses may be affected in the wild. 5) Default construction (rather than value-initialization) leads to a default-constructed pointer. PiperOrigin-RevId: 244180003 -- b9ac5a96581837ffa24532117b7ea302a5569751 by Derek Mauro <dmauro@google.com>: Fix MSVC debug assertion. isprint is undefined for values not representable as unsigned char or EOF. PiperOrigin-RevId: 244083005 -- 41758be6137c2f25e84b50f23938e49484be2903 by Shaindel Schwartz <shaindel@google.com>: Update config settings for Apple platforms. PiperOrigin-RevId: 244040587 -- c90df6a26db94b0305a0c954455a621542a89d91 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 244024427 -- c71e9ceb89495354eca7d02bd905ffeaa9029aec by Derek Mauro <dmauro@google.com>: Adds missing ABSL_DEFAULT_COPTS and ABSL_TEST_COPTS to CMakeLists.txt Don't error on deprecated declarations in tests. It is completely reasonable to test that code marked deprecated still works. PiperOrigin-RevId: 244003941 -- e1326a96527a8ba9b8d120161545260da9c4562e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 243990623 -- 90b8e12934c7711e1bfcc0117d21288bf9220dee by Abseil Team <absl-team@google.com>: Add variation of absl::Base64Escape/WebSafeBase64Escape that directly returns its result. PiperOrigin-RevId: 243894308 -- 317fef3344481ebc5c35712d42f5d8a0fa64dff4 by Abseil Team <absl-team@google.com>: Enable raw logging in Emscripten builds. PiperOrigin-RevId: 243893705 GitOrigin-RevId: 5a5dba4252e764e6737070bf0a31074bf23a3b41 Change-Id: I19293aab73cc98d9e9bf6a9fdc30819764adb9db
2019-04-23 21:04:13 +02:00
#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 char *const kFormats[] = {
"%", "%.3", "%8.5", "%9", "%.60", "%.30", "%03", "%+",
"% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"};
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()};
#ifndef __APPLE__
// Apple formats NaN differently (+nan) vs. (nan)
doubles.push_back(std::nan(""));
#endif
// 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));
}
}
}
for (const char *fmt : kFormats) {
for (char f : {'f', 'F', //
'g', 'G', //
'a', 'A', //
'e', 'E'}) {
std::string fmt_str = std::string(fmt) + f;
for (double d : doubles) {
int i = -10;
FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
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, i),
FormatPack(format, absl::MakeSpan(args)))
<< fmt_str << " " << StrPrint("%.18g", d) << " "
<< StrPrint("%.999f", d);
}
}
}
}
TEST_F(FormatConvertTest, LongDouble) {
const char *const kFormats[] = {"%", "%.3", "%8.5", "%9",
"%.60", "%+", "% ", "%-10"};
// 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.
long double very_precise = 10000000000000000.25L;
std::vector<long double> doubles = {
0.0,
-0.0,
very_precise,
1 / very_precise,
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 (const char *fmt : kFormats) {
for (char f : {'f', 'F', //
'g', 'G', //
'a', 'A', //
'e', 'E'}) {
std::string fmt_str = std::string(fmt) + 'L' + f;
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("%.999Lf", d);
}
}
}
}
TEST_F(FormatConvertTest, IntAsFloat) {
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);
const Expectation kExpect[] = {
{ __LINE__, StrPrint("%f", dx), "%f" },
{ __LINE__, StrPrint("%12f", dx), "%12f" },
{ __LINE__, StrPrint("%.12f", dx), "%.12f" },
{ __LINE__, StrPrint("%12a", dx), "%12a" },
{ __LINE__, StrPrint("%.12a", dx), "%.12a" },
};
for (const Expectation &e : kExpect) {
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", ""));
}
} // namespace
} // namespace str_format_internal
} // namespace absl