| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | // Formatting library for C++ - core tests
 | 
					
						
							| 
									
										
										
										
											2018-03-04 09:16:51 -08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Copyright (c) 2012 - present, Victor Zverovich
 | 
					
						
							|  |  |  | // All rights reserved.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // For the license information refer to format.h.
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2014-07-02 08:38:31 -07:00
										 |  |  | #include <climits>
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2015-10-22 08:56:52 -07:00
										 |  |  | #include <functional>
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | #include <iterator>
 | 
					
						
							| 
									
										
										
										
											2014-06-06 08:07:05 -07:00
										 |  |  | #include <limits>
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #include <memory>
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | #include <string>
 | 
					
						
							|  |  |  | #include <type_traits>
 | 
					
						
							| 
									
										
										
										
											2014-09-29 08:48:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 16:57:59 +03:00
										 |  |  | #include "gmock.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-16 07:51:57 -07:00
										 |  |  | #include "test-assert.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | // Check if fmt/core.h compiles with windows.h included before it.
 | 
					
						
							| 
									
										
										
										
											2014-06-06 07:29:57 -07:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #  include <windows.h>
 | 
					
						
							| 
									
										
										
										
											2014-06-06 07:29:57 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-06 07:42:42 -08:00
										 |  |  | #include "fmt/core.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-06 07:29:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | #undef min
 | 
					
						
							| 
									
										
										
										
											2014-06-06 08:18:53 -07:00
										 |  |  | #undef max
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-04 07:38:21 -07:00
										 |  |  | using fmt::basic_format_arg; | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | using fmt::string_view; | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  | using fmt::internal::buffer; | 
					
						
							| 
									
										
										
										
											2016-12-30 08:05:26 -08:00
										 |  |  | using fmt::internal::value; | 
					
						
							| 
									
										
										
										
											2014-09-29 08:48:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | using testing::_; | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  | using testing::StrictMock; | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							| 
									
										
										
										
											2014-07-04 07:18:44 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | struct test_struct {}; | 
					
						
							| 
									
										
										
										
											2016-05-06 07:37:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-29 09:07:39 -08:00
										 |  |  | template <typename Context, typename T> | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | basic_format_arg<Context> make_arg(const T& value) { | 
					
						
							| 
									
										
										
										
											2016-12-29 09:07:39 -08:00
										 |  |  |   return fmt::internal::make_arg<Context>(value); | 
					
						
							| 
									
										
										
										
											2014-09-23 07:59:43 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-29 07:50:05 -07:00
										 |  |  | }  // namespace
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-12 08:33:51 -07:00
										 |  |  | FMT_BEGIN_NAMESPACE | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | template <typename Char> struct formatter<test_struct, Char> { | 
					
						
							| 
									
										
										
										
											2017-09-16 16:50:40 -07:00
										 |  |  |   template <typename ParseContext> | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | 
					
						
							| 
									
										
										
										
											2017-09-16 16:50:40 -07:00
										 |  |  |     return ctx.begin(); | 
					
						
							| 
									
										
										
										
											2017-08-13 13:09:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |   typedef std::back_insert_iterator<buffer<Char>> iterator; | 
					
						
							| 
									
										
										
										
											2018-01-14 07:19:23 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   auto format(test_struct, basic_format_context<iterator, char>& ctx) | 
					
						
							| 
									
										
										
										
											2018-04-22 09:16:32 -07:00
										 |  |  |       -> decltype(ctx.out()) { | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |     const Char* test = "test"; | 
					
						
							| 
									
										
										
										
											2018-04-22 09:16:32 -07:00
										 |  |  |     return std::copy_n(test, std::strlen(test), ctx.out()); | 
					
						
							| 
									
										
										
										
											2017-08-13 13:09:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-05-12 08:33:51 -07:00
										 |  |  | FMT_END_NAMESPACE | 
					
						
							| 
									
										
										
										
											2017-08-13 13:09:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-24 06:34:28 -07:00
										 |  |  | #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
 | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  | TEST(BufferTest, Noncopyable) { | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |   EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value); | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #  if !FMT_MSC_VER
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   // std::is_copy_assignable is broken in MSVC2013.
 | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |   EXPECT_FALSE(std::is_copy_assignable<buffer<char>>::value); | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #  endif
 | 
					
						
							| 
									
										
										
										
											2014-09-29 08:48:16 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  | TEST(BufferTest, Nonmoveable) { | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |   EXPECT_FALSE(std::is_move_constructible<buffer<char>>::value); | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #  if !FMT_MSC_VER
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   // std::is_move_assignable is broken in MSVC2013.
 | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |   EXPECT_FALSE(std::is_move_assignable<buffer<char>>::value); | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #  endif
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-24 06:34:28 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-09-29 08:48:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  | // A test buffer with a dummy grow method.
 | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  | template <typename T> struct test_buffer : buffer<T> { | 
					
						
							| 
									
										
										
										
											2019-05-30 07:01:31 -07:00
										 |  |  |   void grow(std::size_t capacity) { this->set(nullptr, capacity); } | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  | template <typename T> struct mock_buffer : buffer<T> { | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   MOCK_METHOD1(do_grow, void(std::size_t capacity)); | 
					
						
							| 
									
										
										
										
											2014-10-01 09:32:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-12 07:30:20 -07:00
										 |  |  |   void grow(std::size_t capacity) { | 
					
						
							|  |  |  |     this->set(this->data(), capacity); | 
					
						
							|  |  |  |     do_grow(capacity); | 
					
						
							| 
									
										
										
										
											2014-10-01 09:32:31 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   mock_buffer() {} | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   mock_buffer(T* data) { this->set(data, 0); } | 
					
						
							|  |  |  |   mock_buffer(T* data, std::size_t capacity) { this->set(data, capacity); } | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(BufferTest, Ctor) { | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |     mock_buffer<int> buffer; | 
					
						
							| 
									
										
										
										
											2019-10-08 13:28:39 +00:00
										 |  |  |     EXPECT_EQ(nullptr, buffer.data()); | 
					
						
							| 
									
										
										
										
											2018-06-06 16:57:59 +03:00
										 |  |  |     EXPECT_EQ(static_cast<size_t>(0), buffer.size()); | 
					
						
							|  |  |  |     EXPECT_EQ(static_cast<size_t>(0), buffer.capacity()); | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int dummy; | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |     mock_buffer<int> buffer(&dummy); | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  |     EXPECT_EQ(&dummy, &buffer[0]); | 
					
						
							| 
									
										
										
										
											2018-06-06 16:57:59 +03:00
										 |  |  |     EXPECT_EQ(static_cast<size_t>(0), buffer.size()); | 
					
						
							|  |  |  |     EXPECT_EQ(static_cast<size_t>(0), buffer.capacity()); | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int dummy; | 
					
						
							|  |  |  |     std::size_t capacity = std::numeric_limits<std::size_t>::max(); | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |     mock_buffer<int> buffer(&dummy, capacity); | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  |     EXPECT_EQ(&dummy, &buffer[0]); | 
					
						
							| 
									
										
										
										
											2018-06-06 16:57:59 +03:00
										 |  |  |     EXPECT_EQ(static_cast<size_t>(0), buffer.size()); | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  |     EXPECT_EQ(capacity, buffer.capacity()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | struct dying_buffer : test_buffer<int> { | 
					
						
							| 
									
										
										
										
											2014-10-01 08:24:47 -07:00
										 |  |  |   MOCK_METHOD0(die, void()); | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   ~dying_buffer() { die(); } | 
					
						
							| 
									
										
										
										
											2019-10-12 02:44:20 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |  private: | 
					
						
							|  |  |  |   virtual void avoid_weak_vtable(); | 
					
						
							| 
									
										
										
										
											2014-10-01 08:24:47 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-12 02:44:20 +09:00
										 |  |  | void dying_buffer::avoid_weak_vtable() {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  | TEST(BufferTest, VirtualDtor) { | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   typedef StrictMock<dying_buffer> stict_mock_buffer; | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   stict_mock_buffer* mock_buffer = new stict_mock_buffer(); | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   EXPECT_CALL(*mock_buffer, die()); | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |   buffer<int>* buffer = mock_buffer; | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  |   delete buffer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(BufferTest, Access) { | 
					
						
							|  |  |  |   char data[10]; | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   mock_buffer<char> buffer(data, sizeof(data)); | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  |   buffer[0] = 11; | 
					
						
							|  |  |  |   EXPECT_EQ(11, buffer[0]); | 
					
						
							|  |  |  |   buffer[3] = 42; | 
					
						
							|  |  |  |   EXPECT_EQ(42, *(&buffer[0] + 3)); | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |   const fmt::internal::buffer<char>& const_buffer = buffer; | 
					
						
							| 
									
										
										
										
											2014-09-30 07:30:27 -07:00
										 |  |  |   EXPECT_EQ(42, const_buffer[3]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  | TEST(BufferTest, Resize) { | 
					
						
							|  |  |  |   char data[123]; | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   mock_buffer<char> buffer(data, sizeof(data)); | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   buffer[10] = 42; | 
					
						
							|  |  |  |   EXPECT_EQ(42, buffer[10]); | 
					
						
							|  |  |  |   buffer.resize(20); | 
					
						
							|  |  |  |   EXPECT_EQ(20u, buffer.size()); | 
					
						
							|  |  |  |   EXPECT_EQ(123u, buffer.capacity()); | 
					
						
							|  |  |  |   EXPECT_EQ(42, buffer[10]); | 
					
						
							|  |  |  |   buffer.resize(5); | 
					
						
							|  |  |  |   EXPECT_EQ(5u, buffer.size()); | 
					
						
							|  |  |  |   EXPECT_EQ(123u, buffer.capacity()); | 
					
						
							|  |  |  |   EXPECT_EQ(42, buffer[10]); | 
					
						
							|  |  |  |   // Check if resize calls grow.
 | 
					
						
							| 
									
										
										
										
											2014-10-01 09:32:31 -07:00
										 |  |  |   EXPECT_CALL(buffer, do_grow(124)); | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   buffer.resize(124); | 
					
						
							| 
									
										
										
										
											2014-10-01 09:32:31 -07:00
										 |  |  |   EXPECT_CALL(buffer, do_grow(200)); | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   buffer.resize(200); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(BufferTest, Clear) { | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   test_buffer<char> buffer; | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   buffer.resize(20); | 
					
						
							| 
									
										
										
										
											2017-03-11 07:43:26 -08:00
										 |  |  |   buffer.resize(0); | 
					
						
							| 
									
										
										
										
											2018-06-06 16:57:59 +03:00
										 |  |  |   EXPECT_EQ(static_cast<size_t>(0), buffer.size()); | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   EXPECT_EQ(20u, buffer.capacity()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(BufferTest, Append) { | 
					
						
							|  |  |  |   char data[15]; | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   mock_buffer<char> buffer(data, 10); | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   const char* test = "test"; | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   buffer.append(test, test + 5); | 
					
						
							|  |  |  |   EXPECT_STREQ(test, &buffer[0]); | 
					
						
							|  |  |  |   EXPECT_EQ(5u, buffer.size()); | 
					
						
							|  |  |  |   buffer.resize(10); | 
					
						
							| 
									
										
										
										
											2014-10-01 09:32:31 -07:00
										 |  |  |   EXPECT_CALL(buffer, do_grow(12)); | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   buffer.append(test, test + 2); | 
					
						
							|  |  |  |   EXPECT_EQ('t', buffer[10]); | 
					
						
							|  |  |  |   EXPECT_EQ('e', buffer[11]); | 
					
						
							|  |  |  |   EXPECT_EQ(12u, buffer.size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(BufferTest, AppendAllocatesEnoughStorage) { | 
					
						
							|  |  |  |   char data[19]; | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   mock_buffer<char> buffer(data, 10); | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   const char* test = "abcdefgh"; | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   buffer.resize(10); | 
					
						
							| 
									
										
										
										
											2014-10-01 09:32:31 -07:00
										 |  |  |   EXPECT_CALL(buffer, do_grow(19)); | 
					
						
							| 
									
										
										
										
											2014-10-01 08:12:10 -07:00
										 |  |  |   buffer.append(test, test + 9); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(ArgTest, FormatArgs) { | 
					
						
							| 
									
										
										
										
											2017-12-03 07:32:04 -08:00
										 |  |  |   fmt::format_args args; | 
					
						
							| 
									
										
										
										
											2018-04-21 14:29:24 -07:00
										 |  |  |   EXPECT_FALSE(args.get(1)); | 
					
						
							| 
									
										
										
										
											2014-09-25 09:11:51 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-14 11:00:27 -08:00
										 |  |  | struct custom_context { | 
					
						
							| 
									
										
										
										
											2018-02-11 09:23:47 -08:00
										 |  |  |   typedef char char_type; | 
					
						
							| 
									
										
										
										
											2017-08-13 13:09:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   template <typename T> struct formatter_type { | 
					
						
							| 
									
										
										
										
											2019-06-02 16:04:17 -07:00
										 |  |  |     template <typename ParseContext> | 
					
						
							|  |  |  |     auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | 
					
						
							|  |  |  |       return ctx.begin(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const char* format(const T&, custom_context& ctx) { | 
					
						
							|  |  |  |       ctx.called = true; | 
					
						
							|  |  |  |       return nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-13 13:09:02 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 16:11:24 -08:00
										 |  |  |   bool called; | 
					
						
							| 
									
										
										
										
											2019-02-09 16:15:20 -08:00
										 |  |  |   fmt::format_parse_context ctx; | 
					
						
							| 
									
										
										
										
											2015-12-02 08:41:05 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-09 16:15:20 -08:00
										 |  |  |   fmt::format_parse_context& parse_context() { return ctx; } | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   void advance_to(const char*) {} | 
					
						
							| 
									
										
										
										
											2017-08-13 13:09:02 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-12-02 08:41:05 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(ArgTest, MakeValueWithCustomContext) { | 
					
						
							|  |  |  |   test_struct t; | 
					
						
							| 
									
										
										
										
											2019-06-09 21:10:09 -07:00
										 |  |  |   fmt::internal::value<custom_context> arg( | 
					
						
							|  |  |  |       fmt::internal::arg_mapper<custom_context>().map(t)); | 
					
						
							| 
									
										
										
										
											2019-02-09 16:15:20 -08:00
										 |  |  |   custom_context ctx = {false, fmt::format_parse_context("")}; | 
					
						
							|  |  |  |   arg.custom.format(&t, ctx.parse_context(), ctx); | 
					
						
							| 
									
										
										
										
											2016-11-06 16:11:24 -08:00
										 |  |  |   EXPECT_TRUE(ctx.called); | 
					
						
							| 
									
										
										
										
											2015-12-02 08:41:05 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-12 08:33:51 -07:00
										 |  |  | FMT_BEGIN_NAMESPACE | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | namespace internal { | 
					
						
							| 
									
										
										
										
											2016-12-28 07:55:33 -08:00
										 |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2017-02-19 06:46:51 -08:00
										 |  |  | bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) { | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  |   return lhs.value == rhs.value; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | }  // namespace internal
 | 
					
						
							| 
									
										
										
										
											2018-05-12 08:33:51 -07:00
										 |  |  | FMT_END_NAMESPACE | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-03 14:04:59 -08:00
										 |  |  | // Use a unique result type to make sure that there are no undesirable
 | 
					
						
							|  |  |  | // conversions.
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | struct test_result {}; | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | template <typename T> struct mock_visitor { | 
					
						
							|  |  |  |   template <typename U> struct result { typedef test_result type; }; | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   mock_visitor() { | 
					
						
							|  |  |  |     ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result())); | 
					
						
							| 
									
										
										
										
											2016-04-20 09:11:33 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   MOCK_METHOD1_T(visit, test_result(T value)); | 
					
						
							|  |  |  |   MOCK_METHOD0_T(unexpected, void()); | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   test_result operator()(T value) { return visit(value); } | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   template <typename U> test_result operator()(U) { | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  |     unexpected(); | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |     return test_result(); | 
					
						
							| 
									
										
										
										
											2014-07-14 07:27:07 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | template <typename T> struct visit_type { typedef T Type; }; | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | #define VISIT_TYPE(Type_, visit_type_) \
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   template <> struct visit_type<Type_> { typedef visit_type_ Type; } | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | VISIT_TYPE(signed char, int); | 
					
						
							|  |  |  | VISIT_TYPE(unsigned char, unsigned); | 
					
						
							|  |  |  | VISIT_TYPE(short, int); | 
					
						
							|  |  |  | VISIT_TYPE(unsigned short, unsigned); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if LONG_MAX == INT_MAX
 | 
					
						
							|  |  |  | VISIT_TYPE(long, int); | 
					
						
							|  |  |  | VISIT_TYPE(unsigned long, unsigned); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2017-08-26 09:09:43 -07:00
										 |  |  | VISIT_TYPE(long, long long); | 
					
						
							|  |  |  | VISIT_TYPE(unsigned long, unsigned long long); | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-29 16:31:25 -05:00
										 |  |  | #define CHECK_ARG_(Char, expected, value)                                     \
 | 
					
						
							|  |  |  |   {                                                                           \ | 
					
						
							|  |  |  |     testing::StrictMock<mock_visitor<decltype(expected)>> visitor;            \ | 
					
						
							|  |  |  |     EXPECT_CALL(visitor, visit(expected));                                    \ | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |     typedef std::back_insert_iterator<buffer<Char>> iterator;                 \ | 
					
						
							| 
									
										
										
										
											2019-01-29 16:31:25 -05:00
										 |  |  |     fmt::visit_format_arg(                                                    \ | 
					
						
							|  |  |  |         visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \ | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #define CHECK_ARG(value, typename_)                          \
 | 
					
						
							|  |  |  |   {                                                          \ | 
					
						
							|  |  |  |     typedef decltype(value) value_type;                      \ | 
					
						
							|  |  |  |     typename_ visit_type<value_type>::Type expected = value; \ | 
					
						
							|  |  |  |     CHECK_ARG_(char, expected, value)                        \ | 
					
						
							|  |  |  |     CHECK_ARG_(wchar_t, expected, value)                     \ | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | template <typename T> class NumericArgTest : public testing::Test {}; | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | typedef ::testing::Types<bool, signed char, unsigned char, signed, | 
					
						
							|  |  |  |                          unsigned short, int, unsigned, long, unsigned long, | 
					
						
							|  |  |  |                          long long, unsigned long long, float, double, | 
					
						
							|  |  |  |                          long double> | 
					
						
							|  |  |  |     Types; | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | TYPED_TEST_CASE(NumericArgTest, Types); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename T> | 
					
						
							|  |  |  | typename std::enable_if<std::is_integral<T>::value, T>::type test_value() { | 
					
						
							|  |  |  |   return static_cast<T>(42); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename T> | 
					
						
							|  |  |  | typename std::enable_if<std::is_floating_point<T>::value, T>::type | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | test_value() { | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  |   return static_cast<T>(4.2); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TYPED_TEST(NumericArgTest, MakeAndVisit) { | 
					
						
							| 
									
										
										
										
											2018-03-03 14:04:59 -08:00
										 |  |  |   CHECK_ARG(test_value<TypeParam>(), typename); | 
					
						
							|  |  |  |   CHECK_ARG(std::numeric_limits<TypeParam>::min(), typename); | 
					
						
							|  |  |  |   CHECK_ARG(std::numeric_limits<TypeParam>::max(), typename); | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(ArgTest, CharArg) { | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  |   CHECK_ARG_(char, 'a', 'a'); | 
					
						
							|  |  |  |   CHECK_ARG_(wchar_t, L'a', 'a'); | 
					
						
							|  |  |  |   CHECK_ARG_(wchar_t, L'a', L'a'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(ArgTest, StringArg) { | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  |   char str_data[] = "test"; | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   char* str = str_data; | 
					
						
							|  |  |  |   const char* cstr = str; | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  |   CHECK_ARG_(char, cstr, str); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:52:52 -08:00
										 |  |  |   string_view sref(str); | 
					
						
							| 
									
										
										
										
											2016-12-11 21:13:54 -08:00
										 |  |  |   CHECK_ARG_(char, sref, std::string(str)); | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(ArgTest, WStringArg) { | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  |   wchar_t str_data[] = L"test"; | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   wchar_t* str = str_data; | 
					
						
							|  |  |  |   const wchar_t* cstr = str; | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:52:52 -08:00
										 |  |  |   fmt::wstring_view sref(str); | 
					
						
							| 
									
										
										
										
											2017-11-19 10:28:01 -08:00
										 |  |  |   CHECK_ARG_(wchar_t, cstr, str); | 
					
						
							|  |  |  |   CHECK_ARG_(wchar_t, cstr, cstr); | 
					
						
							| 
									
										
										
										
											2016-12-11 21:13:54 -08:00
										 |  |  |   CHECK_ARG_(wchar_t, sref, std::wstring(str)); | 
					
						
							| 
									
										
										
										
											2017-02-18 06:52:52 -08:00
										 |  |  |   CHECK_ARG_(wchar_t, sref, fmt::wstring_view(str)); | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(ArgTest, PointerArg) { | 
					
						
							| 
									
										
										
										
											2019-05-30 07:01:31 -07:00
										 |  |  |   void* p = nullptr; | 
					
						
							|  |  |  |   const void* cp = nullptr; | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  |   CHECK_ARG_(char, cp, p); | 
					
						
							|  |  |  |   CHECK_ARG_(wchar_t, cp, p); | 
					
						
							| 
									
										
										
										
											2018-03-03 14:04:59 -08:00
										 |  |  |   CHECK_ARG(cp, ); | 
					
						
							| 
									
										
										
										
											2016-12-11 13:22:45 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-03 14:04:59 -08:00
										 |  |  | struct check_custom { | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   test_result operator()( | 
					
						
							|  |  |  |       fmt::basic_format_arg<fmt::format_context>::handle h) const { | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |     struct test_buffer : fmt::internal::buffer<char> { | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |       char data[10]; | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |       test_buffer() : fmt::internal::buffer<char>(data, 0, 10) {} | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |       void grow(std::size_t) {} | 
					
						
							|  |  |  |     } buffer; | 
					
						
							| 
									
										
										
										
											2019-04-07 10:05:49 -07:00
										 |  |  |     fmt::internal::buffer<char>& base = buffer; | 
					
						
							| 
									
										
										
										
											2019-02-09 19:34:42 -08:00
										 |  |  |     fmt::format_parse_context parse_ctx(""); | 
					
						
							|  |  |  |     fmt::format_context ctx(std::back_inserter(base), fmt::format_args()); | 
					
						
							|  |  |  |     h.format(parse_ctx, ctx); | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |     EXPECT_EQ("test", std::string(buffer.data, buffer.size())); | 
					
						
							|  |  |  |     return test_result(); | 
					
						
							| 
									
										
										
										
											2018-03-03 14:04:59 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(ArgTest, CustomArg) { | 
					
						
							|  |  |  |   test_struct test; | 
					
						
							|  |  |  |   typedef mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle> | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |       visitor; | 
					
						
							| 
									
										
										
										
											2018-03-03 14:04:59 -08:00
										 |  |  |   testing::StrictMock<visitor> v; | 
					
						
							|  |  |  |   EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom())); | 
					
						
							| 
									
										
										
										
											2019-01-29 16:31:25 -05:00
										 |  |  |   fmt::visit_format_arg(v, make_arg<fmt::format_context>(test)); | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(ArgTest, VisitInvalidArg) { | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   testing::StrictMock<mock_visitor<fmt::monostate>> visitor; | 
					
						
							| 
									
										
										
										
											2016-12-27 07:43:25 -08:00
										 |  |  |   EXPECT_CALL(visitor, visit(_)); | 
					
						
							| 
									
										
										
										
											2018-04-08 07:03:44 -07:00
										 |  |  |   fmt::basic_format_arg<fmt::format_context> arg; | 
					
						
							| 
									
										
										
										
											2019-01-29 16:31:25 -05:00
										 |  |  |   fmt::visit_format_arg(visitor, arg); | 
					
						
							| 
									
										
										
										
											2014-07-16 07:55:31 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-16 07:51:57 -07:00
										 |  |  | TEST(FormatDynArgsTest, Basic) { | 
					
						
							|  |  |  |   fmt::dynamic_format_arg_store<fmt::format_context> store; | 
					
						
							|  |  |  |   store.push_back(42); | 
					
						
							|  |  |  |   store.push_back("abc1"); | 
					
						
							|  |  |  |   store.push_back(1.5f); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::string result = fmt::vformat("{} and {} and {}", store); | 
					
						
							|  |  |  |   EXPECT_EQ("42 and abc1 and 1.5", result); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatDynArgsTest, StringsAndRefs) { | 
					
						
							|  |  |  |   // Unfortunately the tests are compiled with old ABI so strings use COW.
 | 
					
						
							|  |  |  |   fmt::dynamic_format_arg_store<fmt::format_context> store; | 
					
						
							|  |  |  |   char str[] = "1234567890"; | 
					
						
							|  |  |  |   store.push_back(str); | 
					
						
							|  |  |  |   store.push_back(std::cref(str)); | 
					
						
							|  |  |  |   store.push_back(fmt::string_view{str}); | 
					
						
							|  |  |  |   str[0] = 'X'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::string result = fmt::vformat("{} and {} and {}", store); | 
					
						
							|  |  |  |   EXPECT_EQ("1234567890 and X234567890 and X234567890", result); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct custom_type { | 
					
						
							|  |  |  |   int i = 0; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FMT_BEGIN_NAMESPACE | 
					
						
							|  |  |  | template <> struct formatter<custom_type> { | 
					
						
							|  |  |  |   auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { | 
					
						
							|  |  |  |     return ctx.begin(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template <typename FormatContext> | 
					
						
							| 
									
										
										
										
											2020-03-21 08:51:48 -07:00
										 |  |  |   auto format(const custom_type& p, FormatContext& ctx) -> decltype(ctx.out()) { | 
					
						
							| 
									
										
										
										
											2020-03-16 07:51:57 -07:00
										 |  |  |     return format_to(ctx.out(), "cust={}", p.i); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | FMT_END_NAMESPACE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatDynArgsTest, CustomFormat) { | 
					
						
							|  |  |  |   fmt::dynamic_format_arg_store<fmt::format_context> store; | 
					
						
							|  |  |  |   custom_type c{}; | 
					
						
							|  |  |  |   store.push_back(c); | 
					
						
							|  |  |  |   ++c.i; | 
					
						
							|  |  |  |   store.push_back(c); | 
					
						
							|  |  |  |   ++c.i; | 
					
						
							|  |  |  |   store.push_back(std::cref(c)); | 
					
						
							|  |  |  |   ++c.i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::string result = fmt::vformat("{} and {} and {}", store); | 
					
						
							|  |  |  |   EXPECT_EQ("cust=0 and cust=1 and cust=3", result); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatDynArgsTest, NamedArgByRef) { | 
					
						
							|  |  |  |   fmt::dynamic_format_arg_store<fmt::format_context> store; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Note: fmt::arg() constructs an object which holds a reference
 | 
					
						
							|  |  |  |   // to its value. It's not an aggregate, so it doesn't extend the
 | 
					
						
							|  |  |  |   // reference lifetime. As a result, it's a very bad idea passing temporary
 | 
					
						
							|  |  |  |   // as a named argument value. Only GCC with optimization level >0
 | 
					
						
							|  |  |  |   // complains about this.
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   // A real life usecase is when you have both name and value alive
 | 
					
						
							|  |  |  |   // guarantee their lifetime and thus don't want them to be copied into
 | 
					
						
							|  |  |  |   // storages.
 | 
					
						
							|  |  |  |   int a1_val{42}; | 
					
						
							|  |  |  |   auto a1 = fmt::arg("a1_", a1_val); | 
					
						
							|  |  |  |   store.push_back(std::cref(a1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::string result = fmt::vformat("{a1_}",  // and {} and {}",
 | 
					
						
							|  |  |  |                                     store); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   EXPECT_EQ("42", result); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 08:51:48 -07:00
										 |  |  | struct copy_throwable { | 
					
						
							|  |  |  |   copy_throwable() {} | 
					
						
							|  |  |  |   copy_throwable(const copy_throwable&) { throw "deal with it"; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FMT_BEGIN_NAMESPACE | 
					
						
							|  |  |  | template <> struct formatter<copy_throwable> { | 
					
						
							|  |  |  |   auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { | 
					
						
							|  |  |  |     return ctx.begin(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   auto format(copy_throwable, format_context& ctx) -> decltype(ctx.out()) { | 
					
						
							|  |  |  |     return ctx.out(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | FMT_END_NAMESPACE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatDynArgsTest, ThrowOnCopy) { | 
					
						
							|  |  |  |   fmt::dynamic_format_arg_store<fmt::format_context> store; | 
					
						
							|  |  |  |   store.push_back(std::string("foo")); | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     store.push_back(copy_throwable()); | 
					
						
							|  |  |  |   } catch (...) { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   EXPECT_EQ(fmt::vformat("{}", store), "foo"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-01 08:38:00 -08:00
										 |  |  | TEST(StringViewTest, ValueType) { | 
					
						
							|  |  |  |   static_assert(std::is_same<string_view::value_type, char>::value, ""); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(StringViewTest, Length) { | 
					
						
							| 
									
										
										
										
											2020-02-01 08:38:00 -08:00
										 |  |  |   // Test that string_view::size() returns string length, not buffer size.
 | 
					
						
							| 
									
										
										
										
											2015-02-24 09:52:16 -08:00
										 |  |  |   char str[100] = "some string"; | 
					
						
							| 
									
										
										
										
											2017-02-18 06:52:52 -08:00
										 |  |  |   EXPECT_EQ(std::strlen(str), string_view(str).size()); | 
					
						
							| 
									
										
										
										
											2015-02-24 09:52:16 -08:00
										 |  |  |   EXPECT_LT(std::strlen(str), sizeof(str)); | 
					
						
							| 
									
										
										
										
											2014-10-30 06:27:44 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | // Check string_view's comparison operator.
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | template <template <typename> class Op> void check_op() { | 
					
						
							|  |  |  |   const char* inputs[] = {"foo", "fop", "fo"}; | 
					
						
							| 
									
										
										
										
											2015-10-22 08:41:42 -07:00
										 |  |  |   std::size_t num_inputs = sizeof(inputs) / sizeof(*inputs); | 
					
						
							|  |  |  |   for (std::size_t i = 0; i < num_inputs; ++i) { | 
					
						
							|  |  |  |     for (std::size_t j = 0; j < num_inputs; ++j) { | 
					
						
							| 
									
										
										
										
											2017-02-18 06:52:52 -08:00
										 |  |  |       string_view lhs(inputs[i]), rhs(inputs[j]); | 
					
						
							|  |  |  |       EXPECT_EQ(Op<int>()(lhs.compare(rhs), 0), Op<string_view>()(lhs, rhs)); | 
					
						
							| 
									
										
										
										
											2015-10-22 08:41:42 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(StringViewTest, Compare) { | 
					
						
							|  |  |  |   EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0); | 
					
						
							| 
									
										
										
										
											2017-02-18 06:52:52 -08:00
										 |  |  |   EXPECT_GT(string_view("fop").compare(string_view("foo")), 0); | 
					
						
							|  |  |  |   EXPECT_LT(string_view("foo").compare(string_view("fop")), 0); | 
					
						
							|  |  |  |   EXPECT_GT(string_view("foo").compare(string_view("fo")), 0); | 
					
						
							|  |  |  |   EXPECT_LT(string_view("fo").compare(string_view("foo")), 0); | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  |   check_op<std::equal_to>(); | 
					
						
							|  |  |  |   check_op<std::not_equal_to>(); | 
					
						
							|  |  |  |   check_op<std::less>(); | 
					
						
							|  |  |  |   check_op<std::less_equal>(); | 
					
						
							|  |  |  |   check_op<std::greater>(); | 
					
						
							|  |  |  |   check_op<std::greater_equal>(); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 07:08:04 -07:00
										 |  |  | struct enabled_formatter {}; | 
					
						
							|  |  |  | struct disabled_formatter {}; | 
					
						
							|  |  |  | struct disabled_formatter_convertible { | 
					
						
							|  |  |  |   operator int() const { return 42; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FMT_BEGIN_NAMESPACE | 
					
						
							|  |  |  | template <> struct formatter<enabled_formatter> { | 
					
						
							|  |  |  |   auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { | 
					
						
							|  |  |  |     return ctx.begin(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   auto format(enabled_formatter, format_context& ctx) -> decltype(ctx.out()) { | 
					
						
							|  |  |  |     return ctx.out(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | FMT_END_NAMESPACE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(CoreTest, HasFormatter) { | 
					
						
							| 
									
										
										
										
											2019-11-14 10:08:24 -05:00
										 |  |  |   using fmt::has_formatter; | 
					
						
							| 
									
										
										
										
											2019-06-07 07:08:04 -07:00
										 |  |  |   using context = fmt::format_context; | 
					
						
							| 
									
										
										
										
											2019-11-14 10:08:24 -05:00
										 |  |  |   static_assert(has_formatter<enabled_formatter, context>::value, ""); | 
					
						
							|  |  |  |   static_assert(!has_formatter<disabled_formatter, context>::value, ""); | 
					
						
							| 
									
										
										
										
											2019-12-21 13:10:45 -08:00
										 |  |  |   static_assert(!has_formatter<disabled_formatter_convertible, context>::value, | 
					
						
							|  |  |  |                 ""); | 
					
						
							| 
									
										
										
										
											2018-06-07 20:20:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 06:25:46 -07:00
										 |  |  | struct convertible_to_int { | 
					
						
							|  |  |  |   operator int() const { return 42; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 18:47:48 -08:00
										 |  |  | struct convertible_to_c_string { | 
					
						
							|  |  |  |   operator const char*() const { return "foo"; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 06:25:46 -07:00
										 |  |  | FMT_BEGIN_NAMESPACE | 
					
						
							|  |  |  | template <> struct formatter<convertible_to_int> { | 
					
						
							|  |  |  |   auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { | 
					
						
							|  |  |  |     return ctx.begin(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   auto format(convertible_to_int, format_context& ctx) -> decltype(ctx.out()) { | 
					
						
							|  |  |  |     return std::copy_n("foo", 3, ctx.out()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-02-07 18:47:48 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | template <> struct formatter<convertible_to_c_string> { | 
					
						
							|  |  |  |   auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { | 
					
						
							|  |  |  |     return ctx.begin(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   auto format(convertible_to_c_string, format_context& ctx) | 
					
						
							|  |  |  |       -> decltype(ctx.out()) { | 
					
						
							|  |  |  |     return std::copy_n("bar", 3, ctx.out()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-06-07 06:25:46 -07:00
										 |  |  | FMT_END_NAMESPACE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(CoreTest, FormatterOverridesImplicitConversion) { | 
					
						
							|  |  |  |   EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo"); | 
					
						
							| 
									
										
										
										
											2020-02-07 18:47:48 -08:00
										 |  |  |   EXPECT_EQ(fmt::format("{}", convertible_to_c_string()), "bar"); | 
					
						
							| 
									
										
										
										
											2019-06-07 06:25:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  | namespace my_ns { | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | template <typename Char> class my_string { | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  |  public: | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   my_string(const Char* s) : s_(s) {} | 
					
						
							|  |  |  |   const Char* data() const FMT_NOEXCEPT { return s_.data(); } | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  |   std::size_t length() const FMT_NOEXCEPT { return s_.size(); } | 
					
						
							|  |  |  |   operator const Char*() const { return s_.c_str(); } | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  |  private: | 
					
						
							|  |  |  |   std::basic_string<Char> s_; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | inline fmt::basic_string_view<Char> to_string_view(const my_string<Char>& s) | 
					
						
							|  |  |  |     FMT_NOEXCEPT { | 
					
						
							|  |  |  |   return {s.data(), s.length()}; | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct non_string {}; | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | }  // namespace my_ns
 | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace FakeQt { | 
					
						
							|  |  |  | class QString { | 
					
						
							|  |  |  |  public: | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  |   QString(const wchar_t* s) : s_(std::make_shared<std::wstring>(s)) {} | 
					
						
							|  |  |  |   const wchar_t* utf16() const FMT_NOEXCEPT { return s_->data(); } | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  |   int size() const FMT_NOEXCEPT { return static_cast<int>(s_->size()); } | 
					
						
							| 
									
										
										
										
											2019-05-30 20:50:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  |  private: | 
					
						
							|  |  |  |   std::shared_ptr<std::wstring> s_; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | inline fmt::basic_string_view<wchar_t> to_string_view(const QString& s) | 
					
						
							|  |  |  |     FMT_NOEXCEPT { | 
					
						
							|  |  |  |   return {s.utf16(), static_cast<std::size_t>(s.size())}; | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | }  // namespace FakeQt
 | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | template <typename T> class IsStringTest : public testing::Test {}; | 
					
						
							| 
									
										
										
										
											2018-10-07 18:54:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef ::testing::Types<char, wchar_t, char16_t, char32_t> StringCharTypes; | 
					
						
							|  |  |  | TYPED_TEST_CASE(IsStringTest, StringCharTypes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							|  |  |  | struct derived_from_string_view : fmt::basic_string_view<Char> {}; | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | }  // namespace
 | 
					
						
							| 
									
										
										
										
											2018-10-07 18:54:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | TYPED_TEST(IsStringTest, IsString) { | 
					
						
							| 
									
										
										
										
											2019-05-30 20:50:07 -07:00
										 |  |  |   EXPECT_TRUE(fmt::internal::is_string<TypeParam*>::value); | 
					
						
							|  |  |  |   EXPECT_TRUE(fmt::internal::is_string<const TypeParam*>::value); | 
					
						
							|  |  |  |   EXPECT_TRUE(fmt::internal::is_string<TypeParam[2]>::value); | 
					
						
							|  |  |  |   EXPECT_TRUE(fmt::internal::is_string<const TypeParam[2]>::value); | 
					
						
							|  |  |  |   EXPECT_TRUE(fmt::internal::is_string<std::basic_string<TypeParam>>::value); | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  |   EXPECT_TRUE( | 
					
						
							| 
									
										
										
										
											2019-05-30 20:50:07 -07:00
										 |  |  |       fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value); | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  |   EXPECT_TRUE( | 
					
						
							| 
									
										
										
										
											2019-05-30 20:50:07 -07:00
										 |  |  |       fmt::internal::is_string<derived_from_string_view<TypeParam>>::value); | 
					
						
							|  |  |  |   using string_view = fmt::internal::std_string_view<TypeParam>; | 
					
						
							|  |  |  |   EXPECT_TRUE(std::is_empty<string_view>::value != | 
					
						
							|  |  |  |               fmt::internal::is_string<string_view>::value); | 
					
						
							|  |  |  |   EXPECT_TRUE(fmt::internal::is_string<my_ns::my_string<TypeParam>>::value); | 
					
						
							|  |  |  |   EXPECT_FALSE(fmt::internal::is_string<my_ns::non_string>::value); | 
					
						
							|  |  |  |   EXPECT_TRUE(fmt::internal::is_string<FakeQt::QString>::value); | 
					
						
							| 
									
										
										
										
											2018-10-07 18:54:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | TEST(CoreTest, Format) { | 
					
						
							|  |  |  |   // This should work without including fmt/format.h.
 | 
					
						
							|  |  |  | #ifdef FMT_FORMAT_H_
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #  error fmt/format.h must not be included in the core test
 | 
					
						
							| 
									
										
										
										
											2018-09-19 08:55:45 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |   EXPECT_EQ(fmt::format("{}", 42), "42"); | 
					
						
							| 
									
										
										
										
											2018-06-07 20:20:36 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-24 18:42:42 -07:00
										 |  |  | TEST(CoreTest, FormatTo) { | 
					
						
							|  |  |  |   // This should work without including fmt/format.h.
 | 
					
						
							|  |  |  | #ifdef FMT_FORMAT_H_
 | 
					
						
							| 
									
										
										
										
											2019-01-12 18:27:38 -08:00
										 |  |  | #  error fmt/format.h must not be included in the core test
 | 
					
						
							| 
									
										
										
										
											2018-10-24 18:42:42 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |   std::string s; | 
					
						
							|  |  |  |   fmt::format_to(std::back_inserter(s), "{}", 42); | 
					
						
							|  |  |  |   EXPECT_EQ(s, "42"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  | TEST(CoreTest, ToStringViewForeignStrings) { | 
					
						
							|  |  |  |   using namespace my_ns; | 
					
						
							|  |  |  |   using namespace FakeQt; | 
					
						
							|  |  |  |   EXPECT_EQ(to_string_view(my_string<char>("42")), "42"); | 
					
						
							|  |  |  |   EXPECT_EQ(to_string_view(my_string<wchar_t>(L"42")), L"42"); | 
					
						
							|  |  |  |   EXPECT_EQ(to_string_view(QString(L"42")), L"42"); | 
					
						
							|  |  |  |   fmt::internal::type type = | 
					
						
							| 
									
										
										
										
											2019-06-10 21:21:45 -07:00
										 |  |  |       fmt::internal::mapped_type_constant<my_string<char>, | 
					
						
							|  |  |  |                                           fmt::format_context>::value; | 
					
						
							| 
									
										
										
										
											2019-12-21 09:31:14 -08:00
										 |  |  |   EXPECT_EQ(type, fmt::internal::type::string_type); | 
					
						
							| 
									
										
										
										
											2019-06-10 21:21:45 -07:00
										 |  |  |   type = fmt::internal::mapped_type_constant<my_string<wchar_t>, | 
					
						
							|  |  |  |                                              fmt::wformat_context>::value; | 
					
						
							| 
									
										
										
										
											2019-12-21 09:31:14 -08:00
										 |  |  |   EXPECT_EQ(type, fmt::internal::type::string_type); | 
					
						
							| 
									
										
										
										
											2019-06-10 21:21:45 -07:00
										 |  |  |   type = | 
					
						
							|  |  |  |       fmt::internal::mapped_type_constant<QString, fmt::wformat_context>::value; | 
					
						
							| 
									
										
										
										
											2019-12-21 09:31:14 -08:00
										 |  |  |   EXPECT_EQ(type, fmt::internal::type::string_type); | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  |   // Does not compile: only wide format contexts are compatible with QString!
 | 
					
						
							| 
									
										
										
										
											2019-06-10 21:21:45 -07:00
										 |  |  |   // type = fmt::internal::mapped_type_constant<QString,
 | 
					
						
							|  |  |  |   // fmt::format_context>::value;
 | 
					
						
							| 
									
										
										
										
											2018-10-08 20:14:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(CoreTest, FormatForeignStrings) { | 
					
						
							|  |  |  |   using namespace my_ns; | 
					
						
							|  |  |  |   using namespace FakeQt; | 
					
						
							|  |  |  |   EXPECT_EQ(fmt::format(my_string<char>("{}"), 42), "42"); | 
					
						
							|  |  |  |   EXPECT_EQ(fmt::format(my_string<wchar_t>(L"{}"), 42), L"42"); | 
					
						
							|  |  |  |   EXPECT_EQ(fmt::format(QString(L"{}"), 42), L"42"); | 
					
						
							|  |  |  |   EXPECT_EQ(fmt::format(QString(L"{}"), my_string<wchar_t>(L"42")), L"42"); | 
					
						
							|  |  |  |   EXPECT_EQ(fmt::format(my_string<wchar_t>(L"{}"), QString(L"42")), L"42"); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-27 17:10:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-09 21:10:09 -07:00
										 |  |  | struct implicitly_convertible_to_string { | 
					
						
							|  |  |  |   operator std::string() const { return "foo"; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 17:10:19 -07:00
										 |  |  | struct implicitly_convertible_to_string_view { | 
					
						
							|  |  |  |   operator fmt::string_view() const { return "foo"; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatterTest, FormatImplicitlyConvertibleToStringView) { | 
					
						
							|  |  |  |   EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // std::is_constructible is broken in MSVC until version 2015.
 | 
					
						
							| 
									
										
										
										
											2019-05-30 07:01:31 -07:00
										 |  |  | #if !FMT_MSC_VER || FMT_MSC_VER >= 1900
 | 
					
						
							| 
									
										
										
										
											2018-10-27 17:10:19 -07:00
										 |  |  | struct explicitly_convertible_to_string_view { | 
					
						
							|  |  |  |   explicit operator fmt::string_view() const { return "foo"; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatterTest, FormatExplicitlyConvertibleToStringView) { | 
					
						
							|  |  |  |   EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-21 13:10:45 -08:00
										 |  |  | #  ifdef FMT_USE_STRING_VIEW
 | 
					
						
							| 
									
										
										
										
											2019-10-04 17:21:10 -07:00
										 |  |  | struct explicitly_convertible_to_std_string_view { | 
					
						
							|  |  |  |   explicit operator std::string_view() const { return "foo"; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) { | 
					
						
							|  |  |  |   EXPECT_EQ("foo", | 
					
						
							|  |  |  |             fmt::format("{}", explicitly_convertible_to_std_string_view())); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-12-21 13:10:45 -08:00
										 |  |  | #  endif
 | 
					
						
							| 
									
										
										
										
											2019-10-04 17:21:10 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 17:10:19 -07:00
										 |  |  | struct explicitly_convertible_to_wstring_view { | 
					
						
							|  |  |  |   explicit operator fmt::wstring_view() const { return L"foo"; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatterTest, FormatExplicitlyConvertibleToWStringView) { | 
					
						
							|  |  |  |   EXPECT_EQ(L"foo", | 
					
						
							|  |  |  |             fmt::format(L"{}", explicitly_convertible_to_wstring_view())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-11-25 08:30:47 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct disabled_rvalue_conversion { | 
					
						
							|  |  |  |   operator const char*() const& { return "foo"; } | 
					
						
							| 
									
										
										
										
											2019-12-21 13:10:45 -08:00
										 |  |  |   operator const char*() & { return "foo"; } | 
					
						
							| 
									
										
										
										
											2019-11-25 08:30:47 -08:00
										 |  |  |   operator const char*() const&& = delete; | 
					
						
							| 
									
										
										
										
											2019-12-21 13:10:45 -08:00
										 |  |  |   operator const char*() && = delete; | 
					
						
							| 
									
										
										
										
											2019-11-25 08:30:47 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatterTest, DisabledRValueConversion) { | 
					
						
							|  |  |  |   EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion())); | 
					
						
							|  |  |  | } |