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 <algorithm> // std::copy_n
15 #include <climits> // INT_MAX
16 #include <cstring> // std::strlen
17 #include <functional> // std::equal_to
18 #include <iterator> // std::back_insert_iterator
19 #include <limits> // std::numeric_limits
20 #include <string> // std::string
21 #include <type_traits> // std::is_same
23 #include "gmock/gmock.h"
25 using fmt::string_view
;
26 using fmt::detail::buffer
;
29 using testing::Invoke
;
30 using testing::Return
;
33 # error core-test includes format.h
36 TEST(string_view_test
, value_type
) {
37 static_assert(std::is_same
<string_view::value_type
, char>::value
, "");
40 TEST(string_view_test
, ctor
) {
41 EXPECT_STREQ("abc", fmt::string_view("abc").data());
42 EXPECT_EQ(3u, fmt::string_view("abc").size());
44 EXPECT_STREQ("defg", fmt::string_view(std::string("defg")).data());
45 EXPECT_EQ(4u, fmt::string_view(std::string("defg")).size());
48 TEST(string_view_test
, length
) {
49 // Test that string_view::size() returns string length, not buffer size.
50 char str
[100] = "some string";
51 EXPECT_EQ(std::strlen(str
), string_view(str
).size());
52 EXPECT_LT(std::strlen(str
), sizeof(str
));
55 // Check string_view's comparison operator.
56 template <template <typename
> class Op
> void check_op() {
57 const char* inputs
[] = {"foo", "fop", "fo"};
58 size_t num_inputs
= sizeof(inputs
) / sizeof(*inputs
);
59 for (size_t i
= 0; i
< num_inputs
; ++i
) {
60 for (size_t j
= 0; j
< num_inputs
; ++j
) {
61 string_view
lhs(inputs
[i
]), rhs(inputs
[j
]);
62 EXPECT_EQ(Op
<int>()(lhs
.compare(rhs
), 0), Op
<string_view
>()(lhs
, rhs
));
67 TEST(string_view_test
, compare
) {
68 EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0);
69 EXPECT_GT(string_view("fop").compare(string_view("foo")), 0);
70 EXPECT_LT(string_view("foo").compare(string_view("fop")), 0);
71 EXPECT_GT(string_view("foo").compare(string_view("fo")), 0);
72 EXPECT_LT(string_view("fo").compare(string_view("foo")), 0);
73 check_op
<std::equal_to
>();
74 check_op
<std::not_equal_to
>();
75 check_op
<std::less
>();
76 check_op
<std::less_equal
>();
77 check_op
<std::greater
>();
78 check_op
<std::greater_equal
>();
82 template <typename Char
> class test_string
{
84 std::basic_string
<Char
> s_
;
87 test_string(const Char
* s
) : s_(s
) {}
88 const Char
* data() const { return s_
.data(); }
89 size_t length() const { return s_
.size(); }
90 operator const Char
*() const { return s_
.c_str(); }
93 template <typename Char
>
94 fmt::basic_string_view
<Char
> to_string_view(const test_string
<Char
>& s
) {
95 return {s
.data(), s
.length()};
97 } // namespace test_ns
99 TEST(core_test
, is_output_iterator
) {
100 EXPECT_TRUE((fmt::detail::is_output_iterator
<char*, char>::value
));
101 EXPECT_FALSE((fmt::detail::is_output_iterator
<const char*, char>::value
));
102 EXPECT_FALSE((fmt::detail::is_output_iterator
<std::string
, char>::value
));
104 (fmt::detail::is_output_iterator
<std::back_insert_iterator
<std::string
>,
107 (fmt::detail::is_output_iterator
<std::string::iterator
, char>::value
));
108 EXPECT_FALSE((fmt::detail::is_output_iterator
<std::string::const_iterator
,
112 TEST(core_test
, buffer_appender
) {
113 // back_insert_iterator is not default-constructible before C++20, so
114 // buffer_appender can only be default-constructible when back_insert_iterator
117 std::is_default_constructible
<
118 std::back_insert_iterator
<fmt::detail::buffer
<char>>>::value
==
119 std::is_default_constructible
<
120 fmt::detail::buffer_appender
<char>>::value
,
123 #ifdef __cpp_lib_ranges
124 static_assert(std::output_iterator
<fmt::detail::buffer_appender
<char>, char>);
128 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
129 TEST(buffer_test
, noncopyable
) {
130 EXPECT_FALSE(std::is_copy_constructible
<buffer
<char>>::value
);
132 // std::is_copy_assignable is broken in MSVC2013.
133 EXPECT_FALSE(std::is_copy_assignable
<buffer
<char>>::value
);
137 TEST(buffer_test
, nonmoveable
) {
138 EXPECT_FALSE(std::is_move_constructible
<buffer
<char>>::value
);
140 // std::is_move_assignable is broken in MSVC2013.
141 EXPECT_FALSE(std::is_move_assignable
<buffer
<char>>::value
);
146 TEST(buffer_test
, indestructible
) {
147 static_assert(!std::is_destructible
<fmt::detail::buffer
<int>>(),
148 "buffer's destructor is protected");
151 template <typename T
> struct mock_buffer final
: buffer
<T
> {
152 MOCK_METHOD1(do_grow
, size_t(size_t capacity
));
154 void grow(size_t capacity
) { this->set(this->data(), do_grow(capacity
)); }
156 mock_buffer(T
* data
= nullptr, size_t buf_capacity
= 0) {
157 this->set(data
, buf_capacity
);
158 ON_CALL(*this, do_grow(_
)).WillByDefault(Invoke([](size_t capacity
) {
164 TEST(buffer_test
, ctor
) {
166 mock_buffer
<int> buffer
;
167 EXPECT_EQ(nullptr, buffer
.data());
168 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
169 EXPECT_EQ(static_cast<size_t>(0), buffer
.capacity());
173 mock_buffer
<int> buffer(&dummy
);
174 EXPECT_EQ(&dummy
, &buffer
[0]);
175 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
176 EXPECT_EQ(static_cast<size_t>(0), buffer
.capacity());
180 size_t capacity
= std::numeric_limits
<size_t>::max();
181 mock_buffer
<int> buffer(&dummy
, capacity
);
182 EXPECT_EQ(&dummy
, &buffer
[0]);
183 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
184 EXPECT_EQ(capacity
, buffer
.capacity());
188 TEST(buffer_test
, access
) {
190 mock_buffer
<char> buffer(data
, sizeof(data
));
192 EXPECT_EQ(11, buffer
[0]);
194 EXPECT_EQ(42, *(&buffer
[0] + 3));
195 const fmt::detail::buffer
<char>& const_buffer
= buffer
;
196 EXPECT_EQ(42, const_buffer
[3]);
199 TEST(buffer_test
, try_resize
) {
201 mock_buffer
<char> buffer(data
, sizeof(data
));
203 EXPECT_EQ(42, buffer
[10]);
204 buffer
.try_resize(20);
205 EXPECT_EQ(20u, buffer
.size());
206 EXPECT_EQ(123u, buffer
.capacity());
207 EXPECT_EQ(42, buffer
[10]);
208 buffer
.try_resize(5);
209 EXPECT_EQ(5u, buffer
.size());
210 EXPECT_EQ(123u, buffer
.capacity());
211 EXPECT_EQ(42, buffer
[10]);
212 // Check if try_resize calls grow.
213 EXPECT_CALL(buffer
, do_grow(124));
214 buffer
.try_resize(124);
215 EXPECT_CALL(buffer
, do_grow(200));
216 buffer
.try_resize(200);
219 TEST(buffer_test
, try_resize_partial
) {
221 mock_buffer
<char> buffer(data
, sizeof(data
));
222 EXPECT_CALL(buffer
, do_grow(20)).WillOnce(Return(15));
223 buffer
.try_resize(20);
224 EXPECT_EQ(buffer
.capacity(), 15);
225 EXPECT_EQ(buffer
.size(), 15);
228 TEST(buffer_test
, clear
) {
229 mock_buffer
<char> buffer
;
230 EXPECT_CALL(buffer
, do_grow(20));
231 buffer
.try_resize(20);
232 buffer
.try_resize(0);
233 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
234 EXPECT_EQ(20u, buffer
.capacity());
237 TEST(buffer_test
, append
) {
239 mock_buffer
<char> buffer(data
, 10);
241 buffer
.append(test
, test
+ 5);
242 EXPECT_STREQ(test
, &buffer
[0]);
243 EXPECT_EQ(5u, buffer
.size());
244 buffer
.try_resize(10);
245 EXPECT_CALL(buffer
, do_grow(12));
246 buffer
.append(test
, test
+ 2);
247 EXPECT_EQ('t', buffer
[10]);
248 EXPECT_EQ('e', buffer
[11]);
249 EXPECT_EQ(12u, buffer
.size());
252 TEST(buffer_test
, append_partial
) {
254 mock_buffer
<char> buffer(data
, sizeof(data
));
255 testing::InSequence seq
;
256 EXPECT_CALL(buffer
, do_grow(15)).WillOnce(Return(10));
257 EXPECT_CALL(buffer
, do_grow(15)).WillOnce(Invoke([&buffer
](size_t) {
258 EXPECT_EQ(fmt::string_view(buffer
.data(), buffer
.size()), "0123456789");
262 auto test
= "0123456789abcde";
263 buffer
.append(test
, test
+ 15);
266 TEST(buffer_test
, append_allocates_enough_storage
) {
268 mock_buffer
<char> buffer(data
, 10);
269 auto test
= "abcdefgh";
270 buffer
.try_resize(10);
271 EXPECT_CALL(buffer
, do_grow(19));
272 buffer
.append(test
, test
+ 9);
275 struct custom_context
{
276 using char_type
= char;
277 using parse_context_type
= fmt::format_parse_context
;
281 template <typename T
> struct formatter_type
{
282 auto parse(fmt::format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
286 const char* format(const T
&, custom_context
& ctx
) {
292 void advance_to(const char*) {}
295 struct test_struct
{};
298 template <typename Char
> struct formatter
<test_struct
, Char
> {
299 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
303 auto format(test_struct
, format_context
& ctx
) -> decltype(ctx
.out()) {
304 auto test
= string_view("test");
305 return std::copy_n(test
.data(), test
.size(), ctx
.out());
310 TEST(arg_test
, format_args
) {
311 auto args
= fmt::format_args();
312 EXPECT_FALSE(args
.get(1));
315 TEST(arg_test
, make_value_with_custom_context
) {
316 auto t
= test_struct();
317 fmt::detail::value
<custom_context
> arg(
318 fmt::detail::arg_mapper
<custom_context
>().map(t
));
319 auto ctx
= custom_context();
320 auto parse_ctx
= fmt::format_parse_context("");
321 arg
.custom
.format(&t
, parse_ctx
, ctx
);
322 EXPECT_TRUE(ctx
.called
);
325 // Use a unique result type to make sure that there are no undesirable
327 struct test_result
{};
329 template <typename T
> struct mock_visitor
{
330 template <typename U
> struct result
{ using type
= test_result
; };
333 ON_CALL(*this, visit(_
)).WillByDefault(Return(test_result()));
336 MOCK_METHOD1_T(visit
, test_result(T value
));
337 MOCK_METHOD0_T(unexpected
, void());
339 test_result
operator()(T value
) { return visit(value
); }
341 template <typename U
> test_result
operator()(U
) {
343 return test_result();
347 template <typename T
> struct visit_type
{ using type
= T
; };
349 #define VISIT_TYPE(type_, visit_type_) \
350 template <> struct visit_type<type_> { using type = visit_type_; }
352 VISIT_TYPE(signed char, int);
353 VISIT_TYPE(unsigned char, unsigned);
354 VISIT_TYPE(short, int);
355 VISIT_TYPE(unsigned short, unsigned);
357 #if LONG_MAX == INT_MAX
358 VISIT_TYPE(long, int);
359 VISIT_TYPE(unsigned long, unsigned);
361 VISIT_TYPE(long, long long);
362 VISIT_TYPE(unsigned long, unsigned long long);
365 #define CHECK_ARG(Char, expected, value) \
367 testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
368 EXPECT_CALL(visitor, visit(expected)); \
369 using iterator = std::back_insert_iterator<buffer<Char>>; \
370 fmt::visit_format_arg( \
372 fmt::detail::make_arg<fmt::basic_format_context<iterator, Char>>( \
376 #define CHECK_ARG_SIMPLE(value) \
378 using value_type = decltype(value); \
379 typename visit_type<value_type>::type expected = value; \
380 CHECK_ARG(char, expected, value) \
381 CHECK_ARG(wchar_t, expected, value) \
384 template <typename T
> class numeric_arg_test
: public testing::Test
{};
387 testing::Types
<bool, signed char, unsigned char, short, unsigned short, int,
388 unsigned, long, unsigned long, long long, unsigned long long,
389 float, double, long double>;
390 TYPED_TEST_SUITE(numeric_arg_test
, types
);
392 template <typename T
, fmt::enable_if_t
<std::is_integral
<T
>::value
, int> = 0>
394 return static_cast<T
>(42);
397 template <typename T
,
398 fmt::enable_if_t
<std::is_floating_point
<T
>::value
, int> = 0>
400 return static_cast<T
>(4.2);
403 TYPED_TEST(numeric_arg_test
, make_and_visit
) {
404 CHECK_ARG_SIMPLE(test_value
<TypeParam
>());
405 CHECK_ARG_SIMPLE(std::numeric_limits
<TypeParam
>::min());
406 CHECK_ARG_SIMPLE(std::numeric_limits
<TypeParam
>::max());
410 template <> struct is_char
<wchar_t> : std::true_type
{};
413 TEST(arg_test
, char_arg
) {
414 CHECK_ARG(char, 'a', 'a');
415 CHECK_ARG(wchar_t, L
'a', 'a');
416 CHECK_ARG(wchar_t, L
'a', L
'a');
419 TEST(arg_test
, string_arg
) {
420 char str_data
[] = "test";
421 char* str
= str_data
;
422 const char* cstr
= str
;
423 CHECK_ARG(char, cstr
, str
);
425 auto sv
= fmt::string_view(str
);
426 CHECK_ARG(char, sv
, std::string(str
));
429 TEST(arg_test
, wstring_arg
) {
430 wchar_t str_data
[] = L
"test";
431 wchar_t* str
= str_data
;
432 const wchar_t* cstr
= str
;
434 auto sv
= fmt::basic_string_view
<wchar_t>(str
);
435 CHECK_ARG(wchar_t, cstr
, str
);
436 CHECK_ARG(wchar_t, cstr
, cstr
);
437 CHECK_ARG(wchar_t, sv
, std::wstring(str
));
438 CHECK_ARG(wchar_t, sv
, fmt::basic_string_view
<wchar_t>(str
));
441 TEST(arg_test
, pointer_arg
) {
443 const void* cp
= nullptr;
444 CHECK_ARG(char, cp
, p
);
445 CHECK_ARG(wchar_t, cp
, p
);
446 CHECK_ARG_SIMPLE(cp
);
449 struct check_custom
{
450 test_result
operator()(
451 fmt::basic_format_arg
<fmt::format_context
>::handle h
) const {
452 struct test_buffer final
: fmt::detail::buffer
<char> {
454 test_buffer() : fmt::detail::buffer
<char>(data
, 0, 10) {}
457 auto parse_ctx
= fmt::format_parse_context("");
458 auto ctx
= fmt::format_context(fmt::detail::buffer_appender
<char>(buffer
),
460 h
.format(parse_ctx
, ctx
);
461 EXPECT_EQ("test", std::string(buffer
.data
, buffer
.size()));
462 return test_result();
466 TEST(arg_test
, custom_arg
) {
467 auto test
= test_struct();
469 mock_visitor
<fmt::basic_format_arg
<fmt::format_context
>::handle
>;
470 testing::StrictMock
<visitor
> v
;
471 EXPECT_CALL(v
, visit(_
)).WillOnce(Invoke(check_custom()));
472 fmt::visit_format_arg(v
, fmt::detail::make_arg
<fmt::format_context
>(test
));
475 TEST(arg_test
, visit_invalid_arg
) {
476 testing::StrictMock
<mock_visitor
<fmt::monostate
>> visitor
;
477 EXPECT_CALL(visitor
, visit(_
));
478 auto arg
= fmt::basic_format_arg
<fmt::format_context
>();
479 fmt::visit_format_arg(visitor
, arg
);
482 #if FMT_USE_CONSTEXPR
484 enum class arg_id_result
{ none
, empty
, index
, name
, error
};
485 struct test_arg_id_handler
{
486 arg_id_result res
= arg_id_result::none
;
490 constexpr void operator()() { res
= arg_id_result::empty
; }
492 constexpr void operator()(int i
) {
493 res
= arg_id_result::index
;
497 constexpr void operator()(string_view n
) {
498 res
= arg_id_result::name
;
502 constexpr void on_error(const char*) { res
= arg_id_result::error
; }
506 constexpr test_arg_id_handler
parse_arg_id(const char (&s
)[N
]) {
507 test_arg_id_handler h
;
508 fmt::detail::parse_arg_id(s
, s
+ N
, h
);
512 TEST(format_test
, constexpr_parse_arg_id
) {
513 static_assert(parse_arg_id(":").res
== arg_id_result::empty
, "");
514 static_assert(parse_arg_id("}").res
== arg_id_result::empty
, "");
515 static_assert(parse_arg_id("42:").res
== arg_id_result::index
, "");
516 static_assert(parse_arg_id("42:").index
== 42, "");
517 static_assert(parse_arg_id("foo:").res
== arg_id_result::name
, "");
518 static_assert(parse_arg_id("foo:").name
.size() == 3, "");
519 static_assert(parse_arg_id("!").res
== arg_id_result::error
, "");
522 struct test_format_specs_handler
{
523 enum result
{ none
, hash
, zero
, loc
, error
};
526 fmt::align_t alignment
= fmt::align::none
;
527 fmt::sign_t sign
= fmt::sign::none
;
530 fmt::detail::arg_ref
<char> width_ref
;
532 fmt::detail::arg_ref
<char> precision_ref
;
535 // Workaround for MSVC2017 bug that results in "expression did not evaluate
536 // to a constant" with compiler-generated copy ctor.
537 constexpr test_format_specs_handler() {}
538 constexpr test_format_specs_handler(const test_format_specs_handler
& other
) =
541 constexpr void on_align(fmt::align_t a
) { alignment
= a
; }
542 constexpr void on_fill(fmt::string_view f
) { fill
= f
[0]; }
543 constexpr void on_sign(fmt::sign_t s
) { sign
= s
; }
544 constexpr void on_hash() { res
= hash
; }
545 constexpr void on_zero() { res
= zero
; }
546 constexpr void on_localized() { res
= loc
; }
548 constexpr void on_width(int w
) { width
= w
; }
549 constexpr void on_dynamic_width(fmt::detail::auto_id
) {}
550 constexpr void on_dynamic_width(int index
) { width_ref
= index
; }
551 constexpr void on_dynamic_width(string_view
) {}
553 constexpr void on_precision(int p
) { precision
= p
; }
554 constexpr void on_dynamic_precision(fmt::detail::auto_id
) {}
555 constexpr void on_dynamic_precision(int index
) { precision_ref
= index
; }
556 constexpr void on_dynamic_precision(string_view
) {}
558 constexpr void end_precision() {}
559 constexpr void on_type(char t
) { type
= t
; }
560 constexpr void on_error(const char*) { res
= error
; }
564 constexpr test_format_specs_handler
parse_test_specs(const char (&s
)[N
]) {
565 auto h
= test_format_specs_handler();
566 fmt::detail::parse_format_specs(s
, s
+ N
, h
);
570 TEST(core_test
, constexpr_parse_format_specs
) {
571 using handler
= test_format_specs_handler
;
572 static_assert(parse_test_specs("<").alignment
== fmt::align::left
, "");
573 static_assert(parse_test_specs("*^").fill
== '*', "");
574 static_assert(parse_test_specs("+").sign
== fmt::sign::plus
, "");
575 static_assert(parse_test_specs("-").sign
== fmt::sign::minus
, "");
576 static_assert(parse_test_specs(" ").sign
== fmt::sign::space
, "");
577 static_assert(parse_test_specs("#").res
== handler::hash
, "");
578 static_assert(parse_test_specs("0").res
== handler::zero
, "");
579 static_assert(parse_test_specs("L").res
== handler::loc
, "");
580 static_assert(parse_test_specs("42").width
== 42, "");
581 static_assert(parse_test_specs("{42}").width_ref
.val
.index
== 42, "");
582 static_assert(parse_test_specs(".42").precision
== 42, "");
583 static_assert(parse_test_specs(".{42}").precision_ref
.val
.index
== 42, "");
584 static_assert(parse_test_specs("d").type
== 'd', "");
585 static_assert(parse_test_specs("{<").res
== handler::error
, "");
588 struct test_parse_context
{
589 using char_type
= char;
591 constexpr int next_arg_id() { return 11; }
592 template <typename Id
> FMT_CONSTEXPR
void check_arg_id(Id
) {}
594 constexpr const char* begin() { return nullptr; }
595 constexpr const char* end() { return nullptr; }
597 void on_error(const char*) {}
601 constexpr fmt::detail::dynamic_format_specs
<char> parse_dynamic_specs(
602 const char (&s
)[N
]) {
603 auto specs
= fmt::detail::dynamic_format_specs
<char>();
604 auto ctx
= test_parse_context();
605 auto h
= fmt::detail::dynamic_specs_handler
<test_parse_context
>(specs
, ctx
);
606 parse_format_specs(s
, s
+ N
, h
);
610 TEST(format_test
, constexpr_dynamic_specs_handler
) {
611 static_assert(parse_dynamic_specs("<").align
== fmt::align::left
, "");
612 static_assert(parse_dynamic_specs("*^").fill
[0] == '*', "");
613 static_assert(parse_dynamic_specs("+").sign
== fmt::sign::plus
, "");
614 static_assert(parse_dynamic_specs("-").sign
== fmt::sign::minus
, "");
615 static_assert(parse_dynamic_specs(" ").sign
== fmt::sign::space
, "");
616 static_assert(parse_dynamic_specs("#").alt
, "");
617 static_assert(parse_dynamic_specs("0").align
== fmt::align::numeric
, "");
618 static_assert(parse_dynamic_specs("42").width
== 42, "");
619 static_assert(parse_dynamic_specs("{}").width_ref
.val
.index
== 11, "");
620 static_assert(parse_dynamic_specs("{42}").width_ref
.val
.index
== 42, "");
621 static_assert(parse_dynamic_specs(".42").precision
== 42, "");
622 static_assert(parse_dynamic_specs(".{}").precision_ref
.val
.index
== 11, "");
623 static_assert(parse_dynamic_specs(".{42}").precision_ref
.val
.index
== 42, "");
624 static_assert(parse_dynamic_specs("d").type
== 'd', "");
628 constexpr test_format_specs_handler
check_specs(const char (&s
)[N
]) {
629 fmt::detail::specs_checker
<test_format_specs_handler
> checker(
630 test_format_specs_handler(), fmt::detail::type::double_type
);
631 parse_format_specs(s
, s
+ N
, checker
);
635 TEST(format_test
, constexpr_specs_checker
) {
636 using handler
= test_format_specs_handler
;
637 static_assert(check_specs("<").alignment
== fmt::align::left
, "");
638 static_assert(check_specs("*^").fill
== '*', "");
639 static_assert(check_specs("+").sign
== fmt::sign::plus
, "");
640 static_assert(check_specs("-").sign
== fmt::sign::minus
, "");
641 static_assert(check_specs(" ").sign
== fmt::sign::space
, "");
642 static_assert(check_specs("#").res
== handler::hash
, "");
643 static_assert(check_specs("0").res
== handler::zero
, "");
644 static_assert(check_specs("42").width
== 42, "");
645 static_assert(check_specs("{42}").width_ref
.val
.index
== 42, "");
646 static_assert(check_specs(".42").precision
== 42, "");
647 static_assert(check_specs(".{42}").precision_ref
.val
.index
== 42, "");
648 static_assert(check_specs("d").type
== 'd', "");
649 static_assert(check_specs("{<").res
== handler::error
, "");
652 struct test_format_string_handler
{
653 constexpr void on_text(const char*, const char*) {}
655 constexpr int on_arg_id() { return 0; }
657 template <typename T
> constexpr int on_arg_id(T
) { return 0; }
659 constexpr void on_replacement_field(int, const char*) {}
661 constexpr const char* on_format_specs(int, const char* begin
, const char*) {
665 constexpr void on_error(const char*) { error
= true; }
670 template <size_t N
> constexpr bool parse_string(const char (&s
)[N
]) {
671 auto h
= test_format_string_handler();
672 fmt::detail::parse_format_string
<true>(fmt::string_view(s
, N
- 1), h
);
676 TEST(format_test
, constexpr_parse_format_string
) {
677 static_assert(parse_string("foo"), "");
678 static_assert(!parse_string("}"), "");
679 static_assert(parse_string("{}"), "");
680 static_assert(parse_string("{42}"), "");
681 static_assert(parse_string("{foo}"), "");
682 static_assert(parse_string("{:}"), "");
684 #endif // FMT_USE_CONSTEXPR
686 struct enabled_formatter
{};
687 struct disabled_formatter
{};
688 struct disabled_formatter_convertible
{
689 operator int() const { return 42; }
693 template <> struct formatter
<enabled_formatter
> {
694 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
697 auto format(enabled_formatter
, format_context
& ctx
) -> decltype(ctx
.out()) {
703 TEST(core_test
, has_formatter
) {
704 using fmt::has_formatter
;
705 using context
= fmt::format_context
;
706 static_assert(has_formatter
<enabled_formatter
, context
>::value
, "");
707 static_assert(!has_formatter
<disabled_formatter
, context
>::value
, "");
708 static_assert(!has_formatter
<disabled_formatter_convertible
, context
>::value
,
712 TEST(core_test
, is_formattable
) {
713 static_assert(fmt::is_formattable
<enabled_formatter
>::value
, "");
714 static_assert(!fmt::is_formattable
<disabled_formatter
>::value
, "");
715 static_assert(fmt::is_formattable
<disabled_formatter_convertible
>::value
, "");
718 TEST(core_test
, format
) { EXPECT_EQ(fmt::format("{}", 42), "42"); }
720 TEST(core_test
, format_to
) {
722 fmt::format_to(std::back_inserter(s
), "{}", 42);
726 struct convertible_to_int
{
727 operator int() const { return 42; }
730 struct convertible_to_c_string
{
731 operator const char*() const { return "foo"; }
735 template <> struct formatter
<convertible_to_int
> {
736 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
739 auto format(convertible_to_int
, format_context
& ctx
) -> decltype(ctx
.out()) {
740 return std::copy_n("foo", 3, ctx
.out());
744 template <> struct formatter
<convertible_to_c_string
> {
745 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
748 auto format(convertible_to_c_string
, format_context
& ctx
)
749 -> decltype(ctx
.out()) {
750 return std::copy_n("bar", 3, ctx
.out());
755 TEST(core_test
, formatter_overrides_implicit_conversion
) {
756 EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo");
757 EXPECT_EQ(fmt::format("{}", convertible_to_c_string()), "bar");
760 // Test that check is not found by ADL.
761 template <typename T
> void check(T
);
762 TEST(core_test
, adl_check
) {
763 EXPECT_EQ(fmt::format("{}", test_struct()), "test");
766 TEST(core_test
, to_string_view_foreign_strings
) {
767 using namespace test_ns
;
768 EXPECT_EQ(to_string_view(test_string
<char>("42")), "42");
769 fmt::detail::type type
=
770 fmt::detail::mapped_type_constant
<test_string
<char>,
771 fmt::format_context
>::value
;
772 EXPECT_EQ(type
, fmt::detail::type::string_type
);
775 struct implicitly_convertible_to_string
{
776 operator std::string() const { return "foo"; }
779 struct implicitly_convertible_to_string_view
{
780 operator fmt::string_view() const { return "foo"; }
783 TEST(core_test
, format_implicitly_convertible_to_string_view
) {
784 EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view()));
787 // std::is_constructible is broken in MSVC until version 2015.
788 #if !FMT_MSC_VER || FMT_MSC_VER >= 1900
789 struct explicitly_convertible_to_string_view
{
790 explicit operator fmt::string_view() const { return "foo"; }
793 TEST(core_test
, format_explicitly_convertible_to_string_view
) {
794 EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
797 # ifdef FMT_USE_STRING_VIEW
798 struct explicitly_convertible_to_std_string_view
{
799 explicit operator std::string_view() const { return "foo"; }
802 TEST(core_test
, format_explicitly_convertible_to_std_string_view
) {
804 fmt::format("{}", explicitly_convertible_to_std_string_view()));
809 struct convertible_to_long_long
{
810 operator long long() const { return 1LL << 32; }
813 TEST(format_test
, format_convertible_to_long_long
) {
814 EXPECT_EQ("100000000", fmt::format("{:x}", convertible_to_long_long()));
817 struct disabled_rvalue_conversion
{
818 operator const char*() const& { return "foo"; }
819 operator const char*() & { return "foo"; }
820 operator const char*() const&& = delete;
821 operator const char*() && = delete;
824 TEST(core_test
, disabled_rvalue_conversion
) {
825 EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion()));
829 template <typename
... T
> void make_format_args(const T
&...) = delete;
831 struct string
: std::string
{};
832 } // namespace adl_test
834 // Test that formatting functions compile when make_format_args is found by ADL.
835 TEST(core_test
, adl
) {
836 // Only check compilation and don't run the code to avoid polluting the output
837 // and since the output is tested elsewhere.
838 if (fmt::detail::const_check(true)) return;
839 auto s
= adl_test::string();
841 fmt::format("{}", s
);
842 fmt::format_to(buf
, "{}", s
);
843 fmt::format_to_n(buf
, 10, "{}", s
);
844 fmt::formatted_size("{}", s
);
846 fmt::print(stdout
, "{}", s
);