Merge commit '2abfcd02f1868bc12b5b0934101d2845c41e3cf5' into dev
This commit is contained in:
32
external/fmt/test/CMakeLists.txt
vendored
32
external/fmt/test/CMakeLists.txt
vendored
@@ -8,22 +8,6 @@ target_include_directories(test-main PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
|
||||
target_link_libraries(test-main gtest fmt)
|
||||
|
||||
function(add_fmt_executable name)
|
||||
add_executable(${name} ${ARGN})
|
||||
# (Wstringop-overflow) - [meta-bug] bogus/missing -Wstringop-overflow warnings
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88443
|
||||
# Bogus -Wstringop-overflow warning
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100395
|
||||
# [10 Regression] spurious -Wstringop-overflow writing to a trailing array plus offset
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95353
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND
|
||||
NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
|
||||
target_compile_options(${name} PRIVATE -Wno-stringop-overflow)
|
||||
# The linker flag is needed for LTO.
|
||||
target_link_libraries(${name} -Wno-stringop-overflow)
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
# Adds a test.
|
||||
# Usage: add_fmt_test(name srcs...)
|
||||
function(add_fmt_test name)
|
||||
@@ -42,9 +26,13 @@ function(add_fmt_test name)
|
||||
else ()
|
||||
set(libs test-main fmt)
|
||||
endif ()
|
||||
add_fmt_executable(${name} ${sources})
|
||||
add_executable(${name} ${sources})
|
||||
target_link_libraries(${name} ${libs})
|
||||
|
||||
if (ADD_FMT_TEST_HEADER_ONLY AND NOT FMT_UNICODE)
|
||||
target_compile_definitions(${name} PUBLIC FMT_UNICODE=0)
|
||||
endif ()
|
||||
|
||||
# Define if certain C++ features can be used.
|
||||
if (FMT_PEDANTIC)
|
||||
target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
@@ -106,6 +94,9 @@ add_fmt_test(enforce-checks-test)
|
||||
target_compile_definitions(enforce-checks-test PRIVATE
|
||||
-DFMT_ENFORCE_COMPILE_STRING)
|
||||
|
||||
add_executable(perf-sanity perf-sanity.cc)
|
||||
target_link_libraries(perf-sanity fmt::fmt)
|
||||
|
||||
if (FMT_MODULE)
|
||||
# The tests need {fmt} to be compiled as traditional library
|
||||
# because of visibility of implementation details.
|
||||
@@ -138,7 +129,7 @@ if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC)
|
||||
endif()
|
||||
|
||||
if (NOT MSVC_STATIC_RUNTIME)
|
||||
add_fmt_executable(posix-mock-test
|
||||
add_executable(posix-mock-test
|
||||
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
|
||||
target_include_directories(
|
||||
posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
||||
@@ -146,6 +137,9 @@ if (NOT MSVC_STATIC_RUNTIME)
|
||||
if (FMT_PEDANTIC)
|
||||
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
endif ()
|
||||
if (MSVC)
|
||||
target_compile_options(posix-mock-test PRIVATE /utf-8)
|
||||
endif ()
|
||||
add_test(NAME posix-mock-test COMMAND posix-mock-test)
|
||||
add_fmt_test(os-test)
|
||||
endif ()
|
||||
@@ -226,7 +220,7 @@ if (FMT_PEDANTIC AND NOT WIN32 AND NOT (
|
||||
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
||||
endif ()
|
||||
|
||||
# This test are disabled on Windows because it is only *NIX issue.
|
||||
# This test is disabled on Windows because it is POSIX-specific.
|
||||
if (FMT_PEDANTIC AND NOT WIN32)
|
||||
add_test(static-export-test ${CMAKE_CTEST_COMMAND}
|
||||
-C ${CMAKE_BUILD_TYPE}
|
||||
|
||||
288
external/fmt/test/base-test.cc
vendored
288
external/fmt/test/base-test.cc
vendored
@@ -92,7 +92,11 @@ TEST(string_view_test, compare) {
|
||||
check_op<std::greater_equal>();
|
||||
}
|
||||
|
||||
TEST(core_test, is_output_iterator) {
|
||||
TEST(base_test, is_locking) {
|
||||
EXPECT_FALSE(fmt::detail::is_locking<const char(&)[3]>());
|
||||
}
|
||||
|
||||
TEST(base_test, is_output_iterator) {
|
||||
EXPECT_TRUE((fmt::detail::is_output_iterator<char*, char>::value));
|
||||
EXPECT_FALSE((fmt::detail::is_output_iterator<const char*, char>::value));
|
||||
EXPECT_FALSE((fmt::detail::is_output_iterator<std::string, char>::value));
|
||||
@@ -105,19 +109,13 @@ TEST(core_test, is_output_iterator) {
|
||||
char>::value));
|
||||
}
|
||||
|
||||
TEST(core_test, is_back_insert_iterator) {
|
||||
TEST(base_test, is_back_insert_iterator) {
|
||||
EXPECT_TRUE(fmt::detail::is_back_insert_iterator<
|
||||
std::back_insert_iterator<std::string>>::value);
|
||||
EXPECT_FALSE(fmt::detail::is_back_insert_iterator<
|
||||
std::front_insert_iterator<std::string>>::value);
|
||||
}
|
||||
|
||||
TEST(core_test, buffer_appender) {
|
||||
#ifdef __cpp_lib_ranges
|
||||
static_assert(std::output_iterator<fmt::appender, char>);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
|
||||
TEST(buffer_test, noncopyable) {
|
||||
EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value);
|
||||
@@ -268,26 +266,15 @@ TEST(buffer_test, append_allocates_enough_storage) {
|
||||
buffer.append(test, test + 9);
|
||||
}
|
||||
|
||||
struct custom_context {
|
||||
using char_type = char;
|
||||
using parse_context_type = fmt::format_parse_context;
|
||||
|
||||
bool called = false;
|
||||
|
||||
template <typename T> struct formatter_type {
|
||||
FMT_CONSTEXPR auto parse(fmt::format_parse_context& ctx)
|
||||
-> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
const char* format(const T&, custom_context& ctx) const {
|
||||
ctx.called = true;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void advance_to(const char*) {}
|
||||
};
|
||||
TEST(base_test, get_buffer) {
|
||||
mock_buffer<char> buffer;
|
||||
void* buffer_ptr = &buffer;
|
||||
auto&& appender_result = fmt::detail::get_buffer<char>(fmt::appender(buffer));
|
||||
EXPECT_EQ(&appender_result, buffer_ptr);
|
||||
auto&& back_inserter_result =
|
||||
fmt::detail::get_buffer<char>(std::back_inserter(buffer));
|
||||
EXPECT_EQ(&back_inserter_result, buffer_ptr);
|
||||
}
|
||||
|
||||
struct test_struct {};
|
||||
|
||||
@@ -308,16 +295,6 @@ TEST(arg_test, format_args) {
|
||||
EXPECT_FALSE(args.get(1));
|
||||
}
|
||||
|
||||
TEST(arg_test, make_value_with_custom_context) {
|
||||
auto t = test_struct();
|
||||
auto arg = fmt::detail::value<custom_context>(
|
||||
fmt::detail::arg_mapper<custom_context>().map(t));
|
||||
auto ctx = custom_context();
|
||||
auto parse_ctx = fmt::format_parse_context("");
|
||||
arg.custom.format(&t, parse_ctx, ctx);
|
||||
EXPECT_TRUE(ctx.called);
|
||||
}
|
||||
|
||||
// Use a unique result type to make sure that there are no undesirable
|
||||
// conversions.
|
||||
struct test_result {};
|
||||
@@ -364,29 +341,35 @@ VISIT_TYPE(long, long long);
|
||||
VISIT_TYPE(unsigned long, unsigned long long);
|
||||
#endif
|
||||
|
||||
#define CHECK_ARG(Char, expected, value) \
|
||||
{ \
|
||||
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
||||
EXPECT_CALL(visitor, visit(expected)); \
|
||||
using iterator = fmt::basic_appender<Char>; \
|
||||
auto var = value; \
|
||||
fmt::detail::make_arg<fmt::basic_format_context<iterator, Char>>(var) \
|
||||
.visit(visitor); \
|
||||
}
|
||||
#if FMT_BUILTIN_TYPES
|
||||
# define CHECK_ARG(expected, value) \
|
||||
{ \
|
||||
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
||||
EXPECT_CALL(visitor, visit(expected)); \
|
||||
auto var = value; \
|
||||
fmt::basic_format_arg<fmt::format_context>(var).visit(visitor); \
|
||||
}
|
||||
#else
|
||||
# define CHECK_ARG(expected, value)
|
||||
#endif
|
||||
|
||||
#define CHECK_ARG_SIMPLE(value) \
|
||||
{ \
|
||||
using value_type = decltype(value); \
|
||||
typename visit_type<value_type>::type expected = value; \
|
||||
CHECK_ARG(char, expected, value) \
|
||||
CHECK_ARG(expected, value) \
|
||||
}
|
||||
|
||||
template <typename T> class numeric_arg_test : public testing::Test {};
|
||||
|
||||
#if FMT_BUILTIN_TYPES
|
||||
using test_types =
|
||||
testing::Types<bool, signed char, unsigned char, short, unsigned short, int,
|
||||
unsigned, long, unsigned long, long long, unsigned long long,
|
||||
float, double, long double>;
|
||||
#else
|
||||
using test_types = testing::Types<int>;
|
||||
#endif
|
||||
TYPED_TEST_SUITE(numeric_arg_test, test_types);
|
||||
|
||||
template <typename T, fmt::enable_if_t<std::is_integral<T>::value, int> = 0>
|
||||
@@ -406,25 +389,33 @@ TYPED_TEST(numeric_arg_test, make_and_visit) {
|
||||
CHECK_ARG_SIMPLE(std::numeric_limits<TypeParam>::max());
|
||||
}
|
||||
|
||||
TEST(arg_test, char_arg) { CHECK_ARG(char, 'a', 'a'); }
|
||||
TEST(arg_test, char_arg) { CHECK_ARG('a', 'a'); }
|
||||
|
||||
TEST(arg_test, string_arg) {
|
||||
char str_data[] = "test";
|
||||
char* str = str_data;
|
||||
const char* cstr = str;
|
||||
CHECK_ARG(char, cstr, str);
|
||||
CHECK_ARG(cstr, str);
|
||||
|
||||
auto sv = fmt::string_view(str);
|
||||
CHECK_ARG(char, sv, std::string(str));
|
||||
CHECK_ARG(sv, std::string(str));
|
||||
}
|
||||
|
||||
TEST(arg_test, pointer_arg) {
|
||||
void* p = nullptr;
|
||||
const void* cp = nullptr;
|
||||
CHECK_ARG(char, cp, p);
|
||||
CHECK_ARG(cp, p);
|
||||
CHECK_ARG_SIMPLE(cp);
|
||||
}
|
||||
|
||||
TEST(arg_test, volatile_pointer_arg) {
|
||||
const void* p = nullptr;
|
||||
volatile int* vip = nullptr;
|
||||
const volatile int* cvip = nullptr;
|
||||
CHECK_ARG(p, static_cast<volatile void*>(vip));
|
||||
CHECK_ARG(p, static_cast<const volatile void*>(cvip));
|
||||
}
|
||||
|
||||
struct check_custom {
|
||||
auto operator()(fmt::basic_format_arg<fmt::format_context>::handle h) const
|
||||
-> test_result {
|
||||
@@ -448,7 +439,7 @@ TEST(arg_test, custom_arg) {
|
||||
mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>;
|
||||
auto&& v = testing::StrictMock<visitor>();
|
||||
EXPECT_CALL(v, visit(_)).WillOnce(Invoke(check_custom()));
|
||||
fmt::detail::make_arg<fmt::format_context>(test).visit(v);
|
||||
fmt::basic_format_arg<fmt::format_context>(test).visit(v);
|
||||
}
|
||||
|
||||
TEST(arg_test, visit_invalid_arg) {
|
||||
@@ -459,14 +450,12 @@ TEST(arg_test, visit_invalid_arg) {
|
||||
|
||||
#if FMT_USE_CONSTEXPR
|
||||
|
||||
enum class arg_id_result { none, empty, index, name };
|
||||
enum class arg_id_result { none, index, name };
|
||||
struct test_arg_id_handler {
|
||||
arg_id_result res = arg_id_result::none;
|
||||
int index = 0;
|
||||
string_view name;
|
||||
|
||||
constexpr void on_auto() { res = arg_id_result::empty; }
|
||||
|
||||
constexpr void on_index(int i) {
|
||||
res = arg_id_result::index;
|
||||
index = i;
|
||||
@@ -485,9 +474,7 @@ constexpr test_arg_id_handler parse_arg_id(const char (&s)[N]) {
|
||||
return h;
|
||||
}
|
||||
|
||||
TEST(core_test, constexpr_parse_arg_id) {
|
||||
static_assert(parse_arg_id(":").res == arg_id_result::empty, "");
|
||||
static_assert(parse_arg_id("}").res == arg_id_result::empty, "");
|
||||
TEST(base_test, constexpr_parse_arg_id) {
|
||||
static_assert(parse_arg_id("42:").res == arg_id_result::index, "");
|
||||
static_assert(parse_arg_id("42:").index == 42, "");
|
||||
static_assert(parse_arg_id("foo:").res == arg_id_result::name, "");
|
||||
@@ -503,21 +490,21 @@ template <size_t N> constexpr auto parse_test_specs(const char (&s)[N]) {
|
||||
return specs;
|
||||
}
|
||||
|
||||
TEST(core_test, constexpr_parse_format_specs) {
|
||||
static_assert(parse_test_specs("<").align == fmt::align::left, "");
|
||||
static_assert(parse_test_specs("*^").fill.get<char>() == '*', "");
|
||||
static_assert(parse_test_specs("+").sign == fmt::sign::plus, "");
|
||||
static_assert(parse_test_specs("-").sign == fmt::sign::minus, "");
|
||||
static_assert(parse_test_specs(" ").sign == fmt::sign::space, "");
|
||||
static_assert(parse_test_specs("#").alt, "");
|
||||
static_assert(parse_test_specs("0").align == fmt::align::numeric, "");
|
||||
static_assert(parse_test_specs("L").localized, "");
|
||||
TEST(base_test, constexpr_parse_format_specs) {
|
||||
static_assert(parse_test_specs("<").align() == fmt::align::left, "");
|
||||
static_assert(parse_test_specs("*^").fill_unit<char>() == '*', "");
|
||||
static_assert(parse_test_specs("+").sign() == fmt::sign::plus, "");
|
||||
static_assert(parse_test_specs("-").sign() == fmt::sign::none, "");
|
||||
static_assert(parse_test_specs(" ").sign() == fmt::sign::space, "");
|
||||
static_assert(parse_test_specs("#").alt(), "");
|
||||
static_assert(parse_test_specs("0").align() == fmt::align::numeric, "");
|
||||
static_assert(parse_test_specs("L").localized(), "");
|
||||
static_assert(parse_test_specs("42").width == 42, "");
|
||||
static_assert(parse_test_specs("{42}").width_ref.val.index == 42, "");
|
||||
static_assert(parse_test_specs("{42}").width_ref.index == 42, "");
|
||||
static_assert(parse_test_specs(".42").precision == 42, "");
|
||||
static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, "");
|
||||
static_assert(
|
||||
parse_test_specs("f").type == fmt::presentation_type::fixed, "");
|
||||
static_assert(parse_test_specs(".{42}").precision_ref.index == 42, "");
|
||||
static_assert(parse_test_specs("f").type() == fmt::presentation_type::fixed,
|
||||
"");
|
||||
}
|
||||
|
||||
struct test_format_string_handler {
|
||||
@@ -541,11 +528,11 @@ struct test_format_string_handler {
|
||||
|
||||
template <size_t N> constexpr bool parse_string(const char (&s)[N]) {
|
||||
auto h = test_format_string_handler();
|
||||
fmt::detail::parse_format_string<true>(fmt::string_view(s, N - 1), h);
|
||||
fmt::detail::parse_format_string(fmt::string_view(s, N - 1), h);
|
||||
return !h.error;
|
||||
}
|
||||
|
||||
TEST(core_test, constexpr_parse_format_string) {
|
||||
TEST(base_test, constexpr_parse_format_string) {
|
||||
static_assert(parse_string("foo"), "");
|
||||
static_assert(!parse_string("}"), "");
|
||||
static_assert(parse_string("{}"), "");
|
||||
@@ -584,15 +571,6 @@ template <> struct formatter<enabled_ptr_formatter*> {
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(core_test, has_formatter) {
|
||||
using fmt::has_formatter;
|
||||
using context = fmt::format_context;
|
||||
static_assert(has_formatter<enabled_formatter, context>::value, "");
|
||||
static_assert(!has_formatter<disabled_formatter, context>::value, "");
|
||||
static_assert(!has_formatter<disabled_formatter_convertible, context>::value,
|
||||
"");
|
||||
}
|
||||
|
||||
struct const_formattable {};
|
||||
struct nonconst_formattable {};
|
||||
|
||||
@@ -643,67 +621,83 @@ FMT_END_NAMESPACE
|
||||
|
||||
enum class unformattable_scoped_enum {};
|
||||
|
||||
TEST(core_test, is_formattable) {
|
||||
static_assert(!fmt::is_formattable<wchar_t>::value, "");
|
||||
TEST(base_test, is_formattable) {
|
||||
EXPECT_FALSE(fmt::is_formattable<void>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<wchar_t>::value);
|
||||
#ifdef __cpp_char8_t
|
||||
static_assert(!fmt::is_formattable<char8_t>::value, "");
|
||||
EXPECT_FALSE(fmt::is_formattable<char8_t>::value);
|
||||
#endif
|
||||
static_assert(!fmt::is_formattable<char16_t>::value, "");
|
||||
static_assert(!fmt::is_formattable<char32_t>::value, "");
|
||||
static_assert(!fmt::is_formattable<signed char*>::value, "");
|
||||
static_assert(!fmt::is_formattable<unsigned char*>::value, "");
|
||||
static_assert(!fmt::is_formattable<const signed char*>::value, "");
|
||||
static_assert(!fmt::is_formattable<const unsigned char*>::value, "");
|
||||
static_assert(!fmt::is_formattable<const wchar_t*>::value, "");
|
||||
static_assert(!fmt::is_formattable<const wchar_t[3]>::value, "");
|
||||
static_assert(!fmt::is_formattable<fmt::basic_string_view<wchar_t>>::value,
|
||||
"");
|
||||
static_assert(fmt::is_formattable<enabled_formatter>::value, "");
|
||||
static_assert(!fmt::is_formattable<enabled_ptr_formatter*>::value, "");
|
||||
static_assert(!fmt::is_formattable<disabled_formatter>::value, "");
|
||||
static_assert(!fmt::is_formattable<disabled_formatter_convertible>::value,
|
||||
"");
|
||||
EXPECT_FALSE(fmt::is_formattable<char16_t>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<char32_t>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<signed char*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<unsigned char*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const signed char*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const unsigned char*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const wchar_t*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<const wchar_t[3]>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<fmt::basic_string_view<wchar_t>>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<enabled_ptr_formatter*>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<disabled_formatter>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<disabled_formatter_convertible>::value);
|
||||
|
||||
static_assert(fmt::is_formattable<const_formattable&>::value, "");
|
||||
static_assert(fmt::is_formattable<const const_formattable&>::value, "");
|
||||
EXPECT_TRUE(fmt::is_formattable<enabled_formatter>::value);
|
||||
EXPECT_TRUE(fmt::is_formattable<const_formattable&>::value);
|
||||
EXPECT_TRUE(fmt::is_formattable<const const_formattable&>::value);
|
||||
|
||||
static_assert(fmt::is_formattable<nonconst_formattable&>::value, "");
|
||||
EXPECT_TRUE(fmt::is_formattable<nonconst_formattable&>::value);
|
||||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
|
||||
static_assert(!fmt::is_formattable<const nonconst_formattable&>::value, "");
|
||||
EXPECT_FALSE(fmt::is_formattable<const nonconst_formattable&>::value);
|
||||
#endif
|
||||
|
||||
static_assert(!fmt::is_formattable<convertible_to_pointer>::value, "");
|
||||
EXPECT_FALSE(fmt::is_formattable<convertible_to_pointer>::value);
|
||||
const auto f = convertible_to_pointer_formattable();
|
||||
auto str = std::string();
|
||||
fmt::format_to(std::back_inserter(str), "{}", f);
|
||||
EXPECT_EQ(str, "test");
|
||||
|
||||
static_assert(!fmt::is_formattable<void (*)()>::value, "");
|
||||
EXPECT_FALSE(fmt::is_formattable<void (*)()>::value);
|
||||
|
||||
struct s;
|
||||
static_assert(!fmt::is_formattable<int(s::*)>::value, "");
|
||||
static_assert(!fmt::is_formattable<int (s::*)()>::value, "");
|
||||
static_assert(!fmt::is_formattable<unformattable_scoped_enum>::value, "");
|
||||
static_assert(!fmt::is_formattable<unformattable_scoped_enum>::value, "");
|
||||
EXPECT_FALSE(fmt::is_formattable<int(s::*)>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<int (s::*)()>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<unformattable_scoped_enum>::value);
|
||||
EXPECT_FALSE(fmt::is_formattable<unformattable_scoped_enum>::value);
|
||||
}
|
||||
|
||||
TEST(core_test, format_to) {
|
||||
#ifdef __cpp_concepts
|
||||
TEST(base_test, formattable_concept) {
|
||||
static_assert(fmt::formattable<char>);
|
||||
static_assert(fmt::formattable<char&>);
|
||||
static_assert(fmt::formattable<char&&>);
|
||||
static_assert(fmt::formattable<const char>);
|
||||
static_assert(fmt::formattable<const char&>);
|
||||
static_assert(fmt::formattable<const char&&>);
|
||||
static_assert(fmt::formattable<int>);
|
||||
static_assert(!fmt::formattable<wchar_t>);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(base_test, format_to) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", 42);
|
||||
EXPECT_EQ(s, "42");
|
||||
}
|
||||
|
||||
TEST(core_test, format_to_c_array) {
|
||||
TEST(base_test, format_to_array) {
|
||||
char buffer[4];
|
||||
auto result = fmt::format_to(buffer, "{}", 12345);
|
||||
EXPECT_EQ(4, std::distance(&buffer[0], result.out));
|
||||
EXPECT_EQ(0, std::distance(result.out, result.out_last));
|
||||
EXPECT_TRUE(result.truncated);
|
||||
EXPECT_EQ(buffer + 4, result.out);
|
||||
EXPECT_EQ("1234", fmt::string_view(buffer, 4));
|
||||
|
||||
char* out = nullptr;
|
||||
EXPECT_THROW(out = result, std::runtime_error);
|
||||
(void)out;
|
||||
|
||||
result = fmt::format_to(buffer, "{:s}", "foobar");
|
||||
EXPECT_EQ(4, std::distance(&buffer[0], result.out));
|
||||
EXPECT_EQ(0, std::distance(result.out, result.out_last));
|
||||
EXPECT_TRUE(result.truncated);
|
||||
EXPECT_EQ(buffer + 4, result.out);
|
||||
EXPECT_EQ("foob", fmt::string_view(buffer, 4));
|
||||
|
||||
@@ -713,38 +707,30 @@ TEST(core_test, format_to_c_array) {
|
||||
buffer[3] = 'x';
|
||||
result = fmt::format_to(buffer, "{}", 'A');
|
||||
EXPECT_EQ(1, std::distance(&buffer[0], result.out));
|
||||
EXPECT_EQ(3, std::distance(result.out, result.out_last));
|
||||
EXPECT_FALSE(result.truncated);
|
||||
EXPECT_EQ(buffer + 1, result.out);
|
||||
EXPECT_EQ("Axxx", fmt::string_view(buffer, 4));
|
||||
|
||||
result = fmt::format_to(buffer, "{}{} ", 'B', 'C');
|
||||
EXPECT_EQ(3, std::distance(&buffer[0], result.out));
|
||||
EXPECT_EQ(1, std::distance(result.out, result.out_last));
|
||||
EXPECT_FALSE(result.truncated);
|
||||
EXPECT_EQ(buffer + 3, result.out);
|
||||
EXPECT_EQ("BC x", fmt::string_view(buffer, 4));
|
||||
|
||||
result = fmt::format_to(buffer, "{}", "ABCDE");
|
||||
EXPECT_EQ(4, std::distance(&buffer[0], result.out));
|
||||
EXPECT_EQ(0, std::distance(result.out, result.out_last));
|
||||
EXPECT_TRUE(result.truncated);
|
||||
EXPECT_EQ("ABCD", fmt::string_view(buffer, 4));
|
||||
|
||||
result = fmt::format_to(buffer, "{}", std::string(1000, '*'));
|
||||
result = fmt::format_to(buffer, "{}", std::string(1000, '*').c_str());
|
||||
EXPECT_EQ(4, std::distance(&buffer[0], result.out));
|
||||
EXPECT_EQ(0, std::distance(result.out, result.out_last));
|
||||
EXPECT_TRUE(result.truncated);
|
||||
EXPECT_EQ("****", fmt::string_view(buffer, 4));
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_byte
|
||||
TEST(core_test, format_byte) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", std::byte(42));
|
||||
EXPECT_EQ(s, "42");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test that check is not found by ADL.
|
||||
template <typename T> void check(T);
|
||||
TEST(core_test, adl_check) {
|
||||
TEST(base_test, adl_check) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", test_struct());
|
||||
EXPECT_EQ(s, "test");
|
||||
@@ -754,7 +740,7 @@ struct implicitly_convertible_to_string_view {
|
||||
operator fmt::string_view() const { return "foo"; }
|
||||
};
|
||||
|
||||
TEST(core_test, no_implicit_conversion_to_string_view) {
|
||||
TEST(base_test, no_implicit_conversion_to_string_view) {
|
||||
EXPECT_FALSE(
|
||||
fmt::is_formattable<implicitly_convertible_to_string_view>::value);
|
||||
}
|
||||
@@ -764,7 +750,7 @@ struct implicitly_convertible_to_std_string_view {
|
||||
operator std::string_view() const { return "foo"; }
|
||||
};
|
||||
|
||||
TEST(core_test, no_implicit_conversion_to_std_string_view) {
|
||||
TEST(base_test, no_implicit_conversion_to_std_string_view) {
|
||||
EXPECT_FALSE(
|
||||
fmt::is_formattable<implicitly_convertible_to_std_string_view>::value);
|
||||
}
|
||||
@@ -776,7 +762,7 @@ struct explicitly_convertible_to_string_view {
|
||||
explicit operator fmt::string_view() const { return "foo"; }
|
||||
};
|
||||
|
||||
TEST(core_test, format_explicitly_convertible_to_string_view) {
|
||||
TEST(base_test, format_explicitly_convertible_to_string_view) {
|
||||
// Types explicitly convertible to string_view are not formattable by
|
||||
// default because it may introduce ODR violations.
|
||||
static_assert(
|
||||
@@ -788,7 +774,7 @@ struct explicitly_convertible_to_std_string_view {
|
||||
explicit operator std::string_view() const { return "foo"; }
|
||||
};
|
||||
|
||||
TEST(core_test, format_explicitly_convertible_to_std_string_view) {
|
||||
TEST(base_test, format_explicitly_convertible_to_std_string_view) {
|
||||
// Types explicitly convertible to string_view are not formattable by
|
||||
// default because it may introduce ODR violations.
|
||||
static_assert(
|
||||
@@ -798,20 +784,19 @@ TEST(core_test, format_explicitly_convertible_to_std_string_view) {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
TEST(core_test, has_const_formatter) {
|
||||
EXPECT_TRUE((fmt::detail::has_const_formatter<const_formattable,
|
||||
fmt::format_context>()));
|
||||
EXPECT_FALSE((fmt::detail::has_const_formatter<nonconst_formattable,
|
||||
fmt::format_context>()));
|
||||
TEST(base_test, has_formatter) {
|
||||
EXPECT_TRUE((fmt::detail::has_formatter<const const_formattable, char>()));
|
||||
EXPECT_FALSE(
|
||||
(fmt::detail::has_formatter<const nonconst_formattable, char>()));
|
||||
}
|
||||
|
||||
TEST(core_test, format_nonconst) {
|
||||
TEST(base_test, format_nonconst) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", nonconst_formattable());
|
||||
EXPECT_EQ(s, "test");
|
||||
}
|
||||
|
||||
TEST(core_test, throw_in_buffer_dtor) {
|
||||
TEST(base_test, throw_in_buffer_dtor) {
|
||||
enum { buffer_size = 256 };
|
||||
|
||||
struct throwing_iterator {
|
||||
@@ -857,8 +842,29 @@ template <> struct formatter<its_a_trap> {
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(format_test, trappy_conversion) {
|
||||
TEST(base_test, trappy_conversion) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", its_a_trap());
|
||||
EXPECT_EQ(s, "x");
|
||||
}
|
||||
|
||||
struct custom_container {
|
||||
char data;
|
||||
|
||||
using value_type = char;
|
||||
|
||||
size_t size() const { return 0; }
|
||||
void resize(size_t) {}
|
||||
|
||||
void push_back(char) {}
|
||||
char& operator[](size_t) { return data; }
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct is_contiguous<custom_container> : std::true_type {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(base_test, format_to_custom_container) {
|
||||
auto c = custom_container();
|
||||
fmt::format_to(std::back_inserter(c), "");
|
||||
}
|
||||
|
||||
106
external/fmt/test/chrono-test.cc
vendored
106
external/fmt/test/chrono-test.cc
vendored
@@ -539,6 +539,7 @@ TEST(chrono_test, format_specs) {
|
||||
EXPECT_EQ(fmt::format("{:%I}", std::chrono::hours(24)), "12");
|
||||
EXPECT_EQ(fmt::format("{:%I}", std::chrono::hours(4)), "04");
|
||||
EXPECT_EQ(fmt::format("{:%I}", std::chrono::hours(14)), "02");
|
||||
EXPECT_EQ(fmt::format("{:%j}", days(12)), "12");
|
||||
EXPECT_EQ(fmt::format("{:%j}", days(12345)), "12345");
|
||||
EXPECT_EQ(fmt::format("{:%j}", std::chrono::hours(12345 * 24 + 12)), "12345");
|
||||
EXPECT_EQ(fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345)),
|
||||
@@ -751,17 +752,21 @@ TEST(chrono_test, unsigned_duration) {
|
||||
TEST(chrono_test, weekday) {
|
||||
auto loc = get_locale("es_ES.UTF-8");
|
||||
std::locale::global(loc);
|
||||
|
||||
auto sat = fmt::weekday(6);
|
||||
|
||||
auto tm = std::tm();
|
||||
tm.tm_wday = static_cast<int>(sat.c_encoding());
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", sat), "Sat");
|
||||
EXPECT_EQ(fmt::format("{:%a}", sat), "Sat");
|
||||
EXPECT_EQ(fmt::format("{:%A}", sat), "Saturday");
|
||||
EXPECT_EQ(fmt::format("{:%a}", tm), "Sat");
|
||||
|
||||
if (loc != std::locale::classic()) {
|
||||
auto saturdays = std::vector<std::string>{"sáb", "sá."};
|
||||
auto saturdays = std::vector<std::string>{"sáb", "sá.", "sáb."};
|
||||
EXPECT_THAT(saturdays, Contains(fmt::format(loc, "{:L}", sat)));
|
||||
EXPECT_THAT(saturdays, Contains(fmt::format(loc, "{:%a}", sat)));
|
||||
EXPECT_THAT(saturdays, Contains(fmt::format(loc, "{:%a}", tm)));
|
||||
}
|
||||
}
|
||||
@@ -791,6 +796,14 @@ TEST(chrono_test, cpp20_duration_subsecond_support) {
|
||||
"01.234000");
|
||||
EXPECT_EQ(fmt::format("{:.6%S}", std::chrono::milliseconds{-1234}),
|
||||
"-01.234000");
|
||||
EXPECT_EQ(fmt::format("{:.2%S}", std::chrono::milliseconds{12345}), "12.34");
|
||||
EXPECT_EQ(fmt::format("{:.2%S}", std::chrono::milliseconds{12375}), "12.37");
|
||||
EXPECT_EQ(fmt::format("{:.2%S}", std::chrono::milliseconds{-12375}),
|
||||
"-12.37");
|
||||
EXPECT_EQ(fmt::format("{:.0%S}", std::chrono::milliseconds{12054}), "12");
|
||||
EXPECT_EQ(fmt::format("{:.2%S}", std::chrono::milliseconds{99999}), "39.99");
|
||||
EXPECT_EQ(fmt::format("{:.2%S}", std::chrono::milliseconds{1000}), "01.00");
|
||||
EXPECT_EQ(fmt::format("{:.3%S}", std::chrono::milliseconds{1}), "00.001");
|
||||
EXPECT_EQ(fmt::format("{:.3%S}", std::chrono::seconds{1234}), "34.000");
|
||||
EXPECT_EQ(fmt::format("{:.3%S}", std::chrono::hours{1234}), "00.000");
|
||||
EXPECT_EQ(fmt::format("{:.5%S}", dms(1.234)), "00.00123");
|
||||
@@ -953,13 +966,11 @@ TEST(chrono_test, glibc_extensions) {
|
||||
std::chrono::seconds(3);
|
||||
|
||||
EXPECT_EQ(fmt::format("{:%I,%H,%M,%S}", d), "01,01,02,03");
|
||||
EXPECT_EQ(fmt::format("{:%0I,%0H,%0M,%0S}", d), "01,01,02,03");
|
||||
EXPECT_EQ(fmt::format("{:%_I,%_H,%_M,%_S}", d), " 1, 1, 2, 3");
|
||||
EXPECT_EQ(fmt::format("{:%-I,%-H,%-M,%-S}", d), "1,1,2,3");
|
||||
EXPECT_EQ(fmt::format("{:%-I,%H,%M,%S}", d), "1,01,02,03");
|
||||
|
||||
EXPECT_EQ(fmt::format("{:%OI,%OH,%OM,%OS}", d), "01,01,02,03");
|
||||
EXPECT_EQ(fmt::format("{:%0OI,%0OH,%0OM,%0OS}", d), "01,01,02,03");
|
||||
EXPECT_EQ(fmt::format("{:%_OI,%_OH,%_OM,%_OS}", d), " 1, 1, 2, 3");
|
||||
EXPECT_EQ(fmt::format("{:%-OI,%-OH,%-OM,%-OS}", d), "1,1,2,3");
|
||||
}
|
||||
@@ -967,12 +978,10 @@ TEST(chrono_test, glibc_extensions) {
|
||||
{
|
||||
const auto tm = make_tm(1970, 1, 1, 1, 2, 3);
|
||||
EXPECT_EQ(fmt::format("{:%I,%H,%M,%S}", tm), "01,01,02,03");
|
||||
EXPECT_EQ(fmt::format("{:%0I,%0H,%0M,%0S}", tm), "01,01,02,03");
|
||||
EXPECT_EQ(fmt::format("{:%_I,%_H,%_M,%_S}", tm), " 1, 1, 2, 3");
|
||||
EXPECT_EQ(fmt::format("{:%-I,%-H,%-M,%-S}", tm), "1,1,2,3");
|
||||
|
||||
EXPECT_EQ(fmt::format("{:%OI,%OH,%OM,%OS}", tm), "01,01,02,03");
|
||||
EXPECT_EQ(fmt::format("{:%0OI,%0OH,%0OM,%0OS}", tm), "01,01,02,03");
|
||||
EXPECT_EQ(fmt::format("{:%_OI,%_OH,%_OM,%_OS}", tm), " 1, 1, 2, 3");
|
||||
EXPECT_EQ(fmt::format("{:%-OI,%-OH,%-OM,%-OS}", tm), "1,1,2,3");
|
||||
}
|
||||
@@ -980,21 +989,100 @@ TEST(chrono_test, glibc_extensions) {
|
||||
{
|
||||
const auto d = std::chrono::seconds(3) + std::chrono::milliseconds(140);
|
||||
EXPECT_EQ(fmt::format("{:%S}", d), "03.140");
|
||||
EXPECT_EQ(fmt::format("{:%0S}", d), "03.140");
|
||||
EXPECT_EQ(fmt::format("{:%_S}", d), " 3.140");
|
||||
EXPECT_EQ(fmt::format("{:%-S}", d), "3.140");
|
||||
}
|
||||
|
||||
{
|
||||
const auto d = std::chrono::duration<double>(3.14);
|
||||
auto d = std::chrono::duration<double>(3.14);
|
||||
EXPECT_EQ(fmt::format("{:%S}", d), "03.140000");
|
||||
EXPECT_EQ(fmt::format("{:%0S}", d), "03.140000");
|
||||
EXPECT_EQ(fmt::format("{:%_S}", d), " 3.140000");
|
||||
EXPECT_EQ(fmt::format("{:%-S}", d), "3.140000");
|
||||
}
|
||||
|
||||
{
|
||||
auto t = std::tm();
|
||||
t.tm_yday = 7;
|
||||
EXPECT_EQ(fmt::format("{:%U,%W,%V}", t), "02,01,01");
|
||||
EXPECT_EQ(fmt::format("{:%_U,%_W,%_V}", t), " 2, 1, 1");
|
||||
EXPECT_EQ(fmt::format("{:%-U,%-W,%-V}", t), "2,1,1");
|
||||
|
||||
EXPECT_EQ(fmt::format("{:%j}", t), "008");
|
||||
EXPECT_EQ(fmt::format("{:%_j}", t), " 8");
|
||||
EXPECT_EQ(fmt::format("{:%-j}", t), "8");
|
||||
}
|
||||
|
||||
{
|
||||
auto t = std::tm();
|
||||
t.tm_mday = 7;
|
||||
EXPECT_EQ(fmt::format("{:%d}", t), "07");
|
||||
EXPECT_EQ(fmt::format("{:%_d}", t), " 7");
|
||||
EXPECT_EQ(fmt::format("{:%-d}", t), "7");
|
||||
|
||||
EXPECT_EQ(fmt::format("{:%e}", t), " 7");
|
||||
}
|
||||
|
||||
{
|
||||
auto t = std::tm();
|
||||
t.tm_year = 7 - 1900;
|
||||
EXPECT_EQ(fmt::format("{:%Y}", t), "0007");
|
||||
EXPECT_EQ(fmt::format("{:%_Y}", t), " 7");
|
||||
EXPECT_EQ(fmt::format("{:%-Y}", t), "7");
|
||||
}
|
||||
|
||||
{
|
||||
auto t = std::tm();
|
||||
t.tm_year = -5 - 1900;
|
||||
EXPECT_EQ(fmt::format( "{:%Y}", t), "-005");
|
||||
EXPECT_EQ(fmt::format("{:%_Y}", t), " -5");
|
||||
EXPECT_EQ(fmt::format("{:%-Y}", t), "-5");
|
||||
}
|
||||
|
||||
{
|
||||
auto t = std::tm();
|
||||
t.tm_mon = 7 - 1;
|
||||
EXPECT_EQ(fmt::format("{:%m}", t), "07");
|
||||
EXPECT_EQ(fmt::format("{:%_m}", t), " 7");
|
||||
EXPECT_EQ(fmt::format("{:%-m}", t), "7");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
TEST(chrono_test, out_of_range) {
|
||||
auto d = std::chrono::duration<unsigned long, std::giga>(538976288);
|
||||
EXPECT_THROW((void)fmt::format("{:%j}", d), fmt::format_error);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(chrono_test, year_month_day) {
|
||||
auto loc = get_locale("es_ES.UTF-8");
|
||||
std::locale::global(loc);
|
||||
|
||||
auto year = fmt::year(2024);
|
||||
auto month = fmt::month(1);
|
||||
auto day = fmt::day(1);
|
||||
auto ymd = fmt::year_month_day(year, month, day);
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", year), "2024");
|
||||
EXPECT_EQ(fmt::format("{:%Y}", year), "2024");
|
||||
EXPECT_EQ(fmt::format("{:%y}", year), "24");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", month), "Jan");
|
||||
EXPECT_EQ(fmt::format("{:%m}", month), "01");
|
||||
EXPECT_EQ(fmt::format("{:%b}", month), "Jan");
|
||||
EXPECT_EQ(fmt::format("{:%B}", month), "January");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", day), "01");
|
||||
EXPECT_EQ(fmt::format("{:%d}", day), "01");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", ymd), "2024-01-01");
|
||||
EXPECT_EQ(fmt::format("{:%Y-%m-%d}", ymd), "2024-01-01");
|
||||
EXPECT_EQ(fmt::format("{:%Y-%b-%d}", ymd), "2024-Jan-01");
|
||||
EXPECT_EQ(fmt::format("{:%Y-%B-%d}", ymd), "2024-January-01");
|
||||
|
||||
if (loc != std::locale::classic()) {
|
||||
auto months = std::vector<std::string>{"ene.", "ene"};
|
||||
EXPECT_THAT(months, Contains(fmt::format(loc, "{:L}", month)));
|
||||
EXPECT_THAT(months, Contains(fmt::format(loc, "{:%b}", month)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +115,7 @@ function (run_tests)
|
||||
endif ()
|
||||
endfunction ()
|
||||
|
||||
|
||||
# check if the source file skeleton compiles
|
||||
# Check if the source file skeleton compiles.
|
||||
expect_compile(check "")
|
||||
expect_compile(check-error "compilation_error" ERROR)
|
||||
|
||||
@@ -166,31 +165,6 @@ expect_compile(format-lots-of-arguments-with-function "
|
||||
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, f);
|
||||
" ERROR)
|
||||
|
||||
# Check if user-defined literals are available
|
||||
include(CheckCXXSourceCompiles)
|
||||
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
|
||||
check_cxx_source_compiles("
|
||||
void operator\"\" _udl(long double);
|
||||
int main() {}"
|
||||
SUPPORTS_USER_DEFINED_LITERALS)
|
||||
set(CMAKE_REQUIRED_FLAGS )
|
||||
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
|
||||
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
|
||||
endif ()
|
||||
|
||||
# Make sure that compiler features detected in the header
|
||||
# match the features detected in CMake.
|
||||
if (SUPPORTS_USER_DEFINED_LITERALS)
|
||||
set(supports_udl 1)
|
||||
else ()
|
||||
set(supports_udl 0)
|
||||
endif ()
|
||||
expect_compile(udl-check "
|
||||
#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl}
|
||||
# error
|
||||
#endif
|
||||
")
|
||||
|
||||
if (CMAKE_CXX_STANDARD GREATER_EQUAL 20)
|
||||
# Compile-time argument type check
|
||||
expect_compile(format-string-number-spec "
|
||||
|
||||
11
external/fmt/test/compile-test.cc
vendored
11
external/fmt/test/compile-test.cc
vendored
@@ -14,14 +14,6 @@
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest-extra.h"
|
||||
|
||||
TEST(iterator_test, counting_iterator) {
|
||||
auto it = fmt::detail::counting_iterator();
|
||||
auto prev = it++;
|
||||
EXPECT_EQ(prev.count(), 0);
|
||||
EXPECT_EQ(it.count(), 1);
|
||||
EXPECT_EQ((it + 41).count(), 42);
|
||||
}
|
||||
|
||||
TEST(compile_test, compile_fallback) {
|
||||
// FMT_COMPILE should fallback on runtime formatting when `if constexpr` is
|
||||
// not available.
|
||||
@@ -206,7 +198,7 @@ TEST(compile_test, format_to_n) {
|
||||
EXPECT_STREQ("2a", buffer);
|
||||
}
|
||||
|
||||
# ifdef __cpp_lib_bit_cast
|
||||
# if FMT_USE_CONSTEVAL && (!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940)
|
||||
TEST(compile_test, constexpr_formatted_size) {
|
||||
FMT_CONSTEXPR20 size_t size = fmt::formatted_size(FMT_COMPILE("{}"), 42);
|
||||
EXPECT_EQ(size, 2);
|
||||
@@ -342,6 +334,7 @@ TEST(compile_time_formatting_test, integer) {
|
||||
EXPECT_EQ("0X4A", test_format<5>(FMT_COMPILE("{:#X}"), 0x4a));
|
||||
|
||||
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42));
|
||||
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42l));
|
||||
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ll));
|
||||
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ull));
|
||||
|
||||
|
||||
2
external/fmt/test/format-impl-test.cc
vendored
2
external/fmt/test/format-impl-test.cc
vendored
@@ -344,7 +344,7 @@ TEST(format_impl_test, write_dragon_even) {
|
||||
if (!FMT_MSC_VERSION) EXPECT_EQ(s, "33554450");
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(FMT_WINDOWS_NO_WCHAR)
|
||||
#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE)
|
||||
# include <windows.h>
|
||||
|
||||
TEST(format_impl_test, write_console_signature) {
|
||||
|
||||
313
external/fmt/test/format-test.cc
vendored
313
external/fmt/test/format-test.cc
vendored
@@ -15,17 +15,28 @@
|
||||
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include <climits> // INT_MAX
|
||||
#include <cmath> // std::signbit
|
||||
#include <cstring> // std::strlen
|
||||
#include <iterator> // std::back_inserter
|
||||
#include <list> // std::list
|
||||
#include <type_traits> // std::is_default_constructible
|
||||
#include <cfenv> // fegetexceptflag and FE_ALL_EXCEPT
|
||||
#include <climits> // INT_MAX
|
||||
#include <cmath> // std::signbit
|
||||
#include <condition_variable> // std::condition_variable
|
||||
#include <cstring> // std::strlen
|
||||
#include <iterator> // std::back_inserter
|
||||
#include <list> // std::list
|
||||
#include <mutex> // std::mutex
|
||||
#include <string> // std::string
|
||||
#include <thread> // std::thread
|
||||
#include <type_traits> // std::is_default_constructible
|
||||
#if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<version>)
|
||||
# include <version>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "gtest-extra.h"
|
||||
#include "mock-allocator.h"
|
||||
#include "util.h"
|
||||
|
||||
using fmt::basic_memory_buffer;
|
||||
using fmt::format_error;
|
||||
using fmt::memory_buffer;
|
||||
@@ -37,6 +48,10 @@ using fmt::detail::uint128_fallback;
|
||||
using testing::Return;
|
||||
using testing::StrictMock;
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
static_assert(std::output_iterator<fmt::appender, char>);
|
||||
#endif
|
||||
|
||||
enum { buffer_size = 256 };
|
||||
|
||||
TEST(uint128_test, ctor) {
|
||||
@@ -105,6 +120,14 @@ TEST(float_test, isfinite) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void check_no_fp_exception() {
|
||||
fexcept_t fe;
|
||||
fegetexceptflag(&fe, FE_ALL_EXCEPT);
|
||||
|
||||
// No exception flags should have been set
|
||||
EXPECT_TRUE(fe == 0);
|
||||
}
|
||||
|
||||
template <typename Float> void check_isnan() {
|
||||
using fmt::detail::isnan;
|
||||
EXPECT_FALSE(isnan(Float(0.0)));
|
||||
@@ -117,6 +140,17 @@ template <typename Float> void check_isnan() {
|
||||
EXPECT_FALSE(isnan(Float(-limits::infinity())));
|
||||
EXPECT_TRUE(isnan(Float(limits::quiet_NaN())));
|
||||
EXPECT_TRUE(isnan(Float(-limits::quiet_NaN())));
|
||||
|
||||
// Sanity check: make sure no error has occurred before we start
|
||||
check_no_fp_exception();
|
||||
|
||||
// Check that no exception is raised for the non-NaN case
|
||||
isnan(Float(42.0));
|
||||
check_no_fp_exception();
|
||||
|
||||
// Check that no exception is raised for the NaN case
|
||||
isnan(Float(limits::quiet_NaN()));
|
||||
check_no_fp_exception();
|
||||
}
|
||||
|
||||
TEST(float_test, isnan) {
|
||||
@@ -239,7 +273,8 @@ TEST(util_test, format_system_error) {
|
||||
throws_on_alloc = true;
|
||||
}
|
||||
if (!throws_on_alloc) {
|
||||
fmt::print("warning: std::allocator allocates {} chars\n", max_size);
|
||||
fmt::print(stderr, "warning: std::allocator allocates {} chars\n",
|
||||
max_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -446,6 +481,12 @@ TEST(memory_buffer_test, max_size_allocator_overflow) {
|
||||
EXPECT_THROW(buffer.resize(161), std::exception);
|
||||
}
|
||||
|
||||
TEST(format_test, digits2_alignment) {
|
||||
auto p =
|
||||
fmt::detail::bit_cast<fmt::detail::uintptr_t>(fmt::detail::digits2(0));
|
||||
EXPECT_EQ(p % 2, 0);
|
||||
}
|
||||
|
||||
TEST(format_test, exception_from_lib) {
|
||||
EXPECT_THROW_MSG(fmt::report_error("test"), format_error, "test");
|
||||
}
|
||||
@@ -769,7 +810,7 @@ TEST(format_test, hash_flag) {
|
||||
EXPECT_EQ(fmt::format("{:#.2g}", 0.5), "0.50");
|
||||
EXPECT_EQ(fmt::format("{:#.0f}", 0.5), "0.");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#"), 'c'), format_error,
|
||||
"missing '}' in format string");
|
||||
"invalid format specifier for char");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), 'c'), format_error,
|
||||
"invalid format specifier for char");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), "abc"), format_error,
|
||||
@@ -790,7 +831,7 @@ TEST(format_test, zero_flag) {
|
||||
EXPECT_EQ(fmt::format("{0:07}", -42.0), "-000042");
|
||||
EXPECT_EQ(fmt::format("{0:07}", -42.0l), "-000042");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:0"), 'c'), format_error,
|
||||
"missing '}' in format string");
|
||||
"invalid format specifier for char");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), 'c'), format_error,
|
||||
"invalid format specifier for char");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), "abc"), format_error,
|
||||
@@ -837,6 +878,10 @@ TEST(format_test, width) {
|
||||
EXPECT_EQ(fmt::format("{:>06.0f}", 0.00884311), " 0");
|
||||
}
|
||||
|
||||
auto bad_dynamic_spec_msg = FMT_BUILTIN_TYPES
|
||||
? "width/precision is out of range"
|
||||
: "width/precision is not integer";
|
||||
|
||||
TEST(format_test, runtime_width) {
|
||||
auto int_maxer = std::to_string(INT_MAX + 1u);
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{" + int_maxer), 0),
|
||||
@@ -859,23 +904,23 @@ TEST(format_test, runtime_width) {
|
||||
"invalid format string");
|
||||
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1), format_error,
|
||||
"negative width");
|
||||
"width/precision is out of range");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1u)),
|
||||
format_error, "number is too big");
|
||||
format_error, bad_dynamic_spec_msg);
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1l), format_error,
|
||||
"negative width");
|
||||
bad_dynamic_spec_msg);
|
||||
if (fmt::detail::const_check(sizeof(long) > sizeof(int))) {
|
||||
long value = INT_MAX;
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (value + 1)),
|
||||
format_error, "number is too big");
|
||||
format_error, bad_dynamic_spec_msg);
|
||||
}
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1ul)),
|
||||
format_error, "number is too big");
|
||||
format_error, bad_dynamic_spec_msg);
|
||||
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, '0'), format_error,
|
||||
"width is not integer");
|
||||
"width/precision is not integer");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, 0.0), format_error,
|
||||
"width is not integer");
|
||||
"width/precision is not integer");
|
||||
|
||||
EXPECT_EQ(fmt::format("{0:{1}}", -42, 4), " -42");
|
||||
EXPECT_EQ(fmt::format("{0:{1}}", 42u, 5), " 42");
|
||||
@@ -892,6 +937,10 @@ TEST(format_test, runtime_width) {
|
||||
EXPECT_EQ(fmt::format("{:{}}", 42, short(4)), " 42");
|
||||
}
|
||||
|
||||
TEST(format_test, exponent_range) {
|
||||
for (int e = -1074; e <= 1023; ++e) (void)fmt::format("{}", std::ldexp(1, e));
|
||||
}
|
||||
|
||||
TEST(format_test, precision) {
|
||||
char format_str[buffer_size];
|
||||
safe_sprintf(format_str, "{0:.%u", UINT_MAX);
|
||||
@@ -914,7 +963,7 @@ TEST(format_test, precision) {
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:."), 0.0), format_error,
|
||||
"invalid precision");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.}"), 0.0), format_error,
|
||||
"invalid precision");
|
||||
"invalid format string");
|
||||
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2"), 0), format_error,
|
||||
"invalid format specifier");
|
||||
@@ -950,6 +999,9 @@ TEST(format_test, precision) {
|
||||
EXPECT_EQ(fmt::format("{0:.3}", 1.1), "1.1");
|
||||
EXPECT_EQ(fmt::format("{:.0e}", 1.0L), "1e+00");
|
||||
EXPECT_EQ(fmt::format("{:9.1e}", 0.0), " 0.0e+00");
|
||||
EXPECT_EQ(fmt::format("{:.7f}", 0.0000000000000071054273576010018587L),
|
||||
"0.0000000");
|
||||
|
||||
EXPECT_EQ(
|
||||
fmt::format("{:.494}", 4.9406564584124654E-324),
|
||||
"4.9406564584124654417656879286822137236505980261432476442558568250067550"
|
||||
@@ -1032,13 +1084,15 @@ TEST(format_test, precision) {
|
||||
EXPECT_THROW_MSG(
|
||||
(void)fmt::format("{:.2147483646f}", -2.2121295195081227E+304),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{:.f}"), 42.0), format_error,
|
||||
"invalid format string");
|
||||
|
||||
EXPECT_EQ(fmt::format("{0:.2}", "str"), "st");
|
||||
EXPECT_EQ(fmt::format("{0:.5}", "вожыкі"), "вожык");
|
||||
EXPECT_EQ(fmt::format("{0:.6}", "123456\xad"), "123456");
|
||||
}
|
||||
|
||||
TEST(xchar_test, utf8_precision) {
|
||||
TEST(format_test, utf8_precision) {
|
||||
auto result = fmt::format("{:.4}", "caf\u00e9s"); // cafés
|
||||
EXPECT_EQ(fmt::detail::compute_width(result), 4);
|
||||
EXPECT_EQ(result, "caf\u00e9");
|
||||
@@ -1075,23 +1129,23 @@ TEST(format_test, runtime_precision) {
|
||||
"invalid format string");
|
||||
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, -1),
|
||||
format_error, "negative precision");
|
||||
format_error, "width/precision is out of range");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (INT_MAX + 1u)),
|
||||
format_error, "number is too big");
|
||||
format_error, bad_dynamic_spec_msg);
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, -1l),
|
||||
format_error, "negative precision");
|
||||
format_error, bad_dynamic_spec_msg);
|
||||
if (fmt::detail::const_check(sizeof(long) > sizeof(int))) {
|
||||
long value = INT_MAX;
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (value + 1)),
|
||||
format_error, "number is too big");
|
||||
format_error, bad_dynamic_spec_msg);
|
||||
}
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (INT_MAX + 1ul)),
|
||||
format_error, "number is too big");
|
||||
format_error, bad_dynamic_spec_msg);
|
||||
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, '0'),
|
||||
format_error, "precision is not integer");
|
||||
format_error, "width/precision is not integer");
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, 0.0),
|
||||
format_error, "precision is not integer");
|
||||
format_error, "width/precision is not integer");
|
||||
|
||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42, 2), format_error,
|
||||
"invalid format specifier");
|
||||
@@ -1622,6 +1676,20 @@ TEST(format_test, format_explicitly_convertible_to_std_string_view) {
|
||||
EXPECT_EQ("'foo'",
|
||||
fmt::format("{}", explicitly_convertible_to_std_string_view()));
|
||||
}
|
||||
|
||||
struct convertible_to_std_string_view {
|
||||
operator std::string_view() const noexcept { return "Hi there"; }
|
||||
};
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <>
|
||||
class formatter<convertible_to_std_string_view>
|
||||
: public formatter<std::string_view> {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(format_test, format_implicitly_convertible_and_inherits_string_view) {
|
||||
static_assert(fmt::is_formattable<convertible_to_std_string_view>{}, "");
|
||||
EXPECT_EQ("Hi there", fmt::format("{}", convertible_to_std_string_view{}));
|
||||
}
|
||||
#endif
|
||||
|
||||
class Answer {};
|
||||
@@ -1752,6 +1820,71 @@ TEST(format_test, big_print) {
|
||||
EXPECT_WRITE(stdout, big_print(), std::string(count, 'x'));
|
||||
}
|
||||
|
||||
// Windows CRT implements _IOLBF incorrectly (full buffering).
|
||||
#if FMT_USE_FCNTL && !defined(_WIN32)
|
||||
TEST(format_test, line_buffering) {
|
||||
auto pipe = fmt::pipe();
|
||||
|
||||
int write_fd = pipe.write_end.descriptor();
|
||||
auto write_end = pipe.write_end.fdopen("w");
|
||||
setvbuf(write_end.get(), nullptr, _IOLBF, 4096);
|
||||
write_end.print("42\n");
|
||||
close(write_fd);
|
||||
try {
|
||||
write_end.close();
|
||||
} catch (const std::system_error&) {
|
||||
}
|
||||
|
||||
auto read_end = pipe.read_end.fdopen("r");
|
||||
std::thread reader([&]() {
|
||||
int n = 0;
|
||||
int result = fscanf(read_end.get(), "%d", &n);
|
||||
(void)result;
|
||||
EXPECT_EQ(n, 42);
|
||||
});
|
||||
|
||||
reader.join();
|
||||
}
|
||||
#endif
|
||||
|
||||
struct deadlockable {
|
||||
int value = 0;
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<deadlockable> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(const deadlockable& d, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
std::lock_guard<std::mutex> lock(d.mutex);
|
||||
return format_to(ctx.out(), "{}", d.value);
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(format_test, locking_formatter) {
|
||||
auto f = fmt::buffered_file();
|
||||
try {
|
||||
f = fmt::buffered_file("/dev/null", "w");
|
||||
} catch (const std::system_error&) {
|
||||
fmt::print(stderr, "warning: /dev/null is not supported\n");
|
||||
return;
|
||||
}
|
||||
deadlockable d;
|
||||
auto t = std::thread([&]() {
|
||||
fmt::print(f.get(), "start t\n");
|
||||
std::lock_guard<std::mutex> lock(d.mutex);
|
||||
for (int i = 0; i < 1000000; ++i) d.value += 10;
|
||||
fmt::print(f.get(), "done\n");
|
||||
});
|
||||
for (int i = 0; i < 100; ++i) fmt::print(f.get(), "{}", d);
|
||||
t.join();
|
||||
}
|
||||
|
||||
TEST(format_test, variadic) {
|
||||
EXPECT_EQ(fmt::format("{}c{}", "ab", 1), "abc1");
|
||||
}
|
||||
@@ -1765,6 +1898,9 @@ TEST(format_test, bytes) {
|
||||
TEST(format_test, group_digits_view) {
|
||||
EXPECT_EQ(fmt::format("{}", fmt::group_digits(10000000)), "10,000,000");
|
||||
EXPECT_EQ(fmt::format("{:8}", fmt::group_digits(1000)), " 1,000");
|
||||
EXPECT_EQ(fmt::format("{}", fmt::group_digits(-10000000)), "-10,000,000");
|
||||
EXPECT_EQ(fmt::format("{:8}", fmt::group_digits(-1000)), " -1,000");
|
||||
EXPECT_EQ(fmt::format("{:8}", fmt::group_digits(-100)), " -100");
|
||||
}
|
||||
|
||||
#ifdef __cpp_generic_lambdas
|
||||
@@ -1869,7 +2005,6 @@ TEST(format_test, custom_format_compile_time_string) {
|
||||
EXPECT_EQ(fmt::format(FMT_STRING("{}"), const_answer), "42");
|
||||
}
|
||||
|
||||
#if FMT_USE_USER_DEFINED_LITERALS
|
||||
TEST(format_test, named_arg_udl) {
|
||||
using namespace fmt::literals;
|
||||
auto udl_a = fmt::format("{first}{second}{first}{third}", "first"_a = "abra",
|
||||
@@ -1881,13 +2016,12 @@ TEST(format_test, named_arg_udl) {
|
||||
|
||||
EXPECT_EQ(fmt::format("{answer}", "answer"_a = Answer()), "42");
|
||||
}
|
||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||
|
||||
TEST(format_test, enum) { EXPECT_EQ(fmt::format("{}", foo), "0"); }
|
||||
|
||||
TEST(format_test, formatter_not_specialized) {
|
||||
static_assert(!fmt::has_formatter<fmt::formatter<test_enum>,
|
||||
fmt::format_context>::value,
|
||||
static_assert(!fmt::is_formattable<fmt::formatter<test_enum>,
|
||||
fmt::format_context>::value,
|
||||
"");
|
||||
}
|
||||
|
||||
@@ -1896,6 +2030,8 @@ enum big_enum : unsigned long long { big_enum_value = 5000000000ULL };
|
||||
auto format_as(big_enum e) -> unsigned long long { return e; }
|
||||
|
||||
TEST(format_test, strong_enum) {
|
||||
auto arg = fmt::basic_format_arg<fmt::context>(big_enum_value);
|
||||
EXPECT_EQ(arg.type(), fmt::detail::type::ulong_long_type);
|
||||
EXPECT_EQ(fmt::format("{}", big_enum_value), "5000000000");
|
||||
}
|
||||
#endif
|
||||
@@ -1947,6 +2083,13 @@ TEST(format_test, output_iterators) {
|
||||
EXPECT_EQ("42", s.str());
|
||||
}
|
||||
|
||||
TEST(format_test, fill_via_appender) {
|
||||
fmt::memory_buffer buf;
|
||||
auto it = fmt::appender(buf);
|
||||
std::fill_n(it, 3, '~');
|
||||
EXPECT_EQ(fmt::to_string(buf), "~~~");
|
||||
}
|
||||
|
||||
TEST(format_test, formatted_size) {
|
||||
EXPECT_EQ(2u, fmt::formatted_size("{}", 42));
|
||||
EXPECT_EQ(2u, fmt::formatted_size(std::locale(), "{}", 42));
|
||||
@@ -2060,7 +2203,7 @@ TEST(format_test, vformat_to) {
|
||||
fmt::vformat_to(std::back_inserter(s), "{}", args);
|
||||
EXPECT_EQ(s, "42");
|
||||
s.clear();
|
||||
fmt::vformat_to(std::back_inserter(s), FMT_STRING("{}"), args);
|
||||
fmt::vformat_to(std::back_inserter(s), "{}", args);
|
||||
EXPECT_EQ(s, "42");
|
||||
}
|
||||
|
||||
@@ -2147,16 +2290,21 @@ template <typename Char, typename... T> void check_enabled_formatters() {
|
||||
}
|
||||
|
||||
TEST(format_test, test_formatters_enabled) {
|
||||
using custom_string =
|
||||
std::basic_string<char, std::char_traits<char>, mock_allocator<char>>;
|
||||
using custom_wstring = std::basic_string<wchar_t, std::char_traits<wchar_t>,
|
||||
mock_allocator<wchar_t>>;
|
||||
|
||||
check_enabled_formatters<char, bool, char, signed char, unsigned char, short,
|
||||
unsigned short, int, unsigned, long, unsigned long,
|
||||
long long, unsigned long long, float, double,
|
||||
long double, void*, const void*, char*, const char*,
|
||||
std::string, std::nullptr_t>();
|
||||
check_enabled_formatters<wchar_t, bool, wchar_t, signed char, unsigned char,
|
||||
short, unsigned short, int, unsigned, long,
|
||||
unsigned long, long long, unsigned long long, float,
|
||||
double, long double, void*, const void*, wchar_t*,
|
||||
const wchar_t*, std::wstring, std::nullptr_t>();
|
||||
std::string, custom_string, std::nullptr_t>();
|
||||
check_enabled_formatters<
|
||||
wchar_t, bool, wchar_t, signed char, unsigned char, short, unsigned short,
|
||||
int, unsigned, long, unsigned long, long long, unsigned long long, float,
|
||||
double, long double, void*, const void*, wchar_t*, const wchar_t*,
|
||||
std::wstring, custom_wstring, std::nullptr_t>();
|
||||
}
|
||||
|
||||
TEST(format_int_test, data) {
|
||||
@@ -2264,6 +2412,7 @@ namespace adl_test {
|
||||
template <typename... T> void make_format_args(const T&...) = delete;
|
||||
|
||||
struct string : std::string {};
|
||||
auto format_as(const string& s) -> std::string { return s; }
|
||||
} // namespace adl_test
|
||||
|
||||
// Test that formatting functions compile when make_format_args is found by ADL.
|
||||
@@ -2319,3 +2468,93 @@ TEST(format_test, formatter_overrides_implicit_conversion) {
|
||||
EXPECT_EQ(fmt::format("{}", convertible_to_int()), "x");
|
||||
EXPECT_EQ(fmt::format("{}", convertible_to_cstring()), "y");
|
||||
}
|
||||
|
||||
struct ustring {
|
||||
using value_type = unsigned;
|
||||
|
||||
auto find_first_of(value_type, size_t) const -> size_t;
|
||||
|
||||
auto data() const -> const char*;
|
||||
auto size() const -> size_t;
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<ustring> : formatter<std::string> {
|
||||
auto format(const ustring&, format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<std::string>::format("ustring", ctx);
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(format_test, ustring) {
|
||||
EXPECT_EQ(fmt::format("{}", ustring()), "ustring");
|
||||
}
|
||||
|
||||
TEST(format_test, writer) {
|
||||
auto write_to_stdout = []() {
|
||||
auto w = fmt::writer(stdout);
|
||||
w.print("{}", 42);
|
||||
};
|
||||
EXPECT_WRITE(stdout, write_to_stdout(), "42");
|
||||
|
||||
#if FMT_USE_FCNTL
|
||||
auto pipe = fmt::pipe();
|
||||
auto write_end = pipe.write_end.fdopen("w");
|
||||
fmt::writer(write_end.get()).print("42");
|
||||
write_end.close();
|
||||
auto read_end = pipe.read_end.fdopen("r");
|
||||
int n = 0;
|
||||
int result = fscanf(read_end.get(), "%d", &n);
|
||||
(void)result;
|
||||
EXPECT_EQ(n, 42);
|
||||
#endif
|
||||
|
||||
auto s = fmt::string_buffer();
|
||||
fmt::writer(s).print("foo");
|
||||
EXPECT_EQ(s.str(), "foo");
|
||||
}
|
||||
|
||||
#if FMT_USE_BITINT
|
||||
FMT_PRAGMA_CLANG(diagnostic ignored "-Wbit-int-extension")
|
||||
|
||||
TEST(format_test, bitint) {
|
||||
using fmt::detail::bitint;
|
||||
using fmt::detail::ubitint;
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", ubitint<3>(7)), "7");
|
||||
EXPECT_EQ(fmt::format("{}", bitint<7>()), "0");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", ubitint<15>(31000)), "31000");
|
||||
EXPECT_EQ(fmt::format("{}", bitint<16>(INT16_MIN)), "-32768");
|
||||
EXPECT_EQ(fmt::format("{}", bitint<16>(INT16_MAX)), "32767");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", ubitint<32>(4294967295)), "4294967295");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", ubitint<47>(140737488355327ULL)),
|
||||
"140737488355327");
|
||||
EXPECT_EQ(fmt::format("{}", bitint<47>(-40737488355327LL)),
|
||||
"-40737488355327");
|
||||
|
||||
// Check lvalues and const
|
||||
auto a = bitint<8>(0);
|
||||
auto b = ubitint<32>(4294967295);
|
||||
const auto c = bitint<7>(0);
|
||||
const auto d = ubitint<32>(4294967295);
|
||||
EXPECT_EQ(fmt::format("{}", a), "0");
|
||||
EXPECT_EQ(fmt::format("{}", b), "4294967295");
|
||||
EXPECT_EQ(fmt::format("{}", c), "0");
|
||||
EXPECT_EQ(fmt::format("{}", d), "4294967295");
|
||||
|
||||
static_assert(fmt::is_formattable<bitint<64>, char>{}, "");
|
||||
static_assert(fmt::is_formattable<ubitint<64>, char>{}, "");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_byte
|
||||
TEST(base_test, format_byte) {
|
||||
auto s = std::string();
|
||||
fmt::format_to(std::back_inserter(s), "{}", std::byte(42));
|
||||
EXPECT_EQ(s, "42");
|
||||
}
|
||||
#endif
|
||||
|
||||
30
external/fmt/test/gtest/gmock-gtest-all.cc
vendored
30
external/fmt/test/gtest/gmock-gtest-all.cc
vendored
@@ -13360,6 +13360,7 @@ bool UnorderedElementsAreMatcherImplBase::FindPairing(
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -13983,46 +13984,50 @@ MockObjectRegistry g_mock_object_registry;
|
||||
|
||||
// Maps a mock object to the reaction Google Mock should have when an
|
||||
// uninteresting method is called. Protected by g_gmock_mutex.
|
||||
std::map<const void*, internal::CallReaction> g_uninteresting_call_reaction;
|
||||
std::unordered_map<uintptr_t, internal::CallReaction>&
|
||||
UninterestingCallReactionMap() {
|
||||
static auto* map = new std::unordered_map<uintptr_t, internal::CallReaction>;
|
||||
return *map;
|
||||
}
|
||||
|
||||
// Sets the reaction Google Mock should have when an uninteresting
|
||||
// method of the given mock object is called.
|
||||
void SetReactionOnUninterestingCalls(const void* mock_obj,
|
||||
void SetReactionOnUninterestingCalls(uintptr_t mock_obj,
|
||||
internal::CallReaction reaction)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||
g_uninteresting_call_reaction[mock_obj] = reaction;
|
||||
UninterestingCallReactionMap()[mock_obj] = reaction;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Tells Google Mock to allow uninteresting calls on the given mock
|
||||
// object.
|
||||
void Mock::AllowUninterestingCalls(const void* mock_obj)
|
||||
void Mock::AllowUninterestingCalls(uintptr_t mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||
SetReactionOnUninterestingCalls(mock_obj, internal::kAllow);
|
||||
}
|
||||
|
||||
// Tells Google Mock to warn the user about uninteresting calls on the
|
||||
// given mock object.
|
||||
void Mock::WarnUninterestingCalls(const void* mock_obj)
|
||||
void Mock::WarnUninterestingCalls(uintptr_t mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||
SetReactionOnUninterestingCalls(mock_obj, internal::kWarn);
|
||||
}
|
||||
|
||||
// Tells Google Mock to fail uninteresting calls on the given mock
|
||||
// object.
|
||||
void Mock::FailUninterestingCalls(const void* mock_obj)
|
||||
void Mock::FailUninterestingCalls(uintptr_t mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||
SetReactionOnUninterestingCalls(mock_obj, internal::kFail);
|
||||
}
|
||||
|
||||
// Tells Google Mock the given mock object is being destroyed and its
|
||||
// entry in the call-reaction table should be removed.
|
||||
void Mock::UnregisterCallReaction(const void* mock_obj)
|
||||
void Mock::UnregisterCallReaction(uintptr_t mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||
g_uninteresting_call_reaction.erase(mock_obj);
|
||||
UninterestingCallReactionMap().erase(static_cast<uintptr_t>(mock_obj));
|
||||
}
|
||||
|
||||
// Returns the reaction Google Mock will have on uninteresting calls
|
||||
@@ -14031,9 +14036,12 @@ internal::CallReaction Mock::GetReactionOnUninterestingCalls(
|
||||
const void* mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||
return (g_uninteresting_call_reaction.count(mock_obj) == 0) ?
|
||||
internal::intToCallReaction(GMOCK_FLAG(default_mock_behavior)) :
|
||||
g_uninteresting_call_reaction[mock_obj];
|
||||
return (UninterestingCallReactionMap().count(
|
||||
reinterpret_cast<uintptr_t>(mock_obj)) == 0)
|
||||
? internal::intToCallReaction(
|
||||
GMOCK_FLAG(default_mock_behavior))
|
||||
: UninterestingCallReactionMap()[reinterpret_cast<uintptr_t>(
|
||||
mock_obj)];
|
||||
}
|
||||
|
||||
// Tells Google Mock to ignore mock_obj when checking for leaked mock
|
||||
|
||||
34
external/fmt/test/gtest/gmock/gmock.h
vendored
34
external/fmt/test/gtest/gmock/gmock.h
vendored
@@ -2860,6 +2860,7 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||
#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
|
||||
#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -8646,22 +8647,22 @@ class GTEST_API_ Mock {
|
||||
|
||||
// Tells Google Mock to allow uninteresting calls on the given mock
|
||||
// object.
|
||||
static void AllowUninterestingCalls(const void* mock_obj)
|
||||
static void AllowUninterestingCalls(uintptr_t mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
|
||||
|
||||
// Tells Google Mock to warn the user about uninteresting calls on
|
||||
// the given mock object.
|
||||
static void WarnUninterestingCalls(const void* mock_obj)
|
||||
static void WarnUninterestingCalls(uintptr_t mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
|
||||
|
||||
// Tells Google Mock to fail uninteresting calls on the given mock
|
||||
// object.
|
||||
static void FailUninterestingCalls(const void* mock_obj)
|
||||
static void FailUninterestingCalls(uintptr_t mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
|
||||
|
||||
// Tells Google Mock the given mock object is being destroyed and
|
||||
// its entry in the call-reaction table should be removed.
|
||||
static void UnregisterCallReaction(const void* mock_obj)
|
||||
static void UnregisterCallReaction(uintptr_t mock_obj)
|
||||
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
|
||||
|
||||
// Returns the reaction Google Mock will have on uninteresting calls
|
||||
@@ -11417,6 +11418,7 @@ MATCHER(IsFalse, negation ? "is true" : "is false") {
|
||||
#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
|
||||
#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
@@ -11461,25 +11463,37 @@ constexpr bool HasStrictnessModifier() {
|
||||
template <typename Base>
|
||||
class NiceMockImpl {
|
||||
public:
|
||||
NiceMockImpl() { ::testing::Mock::AllowUninterestingCalls(this); }
|
||||
NiceMockImpl() {
|
||||
::testing::Mock::AllowUninterestingCalls(reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
|
||||
~NiceMockImpl() { ::testing::Mock::UnregisterCallReaction(this); }
|
||||
~NiceMockImpl() {
|
||||
::testing::Mock::UnregisterCallReaction(reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Base>
|
||||
class NaggyMockImpl {
|
||||
public:
|
||||
NaggyMockImpl() { ::testing::Mock::WarnUninterestingCalls(this); }
|
||||
NaggyMockImpl() {
|
||||
::testing::Mock::WarnUninterestingCalls(reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
|
||||
~NaggyMockImpl() { ::testing::Mock::UnregisterCallReaction(this); }
|
||||
~NaggyMockImpl() {
|
||||
::testing::Mock::UnregisterCallReaction(reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Base>
|
||||
class StrictMockImpl {
|
||||
public:
|
||||
StrictMockImpl() { ::testing::Mock::FailUninterestingCalls(this); }
|
||||
StrictMockImpl() {
|
||||
::testing::Mock::FailUninterestingCalls(reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
|
||||
~StrictMockImpl() { ::testing::Mock::UnregisterCallReaction(this); }
|
||||
~StrictMockImpl() {
|
||||
::testing::Mock::UnregisterCallReaction(reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
7
external/fmt/test/gtest/gtest/gtest.h
vendored
7
external/fmt/test/gtest/gtest/gtest.h
vendored
@@ -6390,17 +6390,18 @@ class MatcherBase : private MatcherDescriberInterface {
|
||||
}
|
||||
|
||||
protected:
|
||||
MatcherBase() : vtable_(nullptr) {}
|
||||
MatcherBase() : vtable_(nullptr), buffer_() {}
|
||||
|
||||
// Constructs a matcher from its implementation.
|
||||
template <typename U>
|
||||
explicit MatcherBase(const MatcherInterface<U>* impl) {
|
||||
explicit MatcherBase(const MatcherInterface<U>* impl)
|
||||
: vtable_(nullptr), buffer_() {
|
||||
Init(impl);
|
||||
}
|
||||
|
||||
template <typename M, typename = typename std::remove_reference<
|
||||
M>::type::is_gtest_matcher>
|
||||
MatcherBase(M&& m) { // NOLINT
|
||||
MatcherBase(M&& m) : vtable_(nullptr), buffer_() { // NOLINT
|
||||
Init(std::forward<M>(m));
|
||||
}
|
||||
|
||||
|
||||
10
external/fmt/test/mock-allocator.h
vendored
10
external/fmt/test/mock-allocator.h
vendored
@@ -20,6 +20,16 @@ template <typename T> class mock_allocator {
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
template <typename U> struct rebind {
|
||||
using other = mock_allocator<U>;
|
||||
};
|
||||
|
||||
mock_allocator() {}
|
||||
mock_allocator(const mock_allocator&) {}
|
||||
|
||||
|
||||
55
external/fmt/test/os-test.cc
vendored
55
external/fmt/test/os-test.cc
vendored
@@ -18,6 +18,10 @@ using fmt::buffered_file;
|
||||
using testing::HasSubstr;
|
||||
using wstring_view = fmt::basic_string_view<wchar_t>;
|
||||
|
||||
static std::string uniq_file_name(unsigned line_number) {
|
||||
return "test-file" + std::to_string(line_number);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
# include <windows.h>
|
||||
@@ -232,68 +236,75 @@ TEST(buffered_file_test, descriptor) {
|
||||
}
|
||||
|
||||
TEST(ostream_test, move) {
|
||||
fmt::ostream out = fmt::output_file("test-file");
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
fmt::ostream out = fmt::output_file(test_file);
|
||||
fmt::ostream moved(std::move(out));
|
||||
moved.print("hello");
|
||||
}
|
||||
|
||||
TEST(ostream_test, move_while_holding_data) {
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
{
|
||||
fmt::ostream out = fmt::output_file("test-file");
|
||||
fmt::ostream out = fmt::output_file(test_file);
|
||||
out.print("Hello, ");
|
||||
fmt::ostream moved(std::move(out));
|
||||
moved.print("world!\n");
|
||||
}
|
||||
{
|
||||
file in("test-file", file::RDONLY);
|
||||
file in(test_file, file::RDONLY);
|
||||
EXPECT_READ(in, "Hello, world!\n");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ostream_test, print) {
|
||||
fmt::ostream out = fmt::output_file("test-file");
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
fmt::ostream out = fmt::output_file(test_file);
|
||||
out.print("The answer is {}.\n", 42);
|
||||
out.close();
|
||||
file in("test-file", file::RDONLY);
|
||||
file in(test_file, file::RDONLY);
|
||||
EXPECT_READ(in, "The answer is 42.\n");
|
||||
}
|
||||
|
||||
TEST(ostream_test, buffer_boundary) {
|
||||
auto str = std::string(4096, 'x');
|
||||
fmt::ostream out = fmt::output_file("test-file");
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
fmt::ostream out = fmt::output_file(test_file);
|
||||
out.print("{}", str);
|
||||
out.print("{}", str);
|
||||
out.close();
|
||||
file in("test-file", file::RDONLY);
|
||||
file in(test_file, file::RDONLY);
|
||||
EXPECT_READ(in, str + str);
|
||||
}
|
||||
|
||||
TEST(ostream_test, buffer_size) {
|
||||
fmt::ostream out = fmt::output_file("test-file", fmt::buffer_size = 1);
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
fmt::ostream out = fmt::output_file(test_file, fmt::buffer_size = 1);
|
||||
out.print("{}", "foo");
|
||||
out.close();
|
||||
file in("test-file", file::RDONLY);
|
||||
file in(test_file, file::RDONLY);
|
||||
EXPECT_READ(in, "foo");
|
||||
}
|
||||
|
||||
TEST(ostream_test, truncate) {
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
{
|
||||
fmt::ostream out = fmt::output_file("test-file");
|
||||
fmt::ostream out = fmt::output_file(test_file);
|
||||
out.print("0123456789");
|
||||
}
|
||||
{
|
||||
fmt::ostream out = fmt::output_file("test-file");
|
||||
fmt::ostream out = fmt::output_file(test_file);
|
||||
out.print("foo");
|
||||
}
|
||||
file in("test-file", file::RDONLY);
|
||||
file in(test_file, file::RDONLY);
|
||||
EXPECT_EQ("foo", read(in, 4));
|
||||
}
|
||||
|
||||
TEST(ostream_test, flush) {
|
||||
auto out = fmt::output_file("test-file");
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
auto out = fmt::output_file(test_file);
|
||||
out.print("x");
|
||||
out.flush();
|
||||
auto in = fmt::file("test-file", file::RDONLY);
|
||||
auto in = fmt::file(test_file, file::RDONLY);
|
||||
EXPECT_READ(in, "x");
|
||||
}
|
||||
|
||||
@@ -303,10 +314,11 @@ TEST(file_test, default_ctor) {
|
||||
}
|
||||
|
||||
TEST(file_test, open_buffered_file_in_ctor) {
|
||||
FILE* fp = safe_fopen("test-file", "w");
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
FILE* fp = safe_fopen(test_file.c_str(), "w");
|
||||
std::fputs(file_content, fp);
|
||||
std::fclose(fp);
|
||||
file f("test-file", file::RDONLY);
|
||||
file f(test_file.c_str(), file::RDONLY);
|
||||
// Check if the file is open by reading one character from it.
|
||||
char buffer;
|
||||
bool isopen = FMT_POSIX(read(f.descriptor(), &buffer, 1)) == 1;
|
||||
@@ -417,7 +429,8 @@ TEST(file_test, read) {
|
||||
}
|
||||
|
||||
TEST(file_test, read_error) {
|
||||
file f("test-file", file::WRONLY);
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
file f(test_file, file::WRONLY | file::CREATE);
|
||||
char buf;
|
||||
// We intentionally read from a file opened in the write-only mode to
|
||||
// cause error.
|
||||
@@ -426,13 +439,15 @@ TEST(file_test, read_error) {
|
||||
|
||||
TEST(file_test, write) {
|
||||
auto pipe = fmt::pipe();
|
||||
write(pipe.write_end, "test");
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
write(pipe.write_end, test_file);
|
||||
pipe.write_end.close();
|
||||
EXPECT_READ(pipe.read_end, "test");
|
||||
EXPECT_READ(pipe.read_end, test_file);
|
||||
}
|
||||
|
||||
TEST(file_test, write_error) {
|
||||
file f("test-file", file::RDONLY);
|
||||
auto test_file = uniq_file_name(__LINE__);
|
||||
file f(test_file, file::RDONLY | file::CREATE);
|
||||
// We intentionally write to a file opened in the read-only mode to
|
||||
// cause error.
|
||||
EXPECT_SYSTEM_ERROR(f.write(" ", 1), EBADF, "cannot write to file");
|
||||
|
||||
25
external/fmt/test/perf-sanity.cc
vendored
Normal file
25
external/fmt/test/perf-sanity.cc
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// A quick and dirty performance test.
|
||||
// For actual benchmarks see https://github.com/fmtlib/format-benchmark.
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <iterator>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
int main() {
|
||||
const int n = 10000000;
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
for (int iteration = 0; iteration < n; ++iteration) {
|
||||
auto buf = fmt::memory_buffer();
|
||||
fmt::format_to(std::back_inserter(buf),
|
||||
"Hello, {}. The answer is {} and {}.", 1, 2345, 6789);
|
||||
}
|
||||
std::atomic_signal_fence(std::memory_order_acq_rel); // Clobber memory.
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
|
||||
// Print time in milliseconds.
|
||||
std::chrono::duration<double> duration = end - start;
|
||||
fmt::print("{:.1f}\n", duration.count() * 1000);
|
||||
}
|
||||
4
external/fmt/test/printf-test.cc
vendored
4
external/fmt/test/printf-test.cc
vendored
@@ -6,6 +6,10 @@
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/printf.h"
|
||||
// include <format> if possible for https://github.com/fmtlib/fmt/pull/4042
|
||||
#if FMT_HAS_INCLUDE(<format>) && FMT_CPLUSPLUS > 201703L
|
||||
# include <format>
|
||||
#endif
|
||||
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
|
||||
199
external/fmt/test/ranges-test.cc
vendored
199
external/fmt/test/ranges-test.cc
vendored
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "fmt/ranges.h"
|
||||
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
@@ -16,7 +17,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if FMT_HAS_INCLUDE(<ranges>)
|
||||
#if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<ranges>)
|
||||
# include <ranges>
|
||||
#endif
|
||||
|
||||
@@ -58,8 +59,13 @@ TEST(ranges_test, format_vector) {
|
||||
EXPECT_EQ(fmt::format("{:n:#x}", v), "0x1, 0x2, 0x3, 0x5, 0x7, 0xb");
|
||||
|
||||
auto vc = std::vector<char>{'a', 'b', 'c'};
|
||||
auto vec = std::vector<char>{'a', '\n', '\t'};
|
||||
auto vvc = std::vector<std::vector<char>>{vc, vc};
|
||||
EXPECT_EQ(fmt::format("{}", vc), "['a', 'b', 'c']");
|
||||
EXPECT_EQ(fmt::format("{:s}", vc), "\"abc\"");
|
||||
EXPECT_EQ(fmt::format("{:?s}", vec), "\"a\\n\\t\"");
|
||||
EXPECT_EQ(fmt::format("{:s}", vec), "\"a\n\t\"");
|
||||
EXPECT_EQ(fmt::format("{::s}", vvc), "[\"abc\", \"abc\"]");
|
||||
EXPECT_EQ(fmt::format("{}", vvc), "[['a', 'b', 'c'], ['a', 'b', 'c']]");
|
||||
EXPECT_EQ(fmt::format("{:n}", vvc), "['a', 'b', 'c'], ['a', 'b', 'c']");
|
||||
EXPECT_EQ(fmt::format("{:n:n}", vvc), "'a', 'b', 'c', 'a', 'b', 'c'");
|
||||
@@ -84,6 +90,35 @@ TEST(ranges_test, format_map) {
|
||||
EXPECT_EQ(fmt::format("{:n}", m), "\"one\": 1, \"two\": 2");
|
||||
}
|
||||
|
||||
struct test_map_value {};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<test_map_value> : formatter<string_view> {
|
||||
auto format(test_map_value, format_context& ctx) const
|
||||
-> format_context::iterator {
|
||||
return formatter<string_view>::format("foo", ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K>
|
||||
struct formatter<std::pair<K, test_map_value>> : formatter<string_view> {
|
||||
auto format(std::pair<K, test_map_value>, format_context& ctx) const
|
||||
-> format_context::iterator {
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K>
|
||||
struct is_tuple_formattable<std::pair<K, test_map_value>, char>
|
||||
: std::false_type {};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(ranges_test, format_map_custom_pair) {
|
||||
EXPECT_EQ(fmt::format("{}", std::map<int, test_map_value>{{42, {}}}),
|
||||
"{42: \"foo\"}");
|
||||
}
|
||||
|
||||
TEST(ranges_test, format_set) {
|
||||
EXPECT_EQ(fmt::format("{}", std::set<std::string>{"one", "two"}),
|
||||
"{\"one\", \"two\"}");
|
||||
@@ -135,6 +170,8 @@ TEST(ranges_test, format_adl_begin_end) {
|
||||
TEST(ranges_test, format_pair) {
|
||||
auto p = std::pair<int, float>(42, 1.5f);
|
||||
EXPECT_EQ(fmt::format("{}", p), "(42, 1.5)");
|
||||
EXPECT_EQ(fmt::format("{:}", p), "(42, 1.5)");
|
||||
EXPECT_EQ(fmt::format("{:n}", p), "421.5");
|
||||
}
|
||||
|
||||
struct unformattable {};
|
||||
@@ -143,6 +180,7 @@ TEST(ranges_test, format_tuple) {
|
||||
auto t =
|
||||
std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i');
|
||||
EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')");
|
||||
EXPECT_EQ(fmt::format("{:n}", t), "421.5\"this is tuple\"'i'");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()");
|
||||
|
||||
@@ -233,6 +271,33 @@ TEST(ranges_test, disabled_range_formatting_of_path) {
|
||||
fmt::range_format::disabled);
|
||||
}
|
||||
|
||||
struct vector_string : std::vector<char> {
|
||||
using base = std::vector<char>;
|
||||
using base::base;
|
||||
};
|
||||
struct vector_debug_string : std::vector<char> {
|
||||
using base = std::vector<char>;
|
||||
using base::base;
|
||||
};
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <>
|
||||
struct range_format_kind<vector_string, char>
|
||||
: std::integral_constant<range_format, range_format::string> {};
|
||||
template <>
|
||||
struct range_format_kind<vector_debug_string, char>
|
||||
: std::integral_constant<range_format, range_format::debug_string> {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(ranges_test, range_format_string) {
|
||||
const vector_string v{'f', 'o', 'o'};
|
||||
EXPECT_EQ(fmt::format("{}", v), "foo");
|
||||
}
|
||||
|
||||
TEST(ranges_test, range_format_debug_string) {
|
||||
const vector_debug_string v{'f', 'o', 'o'};
|
||||
EXPECT_EQ(fmt::format("{}", v), "\"foo\"");
|
||||
}
|
||||
|
||||
// A range that provides non-const only begin()/end() to test fmt::join
|
||||
// handles that.
|
||||
//
|
||||
@@ -298,8 +363,7 @@ TEST(ranges_test, enum_range) {
|
||||
|
||||
#if !FMT_MSC_VERSION
|
||||
TEST(ranges_test, unformattable_range) {
|
||||
EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>,
|
||||
fmt::format_context>::value));
|
||||
EXPECT_FALSE((fmt::is_formattable<std::vector<unformattable>, char>::value));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -457,23 +521,21 @@ TEST(ranges_test, join_range) {
|
||||
}
|
||||
|
||||
namespace adl {
|
||||
struct vec : std::vector<int> {
|
||||
using std::vector<int>::vector; // inherit all constructors
|
||||
struct vec {
|
||||
int n[2] = {42, 43};
|
||||
};
|
||||
|
||||
// ADL-found begin() and end() skip the first and last element
|
||||
auto begin(vec& v) -> typename vec::iterator { return v.begin() + 1; }
|
||||
auto end(vec& v) -> typename vec::iterator { return v.end() - 1; }
|
||||
}
|
||||
auto begin(const vec& v) -> const int* { return v.n; }
|
||||
auto end(const vec& v) -> const int* { return v.n + 2; }
|
||||
} // namespace adl
|
||||
|
||||
TEST(ranges_test, format_join_adl_begin_end) {
|
||||
auto v = adl::vec{41, 42, 43, 44};
|
||||
EXPECT_EQ(fmt::format("{}", fmt::join(v, "/")), "42/43");
|
||||
EXPECT_EQ(fmt::format("{}", fmt::join(adl::vec(), "/")), "42/43");
|
||||
}
|
||||
|
||||
#endif // FMT_RANGES_TEST_ENABLE_JOIN
|
||||
|
||||
#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 202302L
|
||||
#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 202207L
|
||||
TEST(ranges_test, nested_ranges) {
|
||||
auto l = std::list{1, 2, 3};
|
||||
auto r = std::views::iota(0, 3) | std::views::transform([&l](auto i) {
|
||||
@@ -498,7 +560,7 @@ TEST(ranges_test, escape) {
|
||||
EXPECT_EQ(fmt::format("{}", vec{"\x7f"}), "[\"\\x7f\"]");
|
||||
EXPECT_EQ(fmt::format("{}", vec{"n\xcc\x83"}), "[\"n\xcc\x83\"]");
|
||||
|
||||
if (fmt::detail::is_utf8()) {
|
||||
if (fmt::detail::use_utf8) {
|
||||
EXPECT_EQ(fmt::format("{}", vec{"\xcd\xb8"}), "[\"\\u0378\"]");
|
||||
// Unassigned Unicode code points.
|
||||
EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]");
|
||||
@@ -516,7 +578,11 @@ TEST(ranges_test, escape) {
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", std::vector<std::vector<char>>{{'x'}}),
|
||||
"[['x']]");
|
||||
|
||||
// Disabled due to a clang 17 bug: https://github.com/fmtlib/fmt/issues/4144.
|
||||
#if FMT_CLANG_VERSION >= 1800
|
||||
EXPECT_EQ(fmt::format("{}", std::tuple<std::vector<char>>{{'x'}}), "(['x'])");
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename R> struct fmt_ref_view {
|
||||
@@ -620,3 +686,110 @@ struct lvalue_qualified_begin_end {
|
||||
TEST(ranges_test, lvalue_qualified_begin_end) {
|
||||
EXPECT_EQ(fmt::format("{}", lvalue_qualified_begin_end{}), "[1, 2, 3, 4, 5]");
|
||||
}
|
||||
|
||||
#if !defined(__cpp_lib_ranges) || __cpp_lib_ranges <= 202106L
|
||||
# define ENABLE_STD_VIEWS_TESTS 0
|
||||
#elif FMT_CLANG_VERSION
|
||||
# if FMT_CLANG_VERSION > 1500
|
||||
# define ENABLE_STD_VIEWS_TESTS 1
|
||||
# else
|
||||
# define ENABLE_STD_VIEWS_TESTS 0
|
||||
# endif
|
||||
#else
|
||||
# define ENABLE_STD_VIEWS_TESTS 1
|
||||
#endif
|
||||
|
||||
#if ENABLE_STD_VIEWS_TESTS
|
||||
TEST(ranges_test, input_range_join) {
|
||||
auto iss = std::istringstream("1 2 3 4 5");
|
||||
auto view = std::views::istream<std::string>(iss);
|
||||
EXPECT_EQ("1, 2, 3, 4, 5",
|
||||
fmt::format("{}", fmt::join(view.begin(), view.end(), ", ")));
|
||||
}
|
||||
|
||||
TEST(ranges_test, input_range_join_overload) {
|
||||
auto iss = std::istringstream("1 2 3 4 5");
|
||||
EXPECT_EQ(
|
||||
"1.2.3.4.5",
|
||||
fmt::format("{}", fmt::join(std::views::istream<std::string>(iss), ".")));
|
||||
}
|
||||
|
||||
namespace views_filter_view_test {
|
||||
struct codec_mask {
|
||||
static constexpr auto codecs = std::array{0, 1, 2, 3};
|
||||
int except = 0;
|
||||
};
|
||||
|
||||
auto format_as(codec_mask mask) {
|
||||
// Careful not to capture param by reference here, it will dangle.
|
||||
return codec_mask::codecs |
|
||||
std::views::filter([mask](auto c) { return c != mask.except; });
|
||||
}
|
||||
} // namespace views_filter_view_test
|
||||
|
||||
TEST(ranges_test, format_as_with_ranges_mutable_begin_end) {
|
||||
using namespace views_filter_view_test;
|
||||
{
|
||||
auto make_filter_view = []() {
|
||||
return codec_mask::codecs |
|
||||
std::views::filter([](auto c) { return c != 2; });
|
||||
};
|
||||
auto r = make_filter_view();
|
||||
EXPECT_EQ("[0, 1, 3]", fmt::format("{}", r));
|
||||
EXPECT_EQ("[0, 1, 3]", fmt::format("{}", make_filter_view()));
|
||||
}
|
||||
|
||||
{
|
||||
auto mask = codec_mask{2};
|
||||
const auto const_mask = codec_mask{2};
|
||||
|
||||
EXPECT_EQ("[0, 1, 3]", fmt::format("{}", mask));
|
||||
EXPECT_EQ("[0, 1, 3]", fmt::format("{}", const_mask));
|
||||
EXPECT_EQ("[0, 1, 3]", fmt::format("{}", codec_mask{2}));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST(ranges_test, std_istream_iterator_join) {
|
||||
auto&& iss = std::istringstream("1 2 3 4 5");
|
||||
auto first = std::istream_iterator<int>(iss);
|
||||
auto last = std::istream_iterator<int>();
|
||||
EXPECT_EQ("1, 2, 3, 4, 5", fmt::format("{}", fmt::join(first, last, ", ")));
|
||||
}
|
||||
|
||||
// Mirrors C++20 std::ranges::basic_istream_view::iterator.
|
||||
struct noncopyable_istream_iterator : std::istream_iterator<int> {
|
||||
using base = std::istream_iterator<int>;
|
||||
explicit noncopyable_istream_iterator(std::istringstream& iss) : base{iss} {}
|
||||
noncopyable_istream_iterator(const noncopyable_istream_iterator&) = delete;
|
||||
noncopyable_istream_iterator(noncopyable_istream_iterator&&) = default;
|
||||
};
|
||||
static_assert(!std::is_copy_constructible<noncopyable_istream_iterator>::value,
|
||||
"");
|
||||
|
||||
TEST(ranges_test, movable_only_istream_iter_join) {
|
||||
auto&& iss = std::istringstream("1 2 3 4 5");
|
||||
auto first = noncopyable_istream_iterator(iss);
|
||||
auto last = std::istream_iterator<int>();
|
||||
EXPECT_EQ("1, 2, 3, 4, 5",
|
||||
fmt::format("{}", fmt::join(std::move(first), last, ", ")));
|
||||
}
|
||||
|
||||
struct movable_iter_range {
|
||||
std::istringstream iss{"1 2 3 4 5"};
|
||||
noncopyable_istream_iterator begin() {
|
||||
return noncopyable_istream_iterator{iss};
|
||||
}
|
||||
std::istream_iterator<int> end() { return {}; }
|
||||
};
|
||||
|
||||
TEST(ranges_test, movable_only_istream_iter_join2) {
|
||||
EXPECT_EQ("[1, 2, 3, 4, 5]", fmt::format("{}", movable_iter_range{}));
|
||||
}
|
||||
|
||||
struct not_range {
|
||||
void begin() const {}
|
||||
void end() const {}
|
||||
};
|
||||
static_assert(!fmt::is_formattable<not_range>{}, "");
|
||||
|
||||
25
external/fmt/test/scan-test.cc
vendored
25
external/fmt/test/scan-test.cc
vendored
@@ -110,12 +110,27 @@ TEST(scan_test, invalid_format) {
|
||||
"invalid format string");
|
||||
}
|
||||
|
||||
namespace std {
|
||||
using fmt::scan;
|
||||
using fmt::scan_error;
|
||||
} // namespace std
|
||||
|
||||
TEST(scan_test, example) {
|
||||
std::string key;
|
||||
int value = 0;
|
||||
fmt::scan_to("answer = 42", "{} = {}", key, value);
|
||||
EXPECT_EQ(key, "answer");
|
||||
EXPECT_EQ(value, 42);
|
||||
// Example from https://wg21.link/p1729r3.
|
||||
if (auto result = std::scan<std::string, int>("answer = 42", "{} = {}")) {
|
||||
auto range = result->range();
|
||||
EXPECT_EQ(range.begin(), range.end());
|
||||
EXPECT_EQ(result->begin(), result->end());
|
||||
#ifdef __cpp_structured_bindings
|
||||
const auto& [key, value] = result->values();
|
||||
EXPECT_EQ(key, "answer");
|
||||
EXPECT_EQ(value, 42);
|
||||
#endif
|
||||
} else {
|
||||
std::scan_error error = result.error();
|
||||
(void)error;
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(scan_test, end_of_input) { fmt::scan<int>("", "{}"); }
|
||||
|
||||
86
external/fmt/test/scan.h
vendored
86
external/fmt/test/scan.h
vendored
@@ -10,7 +10,7 @@
|
||||
#include <climits>
|
||||
#include <tuple>
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/format-inl.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
@@ -142,7 +142,7 @@ class scan_buffer {
|
||||
using scan_iterator = scan_buffer::iterator;
|
||||
using scan_sentinel = scan_buffer::sentinel;
|
||||
|
||||
class string_scan_buffer : public scan_buffer {
|
||||
class string_scan_buffer final : public scan_buffer {
|
||||
private:
|
||||
void consume() override {}
|
||||
|
||||
@@ -151,13 +151,15 @@ class string_scan_buffer : public scan_buffer {
|
||||
: scan_buffer(s.begin(), s.end(), true) {}
|
||||
};
|
||||
|
||||
class file_scan_buffer : public scan_buffer {
|
||||
class file_scan_buffer final : public scan_buffer {
|
||||
private:
|
||||
template <typename F, FMT_ENABLE_IF(sizeof(F::_IO_read_ptr) != 0)>
|
||||
template <typename F, FMT_ENABLE_IF(sizeof(F::_IO_read_ptr) != 0 &&
|
||||
!FMT_USE_FALLBACK_FILE)>
|
||||
static auto get_file(F* f, int) -> glibc_file<F> {
|
||||
return f;
|
||||
}
|
||||
template <typename F, FMT_ENABLE_IF(sizeof(F::_p) != 0)>
|
||||
template <typename F,
|
||||
FMT_ENABLE_IF(sizeof(F::_p) != 0 && !FMT_USE_FALLBACK_FILE)>
|
||||
static auto get_file(F* f, int) -> apple_file<F> {
|
||||
return f;
|
||||
}
|
||||
@@ -190,7 +192,10 @@ class file_scan_buffer : public scan_buffer {
|
||||
flockfile(f);
|
||||
fill();
|
||||
}
|
||||
~file_scan_buffer() { funlockfile(file_); }
|
||||
~file_scan_buffer() {
|
||||
FILE* f = file_;
|
||||
funlockfile(f);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
@@ -363,7 +368,7 @@ const char* parse_scan_specs(const char* begin, const char* end,
|
||||
switch (to_ascii(*begin)) {
|
||||
// TODO: parse more scan format specifiers
|
||||
case 'x':
|
||||
specs.type = presentation_type::hex;
|
||||
specs.set_type(presentation_type::hex);
|
||||
++begin;
|
||||
break;
|
||||
case '}':
|
||||
@@ -432,7 +437,7 @@ auto read_hex(scan_iterator it, T& value) -> scan_iterator {
|
||||
template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
|
||||
auto read(scan_iterator it, T& value, const format_specs& specs)
|
||||
-> scan_iterator {
|
||||
if (specs.type == presentation_type::hex) return read_hex(it, value);
|
||||
if (specs.type() == presentation_type::hex) return read_hex(it, value);
|
||||
return read(it, value);
|
||||
}
|
||||
|
||||
@@ -548,47 +553,80 @@ struct scan_handler {
|
||||
return begin;
|
||||
}
|
||||
|
||||
void on_error(const char* message) { report_error(message); }
|
||||
FMT_NORETURN void on_error(const char* message) { report_error(message); }
|
||||
};
|
||||
|
||||
void vscan(detail::scan_buffer& buf, string_view fmt, scan_args args) {
|
||||
auto h = detail::scan_handler(fmt, buf, args);
|
||||
detail::parse_format_string<false>(fmt, h);
|
||||
detail::parse_format_string(fmt, h);
|
||||
}
|
||||
|
||||
template <size_t I, typename... T, FMT_ENABLE_IF(I == sizeof...(T))>
|
||||
void make_args(std::array<scan_arg, sizeof...(T)>&, std::tuple<T...>&) {}
|
||||
|
||||
template <size_t I, typename... T, FMT_ENABLE_IF(I < sizeof...(T))>
|
||||
void make_args(std::array<scan_arg, sizeof...(T)>& args,
|
||||
std::tuple<T...>& values) {
|
||||
using element_type = typename std::tuple_element<I, std::tuple<T...>>::type;
|
||||
static_assert(std::is_same<remove_cvref_t<element_type>, element_type>::value,
|
||||
"");
|
||||
args[I] = std::get<I>(values);
|
||||
make_args<I + 1>(args, values);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename... T>
|
||||
auto make_scan_args(T&... args) -> std::array<scan_arg, sizeof...(T)> {
|
||||
return {{args...}};
|
||||
}
|
||||
|
||||
template <typename... T> class scan_data {
|
||||
template <typename Range, typename... T> class scan_data {
|
||||
private:
|
||||
std::tuple<T...> values_;
|
||||
Range range_;
|
||||
|
||||
public:
|
||||
scan_data() = default;
|
||||
scan_data(T... values) : values_(std::move(values)...) {}
|
||||
|
||||
auto value() const -> decltype(std::get<0>(values_)) {
|
||||
return std::get<0>(values_);
|
||||
}
|
||||
|
||||
auto values() const -> const std::tuple<T...>& { return values_; }
|
||||
|
||||
auto make_args() -> std::array<scan_arg, sizeof...(T)> {
|
||||
auto args = std::array<scan_arg, sizeof...(T)>();
|
||||
detail::make_args<0>(args, values_);
|
||||
return args;
|
||||
}
|
||||
|
||||
auto range() const -> Range { return range_; }
|
||||
|
||||
auto begin() const -> decltype(range_.begin()) { return range_.begin(); }
|
||||
auto end() const -> decltype(range_.end()) { return range_.end(); }
|
||||
};
|
||||
|
||||
template <typename... T>
|
||||
auto make_scan_args(T&... args) -> std::array<scan_arg, sizeof...(T)> {
|
||||
return {{args...}};
|
||||
}
|
||||
|
||||
class scan_error {};
|
||||
|
||||
// A rudimentary version of std::expected for testing the API shape.
|
||||
template <typename T, typename E> class expected {
|
||||
private:
|
||||
T value_;
|
||||
bool has_value_ = true;
|
||||
|
||||
public:
|
||||
expected(T value) : value_(std::move(value)) {}
|
||||
|
||||
explicit operator bool() const { return has_value_; }
|
||||
|
||||
auto operator->() const -> const T* { return &value_; }
|
||||
|
||||
auto error() -> E const { return E(); }
|
||||
};
|
||||
|
||||
template <typename... T>
|
||||
using scan_result = expected<scan_data<T...>, scan_error>;
|
||||
template <typename Range, typename... T>
|
||||
using scan_result = expected<scan_data<Range, T...>, scan_error>;
|
||||
|
||||
auto vscan(string_view input, string_view fmt, scan_args args)
|
||||
-> string_view::iterator {
|
||||
@@ -604,12 +642,12 @@ auto scan_to(string_view input, string_view fmt, T&... args)
|
||||
return vscan(input, fmt, make_scan_args(args...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto scan(string_view input, string_view fmt) -> scan_result<T> {
|
||||
static_assert(std::is_same<remove_cvref_t<T>, T>::value, "");
|
||||
auto value = T();
|
||||
scan_to(input, fmt, value);
|
||||
return scan_data<T>(std::move(value));
|
||||
template <typename... T>
|
||||
auto scan(string_view input, string_view fmt)
|
||||
-> scan_result<string_view, T...> {
|
||||
auto data = scan_data<string_view, T...>();
|
||||
vscan(input, fmt, data.make_args());
|
||||
return data;
|
||||
}
|
||||
|
||||
template <typename Range, typename... T,
|
||||
|
||||
86
external/fmt/test/std-test.cc
vendored
86
external/fmt/test/std-test.cc
vendored
@@ -35,6 +35,11 @@ TEST(std_test, path) {
|
||||
L"\x0447\x044B\x043D\x0430")),
|
||||
"Шчучыншчына");
|
||||
EXPECT_EQ(fmt::format("{}", path(L"\xd800")), "<EFBFBD>");
|
||||
EXPECT_EQ(fmt::format("{}", path(L"HEAD \xd800 TAIL")), "HEAD <20> TAIL");
|
||||
EXPECT_EQ(fmt::format("{}", path(L"HEAD \xD83D\xDE00 TAIL")),
|
||||
"HEAD \xF0\x9F\x98\x80 TAIL");
|
||||
EXPECT_EQ(fmt::format("{}", path(L"HEAD \xD83D\xD83D\xDE00 TAIL")),
|
||||
"HEAD <20>\xF0\x9F\x98\x80 TAIL");
|
||||
EXPECT_EQ(fmt::format("{:?}", path(L"\xd800")), "\"\\ud800\"");
|
||||
# endif
|
||||
}
|
||||
@@ -65,6 +70,37 @@ TEST(std_test, thread_id) {
|
||||
EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty());
|
||||
}
|
||||
|
||||
TEST(std_test, complex) {
|
||||
using limits = std::numeric_limits<double>;
|
||||
EXPECT_EQ(fmt::format("{}", std::complex<double>(1, limits::quiet_NaN())),
|
||||
"(1+nan i)");
|
||||
EXPECT_EQ(fmt::format("{}", std::complex<double>(1, -limits::infinity())),
|
||||
"(1-inf i)");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", std::complex<int>(1, 2)), "(1+2i)");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", std::complex<double>(1, 2.2)), "(1+2.2i)");
|
||||
EXPECT_EQ(fmt::format("{}", std::complex<double>(1, -2.2)), "(1-2.2i)");
|
||||
EXPECT_EQ(fmt::format("{}", std::complex<double>(0, 2.2)), "2.2i");
|
||||
EXPECT_EQ(fmt::format("{}", std::complex<double>(0, -2.2)), "-2.2i");
|
||||
|
||||
EXPECT_EQ(fmt::format("{:+}", std::complex<double>(0, 2.2)), "+2.2i");
|
||||
EXPECT_EQ(fmt::format("{:+}", std::complex<double>(0, -2.2)), "-2.2i");
|
||||
EXPECT_EQ(fmt::format("{:+}", std::complex<double>(1, -2.2)), "(+1-2.2i)");
|
||||
EXPECT_EQ(fmt::format("{:+}", std::complex<double>(1, 2.2)), "(+1+2.2i)");
|
||||
EXPECT_EQ(fmt::format("{: }", std::complex<double>(1, 2.2)), "( 1+2.2i)");
|
||||
EXPECT_EQ(fmt::format("{: }", std::complex<double>(1, -2.2)), "( 1-2.2i)");
|
||||
|
||||
EXPECT_EQ(fmt::format("{:>20.2f}", std::complex<double>(1, 2.2)),
|
||||
" (1.00+2.20i)");
|
||||
EXPECT_EQ(fmt::format("{:<20.2f}", std::complex<double>(1, 2.2)),
|
||||
"(1.00+2.20i) ");
|
||||
EXPECT_EQ(fmt::format("{:<20.2f}", std::complex<double>(1, -2.2)),
|
||||
"(1.00-2.20i) ");
|
||||
EXPECT_EQ(fmt::format("{:<{}.{}f}", std::complex<double>(1, -2.2), 20, 2),
|
||||
"(1.00-2.20i) ");
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_source_location
|
||||
TEST(std_test, source_location) {
|
||||
std::source_location loc = std::source_location::current();
|
||||
@@ -102,6 +138,36 @@ TEST(std_test, optional) {
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(std_test, expected) {
|
||||
#ifdef __cpp_lib_expected
|
||||
EXPECT_EQ(fmt::format("{}", std::expected<void, int>{}), "expected()");
|
||||
EXPECT_EQ(fmt::format("{}", std::expected<int, int>{1}), "expected(1)");
|
||||
EXPECT_EQ(fmt::format("{}", std::expected<int, int>{std::unexpected(1)}),
|
||||
"unexpected(1)");
|
||||
EXPECT_EQ(fmt::format("{}", std::expected<std::string, int>{"test"}),
|
||||
"expected(\"test\")");
|
||||
EXPECT_EQ(fmt::format(
|
||||
"{}", std::expected<int, std::string>{std::unexpected("test")}),
|
||||
"unexpected(\"test\")");
|
||||
EXPECT_EQ(fmt::format("{}", std::expected<char, int>{'a'}), "expected('a')");
|
||||
EXPECT_EQ(fmt::format("{}", std::expected<int, char>{std::unexpected('a')}),
|
||||
"unexpected('a')");
|
||||
|
||||
struct unformattable1 {};
|
||||
struct unformattable2 {};
|
||||
EXPECT_FALSE((fmt::is_formattable<unformattable1>::value));
|
||||
EXPECT_FALSE((fmt::is_formattable<unformattable2>::value));
|
||||
EXPECT_FALSE((fmt::is_formattable<
|
||||
std::expected<unformattable1, unformattable2>>::value));
|
||||
EXPECT_FALSE(
|
||||
(fmt::is_formattable<std::expected<unformattable1, int>>::value));
|
||||
EXPECT_FALSE(
|
||||
(fmt::is_formattable<std::expected<int, unformattable2>>::value));
|
||||
EXPECT_TRUE((fmt::is_formattable<std::expected<int, int>>::value));
|
||||
EXPECT_TRUE((fmt::is_formattable<std::expected<void, int>>::value));
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace my_nso {
|
||||
enum class my_number {
|
||||
one,
|
||||
@@ -199,9 +265,13 @@ TEST(std_test, variant) {
|
||||
}
|
||||
|
||||
TEST(std_test, error_code) {
|
||||
auto& generic = std::generic_category();
|
||||
EXPECT_EQ("generic:42",
|
||||
fmt::format(FMT_STRING("{0}"),
|
||||
std::error_code(42, std::generic_category())));
|
||||
fmt::format(FMT_STRING("{0}"), std::error_code(42, generic)));
|
||||
EXPECT_EQ(" generic:42",
|
||||
fmt::format(FMT_STRING("{:>12}"), std::error_code(42, generic)));
|
||||
EXPECT_EQ("generic:42 ",
|
||||
fmt::format(FMT_STRING("{:12}"), std::error_code(42, generic)));
|
||||
EXPECT_EQ("system:42",
|
||||
fmt::format(FMT_STRING("{0}"),
|
||||
std::error_code(42, fmt::system_category())));
|
||||
@@ -265,6 +335,13 @@ TEST(std_test, exception) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
TEST(std_test, type_info) {
|
||||
EXPECT_EQ(fmt::format("{}", typeid(std::runtime_error)),
|
||||
"std::runtime_error");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(std_test, format_bit_reference) {
|
||||
std::bitset<2> bs(1);
|
||||
EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false");
|
||||
@@ -322,3 +399,8 @@ TEST(std_test, format_shared_ptr) {
|
||||
EXPECT_EQ(fmt::format("{}", fmt::ptr(sp.get())),
|
||||
fmt::format("{}", fmt::ptr(sp)));
|
||||
}
|
||||
|
||||
TEST(std_test, format_reference_wrapper) {
|
||||
int num = 35;
|
||||
EXPECT_EQ("35", fmt::to_string(std::cref(num)));
|
||||
}
|
||||
|
||||
2
external/fmt/test/unicode-test.cc
vendored
2
external/fmt/test/unicode-test.cc
vendored
@@ -15,7 +15,7 @@
|
||||
|
||||
using testing::Contains;
|
||||
|
||||
TEST(unicode_test, is_utf8) { EXPECT_TRUE(fmt::detail::is_utf8()); }
|
||||
TEST(unicode_test, use_utf8) { EXPECT_TRUE(fmt::detail::use_utf8); }
|
||||
|
||||
TEST(unicode_test, legacy_locale) {
|
||||
auto loc = get_locale("be_BY.CP1251", "Belarusian_Belarus.1251");
|
||||
|
||||
9
external/fmt/test/util.cc
vendored
9
external/fmt/test/util.cc
vendored
@@ -36,12 +36,11 @@ std::locale do_get_locale(const char* name) {
|
||||
|
||||
std::locale get_locale(const char* name, const char* alt_name) {
|
||||
auto loc = do_get_locale(name);
|
||||
if (loc == std::locale::classic() && alt_name)
|
||||
loc = do_get_locale(alt_name);
|
||||
if (loc == std::locale::classic() && alt_name) loc = do_get_locale(alt_name);
|
||||
#ifdef __OpenBSD__
|
||||
// Locales are not working in OpenBSD:
|
||||
// https://github.com/fmtlib/fmt/issues/3670.
|
||||
loc = std::locale::classic();
|
||||
// Locales are not working in OpenBSD:
|
||||
// https://github.com/fmtlib/fmt/issues/3670.
|
||||
loc = std::locale::classic();
|
||||
#endif
|
||||
if (loc == std::locale::classic())
|
||||
fmt::print(stderr, "{} locale is missing.\n", name);
|
||||
|
||||
163
external/fmt/test/xchar-test.cc
vendored
163
external/fmt/test/xchar-test.cc
vendored
@@ -78,7 +78,6 @@ TEST(xchar_test, format) {
|
||||
EXPECT_EQ(L"z", fmt::format(L"{}", L'z'));
|
||||
EXPECT_THROW(fmt::format(fmt::runtime(L"{:*\x343E}"), 42), fmt::format_error);
|
||||
EXPECT_EQ(L"true", fmt::format(L"{}", true));
|
||||
EXPECT_EQ(L"a", fmt::format(L"{0}", 'a'));
|
||||
EXPECT_EQ(L"a", fmt::format(L"{0}", L'a'));
|
||||
EXPECT_EQ(L"Cyrillic letter \x42e",
|
||||
fmt::format(L"Cyrillic letter {}", L'\x42e'));
|
||||
@@ -96,105 +95,18 @@ TEST(xchar_test, compile_time_string) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FMT_CPLUSPLUS > 201103L
|
||||
struct custom_char {
|
||||
int value;
|
||||
custom_char() = default;
|
||||
|
||||
template <typename T>
|
||||
constexpr custom_char(T val) : value(static_cast<int>(val)) {}
|
||||
|
||||
constexpr operator char() const {
|
||||
return value <= 0xff ? static_cast<char>(value) : '\0';
|
||||
}
|
||||
constexpr bool operator<(custom_char c) const { return value < c.value; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
|
||||
template <> struct char_traits<custom_char> {
|
||||
using char_type = custom_char;
|
||||
using int_type = int;
|
||||
using off_type = streamoff;
|
||||
using pos_type = streampos;
|
||||
using state_type = mbstate_t;
|
||||
|
||||
static constexpr void assign(char_type& r, const char_type& a) { r = a; }
|
||||
static constexpr bool eq(char_type a, char_type b) { return a == b; }
|
||||
static constexpr bool lt(char_type a, char_type b) { return a < b; }
|
||||
static FMT_CONSTEXPR int compare(const char_type* s1, const char_type* s2,
|
||||
size_t count) {
|
||||
for (; count; count--, s1++, s2++) {
|
||||
if (lt(*s1, *s2)) return -1;
|
||||
if (lt(*s2, *s1)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static FMT_CONSTEXPR size_t length(const char_type* s) {
|
||||
size_t count = 0;
|
||||
while (!eq(*s++, custom_char(0))) count++;
|
||||
return count;
|
||||
}
|
||||
static const char_type* find(const char_type*, size_t, const char_type&);
|
||||
static FMT_CONSTEXPR char_type* move(char_type* dest, const char_type* src,
|
||||
size_t count) {
|
||||
if (count == 0) return dest;
|
||||
char_type* ret = dest;
|
||||
if (src < dest) {
|
||||
dest += count;
|
||||
src += count;
|
||||
for (; count; count--) assign(*--dest, *--src);
|
||||
} else if (src > dest)
|
||||
copy(dest, src, count);
|
||||
return ret;
|
||||
}
|
||||
static FMT_CONSTEXPR char_type* copy(char_type* dest, const char_type* src,
|
||||
size_t count) {
|
||||
char_type* ret = dest;
|
||||
for (; count; count--) assign(*dest++, *src++);
|
||||
return ret;
|
||||
}
|
||||
static FMT_CONSTEXPR char_type* assign(char_type* dest, std::size_t count,
|
||||
char_type a) {
|
||||
char_type* ret = dest;
|
||||
for (; count; count--) assign(*dest++, a);
|
||||
return ret;
|
||||
}
|
||||
static int_type not_eof(int_type);
|
||||
static char_type to_char_type(int_type);
|
||||
static int_type to_int_type(char_type);
|
||||
static bool eq_int_type(int_type, int_type);
|
||||
static int_type eof();
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
auto to_ascii(custom_char c) -> char { return c; }
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct is_char<custom_char> : std::true_type {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(xchar_test, format_custom_char) {
|
||||
const custom_char format[] = {'{', '}', 0};
|
||||
auto result = fmt::format(format, custom_char('x'));
|
||||
EXPECT_EQ(result.size(), 1);
|
||||
EXPECT_EQ(result[0], custom_char('x'));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Convert a char8_t string to std::string. Otherwise GTest will insist on
|
||||
// inserting `char8_t` NTBS into a `char` stream which is disabled by P1423.
|
||||
template <typename S> std::string from_u8str(const S& str) {
|
||||
return std::string(str.begin(), str.end());
|
||||
}
|
||||
|
||||
TEST(xchar_test, format_to) {
|
||||
auto buf = std::vector<wchar_t>();
|
||||
fmt::format_to(std::back_inserter(buf), L"{}{}", 42, L'\0');
|
||||
EXPECT_STREQ(buf.data(), L"42");
|
||||
}
|
||||
|
||||
TEST(xchar_test, compile_time_string_format_to) {
|
||||
std::wstring ws;
|
||||
fmt::format_to(std::back_inserter(ws), FMT_STRING(L"{}"), 42);
|
||||
EXPECT_EQ(L"42", ws);
|
||||
}
|
||||
|
||||
TEST(xchar_test, vformat_to) {
|
||||
int n = 42;
|
||||
auto args = fmt::make_wformat_args(n);
|
||||
@@ -232,7 +144,6 @@ TEST(format_test, wide_format_to_n) {
|
||||
EXPECT_EQ(L"BC x", fmt::wstring_view(buffer, 4));
|
||||
}
|
||||
|
||||
#if FMT_USE_USER_DEFINED_LITERALS
|
||||
TEST(xchar_test, named_arg_udl) {
|
||||
using namespace fmt::literals;
|
||||
auto udl_a =
|
||||
@@ -243,7 +154,6 @@ TEST(xchar_test, named_arg_udl) {
|
||||
fmt::arg(L"second", L"cad"), fmt::arg(L"third", 99)),
|
||||
udl_a);
|
||||
}
|
||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||
|
||||
TEST(xchar_test, print) {
|
||||
// Check that the wide print overload compiles.
|
||||
@@ -517,7 +427,7 @@ TEST(locale_test, format) {
|
||||
fmt::format(small_grouping_loc, "{:L}", max_value<uint32_t>()));
|
||||
}
|
||||
|
||||
TEST(locale_test, format_detault_align) {
|
||||
TEST(locale_test, format_default_align) {
|
||||
auto loc = std::locale({}, new special_grouping<char>());
|
||||
EXPECT_EQ(" 12,345", fmt::format(loc, "{:8L}", 12345));
|
||||
}
|
||||
@@ -562,60 +472,15 @@ TEST(locale_test, int_formatter) {
|
||||
EXPECT_EQ(fmt::to_string(buf), "12,345");
|
||||
}
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <class charT> struct formatter<std::complex<double>, charT> {
|
||||
private:
|
||||
detail::dynamic_format_specs<char> specs_;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR typename basic_format_parse_context<charT>::iterator parse(
|
||||
basic_format_parse_context<charT>& ctx) {
|
||||
auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
|
||||
detail::type::float_type);
|
||||
detail::parse_float_type_spec(specs_);
|
||||
return end;
|
||||
}
|
||||
|
||||
template <class FormatContext>
|
||||
typename FormatContext::iterator format(const std::complex<double>& c,
|
||||
FormatContext& ctx) const {
|
||||
auto specs = specs_;
|
||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
||||
specs.precision, specs.precision_ref, ctx);
|
||||
auto fspecs = std::string();
|
||||
if (specs.precision > 0) fspecs = fmt::format(".{}", specs.precision);
|
||||
if (specs.type == presentation_type::fixed) fspecs += 'f';
|
||||
auto real = fmt::format(ctx.locale().template get<std::locale>(),
|
||||
fmt::runtime("{:" + fspecs + "}"), c.real());
|
||||
auto imag = fmt::format(ctx.locale().template get<std::locale>(),
|
||||
fmt::runtime("{:" + fspecs + "}"), c.imag());
|
||||
auto fill_align_width = std::string();
|
||||
if (specs.width > 0) fill_align_width = fmt::format(">{}", specs.width);
|
||||
return fmt::format_to(ctx.out(), runtime("{:" + fill_align_width + "}"),
|
||||
c.real() != 0 ? fmt::format("({}+{}i)", real, imag)
|
||||
: fmt::format("{}i", imag));
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(locale_test, complex) {
|
||||
std::string s = fmt::format("{}", std::complex<double>(1, 2));
|
||||
EXPECT_EQ(s, "(1+2i)");
|
||||
EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)");
|
||||
EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
|
||||
}
|
||||
|
||||
TEST(locale_test, chrono_weekday) {
|
||||
auto loc = get_locale("es_ES.UTF-8", "Spanish_Spain.1252");
|
||||
auto loc_old = std::locale::global(loc);
|
||||
auto sat = fmt::weekday(6);
|
||||
EXPECT_EQ(fmt::format(L"{}", sat), L"Sat");
|
||||
if (loc != std::locale::classic()) {
|
||||
// L'\xE1' is 'á'.
|
||||
auto saturdays = std::vector<std::wstring>{
|
||||
L"s\xE1"
|
||||
"b",
|
||||
L"s\xE1."};
|
||||
// L'\341' is 'á'.
|
||||
auto saturdays =
|
||||
std::vector<std::wstring>{L"s\341b", L"s\341.", L"s\341b."};
|
||||
EXPECT_THAT(saturdays, Contains(fmt::format(loc, L"{:L}", sat)));
|
||||
}
|
||||
std::locale::global(loc_old);
|
||||
@@ -625,6 +490,14 @@ TEST(locale_test, sign) {
|
||||
EXPECT_EQ(fmt::format(std::locale(), L"{:L}", -50), L"-50");
|
||||
}
|
||||
|
||||
TEST(std_test_xchar, complex) {
|
||||
auto s = fmt::format(L"{}", std::complex<double>(1, 2));
|
||||
EXPECT_EQ(s, L"(1+2i)");
|
||||
EXPECT_EQ(fmt::format(L"{:.2f}", std::complex<double>(1, 2)),
|
||||
L"(1.00+2.00i)");
|
||||
EXPECT_EQ(fmt::format(L"{:8}", std::complex<double>(1, 2)), L"(1+2i) ");
|
||||
}
|
||||
|
||||
TEST(std_test_xchar, optional) {
|
||||
# ifdef __cpp_lib_optional
|
||||
EXPECT_EQ(fmt::format(L"{}", std::optional{L'C'}), L"optional(\'C\')");
|
||||
|
||||
Reference in New Issue
Block a user