| 
									
										
										
										
											2014-09-05 07:35:00 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  Formatting library implementation tests. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Copyright (c) 2012-2014, Victor Zverovich | 
					
						
							|  |  |  |  All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |     list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |     this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |     and/or other materials provided with the distribution. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | 
					
						
							|  |  |  |  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 
					
						
							|  |  |  |  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | 
					
						
							|  |  |  |  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 
					
						
							|  |  |  |  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
					
						
							|  |  |  |  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 
					
						
							|  |  |  |  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  |  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
					
						
							|  |  |  |  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 09:24:54 -07:00
										 |  |  | #define FMT_NOEXCEPT
 | 
					
						
							| 
									
										
										
										
											2015-06-22 08:17:23 -07:00
										 |  |  | #include "test-assert.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-05 07:35:00 -07:00
										 |  |  | // Include format.cc instead of format.h to test implementation-specific stuff.
 | 
					
						
							| 
									
										
										
										
											2016-04-24 09:06:12 -07:00
										 |  |  | #include "fmt/format.cc"
 | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 09:04:28 -08:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  | #include <cstring>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 09:04:28 -08:00
										 |  |  | #include "gmock/gmock.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-05 07:35:00 -07:00
										 |  |  | #include "gtest-extra.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  | #include "util.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-05 07:35:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 09:04:28 -08:00
										 |  |  | #undef min
 | 
					
						
							| 
									
										
										
										
											2014-09-05 08:06:07 -07:00
										 |  |  | #undef max
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-05 07:35:00 -07:00
										 |  |  | TEST(FormatTest, ArgConverter) { | 
					
						
							|  |  |  |   using fmt::internal::Arg; | 
					
						
							|  |  |  |   Arg arg = Arg(); | 
					
						
							|  |  |  |   arg.type = Arg::LONG_LONG; | 
					
						
							|  |  |  |   arg.long_long_value = std::numeric_limits<fmt::LongLong>::max(); | 
					
						
							| 
									
										
										
										
											2015-06-12 07:56:58 -07:00
										 |  |  |   fmt::ArgConverter<fmt::LongLong>(arg, 'd').visit(arg); | 
					
						
							| 
									
										
										
										
											2014-09-05 07:35:00 -07:00
										 |  |  |   EXPECT_EQ(Arg::LONG_LONG, arg.type); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  | TEST(FormatTest, FormatNegativeNaN) { | 
					
						
							| 
									
										
										
										
											2014-09-05 07:35:00 -07:00
										 |  |  |   double nan = std::numeric_limits<double>::quiet_NaN(); | 
					
						
							| 
									
										
										
										
											2015-11-21 07:20:18 -08:00
										 |  |  |   if (fmt::internal::FPUtil::isnegative(-nan)) | 
					
						
							| 
									
										
										
										
											2014-09-05 07:35:00 -07:00
										 |  |  |     EXPECT_EQ("-nan", fmt::format("{}", -nan)); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     fmt::print("Warning: compiler doesn't handle negative NaN correctly"); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  | TEST(FormatTest, StrError) { | 
					
						
							|  |  |  |   char *message = 0; | 
					
						
							|  |  |  |   char buffer[BUFFER_SIZE]; | 
					
						
							| 
									
										
										
										
											2015-06-22 08:17:23 -07:00
										 |  |  |   EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = 0, 0), "invalid buffer"); | 
					
						
							| 
									
										
										
										
											2016-03-08 06:55:41 -08:00
										 |  |  |   EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0), | 
					
						
							|  |  |  |                 "invalid buffer"); | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  |   buffer[0] = 'x'; | 
					
						
							| 
									
										
										
										
											2015-10-21 08:30:10 -07:00
										 |  |  | #if defined(_GNU_SOURCE) && !defined(__COVERITY__)
 | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  |   // Use invalid error code to make sure that safe_strerror returns an error
 | 
					
						
							|  |  |  |   // message in the buffer rather than a pointer to a static string.
 | 
					
						
							| 
									
										
										
										
											2015-10-21 08:30:10 -07:00
										 |  |  |   int error_code = -1; | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  | #else
 | 
					
						
							|  |  |  |   int error_code = EDOM; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 07:56:58 -07:00
										 |  |  |   int result = fmt::safe_strerror(error_code, message = buffer, BUFFER_SIZE); | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  |   EXPECT_EQ(0, result); | 
					
						
							|  |  |  |   std::size_t message_size = std::strlen(message); | 
					
						
							|  |  |  |   EXPECT_GE(BUFFER_SIZE - 1u, message_size); | 
					
						
							|  |  |  |   EXPECT_EQ(get_system_error(error_code), message); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // safe_strerror never uses buffer on MinGW.
 | 
					
						
							|  |  |  | #ifndef __MINGW32__
 | 
					
						
							| 
									
										
										
										
											2015-06-12 07:56:58 -07:00
										 |  |  |   result = fmt::safe_strerror(error_code, message = buffer, message_size); | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  |   EXPECT_EQ(ERANGE, result); | 
					
						
							| 
									
										
										
										
											2015-06-12 07:56:58 -07:00
										 |  |  |   result = fmt::safe_strerror(error_code, message = buffer, 1); | 
					
						
							| 
									
										
										
										
											2014-09-05 08:44:41 -07:00
										 |  |  |   EXPECT_EQ(buffer, message);  // Message should point to buffer.
 | 
					
						
							|  |  |  |   EXPECT_EQ(ERANGE, result); | 
					
						
							|  |  |  |   EXPECT_STREQ("", message); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  | TEST(FormatTest, FormatErrorCode) { | 
					
						
							|  |  |  |   std::string msg = "error 42", sep = ": "; | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2014-09-29 08:48:16 -07:00
										 |  |  |     fmt::MemoryWriter w; | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  |     w << "garbage"; | 
					
						
							| 
									
										
										
										
											2015-06-12 07:56:58 -07:00
										 |  |  |     fmt::format_error_code(w, 42, "test"); | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  |     EXPECT_EQ("test: " + msg, w.str()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2014-09-29 08:48:16 -07:00
										 |  |  |     fmt::MemoryWriter w; | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  |     std::string prefix( | 
					
						
							|  |  |  |         fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size() + 1, 'x'); | 
					
						
							| 
									
										
										
										
											2015-06-12 07:56:58 -07:00
										 |  |  |     fmt::format_error_code(w, 42, prefix); | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  |     EXPECT_EQ(msg, w.str()); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-03-02 07:01:21 -08:00
										 |  |  |   int codes[] = {42, -1}; | 
					
						
							|  |  |  |   for (std::size_t i = 0, n = sizeof(codes) / sizeof(*codes); i < n; ++i) { | 
					
						
							|  |  |  |     // Test maximum buffer size.
 | 
					
						
							|  |  |  |     msg = fmt::format("error {}", codes[i]); | 
					
						
							| 
									
										
										
										
											2014-09-29 08:48:16 -07:00
										 |  |  |     fmt::MemoryWriter w; | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  |     std::string prefix( | 
					
						
							|  |  |  |         fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size(), 'x'); | 
					
						
							| 
									
										
										
										
											2016-03-02 07:01:21 -08:00
										 |  |  |     fmt::format_error_code(w, codes[i], prefix); | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  |     EXPECT_EQ(prefix + sep + msg, w.str()); | 
					
						
							| 
									
										
										
										
											2014-09-25 07:38:16 -07:00
										 |  |  |     std::size_t size = fmt::internal::INLINE_BUFFER_SIZE; | 
					
						
							|  |  |  |     EXPECT_EQ(size, w.size()); | 
					
						
							| 
									
										
										
										
											2016-03-02 07:01:21 -08:00
										 |  |  |     w.clear(); | 
					
						
							|  |  |  |     // Test with a message that doesn't fit into the buffer.
 | 
					
						
							|  |  |  |     prefix += 'x'; | 
					
						
							|  |  |  |     fmt::format_error_code(w, codes[i], prefix); | 
					
						
							|  |  |  |     EXPECT_EQ(msg, w.str()); | 
					
						
							| 
									
										
										
										
											2014-09-05 08:04:26 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-04 09:04:28 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatTest, WriteToOStream) { | 
					
						
							|  |  |  |   std::ostringstream os; | 
					
						
							|  |  |  |   fmt::MemoryWriter w; | 
					
						
							|  |  |  |   w << "foo"; | 
					
						
							|  |  |  |   fmt::write(os, w); | 
					
						
							|  |  |  |   EXPECT_EQ("foo", os.str()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(FormatTest, WriteToOStreamMaxSize) { | 
					
						
							|  |  |  |   std::size_t max_size = std::numeric_limits<std::size_t>::max(); | 
					
						
							|  |  |  |   std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max(); | 
					
						
							|  |  |  |   if (max_size <= fmt::internal::to_unsigned(max_streamsize)) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class TestWriter : public fmt::BasicWriter<char> { | 
					
						
							|  |  |  |    private: | 
					
						
							|  |  |  |     struct TestBuffer : fmt::Buffer<char> { | 
					
						
							|  |  |  |       explicit TestBuffer(std::size_t size) { size_ = size; } | 
					
						
							|  |  |  |       void grow(std::size_t) {} | 
					
						
							|  |  |  |     } buffer_; | 
					
						
							|  |  |  |    public: | 
					
						
							|  |  |  |     explicit TestWriter(std::size_t size) | 
					
						
							|  |  |  |       : fmt::BasicWriter<char>(buffer_), buffer_(size) {} | 
					
						
							|  |  |  |   } w(max_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   struct MockStreamBuf : std::streambuf { | 
					
						
							|  |  |  |     MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n)); | 
					
						
							|  |  |  |     std::streamsize xsputn(const char *s, std::streamsize n) { | 
					
						
							|  |  |  |       const void *v = s; | 
					
						
							|  |  |  |       return xsputn(v, n); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } buffer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   struct TestOStream : std::ostream { | 
					
						
							|  |  |  |     explicit TestOStream(MockStreamBuf &buffer) : std::ostream(&buffer) {} | 
					
						
							|  |  |  |   } os(buffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   testing::InSequence sequence; | 
					
						
							|  |  |  |   const char *data = 0; | 
					
						
							|  |  |  |   std::size_t size = max_size; | 
					
						
							|  |  |  |   do { | 
					
						
							|  |  |  |     typedef fmt::internal::MakeUnsigned<std::streamsize>::Type UStreamSize; | 
					
						
							|  |  |  |     UStreamSize n = std::min<UStreamSize>( | 
					
						
							|  |  |  |           size, fmt::internal::to_unsigned(max_streamsize)); | 
					
						
							|  |  |  |     EXPECT_CALL(buffer, xsputn(data, static_cast<std::streamsize>(n))) | 
					
						
							|  |  |  |         .WillOnce(testing::Return(max_streamsize)); | 
					
						
							|  |  |  |     data += n; | 
					
						
							| 
									
										
										
										
											2016-03-19 06:39:33 -07:00
										 |  |  |     size -= static_cast<std::size_t>(n); | 
					
						
							| 
									
										
										
										
											2016-03-04 09:04:28 -08:00
										 |  |  |   } while (size != 0); | 
					
						
							|  |  |  |   fmt::write(os, w); | 
					
						
							|  |  |  | } |