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.
15 #include <type_traits>
18 #include "test-assert.h"
22 // Check if fmt/core.h compiles with windows.h included before it.
32 using fmt::basic_format_arg
;
33 using fmt::internal::basic_buffer
;
34 using fmt::internal::value
;
35 using fmt::string_view
;
38 using testing::StrictMock
;
42 struct test_struct
{};
44 template <typename Context
, typename T
>
45 basic_format_arg
<Context
> make_arg(const T
&value
) {
46 return fmt::internal::make_arg
<Context
>(value
);
51 template <typename Char
>
52 struct formatter
<test_struct
, Char
> {
53 template <typename ParseContext
>
54 auto parse(ParseContext
&ctx
) -> decltype(ctx
.begin()) {
58 typedef std::back_insert_iterator
<basic_buffer
<Char
>> iterator
;
60 auto format(test_struct
, basic_format_context
<iterator
, char> &ctx
)
61 -> decltype(ctx
.out()) {
62 const Char
*test
= "test";
63 return std::copy_n(test
, std::strlen(test
), ctx
.out());
68 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
69 TEST(BufferTest
, Noncopyable
) {
70 EXPECT_FALSE(std::is_copy_constructible
<basic_buffer
<char> >::value
);
72 // std::is_copy_assignable is broken in MSVC2013.
73 EXPECT_FALSE(std::is_copy_assignable
<basic_buffer
<char> >::value
);
77 TEST(BufferTest
, Nonmoveable
) {
78 EXPECT_FALSE(std::is_move_constructible
<basic_buffer
<char> >::value
);
80 // std::is_move_assignable is broken in MSVC2013.
81 EXPECT_FALSE(std::is_move_assignable
<basic_buffer
<char> >::value
);
86 // A test buffer with a dummy grow method.
88 struct test_buffer
: basic_buffer
<T
> {
89 void grow(std::size_t capacity
) { this->set(FMT_NULL
, capacity
); }
93 struct mock_buffer
: basic_buffer
<T
> {
94 MOCK_METHOD1(do_grow
, void (std::size_t capacity
));
96 void grow(std::size_t capacity
) {
97 this->set(this->data(), capacity
);
102 mock_buffer(T
*data
) { this->set(data
, 0); }
103 mock_buffer(T
*data
, std::size_t capacity
) { this->set(data
, capacity
); }
106 TEST(BufferTest
, Ctor
) {
108 mock_buffer
<int> buffer
;
109 EXPECT_EQ(FMT_NULL
, &buffer
[0]);
110 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
111 EXPECT_EQ(static_cast<size_t>(0), buffer
.capacity());
115 mock_buffer
<int> buffer(&dummy
);
116 EXPECT_EQ(&dummy
, &buffer
[0]);
117 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
118 EXPECT_EQ(static_cast<size_t>(0), buffer
.capacity());
122 std::size_t capacity
= std::numeric_limits
<std::size_t>::max();
123 mock_buffer
<int> buffer(&dummy
, capacity
);
124 EXPECT_EQ(&dummy
, &buffer
[0]);
125 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
126 EXPECT_EQ(capacity
, buffer
.capacity());
130 struct dying_buffer
: test_buffer
<int> {
131 MOCK_METHOD0(die
, void());
132 ~dying_buffer() { die(); }
135 TEST(BufferTest
, VirtualDtor
) {
136 typedef StrictMock
<dying_buffer
> stict_mock_buffer
;
137 stict_mock_buffer
*mock_buffer
= new stict_mock_buffer();
138 EXPECT_CALL(*mock_buffer
, die());
139 basic_buffer
<int> *buffer
= mock_buffer
;
143 TEST(BufferTest
, Access
) {
145 mock_buffer
<char> buffer(data
, sizeof(data
));
147 EXPECT_EQ(11, buffer
[0]);
149 EXPECT_EQ(42, *(&buffer
[0] + 3));
150 const basic_buffer
<char> &const_buffer
= buffer
;
151 EXPECT_EQ(42, const_buffer
[3]);
154 TEST(BufferTest
, Resize
) {
156 mock_buffer
<char> buffer(data
, sizeof(data
));
158 EXPECT_EQ(42, buffer
[10]);
160 EXPECT_EQ(20u, buffer
.size());
161 EXPECT_EQ(123u, buffer
.capacity());
162 EXPECT_EQ(42, buffer
[10]);
164 EXPECT_EQ(5u, buffer
.size());
165 EXPECT_EQ(123u, buffer
.capacity());
166 EXPECT_EQ(42, buffer
[10]);
167 // Check if resize calls grow.
168 EXPECT_CALL(buffer
, do_grow(124));
170 EXPECT_CALL(buffer
, do_grow(200));
174 TEST(BufferTest
, Clear
) {
175 test_buffer
<char> buffer
;
178 EXPECT_EQ(static_cast<size_t>(0), buffer
.size());
179 EXPECT_EQ(20u, buffer
.capacity());
182 TEST(BufferTest
, Append
) {
184 mock_buffer
<char> buffer(data
, 10);
185 const char *test
= "test";
186 buffer
.append(test
, test
+ 5);
187 EXPECT_STREQ(test
, &buffer
[0]);
188 EXPECT_EQ(5u, buffer
.size());
190 EXPECT_CALL(buffer
, do_grow(12));
191 buffer
.append(test
, test
+ 2);
192 EXPECT_EQ('t', buffer
[10]);
193 EXPECT_EQ('e', buffer
[11]);
194 EXPECT_EQ(12u, buffer
.size());
197 TEST(BufferTest
, AppendAllocatesEnoughStorage
) {
199 mock_buffer
<char> buffer(data
, 10);
200 const char *test
= "abcdefgh";
202 EXPECT_CALL(buffer
, do_grow(19));
203 buffer
.append(test
, test
+ 9);
206 TEST(ArgTest
, FormatArgs
) {
207 fmt::format_args args
;
208 EXPECT_FALSE(args
.get(1));
211 struct custom_context
{
212 typedef char char_type
;
214 template <typename T
>
215 struct formatter_type
{
217 template <typename ParseContext
>
218 auto parse(ParseContext
&ctx
) -> decltype(ctx
.begin()) {
222 const char *format(const T
&, custom_context
& ctx
) {
231 fmt::format_parse_context
parse_context() {
232 return fmt::format_parse_context("");
234 void advance_to(const char *) {}
237 TEST(ArgTest
, MakeValueWithCustomContext
) {
239 fmt::internal::value
<custom_context
> arg
=
240 fmt::internal::make_value
<custom_context
>(t
);
241 custom_context ctx
= {false};
242 arg
.custom
.format(&t
, ctx
);
243 EXPECT_TRUE(ctx
.called
);
248 template <typename Char
>
249 bool operator==(custom_value
<Char
> lhs
, custom_value
<Char
> rhs
) {
250 return lhs
.value
== rhs
.value
;
255 // Use a unique result type to make sure that there are no undesirable
257 struct test_result
{};
259 template <typename T
>
260 struct mock_visitor
{
261 template <typename U
>
262 struct result
{ typedef test_result type
; };
265 ON_CALL(*this, visit(_
)).WillByDefault(testing::Return(test_result()));
268 MOCK_METHOD1_T(visit
, test_result (T value
));
269 MOCK_METHOD0_T(unexpected
, void ());
271 test_result
operator()(T value
) { return visit(value
); }
273 template <typename U
>
274 test_result
operator()(U
) {
276 return test_result();
280 template <typename T
>
281 struct visit_type
{ typedef T Type
; };
283 #define VISIT_TYPE(Type_, visit_type_) \
285 struct visit_type<Type_> { typedef visit_type_ Type; }
287 VISIT_TYPE(signed char, int);
288 VISIT_TYPE(unsigned char, unsigned);
289 VISIT_TYPE(short, int);
290 VISIT_TYPE(unsigned short, unsigned);
292 #if LONG_MAX == INT_MAX
293 VISIT_TYPE(long, int);
294 VISIT_TYPE(unsigned long, unsigned);
296 VISIT_TYPE(long, long long);
297 VISIT_TYPE(unsigned long, unsigned long long);
300 VISIT_TYPE(float, double);
302 #define CHECK_ARG_(Char, expected, value) { \
303 testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
304 EXPECT_CALL(visitor, visit(expected)); \
305 typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
306 fmt::visit(visitor, \
307 make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
310 #define CHECK_ARG(value, typename_) { \
311 typedef decltype(value) value_type; \
312 typename_ visit_type<value_type>::Type expected = value; \
313 CHECK_ARG_(char, expected, value) \
314 CHECK_ARG_(wchar_t, expected, value) \
317 template <typename T
>
318 class NumericArgTest
: public testing::Test
{};
320 typedef ::testing::Types
<
321 bool, signed char, unsigned char, signed, unsigned short,
322 int, unsigned, long, unsigned long, long long, unsigned long long,
323 float, double, long double> Types
;
324 TYPED_TEST_CASE(NumericArgTest
, Types
);
326 template <typename T
>
327 typename
std::enable_if
<std::is_integral
<T
>::value
, T
>::type
test_value() {
328 return static_cast<T
>(42);
331 template <typename T
>
332 typename
std::enable_if
<std::is_floating_point
<T
>::value
, T
>::type
334 return static_cast<T
>(4.2);
337 TYPED_TEST(NumericArgTest
, MakeAndVisit
) {
338 CHECK_ARG(test_value
<TypeParam
>(), typename
);
339 CHECK_ARG(std::numeric_limits
<TypeParam
>::min(), typename
);
340 CHECK_ARG(std::numeric_limits
<TypeParam
>::max(), typename
);
343 TEST(ArgTest
, CharArg
) {
344 CHECK_ARG_(char, 'a', 'a');
345 CHECK_ARG_(wchar_t, L
'a', 'a');
346 CHECK_ARG_(wchar_t, L
'a', L
'a');
349 TEST(ArgTest
, StringArg
) {
350 char str_data
[] = "test";
351 char *str
= str_data
;
352 const char *cstr
= str
;
353 CHECK_ARG_(char, cstr
, str
);
355 string_view
sref(str
);
356 CHECK_ARG_(char, sref
, std::string(str
));
359 TEST(ArgTest
, WStringArg
) {
360 wchar_t str_data
[] = L
"test";
361 wchar_t *str
= str_data
;
362 const wchar_t *cstr
= str
;
364 fmt::wstring_view
sref(str
);
365 CHECK_ARG_(wchar_t, cstr
, str
);
366 CHECK_ARG_(wchar_t, cstr
, cstr
);
367 CHECK_ARG_(wchar_t, sref
, std::wstring(str
));
368 CHECK_ARG_(wchar_t, sref
, fmt::wstring_view(str
));
371 TEST(ArgTest
, PointerArg
) {
373 const void *cp
= FMT_NULL
;
374 CHECK_ARG_(char, cp
, p
);
375 CHECK_ARG_(wchar_t, cp
, p
);
379 struct check_custom
{
380 test_result
operator()(
381 fmt::basic_format_arg
<fmt::format_context
>::handle h
) const {
382 struct test_buffer
: fmt::internal::basic_buffer
<char> {
384 test_buffer() : fmt::internal::basic_buffer
<char>(data
, 0, 10) {}
385 void grow(std::size_t) {}
387 fmt::internal::basic_buffer
<char> &base
= buffer
;
388 fmt::format_context
ctx(std::back_inserter(base
), "", fmt::format_args());
390 EXPECT_EQ("test", std::string(buffer
.data
, buffer
.size()));
391 return test_result();
395 TEST(ArgTest
, CustomArg
) {
397 typedef mock_visitor
<fmt::basic_format_arg
<fmt::format_context
>::handle
>
399 testing::StrictMock
<visitor
> v
;
400 EXPECT_CALL(v
, visit(_
)).WillOnce(testing::Invoke(check_custom()));
401 fmt::visit(v
, make_arg
<fmt::format_context
>(test
));
404 TEST(ArgTest
, VisitInvalidArg
) {
405 testing::StrictMock
< mock_visitor
<fmt::monostate
> > visitor
;
406 EXPECT_CALL(visitor
, visit(_
));
407 fmt::basic_format_arg
<fmt::format_context
> arg
;
411 TEST(StringViewTest
, Length
) {
412 // Test that StringRef::size() returns string length, not buffer size.
413 char str
[100] = "some string";
414 EXPECT_EQ(std::strlen(str
), string_view(str
).size());
415 EXPECT_LT(std::strlen(str
), sizeof(str
));
418 // Check string_view's comparison operator.
419 template <template <typename
> class Op
>
421 const char *inputs
[] = {"foo", "fop", "fo"};
422 std::size_t num_inputs
= sizeof(inputs
) / sizeof(*inputs
);
423 for (std::size_t i
= 0; i
< num_inputs
; ++i
) {
424 for (std::size_t j
= 0; j
< num_inputs
; ++j
) {
425 string_view
lhs(inputs
[i
]), rhs(inputs
[j
]);
426 EXPECT_EQ(Op
<int>()(lhs
.compare(rhs
), 0), Op
<string_view
>()(lhs
, rhs
));
431 TEST(StringViewTest
, Compare
) {
432 EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0);
433 EXPECT_GT(string_view("fop").compare(string_view("foo")), 0);
434 EXPECT_LT(string_view("foo").compare(string_view("fop")), 0);
435 EXPECT_GT(string_view("foo").compare(string_view("fo")), 0);
436 EXPECT_LT(string_view("fo").compare(string_view("foo")), 0);
437 check_op
<std::equal_to
>();
438 check_op
<std::not_equal_to
>();
439 check_op
<std::less
>();
440 check_op
<std::less_equal
>();
441 check_op
<std::greater
>();
442 check_op
<std::greater_equal
>();
447 TEST(CoreTest
, ConvertToInt
) {
448 EXPECT_FALSE((fmt::convert_to_int
<char, char>::value
));
449 EXPECT_FALSE((fmt::convert_to_int
<const char *, char>::value
));
450 EXPECT_TRUE((fmt::convert_to_int
<basic_enum
, char>::value
));
453 enum enum_with_underlying_type
: char {};
455 TEST(CoreTest
, IsEnumConvertibleToInt
) {
456 EXPECT_TRUE((fmt::convert_to_int
<enum_with_underlying_type
, char>::value
));
460 template <typename Char
>
463 my_string(const Char
*s
) : s_(s
) {}
464 const Char
* data() const FMT_NOEXCEPT
{ return s_
.data(); }
465 std::size_t length() const FMT_NOEXCEPT
{ return s_
.size(); }
466 operator const Char
*() const { return s_
.c_str(); }
468 std::basic_string
<Char
> s_
;
471 template <typename Char
>
472 inline fmt::basic_string_view
<Char
>
473 to_string_view(const my_string
<Char
> &s
) FMT_NOEXCEPT
{
474 return { s
.data(), s
.length() };
477 struct non_string
{};
483 QString(const wchar_t *s
) : s_(std::make_shared
<std::wstring
>(s
)) {}
484 const wchar_t *utf16() const FMT_NOEXCEPT
{ return s_
->data(); }
485 int size() const FMT_NOEXCEPT
{ return static_cast<int>(s_
->size()); }
486 #ifdef FMT_STRING_VIEW
487 operator FMT_STRING_VIEW
<wchar_t>() const FMT_NOEXCEPT
{ return *s_
; }
490 std::shared_ptr
<std::wstring
> s_
;
493 inline fmt::basic_string_view
<wchar_t> to_string_view(
494 const QString
&s
) FMT_NOEXCEPT
{
495 return {reinterpret_cast<const wchar_t *>(s
.utf16()),
496 static_cast<std::size_t>(s
.size())};
500 template <typename T
>
501 class IsStringTest
: public testing::Test
{};
503 typedef ::testing::Types
<char, wchar_t, char16_t
, char32_t
> StringCharTypes
;
504 TYPED_TEST_CASE(IsStringTest
, StringCharTypes
);
507 template <typename Char
>
508 struct derived_from_string_view
: fmt::basic_string_view
<Char
> {};
511 TYPED_TEST(IsStringTest
, IsString
) {
512 EXPECT_TRUE((fmt::internal::is_string
<TypeParam
*>::value
));
513 EXPECT_TRUE((fmt::internal::is_string
<const TypeParam
*>::value
));
514 EXPECT_TRUE((fmt::internal::is_string
<TypeParam
[2]>::value
));
515 EXPECT_TRUE((fmt::internal::is_string
<const TypeParam
[2]>::value
));
516 EXPECT_TRUE((fmt::internal::is_string
<std::basic_string
<TypeParam
>>::value
));
518 (fmt::internal::is_string
<fmt::basic_string_view
<TypeParam
>>::value
));
520 (fmt::internal::is_string
<derived_from_string_view
<TypeParam
>>::value
));
521 #ifdef FMT_STRING_VIEW
522 EXPECT_TRUE((fmt::internal::is_string
<FMT_STRING_VIEW
<TypeParam
>>::value
));
524 EXPECT_TRUE((fmt::internal::is_string
<my_ns::my_string
<TypeParam
>>::value
));
525 EXPECT_FALSE((fmt::internal::is_string
<my_ns::non_string
>::value
));
526 EXPECT_TRUE((fmt::internal::is_string
<FakeQt::QString
>::value
));
529 TEST(CoreTest
, Format
) {
530 // This should work without including fmt/format.h.
532 # error fmt/format.h must not be included in the core test
534 EXPECT_EQ(fmt::format("{}", 42), "42");
537 TEST(CoreTest
, FormatTo
) {
538 // This should work without including fmt/format.h.
540 # error fmt/format.h must not be included in the core test
543 fmt::format_to(std::back_inserter(s
), "{}", 42);
547 TEST(CoreTest
, ToStringViewForeignStrings
) {
548 using namespace my_ns
;
549 using namespace FakeQt
;
550 EXPECT_EQ(to_string_view(my_string
<char>("42")), "42");
551 EXPECT_EQ(to_string_view(my_string
<wchar_t>(L
"42")), L
"42");
552 EXPECT_EQ(to_string_view(QString(L
"42")), L
"42");
553 fmt::internal::type type
=
554 fmt::internal::get_type
<fmt::format_context
, my_string
<char>>::value
;
555 EXPECT_EQ(type
, fmt::internal::string_type
);
557 fmt::internal::get_type
<fmt::wformat_context
, my_string
<wchar_t>>::value
;
558 EXPECT_EQ(type
, fmt::internal::string_type
);
559 type
= fmt::internal::get_type
<fmt::wformat_context
, QString
>::value
;
560 EXPECT_EQ(type
, fmt::internal::string_type
);
561 // Does not compile: only wide format contexts are compatible with QString!
562 // type = fmt::internal::get_type<fmt::format_context, QString>::value;
565 TEST(CoreTest
, FormatForeignStrings
) {
566 using namespace my_ns
;
567 using namespace FakeQt
;
568 EXPECT_EQ(fmt::format(my_string
<char>("{}"), 42), "42");
569 EXPECT_EQ(fmt::format(my_string
<wchar_t>(L
"{}"), 42), L
"42");
570 EXPECT_EQ(fmt::format(QString(L
"{}"), 42), L
"42");
571 EXPECT_EQ(fmt::format(QString(L
"{}"), my_string
<wchar_t>(L
"42")), L
"42");
572 EXPECT_EQ(fmt::format(my_string
<wchar_t>(L
"{}"), QString(L
"42")), L
"42");
575 struct implicitly_convertible_to_string_view
{
576 operator fmt::string_view() const { return "foo"; }
579 TEST(FormatterTest
, FormatImplicitlyConvertibleToStringView
) {
580 EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view()));
583 // std::is_constructible is broken in MSVC until version 2015.
584 #if FMT_USE_EXPLICIT && (!FMT_MSC_VER || FMT_MSC_VER >= 1900)
585 struct explicitly_convertible_to_string_view
{
586 explicit operator fmt::string_view() const { return "foo"; }
589 TEST(FormatterTest
, FormatExplicitlyConvertibleToStringView
) {
590 EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
593 struct explicitly_convertible_to_wstring_view
{
594 explicit operator fmt::wstring_view() const { return L
"foo"; }
597 TEST(FormatterTest
, FormatExplicitlyConvertibleToWStringView
) {
599 fmt::format(L
"{}", explicitly_convertible_to_wstring_view()));
602 struct explicitly_convertible_to_string_like
{
605 typename
= typename
std::enable_if
<
606 std::is_constructible
<String
, const char*, std::size_t>::value
>::type
>
607 FMT_EXPLICIT
operator String() const { return String("foo", 3u); }
610 TEST(FormatterTest
, FormatExplicitlyConvertibleToStringLike
) {
611 EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like()));