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