1 // Formatting library for C++ - core tests
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
9 #include "test-assert.h"
14 #include <climits> // INT_MAX
15 #include <cstring> // std::strlen
16 #include <functional> // std::equal_to
17 #include <iterator> // std::back_insert_iterator, std::distance
18 #include <limits> // std::numeric_limits
19 #include <string> // std::string
20 #include <type_traits> // std::is_same
22 #include "gmock/gmock.h"
24 using fmt::string_view
;
25 using fmt::detail::buffer
;
28 using testing::Invoke
;
29 using testing::Return
;
32 # error core-test includes format.h
35 fmt::appender
copy(fmt::string_view s
, fmt::appender out
) {
36 for (char c
: s
) *out
++ = c
;
40 TEST(string_view_test
, value_type
) {
41 static_assert(std::is_same
<string_view::value_type
, char>::value
, "");
44 TEST(string_view_test
, ctor
) {
45 EXPECT_STREQ("abc", fmt::string_view("abc").data());
46 EXPECT_EQ(3u, fmt::string_view("abc").size());
48 EXPECT_STREQ("defg", fmt::string_view(std::string("defg")).data());
49 EXPECT_EQ(4u, fmt::string_view(std::string("defg")).size());
52 TEST(string_view_test
, length
) {
53 // Test that string_view::size() returns string length, not buffer size.
54 char str
[100] = "some string";
55 EXPECT_EQ(std::strlen(str
), string_view(str
).size());
56 EXPECT_LT(std::strlen(str
), sizeof(str
));
59 // Check string_view's comparison operator.
60 template <template <typename
> class Op
> void check_op() {
61 const char* inputs
[] = {"foo", "fop", "fo"};
62 size_t num_inputs
= sizeof(inputs
) / sizeof(*inputs
);
63 for (size_t i
= 0; i
< num_inputs
; ++i
) {
64 for (size_t j
= 0; j
< num_inputs
; ++j
) {
65 string_view
lhs(inputs
[i
]), rhs(inputs
[j
]);
66 EXPECT_EQ(Op
<int>()(lhs
.compare(rhs
), 0), Op
<string_view
>()(lhs
, rhs
));
71 TEST(string_view_test
, compare
) {
72 EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0);
73 EXPECT_GT(string_view("fop").compare(string_view("foo")), 0);
74 EXPECT_LT(string_view("foo").compare(string_view("fop")), 0);
75 EXPECT_GT(string_view("foo").compare(string_view("fo")), 0);
76 EXPECT_LT(string_view("fo").compare(string_view("foo")), 0);
78 EXPECT_TRUE(string_view("foo").starts_with('f'));
79 EXPECT_FALSE(string_view("foo").starts_with('o'));
80 EXPECT_FALSE(string_view().starts_with('o'));
82 EXPECT_TRUE(string_view("foo").starts_with("fo"));
83 EXPECT_TRUE(string_view("foo").starts_with("foo"));
84 EXPECT_FALSE(string_view("foo").starts_with("fooo"));
85 EXPECT_FALSE(string_view().starts_with("fooo"));
87 check_op
<std::equal_to
>();
88 check_op
<std::not_equal_to
>();
89 check_op
<std::less
>();
90 check_op
<std::less_equal
>();
91 check_op
<std::greater
>();
92 check_op
<std::greater_equal
>();
95 TEST(base_test
, is_output_iterator
) {
96 EXPECT_TRUE((fmt::detail::is_output_iterator
<char*, char>::value
));
97 EXPECT_FALSE((fmt::detail::is_output_iterator
<const char*, char>::value
));
98 EXPECT_FALSE((fmt::detail::is_output_iterator
<std::string
, char>::value
));
100 (fmt::detail::is_output_iterator
<std::back_insert_iterator
<std::string
>,
103 (fmt::detail::is_output_iterator
<std::string::iterator
, char>::value
));
104 EXPECT_FALSE((fmt::detail::is_output_iterator
<std::string::const_iterator
,
108 TEST(base_test
, is_back_insert_iterator
) {
109 EXPECT_TRUE(fmt::detail::is_back_insert_iterator
<
110 std::back_insert_iterator
<std::string
>>::value
);
111 EXPECT_FALSE(fmt::detail::is_back_insert_iterator
<
112 std::front_insert_iterator
<std::string
>>::value
);
115 TEST(base_test
, buffer_appender
) {
116 #ifdef __cpp_lib_ranges
117 EXPECT_TRUE((std::output_iterator
<fmt::appender
, char>));
121 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
122 TEST(buffer_test
, noncopyable
) {
123 EXPECT_FALSE(std::is_copy_constructible
<buffer
<char>>::value
);
124 # if !FMT_MSC_VERSION
125 // std::is_copy_assignable is broken in MSVC2013.
126 EXPECT_FALSE(std::is_copy_assignable
<buffer
<char>>::value
);
130 TEST(buffer_test
, nonmoveable
) {
131 EXPECT_FALSE(std::is_move_constructible
<buffer
<char>>::value
);
132 # if !FMT_MSC_VERSION
133 // std::is_move_assignable is broken in MSVC2013.
134 EXPECT_FALSE(std::is_move_assignable
<buffer
<char>>::value
);
139 TEST(buffer_test
, indestructible
) {
140 static_assert(!std::is_destructible
<fmt::detail::buffer
<int>>(),
141 "buffer's destructor is protected");
144 template <typename T
> struct mock_buffer final
: buffer
<T
> {
145 MOCK_METHOD(size_t, do_grow
, (size_t));
147 static void grow(buffer
<T
>& buf
, size_t capacity
) {
148 auto& self
= static_cast<mock_buffer
&>(buf
);
149 self
.set(buf
.data(), self
.do_grow(capacity
));
152 mock_buffer(T
* data
= nullptr, size_t buf_capacity
= 0) : buffer
<T
>(grow
) {
153 this->set(data
, buf_capacity
);
154 ON_CALL(*this, do_grow(_
)).WillByDefault(Invoke([](size_t capacity
) {
160 TEST(buffer_test
, ctor
) {
162 mock_buffer
<int> buffer
;
163 EXPECT_EQ(nullptr, buffer
.data());
164 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
165 EXPECT_EQ(static_cast<size_t>(0), buffer
.capacity());
169 mock_buffer
<int> buffer(&dummy
);
170 EXPECT_EQ(&dummy
, &buffer
[0]);
171 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
172 EXPECT_EQ(static_cast<size_t>(0), buffer
.capacity());
176 size_t capacity
= std::numeric_limits
<size_t>::max();
177 mock_buffer
<int> buffer(&dummy
, capacity
);
178 EXPECT_EQ(&dummy
, &buffer
[0]);
179 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
180 EXPECT_EQ(capacity
, buffer
.capacity());
184 TEST(buffer_test
, access
) {
186 mock_buffer
<char> buffer(data
, sizeof(data
));
188 EXPECT_EQ(11, buffer
[0]);
190 EXPECT_EQ(42, *(&buffer
[0] + 3));
191 const fmt::detail::buffer
<char>& const_buffer
= buffer
;
192 EXPECT_EQ(42, const_buffer
[3]);
195 TEST(buffer_test
, try_resize
) {
197 mock_buffer
<char> buffer(data
, sizeof(data
));
199 EXPECT_EQ(42, buffer
[10]);
200 buffer
.try_resize(20);
201 EXPECT_EQ(20u, buffer
.size());
202 EXPECT_EQ(123u, buffer
.capacity());
203 EXPECT_EQ(42, buffer
[10]);
204 buffer
.try_resize(5);
205 EXPECT_EQ(5u, buffer
.size());
206 EXPECT_EQ(123u, buffer
.capacity());
207 EXPECT_EQ(42, buffer
[10]);
208 // Check if try_resize calls grow.
209 EXPECT_CALL(buffer
, do_grow(124));
210 buffer
.try_resize(124);
211 EXPECT_CALL(buffer
, do_grow(200));
212 buffer
.try_resize(200);
215 TEST(buffer_test
, try_resize_partial
) {
217 mock_buffer
<char> buffer(data
, sizeof(data
));
218 EXPECT_CALL(buffer
, do_grow(20)).WillOnce(Return(15));
219 buffer
.try_resize(20);
220 EXPECT_EQ(buffer
.capacity(), 15);
221 EXPECT_EQ(buffer
.size(), 15);
224 TEST(buffer_test
, clear
) {
225 mock_buffer
<char> buffer
;
226 EXPECT_CALL(buffer
, do_grow(20));
227 buffer
.try_resize(20);
228 buffer
.try_resize(0);
229 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
230 EXPECT_EQ(20u, buffer
.capacity());
233 TEST(buffer_test
, append
) {
235 mock_buffer
<char> buffer(data
, 10);
237 buffer
.append(test
, test
+ 5);
238 EXPECT_STREQ(test
, &buffer
[0]);
239 EXPECT_EQ(5u, buffer
.size());
240 buffer
.try_resize(10);
241 EXPECT_CALL(buffer
, do_grow(12));
242 buffer
.append(test
, test
+ 2);
243 EXPECT_EQ('t', buffer
[10]);
244 EXPECT_EQ('e', buffer
[11]);
245 EXPECT_EQ(12u, buffer
.size());
248 TEST(buffer_test
, append_partial
) {
250 mock_buffer
<char> buffer(data
, sizeof(data
));
251 testing::InSequence seq
;
252 EXPECT_CALL(buffer
, do_grow(15)).WillOnce(Return(10));
253 EXPECT_CALL(buffer
, do_grow(15)).WillOnce(Invoke([&buffer
](size_t) {
254 EXPECT_EQ(fmt::string_view(buffer
.data(), buffer
.size()), "0123456789");
258 auto test
= "0123456789abcde";
259 buffer
.append(test
, test
+ 15);
262 TEST(buffer_test
, append_allocates_enough_storage
) {
264 mock_buffer
<char> buffer(data
, 10);
265 auto test
= "abcdefgh";
266 buffer
.try_resize(10);
267 EXPECT_CALL(buffer
, do_grow(19));
268 buffer
.append(test
, test
+ 9);
271 TEST(base_test
, get_buffer
) {
272 mock_buffer
<char> buffer
;
273 void* buffer_ptr
= &buffer
;
274 auto&& appender_result
= fmt::detail::get_buffer
<char>(fmt::appender(buffer
));
275 EXPECT_EQ(&appender_result
, buffer_ptr
);
276 auto&& back_inserter_result
=
277 fmt::detail::get_buffer
<char>(std::back_inserter(buffer
));
278 EXPECT_EQ(&back_inserter_result
, buffer_ptr
);
281 struct custom_context
{
282 using char_type
= char;
283 using parse_context_type
= fmt::format_parse_context
;
287 template <typename T
> struct formatter_type
{
288 FMT_CONSTEXPR
auto parse(fmt::format_parse_context
& ctx
)
289 -> decltype(ctx
.begin()) {
293 const char* format(const T
&, custom_context
& ctx
) const {
299 void advance_to(const char*) {}
302 struct test_struct
{};
305 template <typename Char
> struct formatter
<test_struct
, Char
> {
306 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
310 auto format(test_struct
, format_context
& ctx
) const -> decltype(ctx
.out()) {
311 return copy("test", ctx
.out());
316 TEST(arg_test
, format_args
) {
317 auto args
= fmt::format_args();
318 EXPECT_FALSE(args
.get(1));
321 TEST(arg_test
, make_value_with_custom_context
) {
322 auto t
= test_struct();
323 auto arg
= fmt::detail::value
<custom_context
>(
324 fmt::detail::arg_mapper
<custom_context
>().map(t
));
325 auto ctx
= custom_context();
326 auto parse_ctx
= fmt::format_parse_context("");
327 arg
.custom
.format(&t
, parse_ctx
, ctx
);
328 EXPECT_TRUE(ctx
.called
);
331 // Use a unique result type to make sure that there are no undesirable
333 struct test_result
{};
335 template <typename T
> struct mock_visitor
{
336 template <typename U
> struct result
{
337 using type
= test_result
;
341 ON_CALL(*this, visit(_
)).WillByDefault(Return(test_result()));
344 MOCK_METHOD(test_result
, visit
, (T
));
345 MOCK_METHOD(void, unexpected
, ());
347 auto operator()(T value
) -> test_result
{ return visit(value
); }
349 template <typename U
> auto operator()(U
) -> test_result
{
351 return test_result();
355 template <typename T
> struct visit_type
{
359 #define VISIT_TYPE(type_, visit_type_) \
360 template <> struct visit_type<type_> { \
361 using type = visit_type_; \
364 VISIT_TYPE(signed char, int);
365 VISIT_TYPE(unsigned char, unsigned);
366 VISIT_TYPE(short, int);
367 VISIT_TYPE(unsigned short, unsigned);
369 #if LONG_MAX == INT_MAX
370 VISIT_TYPE(long, int);
371 VISIT_TYPE(unsigned long, unsigned);
373 VISIT_TYPE(long, long long);
374 VISIT_TYPE(unsigned long, unsigned long long);
377 #define CHECK_ARG(Char, expected, value) \
379 testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
380 EXPECT_CALL(visitor, visit(expected)); \
381 using iterator = fmt::basic_appender<Char>; \
383 fmt::detail::make_arg<fmt::basic_format_context<iterator, Char>>(var) \
387 #define CHECK_ARG_SIMPLE(value) \
389 using value_type = decltype(value); \
390 typename visit_type<value_type>::type expected = value; \
391 CHECK_ARG(char, expected, value) \
394 template <typename T
> class numeric_arg_test
: public testing::Test
{};
397 testing::Types
<bool, signed char, unsigned char, short, unsigned short, int,
398 unsigned, long, unsigned long, long long, unsigned long long,
399 float, double, long double>;
400 TYPED_TEST_SUITE(numeric_arg_test
, test_types
);
402 template <typename T
, fmt::enable_if_t
<std::is_integral
<T
>::value
, int> = 0>
403 auto test_value() -> T
{
404 return static_cast<T
>(42);
407 template <typename T
,
408 fmt::enable_if_t
<std::is_floating_point
<T
>::value
, int> = 0>
409 auto test_value() -> T
{
410 return static_cast<T
>(4.2);
413 TYPED_TEST(numeric_arg_test
, make_and_visit
) {
414 CHECK_ARG_SIMPLE(test_value
<TypeParam
>());
415 CHECK_ARG_SIMPLE(std::numeric_limits
<TypeParam
>::min());
416 CHECK_ARG_SIMPLE(std::numeric_limits
<TypeParam
>::max());
419 TEST(arg_test
, char_arg
) { CHECK_ARG(char, 'a', 'a'); }
421 TEST(arg_test
, string_arg
) {
422 char str_data
[] = "test";
423 char* str
= str_data
;
424 const char* cstr
= str
;
425 CHECK_ARG(char, cstr
, str
);
427 auto sv
= fmt::string_view(str
);
428 CHECK_ARG(char, sv
, std::string(str
));
431 TEST(arg_test
, pointer_arg
) {
433 const void* cp
= nullptr;
434 CHECK_ARG(char, cp
, p
);
435 CHECK_ARG_SIMPLE(cp
);
438 TEST(arg_test
, volatile_pointer_arg
) {
439 const void* p
= nullptr;
440 volatile int* vip
= nullptr;
441 const volatile int* cvip
= nullptr;
442 CHECK_ARG(char, p
, static_cast<volatile void*>(vip
));
443 CHECK_ARG(char, p
, static_cast<const volatile void*>(cvip
));
446 struct check_custom
{
447 auto operator()(fmt::basic_format_arg
<fmt::format_context
>::handle h
) const
449 struct test_buffer final
: fmt::detail::buffer
<char> {
452 : fmt::detail::buffer
<char>([](buffer
<char>&, size_t) {}, data
, 0,
455 auto parse_ctx
= fmt::format_parse_context("");
456 auto ctx
= fmt::format_context(fmt::appender(buffer
), fmt::format_args());
457 h
.format(parse_ctx
, ctx
);
458 EXPECT_EQ("test", std::string(buffer
.data
, buffer
.size()));
459 return test_result();
463 TEST(arg_test
, custom_arg
) {
464 auto test
= test_struct();
466 mock_visitor
<fmt::basic_format_arg
<fmt::format_context
>::handle
>;
467 auto&& v
= testing::StrictMock
<visitor
>();
468 EXPECT_CALL(v
, visit(_
)).WillOnce(Invoke(check_custom()));
469 fmt::detail::make_arg
<fmt::format_context
>(test
).visit(v
);
472 TEST(arg_test
, visit_invalid_arg
) {
473 auto&& visitor
= testing::StrictMock
<mock_visitor
<fmt::monostate
>>();
474 EXPECT_CALL(visitor
, visit(_
));
475 fmt::basic_format_arg
<fmt::format_context
>().visit(visitor
);
478 #if FMT_USE_CONSTEXPR
480 enum class arg_id_result
{ none
, empty
, index
, name
};
481 struct test_arg_id_handler
{
482 arg_id_result res
= arg_id_result::none
;
486 constexpr void on_auto() { res
= arg_id_result::empty
; }
488 constexpr void on_index(int i
) {
489 res
= arg_id_result::index
;
493 constexpr void on_name(string_view n
) {
494 res
= arg_id_result::name
;
500 constexpr test_arg_id_handler
parse_arg_id(const char (&s
)[N
]) {
501 auto h
= test_arg_id_handler();
502 fmt::detail::parse_arg_id(s
, s
+ N
, h
);
506 TEST(base_test
, constexpr_parse_arg_id
) {
507 static_assert(parse_arg_id(":").res
== arg_id_result::empty
, "");
508 static_assert(parse_arg_id("}").res
== arg_id_result::empty
, "");
509 static_assert(parse_arg_id("42:").res
== arg_id_result::index
, "");
510 static_assert(parse_arg_id("42:").index
== 42, "");
511 static_assert(parse_arg_id("foo:").res
== arg_id_result::name
, "");
512 static_assert(parse_arg_id("foo:").name
.size() == 3, "");
515 template <size_t N
> constexpr auto parse_test_specs(const char (&s
)[N
]) {
516 auto ctx
= fmt::detail::compile_parse_context
<char>(fmt::string_view(s
, N
),
518 auto specs
= fmt::detail::dynamic_format_specs
<>();
519 fmt::detail::parse_format_specs(s
, s
+ N
- 1, specs
, ctx
,
520 fmt::detail::type::float_type
);
524 TEST(base_test
, constexpr_parse_format_specs
) {
525 static_assert(parse_test_specs("<").align
== fmt::align::left
, "");
526 static_assert(parse_test_specs("*^").fill
.get
<char>() == '*', "");
527 static_assert(parse_test_specs("+").sign
== fmt::sign::plus
, "");
528 static_assert(parse_test_specs("-").sign
== fmt::sign::minus
, "");
529 static_assert(parse_test_specs(" ").sign
== fmt::sign::space
, "");
530 static_assert(parse_test_specs("#").alt
, "");
531 static_assert(parse_test_specs("0").align
== fmt::align::numeric
, "");
532 static_assert(parse_test_specs("L").localized
, "");
533 static_assert(parse_test_specs("42").width
== 42, "");
534 static_assert(parse_test_specs("{42}").width_ref
.val
.index
== 42, "");
535 static_assert(parse_test_specs(".42").precision
== 42, "");
536 static_assert(parse_test_specs(".{42}").precision_ref
.val
.index
== 42, "");
537 static_assert(parse_test_specs("f").type
== fmt::presentation_type::fixed
,
541 struct test_format_string_handler
{
542 constexpr void on_text(const char*, const char*) {}
544 constexpr auto on_arg_id() -> int { return 0; }
546 template <typename T
> constexpr auto on_arg_id(T
) -> int { return 0; }
548 constexpr void on_replacement_field(int, const char*) {}
550 constexpr auto on_format_specs(int, const char* begin
, const char*) -> const
555 constexpr void on_error(const char*) { error
= true; }
560 template <size_t N
> constexpr bool parse_string(const char (&s
)[N
]) {
561 auto h
= test_format_string_handler();
562 fmt::detail::parse_format_string
<true>(fmt::string_view(s
, N
- 1), h
);
566 TEST(base_test
, constexpr_parse_format_string
) {
567 static_assert(parse_string("foo"), "");
568 static_assert(!parse_string("}"), "");
569 static_assert(parse_string("{}"), "");
570 static_assert(parse_string("{42}"), "");
571 static_assert(parse_string("{foo}"), "");
572 static_assert(parse_string("{:}"), "");
574 #endif // FMT_USE_CONSTEXPR
576 struct enabled_formatter
{};
577 struct enabled_ptr_formatter
{};
578 struct disabled_formatter
{};
579 struct disabled_formatter_convertible
{
580 operator int() const { return 42; }
584 template <> struct formatter
<enabled_formatter
> {
585 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
588 auto format(enabled_formatter
, format_context
& ctx
) const
589 -> decltype(ctx
.out()) {
594 template <> struct formatter
<enabled_ptr_formatter
*> {
595 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
598 auto format(enabled_ptr_formatter
*, format_context
& ctx
) const
599 -> decltype(ctx
.out()) {
605 TEST(base_test
, has_formatter
) {
606 using fmt::has_formatter
;
607 using context
= fmt::format_context
;
608 static_assert(has_formatter
<enabled_formatter
, context
>::value
, "");
609 static_assert(!has_formatter
<disabled_formatter
, context
>::value
, "");
610 static_assert(!has_formatter
<disabled_formatter_convertible
, context
>::value
,
614 struct const_formattable
{};
615 struct nonconst_formattable
{};
618 template <> struct formatter
<const_formattable
> {
619 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
623 auto format(const const_formattable
&, format_context
& ctx
) const
624 -> decltype(ctx
.out()) {
625 return copy("test", ctx
.out());
629 template <> struct formatter
<nonconst_formattable
> {
630 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
634 auto format(nonconst_formattable
&, format_context
& ctx
) const
635 -> decltype(ctx
.out()) {
636 return copy("test", ctx
.out());
641 struct convertible_to_pointer
{
642 operator const int*() const { return nullptr; }
645 struct convertible_to_pointer_formattable
{
646 operator const int*() const { return nullptr; }
650 template <> struct formatter
<convertible_to_pointer_formattable
> {
651 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
655 auto format(convertible_to_pointer_formattable
, format_context
& ctx
) const
656 -> decltype(ctx
.out()) {
657 return copy("test", ctx
.out());
662 enum class unformattable_scoped_enum
{};
664 TEST(base_test
, is_formattable
) {
665 static_assert(!fmt::is_formattable
<wchar_t>::value
, "");
667 static_assert(!fmt::is_formattable
<char8_t
>::value
, "");
669 static_assert(!fmt::is_formattable
<char16_t
>::value
, "");
670 static_assert(!fmt::is_formattable
<char32_t
>::value
, "");
671 static_assert(!fmt::is_formattable
<signed char*>::value
, "");
672 static_assert(!fmt::is_formattable
<unsigned char*>::value
, "");
673 static_assert(!fmt::is_formattable
<const signed char*>::value
, "");
674 static_assert(!fmt::is_formattable
<const unsigned char*>::value
, "");
675 static_assert(!fmt::is_formattable
<const wchar_t*>::value
, "");
676 static_assert(!fmt::is_formattable
<const wchar_t[3]>::value
, "");
677 static_assert(!fmt::is_formattable
<fmt::basic_string_view
<wchar_t>>::value
,
679 static_assert(fmt::is_formattable
<enabled_formatter
>::value
, "");
680 static_assert(!fmt::is_formattable
<enabled_ptr_formatter
*>::value
, "");
681 static_assert(!fmt::is_formattable
<disabled_formatter
>::value
, "");
682 static_assert(!fmt::is_formattable
<disabled_formatter_convertible
>::value
,
685 static_assert(fmt::is_formattable
<const_formattable
&>::value
, "");
686 static_assert(fmt::is_formattable
<const const_formattable
&>::value
, "");
688 static_assert(fmt::is_formattable
<nonconst_formattable
&>::value
, "");
689 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
690 static_assert(!fmt::is_formattable
<const nonconst_formattable
&>::value
, "");
693 static_assert(!fmt::is_formattable
<convertible_to_pointer
>::value
, "");
694 const auto f
= convertible_to_pointer_formattable();
695 auto str
= std::string();
696 fmt::format_to(std::back_inserter(str
), "{}", f
);
697 EXPECT_EQ(str
, "test");
699 static_assert(!fmt::is_formattable
<void (*)()>::value
, "");
702 static_assert(!fmt::is_formattable
<int(s::*)>::value
, "");
703 static_assert(!fmt::is_formattable
<int (s::*)()>::value
, "");
704 static_assert(!fmt::is_formattable
<unformattable_scoped_enum
>::value
, "");
705 static_assert(!fmt::is_formattable
<unformattable_scoped_enum
>::value
, "");
709 TEST(base_test
, formattable
) {
710 static_assert(fmt::formattable
<char>);
711 static_assert(fmt::formattable
<char&>);
712 static_assert(fmt::formattable
<char&&>);
713 static_assert(fmt::formattable
<const char>);
714 static_assert(fmt::formattable
<const char&>);
715 static_assert(fmt::formattable
<const char&&>);
716 static_assert(fmt::formattable
<int>);
717 static_assert(!fmt::formattable
<wchar_t>);
721 TEST(base_test
, format_to
) {
722 auto s
= std::string();
723 fmt::format_to(std::back_inserter(s
), "{}", 42);
727 TEST(base_test
, format_to_array
) {
729 auto result
= fmt::format_to(buffer
, "{}", 12345);
730 EXPECT_EQ(4, std::distance(&buffer
[0], result
.out
));
731 EXPECT_TRUE(result
.truncated
);
732 EXPECT_EQ(buffer
+ 4, result
.out
);
733 EXPECT_EQ("1234", fmt::string_view(buffer
, 4));
736 EXPECT_THROW(out
= result
, std::runtime_error
);
739 result
= fmt::format_to(buffer
, "{:s}", "foobar");
740 EXPECT_EQ(4, std::distance(&buffer
[0], result
.out
));
741 EXPECT_TRUE(result
.truncated
);
742 EXPECT_EQ(buffer
+ 4, result
.out
);
743 EXPECT_EQ("foob", fmt::string_view(buffer
, 4));
749 result
= fmt::format_to(buffer
, "{}", 'A');
750 EXPECT_EQ(1, std::distance(&buffer
[0], result
.out
));
751 EXPECT_FALSE(result
.truncated
);
752 EXPECT_EQ(buffer
+ 1, result
.out
);
753 EXPECT_EQ("Axxx", fmt::string_view(buffer
, 4));
755 result
= fmt::format_to(buffer
, "{}{} ", 'B', 'C');
756 EXPECT_EQ(3, std::distance(&buffer
[0], result
.out
));
757 EXPECT_FALSE(result
.truncated
);
758 EXPECT_EQ(buffer
+ 3, result
.out
);
759 EXPECT_EQ("BC x", fmt::string_view(buffer
, 4));
761 result
= fmt::format_to(buffer
, "{}", "ABCDE");
762 EXPECT_EQ(4, std::distance(&buffer
[0], result
.out
));
763 EXPECT_TRUE(result
.truncated
);
764 EXPECT_EQ("ABCD", fmt::string_view(buffer
, 4));
766 result
= fmt::format_to(buffer
, "{}", std::string(1000, '*'));
767 EXPECT_EQ(4, std::distance(&buffer
[0], result
.out
));
768 EXPECT_TRUE(result
.truncated
);
769 EXPECT_EQ("****", fmt::string_view(buffer
, 4));
772 #ifdef __cpp_lib_byte
773 TEST(base_test
, format_byte
) {
774 auto s
= std::string();
775 fmt::format_to(std::back_inserter(s
), "{}", std::byte(42));
780 // Test that check is not found by ADL.
781 template <typename T
> void check(T
);
782 TEST(base_test
, adl_check
) {
783 auto s
= std::string();
784 fmt::format_to(std::back_inserter(s
), "{}", test_struct());
785 EXPECT_EQ(s
, "test");
788 struct implicitly_convertible_to_string_view
{
789 operator fmt::string_view() const { return "foo"; }
792 TEST(base_test
, no_implicit_conversion_to_string_view
) {
794 fmt::is_formattable
<implicitly_convertible_to_string_view
>::value
);
797 #ifdef FMT_USE_STRING_VIEW
798 struct implicitly_convertible_to_std_string_view
{
799 operator std::string_view() const { return "foo"; }
802 TEST(base_test
, no_implicit_conversion_to_std_string_view
) {
804 fmt::is_formattable
<implicitly_convertible_to_std_string_view
>::value
);
808 // std::is_constructible is broken in MSVC until version 2015.
809 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1900
810 struct explicitly_convertible_to_string_view
{
811 explicit operator fmt::string_view() const { return "foo"; }
814 TEST(base_test
, format_explicitly_convertible_to_string_view
) {
815 // Types explicitly convertible to string_view are not formattable by
816 // default because it may introduce ODR violations.
818 !fmt::is_formattable
<explicitly_convertible_to_string_view
>::value
, "");
821 # ifdef FMT_USE_STRING_VIEW
822 struct explicitly_convertible_to_std_string_view
{
823 explicit operator std::string_view() const { return "foo"; }
826 TEST(base_test
, format_explicitly_convertible_to_std_string_view
) {
827 // Types explicitly convertible to string_view are not formattable by
828 // default because it may introduce ODR violations.
830 !fmt::is_formattable
<explicitly_convertible_to_std_string_view
>::value
,
836 TEST(base_test
, has_const_formatter
) {
837 EXPECT_TRUE((fmt::detail::has_const_formatter
<const_formattable
,
838 fmt::format_context
>()));
839 EXPECT_FALSE((fmt::detail::has_const_formatter
<nonconst_formattable
,
840 fmt::format_context
>()));
843 TEST(base_test
, format_nonconst
) {
844 auto s
= std::string();
845 fmt::format_to(std::back_inserter(s
), "{}", nonconst_formattable());
846 EXPECT_EQ(s
, "test");
849 TEST(base_test
, throw_in_buffer_dtor
) {
850 enum { buffer_size
= 256 };
852 struct throwing_iterator
{
855 auto operator=(char) -> throwing_iterator
& {
856 if (++count
> buffer_size
) throw std::exception();
859 auto operator*() -> throwing_iterator
& { return *this; }
860 auto operator++() -> throwing_iterator
& { return *this; }
861 auto operator++(int) -> throwing_iterator
{ return *this; }
866 fmt::format_to(throwing_iterator
{count
}, fmt::runtime("{:{}}{"), "",
868 } catch (const std::exception
&) {
873 template <typename T
> operator T() const {
881 template <> struct formatter
<its_a_trap
> {
882 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
886 auto format(its_a_trap
, format_context
& ctx
) const
887 -> decltype(ctx
.out()) const {
888 auto out
= ctx
.out();
895 TEST(base_test
, trappy_conversion
) {
896 auto s
= std::string();
897 fmt::format_to(std::back_inserter(s
), "{}", its_a_trap());