Merge commit '2abfcd02f1868bc12b5b0934101d2845c41e3cf5' into dev

This commit is contained in:
SimoneN64
2024-09-22 15:18:54 +02:00
166 changed files with 14259 additions and 22061 deletions

View File

@@ -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), "");
}