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"
12 #define I 42 // simulate https://en.cppreference.com/w/c/numeric/complex/I
16 #include <algorithm> // std::copy_n
17 #include <climits> // INT_MAX
18 #include <cstring> // std::strlen
19 #include <functional> // std::equal_to
20 #include <iterator> // std::back_insert_iterator
21 #include <limits> // std::numeric_limits
22 #include <string> // std::string
23 #include <type_traits> // std::is_same
25 #include "gmock/gmock.h"
27 using fmt::string_view
;
28 using fmt::detail::buffer
;
31 using testing::Invoke
;
32 using testing::Return
;
35 # error core-test includes format.h
38 TEST(string_view_test
, value_type
) {
39 static_assert(std::is_same
<string_view::value_type
, char>::value
, "");
42 TEST(string_view_test
, ctor
) {
43 EXPECT_STREQ("abc", fmt::string_view("abc").data());
44 EXPECT_EQ(3u, fmt::string_view("abc").size());
46 EXPECT_STREQ("defg", fmt::string_view(std::string("defg")).data());
47 EXPECT_EQ(4u, fmt::string_view(std::string("defg")).size());
50 TEST(string_view_test
, length
) {
51 // Test that string_view::size() returns string length, not buffer size.
52 char str
[100] = "some string";
53 EXPECT_EQ(std::strlen(str
), string_view(str
).size());
54 EXPECT_LT(std::strlen(str
), sizeof(str
));
57 // Check string_view's comparison operator.
58 template <template <typename
> class Op
> void check_op() {
59 const char* inputs
[] = {"foo", "fop", "fo"};
60 size_t num_inputs
= sizeof(inputs
) / sizeof(*inputs
);
61 for (size_t i
= 0; i
< num_inputs
; ++i
) {
62 for (size_t j
= 0; j
< num_inputs
; ++j
) {
63 string_view
lhs(inputs
[i
]), rhs(inputs
[j
]);
64 EXPECT_EQ(Op
<int>()(lhs
.compare(rhs
), 0), Op
<string_view
>()(lhs
, rhs
));
69 TEST(string_view_test
, compare
) {
70 EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0);
71 EXPECT_GT(string_view("fop").compare(string_view("foo")), 0);
72 EXPECT_LT(string_view("foo").compare(string_view("fop")), 0);
73 EXPECT_GT(string_view("foo").compare(string_view("fo")), 0);
74 EXPECT_LT(string_view("fo").compare(string_view("foo")), 0);
75 check_op
<std::equal_to
>();
76 check_op
<std::not_equal_to
>();
77 check_op
<std::less
>();
78 check_op
<std::less_equal
>();
79 check_op
<std::greater
>();
80 check_op
<std::greater_equal
>();
84 template <typename Char
> class test_string
{
86 std::basic_string
<Char
> s_
;
89 test_string(const Char
* s
) : s_(s
) {}
90 const Char
* data() const { return s_
.data(); }
91 size_t length() const { return s_
.size(); }
92 operator const Char
*() const { return s_
.c_str(); }
95 template <typename Char
>
96 fmt::basic_string_view
<Char
> to_string_view(const test_string
<Char
>& s
) {
97 return {s
.data(), s
.length()};
99 } // namespace test_ns
101 TEST(core_test
, is_output_iterator
) {
102 EXPECT_TRUE((fmt::detail::is_output_iterator
<char*, char>::value
));
103 EXPECT_FALSE((fmt::detail::is_output_iterator
<const char*, char>::value
));
104 EXPECT_FALSE((fmt::detail::is_output_iterator
<std::string
, char>::value
));
106 (fmt::detail::is_output_iterator
<std::back_insert_iterator
<std::string
>,
109 (fmt::detail::is_output_iterator
<std::string::iterator
, char>::value
));
110 EXPECT_FALSE((fmt::detail::is_output_iterator
<std::string::const_iterator
,
114 TEST(core_test
, buffer_appender
) {
115 // back_insert_iterator is not default-constructible before C++20, so
116 // buffer_appender can only be default-constructible when back_insert_iterator
119 std::is_default_constructible
<
120 std::back_insert_iterator
<fmt::detail::buffer
<char>>>::value
==
121 std::is_default_constructible
<
122 fmt::detail::buffer_appender
<char>>::value
,
125 #ifdef __cpp_lib_ranges
126 static_assert(std::output_iterator
<fmt::detail::buffer_appender
<char>, char>);
130 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
131 TEST(buffer_test
, noncopyable
) {
132 EXPECT_FALSE(std::is_copy_constructible
<buffer
<char>>::value
);
133 # if !FMT_MSC_VERSION
134 // std::is_copy_assignable is broken in MSVC2013.
135 EXPECT_FALSE(std::is_copy_assignable
<buffer
<char>>::value
);
139 TEST(buffer_test
, nonmoveable
) {
140 EXPECT_FALSE(std::is_move_constructible
<buffer
<char>>::value
);
141 # if !FMT_MSC_VERSION
142 // std::is_move_assignable is broken in MSVC2013.
143 EXPECT_FALSE(std::is_move_assignable
<buffer
<char>>::value
);
148 TEST(buffer_test
, indestructible
) {
149 static_assert(!std::is_destructible
<fmt::detail::buffer
<int>>(),
150 "buffer's destructor is protected");
153 template <typename T
> struct mock_buffer final
: buffer
<T
> {
154 MOCK_METHOD1(do_grow
, size_t(size_t capacity
));
156 void grow(size_t capacity
) override
{
157 this->set(this->data(), do_grow(capacity
));
160 mock_buffer(T
* data
= nullptr, size_t buf_capacity
= 0) {
161 this->set(data
, buf_capacity
);
162 ON_CALL(*this, do_grow(_
)).WillByDefault(Invoke([](size_t capacity
) {
168 TEST(buffer_test
, ctor
) {
170 mock_buffer
<int> buffer
;
171 EXPECT_EQ(nullptr, buffer
.data());
172 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
173 EXPECT_EQ(static_cast<size_t>(0), buffer
.capacity());
177 mock_buffer
<int> buffer(&dummy
);
178 EXPECT_EQ(&dummy
, &buffer
[0]);
179 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
180 EXPECT_EQ(static_cast<size_t>(0), buffer
.capacity());
184 size_t capacity
= std::numeric_limits
<size_t>::max();
185 mock_buffer
<int> buffer(&dummy
, capacity
);
186 EXPECT_EQ(&dummy
, &buffer
[0]);
187 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
188 EXPECT_EQ(capacity
, buffer
.capacity());
192 TEST(buffer_test
, access
) {
194 mock_buffer
<char> buffer(data
, sizeof(data
));
196 EXPECT_EQ(11, buffer
[0]);
198 EXPECT_EQ(42, *(&buffer
[0] + 3));
199 const fmt::detail::buffer
<char>& const_buffer
= buffer
;
200 EXPECT_EQ(42, const_buffer
[3]);
203 TEST(buffer_test
, try_resize
) {
205 mock_buffer
<char> buffer(data
, sizeof(data
));
207 EXPECT_EQ(42, buffer
[10]);
208 buffer
.try_resize(20);
209 EXPECT_EQ(20u, buffer
.size());
210 EXPECT_EQ(123u, buffer
.capacity());
211 EXPECT_EQ(42, buffer
[10]);
212 buffer
.try_resize(5);
213 EXPECT_EQ(5u, buffer
.size());
214 EXPECT_EQ(123u, buffer
.capacity());
215 EXPECT_EQ(42, buffer
[10]);
216 // Check if try_resize calls grow.
217 EXPECT_CALL(buffer
, do_grow(124));
218 buffer
.try_resize(124);
219 EXPECT_CALL(buffer
, do_grow(200));
220 buffer
.try_resize(200);
223 TEST(buffer_test
, try_resize_partial
) {
225 mock_buffer
<char> buffer(data
, sizeof(data
));
226 EXPECT_CALL(buffer
, do_grow(20)).WillOnce(Return(15));
227 buffer
.try_resize(20);
228 EXPECT_EQ(buffer
.capacity(), 15);
229 EXPECT_EQ(buffer
.size(), 15);
232 TEST(buffer_test
, clear
) {
233 mock_buffer
<char> buffer
;
234 EXPECT_CALL(buffer
, do_grow(20));
235 buffer
.try_resize(20);
236 buffer
.try_resize(0);
237 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
238 EXPECT_EQ(20u, buffer
.capacity());
241 TEST(buffer_test
, append
) {
243 mock_buffer
<char> buffer(data
, 10);
245 buffer
.append(test
, test
+ 5);
246 EXPECT_STREQ(test
, &buffer
[0]);
247 EXPECT_EQ(5u, buffer
.size());
248 buffer
.try_resize(10);
249 EXPECT_CALL(buffer
, do_grow(12));
250 buffer
.append(test
, test
+ 2);
251 EXPECT_EQ('t', buffer
[10]);
252 EXPECT_EQ('e', buffer
[11]);
253 EXPECT_EQ(12u, buffer
.size());
256 TEST(buffer_test
, append_partial
) {
258 mock_buffer
<char> buffer(data
, sizeof(data
));
259 testing::InSequence seq
;
260 EXPECT_CALL(buffer
, do_grow(15)).WillOnce(Return(10));
261 EXPECT_CALL(buffer
, do_grow(15)).WillOnce(Invoke([&buffer
](size_t) {
262 EXPECT_EQ(fmt::string_view(buffer
.data(), buffer
.size()), "0123456789");
266 auto test
= "0123456789abcde";
267 buffer
.append(test
, test
+ 15);
270 TEST(buffer_test
, append_allocates_enough_storage
) {
272 mock_buffer
<char> buffer(data
, 10);
273 auto test
= "abcdefgh";
274 buffer
.try_resize(10);
275 EXPECT_CALL(buffer
, do_grow(19));
276 buffer
.append(test
, test
+ 9);
279 struct custom_context
{
280 using char_type
= char;
281 using parse_context_type
= fmt::format_parse_context
;
285 template <typename T
> struct formatter_type
{
286 auto parse(fmt::format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
290 const char* format(const T
&, custom_context
& ctx
) {
296 void advance_to(const char*) {}
299 struct test_struct
{};
302 template <typename Char
> struct formatter
<test_struct
, Char
> {
303 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
307 auto format(test_struct
, format_context
& ctx
) -> decltype(ctx
.out()) {
308 auto test
= string_view("test");
309 return std::copy_n(test
.data(), test
.size(), ctx
.out());
314 TEST(arg_test
, format_args
) {
315 auto args
= fmt::format_args();
316 EXPECT_FALSE(args
.get(1));
319 TEST(arg_test
, make_value_with_custom_context
) {
320 auto t
= test_struct();
321 fmt::detail::value
<custom_context
> arg(
322 fmt::detail::arg_mapper
<custom_context
>().map(t
));
323 auto ctx
= custom_context();
324 auto parse_ctx
= fmt::format_parse_context("");
325 arg
.custom
.format(&t
, parse_ctx
, ctx
);
326 EXPECT_TRUE(ctx
.called
);
329 // Use a unique result type to make sure that there are no undesirable
331 struct test_result
{};
333 template <typename T
> struct mock_visitor
{
334 template <typename U
> struct result
{ using type
= test_result
; };
337 ON_CALL(*this, visit(_
)).WillByDefault(Return(test_result()));
340 MOCK_METHOD1_T(visit
, test_result(T value
));
341 MOCK_METHOD0_T(unexpected
, void());
343 test_result
operator()(T value
) { return visit(value
); }
345 template <typename U
> test_result
operator()(U
) {
347 return test_result();
351 template <typename T
> struct visit_type
{ using type
= T
; };
353 #define VISIT_TYPE(type_, visit_type_) \
354 template <> struct visit_type<type_> { using type = visit_type_; }
356 VISIT_TYPE(signed char, int);
357 VISIT_TYPE(unsigned char, unsigned);
358 VISIT_TYPE(short, int);
359 VISIT_TYPE(unsigned short, unsigned);
361 #if LONG_MAX == INT_MAX
362 VISIT_TYPE(long, int);
363 VISIT_TYPE(unsigned long, unsigned);
365 VISIT_TYPE(long, long long);
366 VISIT_TYPE(unsigned long, unsigned long long);
369 #define CHECK_ARG(Char, expected, value) \
371 testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
372 EXPECT_CALL(visitor, visit(expected)); \
373 using iterator = std::back_insert_iterator<buffer<Char>>; \
374 fmt::visit_format_arg( \
376 fmt::detail::make_arg<fmt::basic_format_context<iterator, Char>>( \
380 #define CHECK_ARG_SIMPLE(value) \
382 using value_type = decltype(value); \
383 typename visit_type<value_type>::type expected = value; \
384 CHECK_ARG(char, expected, value) \
385 CHECK_ARG(wchar_t, expected, value) \
388 template <typename T
> class numeric_arg_test
: public testing::Test
{};
391 testing::Types
<bool, signed char, unsigned char, short, unsigned short, int,
392 unsigned, long, unsigned long, long long, unsigned long long,
393 float, double, long double>;
394 TYPED_TEST_SUITE(numeric_arg_test
, test_types
);
396 template <typename T
, fmt::enable_if_t
<std::is_integral
<T
>::value
, int> = 0>
398 return static_cast<T
>(42);
401 template <typename T
,
402 fmt::enable_if_t
<std::is_floating_point
<T
>::value
, int> = 0>
404 return static_cast<T
>(4.2);
407 TYPED_TEST(numeric_arg_test
, make_and_visit
) {
408 CHECK_ARG_SIMPLE(test_value
<TypeParam
>());
409 CHECK_ARG_SIMPLE(std::numeric_limits
<TypeParam
>::min());
410 CHECK_ARG_SIMPLE(std::numeric_limits
<TypeParam
>::max());
413 TEST(arg_test
, char_arg
) { CHECK_ARG(char, 'a', 'a'); }
415 TEST(arg_test
, string_arg
) {
416 char str_data
[] = "test";
417 char* str
= str_data
;
418 const char* cstr
= str
;
419 CHECK_ARG(char, cstr
, str
);
421 auto sv
= fmt::string_view(str
);
422 CHECK_ARG(char, sv
, std::string(str
));
425 TEST(arg_test
, wstring_arg
) {
426 wchar_t str_data
[] = L
"test";
427 wchar_t* str
= str_data
;
428 const wchar_t* cstr
= str
;
430 auto sv
= fmt::basic_string_view
<wchar_t>(str
);
431 CHECK_ARG(wchar_t, cstr
, str
);
432 CHECK_ARG(wchar_t, cstr
, cstr
);
433 CHECK_ARG(wchar_t, sv
, std::wstring(str
));
434 CHECK_ARG(wchar_t, sv
, fmt::basic_string_view
<wchar_t>(str
));
437 TEST(arg_test
, pointer_arg
) {
439 const void* cp
= nullptr;
440 CHECK_ARG(char, cp
, p
);
441 CHECK_ARG(wchar_t, cp
, p
);
442 CHECK_ARG_SIMPLE(cp
);
445 struct check_custom
{
446 test_result
operator()(
447 fmt::basic_format_arg
<fmt::format_context
>::handle h
) const {
448 struct test_buffer final
: fmt::detail::buffer
<char> {
450 test_buffer() : fmt::detail::buffer
<char>(data
, 0, 10) {}
451 void grow(size_t) override
{}
453 auto parse_ctx
= fmt::format_parse_context("");
454 auto ctx
= fmt::format_context(fmt::detail::buffer_appender
<char>(buffer
),
456 h
.format(parse_ctx
, ctx
);
457 EXPECT_EQ("test", std::string(buffer
.data
, buffer
.size()));
458 return test_result();
462 TEST(arg_test
, custom_arg
) {
463 auto test
= test_struct();
465 mock_visitor
<fmt::basic_format_arg
<fmt::format_context
>::handle
>;
466 testing::StrictMock
<visitor
> v
;
467 EXPECT_CALL(v
, visit(_
)).WillOnce(Invoke(check_custom()));
468 fmt::visit_format_arg(v
, fmt::detail::make_arg
<fmt::format_context
>(test
));
471 TEST(arg_test
, visit_invalid_arg
) {
472 testing::StrictMock
<mock_visitor
<fmt::monostate
>> visitor
;
473 EXPECT_CALL(visitor
, visit(_
));
474 auto arg
= fmt::basic_format_arg
<fmt::format_context
>();
475 fmt::visit_format_arg(visitor
, arg
);
478 #if FMT_USE_CONSTEXPR
480 enum class arg_id_result
{ none
, empty
, index
, name
, error
};
481 struct test_arg_id_handler
{
482 arg_id_result res
= arg_id_result::none
;
486 constexpr void operator()() { res
= arg_id_result::empty
; }
488 constexpr void operator()(int i
) {
489 res
= arg_id_result::index
;
493 constexpr void operator()(string_view n
) {
494 res
= arg_id_result::name
;
498 constexpr void on_error(const char*) { res
= arg_id_result::error
; }
502 constexpr test_arg_id_handler
parse_arg_id(const char (&s
)[N
]) {
503 test_arg_id_handler h
;
504 fmt::detail::parse_arg_id(s
, s
+ N
, h
);
508 TEST(format_test
, constexpr_parse_arg_id
) {
509 static_assert(parse_arg_id(":").res
== arg_id_result::empty
, "");
510 static_assert(parse_arg_id("}").res
== arg_id_result::empty
, "");
511 static_assert(parse_arg_id("42:").res
== arg_id_result::index
, "");
512 static_assert(parse_arg_id("42:").index
== 42, "");
513 static_assert(parse_arg_id("foo:").res
== arg_id_result::name
, "");
514 static_assert(parse_arg_id("foo:").name
.size() == 3, "");
515 static_assert(parse_arg_id("!").res
== arg_id_result::error
, "");
518 struct test_format_specs_handler
{
519 enum result
{ none
, hash
, zero
, loc
, error
};
522 fmt::align_t alignment
= fmt::align::none
;
523 fmt::sign_t sign
= fmt::sign::none
;
526 fmt::detail::arg_ref
<char> width_ref
;
528 fmt::detail::arg_ref
<char> precision_ref
;
529 fmt::presentation_type type
= fmt::presentation_type::none
;
531 // Workaround for MSVC2017 bug that results in "expression did not evaluate
532 // to a constant" with compiler-generated copy ctor.
533 constexpr test_format_specs_handler() {}
534 constexpr test_format_specs_handler(const test_format_specs_handler
& other
) =
537 constexpr void on_align(fmt::align_t a
) { alignment
= a
; }
538 constexpr void on_fill(fmt::string_view f
) { fill
= f
[0]; }
539 constexpr void on_sign(fmt::sign_t s
) { sign
= s
; }
540 constexpr void on_hash() { res
= hash
; }
541 constexpr void on_zero() { res
= zero
; }
542 constexpr void on_localized() { res
= loc
; }
544 constexpr void on_width(int w
) { width
= w
; }
545 constexpr void on_dynamic_width(fmt::detail::auto_id
) {}
546 constexpr void on_dynamic_width(int index
) { width_ref
= index
; }
547 constexpr void on_dynamic_width(string_view
) {}
549 constexpr void on_precision(int p
) { precision
= p
; }
550 constexpr void on_dynamic_precision(fmt::detail::auto_id
) {}
551 constexpr void on_dynamic_precision(int index
) { precision_ref
= index
; }
552 constexpr void on_dynamic_precision(string_view
) {}
554 constexpr void end_precision() {}
555 constexpr void on_type(fmt::presentation_type t
) { type
= t
; }
556 constexpr void on_error(const char*) { res
= error
; }
560 constexpr test_format_specs_handler
parse_test_specs(const char (&s
)[N
]) {
561 auto h
= test_format_specs_handler();
562 fmt::detail::parse_format_specs(s
, s
+ N
- 1, h
);
566 TEST(core_test
, constexpr_parse_format_specs
) {
567 using handler
= test_format_specs_handler
;
568 static_assert(parse_test_specs("<").alignment
== fmt::align::left
, "");
569 static_assert(parse_test_specs("*^").fill
== '*', "");
570 static_assert(parse_test_specs("+").sign
== fmt::sign::plus
, "");
571 static_assert(parse_test_specs("-").sign
== fmt::sign::minus
, "");
572 static_assert(parse_test_specs(" ").sign
== fmt::sign::space
, "");
573 static_assert(parse_test_specs("#").res
== handler::hash
, "");
574 static_assert(parse_test_specs("0").res
== handler::zero
, "");
575 static_assert(parse_test_specs("L").res
== handler::loc
, "");
576 static_assert(parse_test_specs("42").width
== 42, "");
577 static_assert(parse_test_specs("{42}").width_ref
.val
.index
== 42, "");
578 static_assert(parse_test_specs(".42").precision
== 42, "");
579 static_assert(parse_test_specs(".{42}").precision_ref
.val
.index
== 42, "");
580 static_assert(parse_test_specs("d").type
== fmt::presentation_type::dec
, "");
581 static_assert(parse_test_specs("{<").res
== handler::error
, "");
584 struct test_parse_context
{
585 using char_type
= char;
587 constexpr int next_arg_id() { return 11; }
588 template <typename Id
> FMT_CONSTEXPR
void check_arg_id(Id
) {}
589 FMT_CONSTEXPR
void check_dynamic_spec(int) {}
591 constexpr const char* begin() { return nullptr; }
592 constexpr const char* end() { return nullptr; }
594 void on_error(const char*) {}
598 constexpr fmt::detail::dynamic_format_specs
<char> parse_dynamic_specs(
599 const char (&s
)[N
]) {
600 auto specs
= fmt::detail::dynamic_format_specs
<char>();
601 auto ctx
= test_parse_context();
602 auto h
= fmt::detail::dynamic_specs_handler
<test_parse_context
>(specs
, ctx
);
603 parse_format_specs(s
, s
+ N
- 1, h
);
607 TEST(format_test
, constexpr_dynamic_specs_handler
) {
608 static_assert(parse_dynamic_specs("<").align
== fmt::align::left
, "");
609 static_assert(parse_dynamic_specs("*^").fill
[0] == '*', "");
610 static_assert(parse_dynamic_specs("+").sign
== fmt::sign::plus
, "");
611 static_assert(parse_dynamic_specs("-").sign
== fmt::sign::minus
, "");
612 static_assert(parse_dynamic_specs(" ").sign
== fmt::sign::space
, "");
613 static_assert(parse_dynamic_specs("#").alt
, "");
614 static_assert(parse_dynamic_specs("0").align
== fmt::align::numeric
, "");
615 static_assert(parse_dynamic_specs("42").width
== 42, "");
616 static_assert(parse_dynamic_specs("{}").width_ref
.val
.index
== 11, "");
617 static_assert(parse_dynamic_specs("{42}").width_ref
.val
.index
== 42, "");
618 static_assert(parse_dynamic_specs(".42").precision
== 42, "");
619 static_assert(parse_dynamic_specs(".{}").precision_ref
.val
.index
== 11, "");
620 static_assert(parse_dynamic_specs(".{42}").precision_ref
.val
.index
== 42, "");
621 static_assert(parse_dynamic_specs("d").type
== fmt::presentation_type::dec
,
626 constexpr test_format_specs_handler
check_specs(const char (&s
)[N
]) {
627 fmt::detail::specs_checker
<test_format_specs_handler
> checker(
628 test_format_specs_handler(), fmt::detail::type::double_type
);
629 parse_format_specs(s
, s
+ N
- 1, checker
);
633 TEST(format_test
, constexpr_specs_checker
) {
634 using handler
= test_format_specs_handler
;
635 static_assert(check_specs("<").alignment
== fmt::align::left
, "");
636 static_assert(check_specs("*^").fill
== '*', "");
637 static_assert(check_specs("+").sign
== fmt::sign::plus
, "");
638 static_assert(check_specs("-").sign
== fmt::sign::minus
, "");
639 static_assert(check_specs(" ").sign
== fmt::sign::space
, "");
640 static_assert(check_specs("#").res
== handler::hash
, "");
641 static_assert(check_specs("0").res
== handler::zero
, "");
642 static_assert(check_specs("42").width
== 42, "");
643 static_assert(check_specs("{42}").width_ref
.val
.index
== 42, "");
644 static_assert(check_specs(".42").precision
== 42, "");
645 static_assert(check_specs(".{42}").precision_ref
.val
.index
== 42, "");
646 static_assert(check_specs("d").type
== fmt::presentation_type::dec
, "");
647 static_assert(check_specs("{<").res
== handler::error
, "");
650 struct test_format_string_handler
{
651 constexpr void on_text(const char*, const char*) {}
653 constexpr int on_arg_id() { return 0; }
655 template <typename T
> constexpr int on_arg_id(T
) { return 0; }
657 constexpr void on_replacement_field(int, const char*) {}
659 constexpr const char* on_format_specs(int, const char* begin
, const char*) {
663 constexpr void on_error(const char*) { error
= true; }
668 template <size_t N
> constexpr bool parse_string(const char (&s
)[N
]) {
669 auto h
= test_format_string_handler();
670 fmt::detail::parse_format_string
<true>(fmt::string_view(s
, N
- 1), h
);
674 TEST(format_test
, constexpr_parse_format_string
) {
675 static_assert(parse_string("foo"), "");
676 static_assert(!parse_string("}"), "");
677 static_assert(parse_string("{}"), "");
678 static_assert(parse_string("{42}"), "");
679 static_assert(parse_string("{foo}"), "");
680 static_assert(parse_string("{:}"), "");
682 #endif // FMT_USE_CONSTEXPR
684 struct enabled_formatter
{};
685 struct enabled_ptr_formatter
{};
686 struct disabled_formatter
{};
687 struct disabled_formatter_convertible
{
688 operator int() const { return 42; }
692 template <> struct formatter
<enabled_formatter
> {
693 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
696 auto format(enabled_formatter
, format_context
& ctx
) -> decltype(ctx
.out()) {
701 template <> struct formatter
<enabled_ptr_formatter
*> {
702 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
705 auto format(enabled_ptr_formatter
*, format_context
& ctx
)
706 -> decltype(ctx
.out()) {
712 TEST(core_test
, has_formatter
) {
713 using fmt::has_formatter
;
714 using context
= fmt::format_context
;
715 static_assert(has_formatter
<enabled_formatter
, context
>::value
, "");
716 static_assert(!has_formatter
<disabled_formatter
, context
>::value
, "");
717 static_assert(!has_formatter
<disabled_formatter_convertible
, context
>::value
,
721 struct const_formattable
{};
722 struct nonconst_formattable
{};
725 template <> struct formatter
<const_formattable
> {
726 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
730 auto format(const const_formattable
&, format_context
& ctx
)
731 -> decltype(ctx
.out()) {
732 auto test
= string_view("test");
733 return std::copy_n(test
.data(), test
.size(), ctx
.out());
737 template <> struct formatter
<nonconst_formattable
> {
738 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
742 auto format(nonconst_formattable
&, format_context
& ctx
)
743 -> decltype(ctx
.out()) {
744 auto test
= string_view("test");
745 return std::copy_n(test
.data(), test
.size(), ctx
.out());
750 struct convertible_to_pointer
{
751 operator const int*() const { return nullptr; }
754 struct convertible_to_pointer_formattable
{
755 operator const int*() const { return nullptr; }
759 template <> struct formatter
<convertible_to_pointer_formattable
> {
760 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
764 auto format(convertible_to_pointer_formattable
, format_context
& ctx
) const
765 -> decltype(ctx
.out()) {
766 auto test
= string_view("test");
767 return std::copy_n(test
.data(), test
.size(), ctx
.out());
772 enum class unformattable_scoped_enum
{};
775 enum class formattable_scoped_enum
{};
776 auto format_as(formattable_scoped_enum
) -> int { return 42; }
778 struct convertible_to_enum
{
779 operator formattable_scoped_enum() const { return {}; }
783 TEST(core_test
, is_formattable
) {
785 // This should be enabled once corresponding map overloads are gone.
786 static_assert(fmt::is_formattable
<signed char*>::value
, "");
787 static_assert(fmt::is_formattable
<unsigned char*>::value
, "");
788 static_assert(fmt::is_formattable
<const signed char*>::value
, "");
789 static_assert(fmt::is_formattable
<const unsigned char*>::value
, "");
791 static_assert(!fmt::is_formattable
<wchar_t>::value
, "");
793 static_assert(!fmt::is_formattable
<char8_t
>::value
, "");
795 static_assert(!fmt::is_formattable
<char16_t
>::value
, "");
796 static_assert(!fmt::is_formattable
<char32_t
>::value
, "");
797 static_assert(!fmt::is_formattable
<const wchar_t*>::value
, "");
798 static_assert(!fmt::is_formattable
<const wchar_t[3]>::value
, "");
799 static_assert(!fmt::is_formattable
<fmt::basic_string_view
<wchar_t>>::value
,
801 static_assert(fmt::is_formattable
<enabled_formatter
>::value
, "");
802 static_assert(!fmt::is_formattable
<enabled_ptr_formatter
*>::value
, "");
803 static_assert(!fmt::is_formattable
<disabled_formatter
>::value
, "");
804 static_assert(fmt::is_formattable
<disabled_formatter_convertible
>::value
, "");
806 static_assert(fmt::is_formattable
<const_formattable
&>::value
, "");
807 static_assert(fmt::is_formattable
<const const_formattable
&>::value
, "");
809 static_assert(fmt::is_formattable
<nonconst_formattable
&>::value
, "");
810 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
811 static_assert(!fmt::is_formattable
<const nonconst_formattable
&>::value
, "");
814 static_assert(!fmt::is_formattable
<convertible_to_pointer
>::value
, "");
815 const auto f
= convertible_to_pointer_formattable();
816 EXPECT_EQ(fmt::format("{}", f
), "test");
818 static_assert(!fmt::is_formattable
<void (*)()>::value
, "");
821 static_assert(!fmt::is_formattable
<int(s::*)>::value
, "");
822 static_assert(!fmt::is_formattable
<int (s::*)()>::value
, "");
823 static_assert(!fmt::is_formattable
<unformattable_scoped_enum
>::value
, "");
824 static_assert(fmt::is_formattable
<test::formattable_scoped_enum
>::value
, "");
825 static_assert(!fmt::is_formattable
<test::convertible_to_enum
>::value
, "");
828 TEST(core_test
, format
) { EXPECT_EQ(fmt::format("{}", 42), "42"); }
830 TEST(core_test
, format_to
) {
832 fmt::format_to(std::back_inserter(s
), "{}", 42);
836 TEST(core_test
, format_as
) {
837 EXPECT_EQ(fmt::format("{}", test::formattable_scoped_enum()), "42");
840 struct convertible_to_int
{
841 operator int() const { return 42; }
844 struct convertible_to_c_string
{
845 operator const char*() const { return "foo"; }
849 template <> struct formatter
<convertible_to_int
> {
850 auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
853 auto format(convertible_to_int
, format_context
& ctx
) -> decltype(ctx
.out()) {
854 return std::copy_n("foo", 3, ctx
.out());
858 template <> struct formatter
<convertible_to_c_string
> {
859 FMT_CONSTEXPR
auto parse(format_parse_context
& ctx
) -> decltype(ctx
.begin()) {
862 auto format(convertible_to_c_string
, format_context
& ctx
)
863 -> decltype(ctx
.out()) {
864 return std::copy_n("bar", 3, ctx
.out());
869 TEST(core_test
, formatter_overrides_implicit_conversion
) {
870 EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo");
871 EXPECT_EQ(fmt::format("{}", convertible_to_c_string()), "bar");
874 // Test that check is not found by ADL.
875 template <typename T
> void check(T
);
876 TEST(core_test
, adl_check
) {
877 EXPECT_EQ(fmt::format("{}", test_struct()), "test");
880 TEST(core_test
, to_string_view_foreign_strings
) {
881 using namespace test_ns
;
882 EXPECT_EQ(to_string_view(test_string
<char>("42")), "42");
883 fmt::detail::type type
=
884 fmt::detail::mapped_type_constant
<test_string
<char>,
885 fmt::format_context
>::value
;
886 EXPECT_EQ(type
, fmt::detail::type::string_type
);
889 struct implicitly_convertible_to_string
{
890 operator std::string() const { return "foo"; }
893 struct implicitly_convertible_to_string_view
{
894 operator fmt::string_view() const { return "foo"; }
897 TEST(core_test
, format_implicitly_convertible_to_string_view
) {
898 EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view()));
901 // std::is_constructible is broken in MSVC until version 2015.
902 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1900
903 struct explicitly_convertible_to_string_view
{
904 explicit operator fmt::string_view() const { return "foo"; }
907 TEST(core_test
, format_explicitly_convertible_to_string_view
) {
908 // Types explicitly convertible to string_view are not formattable by
909 // default because it may introduce ODR violations.
911 !fmt::is_formattable
<explicitly_convertible_to_string_view
>::value
, "");
914 # ifdef FMT_USE_STRING_VIEW
915 struct explicitly_convertible_to_std_string_view
{
916 explicit operator std::string_view() const { return "foo"; }
919 TEST(core_test
, format_explicitly_convertible_to_std_string_view
) {
920 // Types explicitly convertible to string_view are not formattable by
921 // default because it may introduce ODR violations.
923 !fmt::is_formattable
<explicitly_convertible_to_std_string_view
>::value
,
929 struct convertible_to_long_long
{
930 operator long long() const { return 1LL << 32; }
933 TEST(format_test
, format_convertible_to_long_long
) {
934 EXPECT_EQ("100000000", fmt::format("{:x}", convertible_to_long_long()));
937 struct disabled_rvalue_conversion
{
938 operator const char*() const& { return "foo"; }
939 operator const char*() & { return "foo"; }
940 operator const char*() const&& = delete;
941 operator const char*() && = delete;
944 TEST(core_test
, disabled_rvalue_conversion
) {
945 EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion()));
949 template <typename
... T
> void make_format_args(const T
&...) = delete;
951 struct string
: std::string
{};
952 } // namespace adl_test
954 // Test that formatting functions compile when make_format_args is found by ADL.
955 TEST(core_test
, adl
) {
956 // Only check compilation and don't run the code to avoid polluting the output
957 // and since the output is tested elsewhere.
958 if (fmt::detail::const_check(true)) return;
959 auto s
= adl_test::string();
961 (void)fmt::format("{}", s
);
962 fmt::format_to(buf
, "{}", s
);
963 fmt::format_to_n(buf
, 10, "{}", s
);
964 (void)fmt::formatted_size("{}", s
);
966 fmt::print(stdout
, "{}", s
);
969 TEST(core_test
, has_const_formatter
) {
970 EXPECT_TRUE((fmt::detail::has_const_formatter
<const_formattable
,
971 fmt::format_context
>()));
972 EXPECT_FALSE((fmt::detail::has_const_formatter
<nonconst_formattable
,
973 fmt::format_context
>()));
976 TEST(core_test
, format_nonconst
) {
977 EXPECT_EQ(fmt::format("{}", nonconst_formattable()), "test");