1 // Formatting library for C++ - core tests
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7
8 #include <algorithm>
9 #include <climits>
10 #include <cstring>
11 #include <functional>
12 #include <iterator>
13 #include <limits>
14 #include <memory>
15 #include <string>
16 #include <type_traits>
17
18 #include "gmock.h"
19 #include "test-assert.h"
20
21 // Check if fmt/core.h compiles with windows.h included before it.
22 #ifdef _WIN32
23 # include <windows.h>
24 #endif
25
26 #include "fmt/core.h"
27
28 #undef min
29 #undef max
30
31 using fmt::basic_format_arg;
32 using fmt::string_view;
33 using fmt::internal::buffer;
34 using fmt::internal::value;
35
36 using testing::_;
37 using testing::StrictMock;
38
39 namespace {
40
41 struct test_struct {};
42
43 template <typename Context, typename T>
make_arg(const T & value)44 basic_format_arg<Context> make_arg(const T& value) {
45 return fmt::internal::make_arg<Context>(value);
46 }
47 } // namespace
48
49 FMT_BEGIN_NAMESPACE
50 template <typename Char> struct formatter<test_struct, Char> {
51 template <typename ParseContext>
parseformatter52 auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
53 return ctx.begin();
54 }
55
56 typedef std::back_insert_iterator<buffer<Char>> iterator;
57
formatformatter58 auto format(test_struct, basic_format_context<iterator, char>& ctx)
59 -> decltype(ctx.out()) {
60 const Char* test = "test";
61 return std::copy_n(test, std::strlen(test), ctx.out());
62 }
63 };
64 FMT_END_NAMESPACE
65
66 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
TEST(BufferTest,Noncopyable)67 TEST(BufferTest, Noncopyable) {
68 EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value);
69 # if !FMT_MSC_VER
70 // std::is_copy_assignable is broken in MSVC2013.
71 EXPECT_FALSE(std::is_copy_assignable<buffer<char>>::value);
72 # endif
73 }
74
TEST(BufferTest,Nonmoveable)75 TEST(BufferTest, Nonmoveable) {
76 EXPECT_FALSE(std::is_move_constructible<buffer<char>>::value);
77 # if !FMT_MSC_VER
78 // std::is_move_assignable is broken in MSVC2013.
79 EXPECT_FALSE(std::is_move_assignable<buffer<char>>::value);
80 # endif
81 }
82 #endif
83
84 // A test buffer with a dummy grow method.
85 template <typename T> struct test_buffer : buffer<T> {
growtest_buffer86 void grow(std::size_t capacity) { this->set(nullptr, capacity); }
87 };
88
89 template <typename T> struct mock_buffer : buffer<T> {
90 MOCK_METHOD1(do_grow, void(std::size_t capacity));
91
growmock_buffer92 void grow(std::size_t capacity) {
93 this->set(this->data(), capacity);
94 do_grow(capacity);
95 }
96
mock_buffermock_buffer97 mock_buffer() {}
mock_buffermock_buffer98 mock_buffer(T* data) { this->set(data, 0); }
mock_buffermock_buffer99 mock_buffer(T* data, std::size_t capacity) { this->set(data, capacity); }
100 };
101
TEST(BufferTest,Ctor)102 TEST(BufferTest, Ctor) {
103 {
104 mock_buffer<int> buffer;
105 EXPECT_EQ(nullptr, buffer.data());
106 EXPECT_EQ(static_cast<size_t>(0), buffer.size());
107 EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
108 }
109 {
110 int dummy;
111 mock_buffer<int> buffer(&dummy);
112 EXPECT_EQ(&dummy, &buffer[0]);
113 EXPECT_EQ(static_cast<size_t>(0), buffer.size());
114 EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
115 }
116 {
117 int dummy;
118 std::size_t capacity = std::numeric_limits<std::size_t>::max();
119 mock_buffer<int> buffer(&dummy, capacity);
120 EXPECT_EQ(&dummy, &buffer[0]);
121 EXPECT_EQ(static_cast<size_t>(0), buffer.size());
122 EXPECT_EQ(capacity, buffer.capacity());
123 }
124 }
125
126 struct dying_buffer : test_buffer<int> {
127 MOCK_METHOD0(die, void());
~dying_bufferdying_buffer128 ~dying_buffer() { die(); }
129
130 private:
131 virtual void avoid_weak_vtable();
132 };
133
avoid_weak_vtable()134 void dying_buffer::avoid_weak_vtable() {}
135
TEST(BufferTest,VirtualDtor)136 TEST(BufferTest, VirtualDtor) {
137 typedef StrictMock<dying_buffer> stict_mock_buffer;
138 stict_mock_buffer* mock_buffer = new stict_mock_buffer();
139 EXPECT_CALL(*mock_buffer, die());
140 buffer<int>* buffer = mock_buffer;
141 delete buffer;
142 }
143
TEST(BufferTest,Access)144 TEST(BufferTest, Access) {
145 char data[10];
146 mock_buffer<char> buffer(data, sizeof(data));
147 buffer[0] = 11;
148 EXPECT_EQ(11, buffer[0]);
149 buffer[3] = 42;
150 EXPECT_EQ(42, *(&buffer[0] + 3));
151 const fmt::internal::buffer<char>& const_buffer = buffer;
152 EXPECT_EQ(42, const_buffer[3]);
153 }
154
TEST(BufferTest,Resize)155 TEST(BufferTest, Resize) {
156 char data[123];
157 mock_buffer<char> buffer(data, sizeof(data));
158 buffer[10] = 42;
159 EXPECT_EQ(42, buffer[10]);
160 buffer.resize(20);
161 EXPECT_EQ(20u, buffer.size());
162 EXPECT_EQ(123u, buffer.capacity());
163 EXPECT_EQ(42, buffer[10]);
164 buffer.resize(5);
165 EXPECT_EQ(5u, buffer.size());
166 EXPECT_EQ(123u, buffer.capacity());
167 EXPECT_EQ(42, buffer[10]);
168 // Check if resize calls grow.
169 EXPECT_CALL(buffer, do_grow(124));
170 buffer.resize(124);
171 EXPECT_CALL(buffer, do_grow(200));
172 buffer.resize(200);
173 }
174
TEST(BufferTest,Clear)175 TEST(BufferTest, Clear) {
176 test_buffer<char> buffer;
177 buffer.resize(20);
178 buffer.resize(0);
179 EXPECT_EQ(static_cast<size_t>(0), buffer.size());
180 EXPECT_EQ(20u, buffer.capacity());
181 }
182
TEST(BufferTest,Append)183 TEST(BufferTest, Append) {
184 char data[15];
185 mock_buffer<char> buffer(data, 10);
186 const char* test = "test";
187 buffer.append(test, test + 5);
188 EXPECT_STREQ(test, &buffer[0]);
189 EXPECT_EQ(5u, buffer.size());
190 buffer.resize(10);
191 EXPECT_CALL(buffer, do_grow(12));
192 buffer.append(test, test + 2);
193 EXPECT_EQ('t', buffer[10]);
194 EXPECT_EQ('e', buffer[11]);
195 EXPECT_EQ(12u, buffer.size());
196 }
197
TEST(BufferTest,AppendAllocatesEnoughStorage)198 TEST(BufferTest, AppendAllocatesEnoughStorage) {
199 char data[19];
200 mock_buffer<char> buffer(data, 10);
201 const char* test = "abcdefgh";
202 buffer.resize(10);
203 EXPECT_CALL(buffer, do_grow(19));
204 buffer.append(test, test + 9);
205 }
206
TEST(ArgTest,FormatArgs)207 TEST(ArgTest, FormatArgs) {
208 fmt::format_args args;
209 EXPECT_FALSE(args.get(1));
210 }
211
212 struct custom_context {
213 typedef char char_type;
214
215 template <typename T> struct formatter_type {
216 template <typename ParseContext>
parsecustom_context::formatter_type217 auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
218 return ctx.begin();
219 }
220
formatcustom_context::formatter_type221 const char* format(const T&, custom_context& ctx) {
222 ctx.called = true;
223 return nullptr;
224 }
225 };
226
227 bool called;
228 fmt::format_parse_context ctx;
229
parse_contextcustom_context230 fmt::format_parse_context& parse_context() { return ctx; }
advance_tocustom_context231 void advance_to(const char*) {}
232 };
233
TEST(ArgTest,MakeValueWithCustomContext)234 TEST(ArgTest, MakeValueWithCustomContext) {
235 test_struct t;
236 fmt::internal::value<custom_context> arg(
237 fmt::internal::arg_mapper<custom_context>().map(t));
238 custom_context ctx = {false, fmt::format_parse_context("")};
239 arg.custom.format(&t, ctx.parse_context(), ctx);
240 EXPECT_TRUE(ctx.called);
241 }
242
243 FMT_BEGIN_NAMESPACE
244 namespace internal {
245 template <typename Char>
operator ==(custom_value<Char> lhs,custom_value<Char> rhs)246 bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
247 return lhs.value == rhs.value;
248 }
249 } // namespace internal
250 FMT_END_NAMESPACE
251
252 // Use a unique result type to make sure that there are no undesirable
253 // conversions.
254 struct test_result {};
255
256 template <typename T> struct mock_visitor {
257 template <typename U> struct result { typedef test_result type; };
258
mock_visitormock_visitor259 mock_visitor() {
260 ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result()));
261 }
262
263 MOCK_METHOD1_T(visit, test_result(T value));
264 MOCK_METHOD0_T(unexpected, void());
265
operator ()mock_visitor266 test_result operator()(T value) { return visit(value); }
267
operator ()mock_visitor268 template <typename U> test_result operator()(U) {
269 unexpected();
270 return test_result();
271 }
272 };
273
274 template <typename T> struct visit_type { typedef T Type; };
275
276 #define VISIT_TYPE(Type_, visit_type_) \
277 template <> struct visit_type<Type_> { typedef visit_type_ Type; }
278
279 VISIT_TYPE(signed char, int);
280 VISIT_TYPE(unsigned char, unsigned);
281 VISIT_TYPE(short, int);
282 VISIT_TYPE(unsigned short, unsigned);
283
284 #if LONG_MAX == INT_MAX
285 VISIT_TYPE(long, int);
286 VISIT_TYPE(unsigned long, unsigned);
287 #else
288 VISIT_TYPE(long, long long);
289 VISIT_TYPE(unsigned long, unsigned long long);
290 #endif
291
292 #define CHECK_ARG_(Char, expected, value) \
293 { \
294 testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
295 EXPECT_CALL(visitor, visit(expected)); \
296 typedef std::back_insert_iterator<buffer<Char>> iterator; \
297 fmt::visit_format_arg( \
298 visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
299 }
300
301 #define CHECK_ARG(value, typename_) \
302 { \
303 typedef decltype(value) value_type; \
304 typename_ visit_type<value_type>::Type expected = value; \
305 CHECK_ARG_(char, expected, value) \
306 CHECK_ARG_(wchar_t, expected, value) \
307 }
308
309 template <typename T> class NumericArgTest : public testing::Test {};
310
311 typedef ::testing::Types<bool, signed char, unsigned char, signed,
312 unsigned short, int, unsigned, long, unsigned long,
313 long long, unsigned long long, float, double,
314 long double>
315 Types;
316 TYPED_TEST_CASE(NumericArgTest, Types);
317
318 template <typename T>
test_value()319 typename std::enable_if<std::is_integral<T>::value, T>::type test_value() {
320 return static_cast<T>(42);
321 }
322
323 template <typename T>
324 typename std::enable_if<std::is_floating_point<T>::value, T>::type
test_value()325 test_value() {
326 return static_cast<T>(4.2);
327 }
328
TYPED_TEST(NumericArgTest,MakeAndVisit)329 TYPED_TEST(NumericArgTest, MakeAndVisit) {
330 CHECK_ARG(test_value<TypeParam>(), typename);
331 CHECK_ARG(std::numeric_limits<TypeParam>::min(), typename);
332 CHECK_ARG(std::numeric_limits<TypeParam>::max(), typename);
333 }
334
TEST(ArgTest,CharArg)335 TEST(ArgTest, CharArg) {
336 CHECK_ARG_(char, 'a', 'a');
337 CHECK_ARG_(wchar_t, L'a', 'a');
338 CHECK_ARG_(wchar_t, L'a', L'a');
339 }
340
TEST(ArgTest,StringArg)341 TEST(ArgTest, StringArg) {
342 char str_data[] = "test";
343 char* str = str_data;
344 const char* cstr = str;
345 CHECK_ARG_(char, cstr, str);
346
347 string_view sref(str);
348 CHECK_ARG_(char, sref, std::string(str));
349 }
350
TEST(ArgTest,WStringArg)351 TEST(ArgTest, WStringArg) {
352 wchar_t str_data[] = L"test";
353 wchar_t* str = str_data;
354 const wchar_t* cstr = str;
355
356 fmt::wstring_view sref(str);
357 CHECK_ARG_(wchar_t, cstr, str);
358 CHECK_ARG_(wchar_t, cstr, cstr);
359 CHECK_ARG_(wchar_t, sref, std::wstring(str));
360 CHECK_ARG_(wchar_t, sref, fmt::wstring_view(str));
361 }
362
TEST(ArgTest,PointerArg)363 TEST(ArgTest, PointerArg) {
364 void* p = nullptr;
365 const void* cp = nullptr;
366 CHECK_ARG_(char, cp, p);
367 CHECK_ARG_(wchar_t, cp, p);
368 CHECK_ARG(cp, );
369 }
370
371 struct check_custom {
operator ()check_custom372 test_result operator()(
373 fmt::basic_format_arg<fmt::format_context>::handle h) const {
374 struct test_buffer : fmt::internal::buffer<char> {
375 char data[10];
376 test_buffer() : fmt::internal::buffer<char>(data, 0, 10) {}
377 void grow(std::size_t) {}
378 } buffer;
379 fmt::internal::buffer<char>& base = buffer;
380 fmt::format_parse_context parse_ctx("");
381 fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
382 h.format(parse_ctx, ctx);
383 EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
384 return test_result();
385 }
386 };
387
TEST(ArgTest,CustomArg)388 TEST(ArgTest, CustomArg) {
389 test_struct test;
390 typedef mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>
391 visitor;
392 testing::StrictMock<visitor> v;
393 EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
394 fmt::visit_format_arg(v, make_arg<fmt::format_context>(test));
395 }
396
TEST(ArgTest,VisitInvalidArg)397 TEST(ArgTest, VisitInvalidArg) {
398 testing::StrictMock<mock_visitor<fmt::monostate>> visitor;
399 EXPECT_CALL(visitor, visit(_));
400 fmt::basic_format_arg<fmt::format_context> arg;
401 fmt::visit_format_arg(visitor, arg);
402 }
403
TEST(FormatDynArgsTest,Basic)404 TEST(FormatDynArgsTest, Basic) {
405 fmt::dynamic_format_arg_store<fmt::format_context> store;
406 store.push_back(42);
407 store.push_back("abc1");
408 store.push_back(1.5f);
409
410 std::string result = fmt::vformat("{} and {} and {}", store);
411 EXPECT_EQ("42 and abc1 and 1.5", result);
412 }
413
TEST(FormatDynArgsTest,StringsAndRefs)414 TEST(FormatDynArgsTest, StringsAndRefs) {
415 // Unfortunately the tests are compiled with old ABI so strings use COW.
416 fmt::dynamic_format_arg_store<fmt::format_context> store;
417 char str[] = "1234567890";
418 store.push_back(str);
419 store.push_back(std::cref(str));
420 store.push_back(fmt::string_view{str});
421 str[0] = 'X';
422
423 std::string result = fmt::vformat("{} and {} and {}", store);
424 EXPECT_EQ("1234567890 and X234567890 and X234567890", result);
425 }
426
427 struct custom_type {
428 int i = 0;
429 };
430
431 FMT_BEGIN_NAMESPACE
432 template <> struct formatter<custom_type> {
parseformatter433 auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
434 return ctx.begin();
435 }
436
437 template <typename FormatContext>
formatformatter438 auto format(const custom_type& p, FormatContext& ctx) -> decltype(ctx.out()) {
439 return format_to(ctx.out(), "cust={}", p.i);
440 }
441 };
442 FMT_END_NAMESPACE
443
TEST(FormatDynArgsTest,CustomFormat)444 TEST(FormatDynArgsTest, CustomFormat) {
445 fmt::dynamic_format_arg_store<fmt::format_context> store;
446 custom_type c{};
447 store.push_back(c);
448 ++c.i;
449 store.push_back(c);
450 ++c.i;
451 store.push_back(std::cref(c));
452 ++c.i;
453
454 std::string result = fmt::vformat("{} and {} and {}", store);
455 EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
456 }
457
TEST(FormatDynArgsTest,NamedArgByRef)458 TEST(FormatDynArgsTest, NamedArgByRef) {
459 fmt::dynamic_format_arg_store<fmt::format_context> store;
460
461 // Note: fmt::arg() constructs an object which holds a reference
462 // to its value. It's not an aggregate, so it doesn't extend the
463 // reference lifetime. As a result, it's a very bad idea passing temporary
464 // as a named argument value. Only GCC with optimization level >0
465 // complains about this.
466 //
467 // A real life usecase is when you have both name and value alive
468 // guarantee their lifetime and thus don't want them to be copied into
469 // storages.
470 int a1_val{42};
471 auto a1 = fmt::arg("a1_", a1_val);
472 store.push_back(std::cref(a1));
473
474 std::string result = fmt::vformat("{a1_}", // and {} and {}",
475 store);
476
477 EXPECT_EQ("42", result);
478 }
479
480 struct copy_throwable {
copy_throwablecopy_throwable481 copy_throwable() {}
copy_throwablecopy_throwable482 copy_throwable(const copy_throwable&) { throw "deal with it"; }
483 };
484
485 FMT_BEGIN_NAMESPACE
486 template <> struct formatter<copy_throwable> {
parseformatter487 auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
488 return ctx.begin();
489 }
formatformatter490 auto format(copy_throwable, format_context& ctx) -> decltype(ctx.out()) {
491 return ctx.out();
492 }
493 };
494 FMT_END_NAMESPACE
495
TEST(FormatDynArgsTest,ThrowOnCopy)496 TEST(FormatDynArgsTest, ThrowOnCopy) {
497 fmt::dynamic_format_arg_store<fmt::format_context> store;
498 store.push_back(std::string("foo"));
499 try {
500 store.push_back(copy_throwable());
501 } catch (...) {
502 }
503 EXPECT_EQ(fmt::vformat("{}", store), "foo");
504 }
505
TEST(StringViewTest,ValueType)506 TEST(StringViewTest, ValueType) {
507 static_assert(std::is_same<string_view::value_type, char>::value, "");
508 }
509
TEST(StringViewTest,Length)510 TEST(StringViewTest, Length) {
511 // Test that string_view::size() returns string length, not buffer size.
512 char str[100] = "some string";
513 EXPECT_EQ(std::strlen(str), string_view(str).size());
514 EXPECT_LT(std::strlen(str), sizeof(str));
515 }
516
517 // Check string_view's comparison operator.
check_op()518 template <template <typename> class Op> void check_op() {
519 const char* inputs[] = {"foo", "fop", "fo"};
520 std::size_t num_inputs = sizeof(inputs) / sizeof(*inputs);
521 for (std::size_t i = 0; i < num_inputs; ++i) {
522 for (std::size_t j = 0; j < num_inputs; ++j) {
523 string_view lhs(inputs[i]), rhs(inputs[j]);
524 EXPECT_EQ(Op<int>()(lhs.compare(rhs), 0), Op<string_view>()(lhs, rhs));
525 }
526 }
527 }
528
TEST(StringViewTest,Compare)529 TEST(StringViewTest, Compare) {
530 EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0);
531 EXPECT_GT(string_view("fop").compare(string_view("foo")), 0);
532 EXPECT_LT(string_view("foo").compare(string_view("fop")), 0);
533 EXPECT_GT(string_view("foo").compare(string_view("fo")), 0);
534 EXPECT_LT(string_view("fo").compare(string_view("foo")), 0);
535 check_op<std::equal_to>();
536 check_op<std::not_equal_to>();
537 check_op<std::less>();
538 check_op<std::less_equal>();
539 check_op<std::greater>();
540 check_op<std::greater_equal>();
541 }
542
543 struct enabled_formatter {};
544 struct disabled_formatter {};
545 struct disabled_formatter_convertible {
operator intdisabled_formatter_convertible546 operator int() const { return 42; }
547 };
548
549 FMT_BEGIN_NAMESPACE
550 template <> struct formatter<enabled_formatter> {
parseformatter551 auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
552 return ctx.begin();
553 }
formatformatter554 auto format(enabled_formatter, format_context& ctx) -> decltype(ctx.out()) {
555 return ctx.out();
556 }
557 };
558 FMT_END_NAMESPACE
559
TEST(CoreTest,HasFormatter)560 TEST(CoreTest, HasFormatter) {
561 using fmt::has_formatter;
562 using context = fmt::format_context;
563 static_assert(has_formatter<enabled_formatter, context>::value, "");
564 static_assert(!has_formatter<disabled_formatter, context>::value, "");
565 static_assert(!has_formatter<disabled_formatter_convertible, context>::value,
566 "");
567 }
568
569 struct convertible_to_int {
operator intconvertible_to_int570 operator int() const { return 42; }
571 };
572
573 struct convertible_to_c_string {
operator const char*convertible_to_c_string574 operator const char*() const { return "foo"; }
575 };
576
577 FMT_BEGIN_NAMESPACE
578 template <> struct formatter<convertible_to_int> {
parseformatter579 auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
580 return ctx.begin();
581 }
formatformatter582 auto format(convertible_to_int, format_context& ctx) -> decltype(ctx.out()) {
583 return std::copy_n("foo", 3, ctx.out());
584 }
585 };
586
587 template <> struct formatter<convertible_to_c_string> {
parseformatter588 auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
589 return ctx.begin();
590 }
formatformatter591 auto format(convertible_to_c_string, format_context& ctx)
592 -> decltype(ctx.out()) {
593 return std::copy_n("bar", 3, ctx.out());
594 }
595 };
596 FMT_END_NAMESPACE
597
TEST(CoreTest,FormatterOverridesImplicitConversion)598 TEST(CoreTest, FormatterOverridesImplicitConversion) {
599 EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo");
600 EXPECT_EQ(fmt::format("{}", convertible_to_c_string()), "bar");
601 }
602
603 namespace my_ns {
604 template <typename Char> class my_string {
605 public:
my_string(const Char * s)606 my_string(const Char* s) : s_(s) {}
data() const607 const Char* data() const FMT_NOEXCEPT { return s_.data(); }
length() const608 std::size_t length() const FMT_NOEXCEPT { return s_.size(); }
operator const Char*() const609 operator const Char*() const { return s_.c_str(); }
610
611 private:
612 std::basic_string<Char> s_;
613 };
614
615 template <typename Char>
to_string_view(const my_string<Char> & s)616 inline fmt::basic_string_view<Char> to_string_view(const my_string<Char>& s)
617 FMT_NOEXCEPT {
618 return {s.data(), s.length()};
619 }
620
621 struct non_string {};
622 } // namespace my_ns
623
624 namespace FakeQt {
625 class QString {
626 public:
QString(const wchar_t * s)627 QString(const wchar_t* s) : s_(std::make_shared<std::wstring>(s)) {}
utf16() const628 const wchar_t* utf16() const FMT_NOEXCEPT { return s_->data(); }
size() const629 int size() const FMT_NOEXCEPT { return static_cast<int>(s_->size()); }
630
631 private:
632 std::shared_ptr<std::wstring> s_;
633 };
634
to_string_view(const QString & s)635 inline fmt::basic_string_view<wchar_t> to_string_view(const QString& s)
636 FMT_NOEXCEPT {
637 return {s.utf16(), static_cast<std::size_t>(s.size())};
638 }
639 } // namespace FakeQt
640
641 template <typename T> class IsStringTest : public testing::Test {};
642
643 typedef ::testing::Types<char, wchar_t, char16_t, char32_t> StringCharTypes;
644 TYPED_TEST_CASE(IsStringTest, StringCharTypes);
645
646 namespace {
647 template <typename Char>
648 struct derived_from_string_view : fmt::basic_string_view<Char> {};
649 } // namespace
650
TYPED_TEST(IsStringTest,IsString)651 TYPED_TEST(IsStringTest, IsString) {
652 EXPECT_TRUE(fmt::internal::is_string<TypeParam*>::value);
653 EXPECT_TRUE(fmt::internal::is_string<const TypeParam*>::value);
654 EXPECT_TRUE(fmt::internal::is_string<TypeParam[2]>::value);
655 EXPECT_TRUE(fmt::internal::is_string<const TypeParam[2]>::value);
656 EXPECT_TRUE(fmt::internal::is_string<std::basic_string<TypeParam>>::value);
657 EXPECT_TRUE(
658 fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value);
659 EXPECT_TRUE(
660 fmt::internal::is_string<derived_from_string_view<TypeParam>>::value);
661 using string_view = fmt::internal::std_string_view<TypeParam>;
662 EXPECT_TRUE(std::is_empty<string_view>::value !=
663 fmt::internal::is_string<string_view>::value);
664 EXPECT_TRUE(fmt::internal::is_string<my_ns::my_string<TypeParam>>::value);
665 EXPECT_FALSE(fmt::internal::is_string<my_ns::non_string>::value);
666 EXPECT_TRUE(fmt::internal::is_string<FakeQt::QString>::value);
667 }
668
TEST(CoreTest,Format)669 TEST(CoreTest, Format) {
670 // This should work without including fmt/format.h.
671 #ifdef FMT_FORMAT_H_
672 # error fmt/format.h must not be included in the core test
673 #endif
674 EXPECT_EQ(fmt::format("{}", 42), "42");
675 }
676
TEST(CoreTest,FormatTo)677 TEST(CoreTest, FormatTo) {
678 // This should work without including fmt/format.h.
679 #ifdef FMT_FORMAT_H_
680 # error fmt/format.h must not be included in the core test
681 #endif
682 std::string s;
683 fmt::format_to(std::back_inserter(s), "{}", 42);
684 EXPECT_EQ(s, "42");
685 }
686
TEST(CoreTest,ToStringViewForeignStrings)687 TEST(CoreTest, ToStringViewForeignStrings) {
688 using namespace my_ns;
689 using namespace FakeQt;
690 EXPECT_EQ(to_string_view(my_string<char>("42")), "42");
691 EXPECT_EQ(to_string_view(my_string<wchar_t>(L"42")), L"42");
692 EXPECT_EQ(to_string_view(QString(L"42")), L"42");
693 fmt::internal::type type =
694 fmt::internal::mapped_type_constant<my_string<char>,
695 fmt::format_context>::value;
696 EXPECT_EQ(type, fmt::internal::type::string_type);
697 type = fmt::internal::mapped_type_constant<my_string<wchar_t>,
698 fmt::wformat_context>::value;
699 EXPECT_EQ(type, fmt::internal::type::string_type);
700 type =
701 fmt::internal::mapped_type_constant<QString, fmt::wformat_context>::value;
702 EXPECT_EQ(type, fmt::internal::type::string_type);
703 // Does not compile: only wide format contexts are compatible with QString!
704 // type = fmt::internal::mapped_type_constant<QString,
705 // fmt::format_context>::value;
706 }
707
TEST(CoreTest,FormatForeignStrings)708 TEST(CoreTest, FormatForeignStrings) {
709 using namespace my_ns;
710 using namespace FakeQt;
711 EXPECT_EQ(fmt::format(my_string<char>("{}"), 42), "42");
712 EXPECT_EQ(fmt::format(my_string<wchar_t>(L"{}"), 42), L"42");
713 EXPECT_EQ(fmt::format(QString(L"{}"), 42), L"42");
714 EXPECT_EQ(fmt::format(QString(L"{}"), my_string<wchar_t>(L"42")), L"42");
715 EXPECT_EQ(fmt::format(my_string<wchar_t>(L"{}"), QString(L"42")), L"42");
716 }
717
718 struct implicitly_convertible_to_string {
operator std::stringimplicitly_convertible_to_string719 operator std::string() const { return "foo"; }
720 };
721
722 struct implicitly_convertible_to_string_view {
operator fmt::string_viewimplicitly_convertible_to_string_view723 operator fmt::string_view() const { return "foo"; }
724 };
725
TEST(FormatterTest,FormatImplicitlyConvertibleToStringView)726 TEST(FormatterTest, FormatImplicitlyConvertibleToStringView) {
727 EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view()));
728 }
729
730 // std::is_constructible is broken in MSVC until version 2015.
731 #if !FMT_MSC_VER || FMT_MSC_VER >= 1900
732 struct explicitly_convertible_to_string_view {
operator fmt::string_viewexplicitly_convertible_to_string_view733 explicit operator fmt::string_view() const { return "foo"; }
734 };
735
TEST(FormatterTest,FormatExplicitlyConvertibleToStringView)736 TEST(FormatterTest, FormatExplicitlyConvertibleToStringView) {
737 EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
738 }
739
740 # ifdef FMT_USE_STRING_VIEW
741 struct explicitly_convertible_to_std_string_view {
operator std::string_viewexplicitly_convertible_to_std_string_view742 explicit operator std::string_view() const { return "foo"; }
743 };
744
TEST(FormatterTest,FormatExplicitlyConvertibleToStdStringView)745 TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) {
746 EXPECT_EQ("foo",
747 fmt::format("{}", explicitly_convertible_to_std_string_view()));
748 }
749 # endif
750
751 struct explicitly_convertible_to_wstring_view {
operator fmt::wstring_viewexplicitly_convertible_to_wstring_view752 explicit operator fmt::wstring_view() const { return L"foo"; }
753 };
754
TEST(FormatterTest,FormatExplicitlyConvertibleToWStringView)755 TEST(FormatterTest, FormatExplicitlyConvertibleToWStringView) {
756 EXPECT_EQ(L"foo",
757 fmt::format(L"{}", explicitly_convertible_to_wstring_view()));
758 }
759 #endif
760
761 struct disabled_rvalue_conversion {
operator const char*disabled_rvalue_conversion762 operator const char*() const& { return "foo"; }
operator const char*disabled_rvalue_conversion763 operator const char*() & { return "foo"; }
764 operator const char*() const&& = delete;
765 operator const char*() && = delete;
766 };
767
TEST(FormatterTest,DisabledRValueConversion)768 TEST(FormatterTest, DisabledRValueConversion) {
769 EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion()));
770 }
771