Home | History | Annotate | Download | only in test
      1 /*
      2  std::ostream support tests
      3 
      4  Copyright (c) 2012-2016, Victor Zverovich
      5  All rights reserved.
      6 
      7  Redistribution and use in source and binary forms, with or without
      8  modification, are permitted provided that the following conditions are met:
      9 
     10  1. Redistributions of source code must retain the above copyright notice, this
     11     list of conditions and the following disclaimer.
     12  2. Redistributions in binary form must reproduce the above copyright notice,
     13     this list of conditions and the following disclaimer in the documentation
     14     and/or other materials provided with the distribution.
     15 
     16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     20  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "fmt/ostream.h"
     29 
     30 #include <sstream>
     31 #include "gmock/gmock.h"
     32 #include "gtest-extra.h"
     33 #include "util.h"
     34 
     35 using fmt::format;
     36 using fmt::FormatError;
     37 
     38 std::ostream &operator<<(std::ostream &os, const Date &d) {
     39   os << d.year() << '-' << d.month() << '-' << d.day();
     40   return os;
     41 }
     42 
     43 std::wostream &operator<<(std::wostream &os, const Date &d) {
     44   os << d.year() << L'-' << d.month() << L'-' << d.day();
     45   return os;
     46 }
     47 
     48 enum TestEnum {};
     49 std::ostream &operator<<(std::ostream &os, TestEnum) {
     50   return os << "TestEnum";
     51 }
     52 
     53 enum TestEnum2 {A};
     54 
     55 TEST(OStreamTest, Enum) {
     56   EXPECT_FALSE(fmt::internal::ConvertToInt<TestEnum>::value);
     57   EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
     58   EXPECT_EQ("0", fmt::format("{}", A));
     59 }
     60 
     61 struct TestArgFormatter : fmt::BasicArgFormatter<TestArgFormatter, char> {
     62   TestArgFormatter(fmt::BasicFormatter<char, TestArgFormatter> &f,
     63                    fmt::FormatSpec &s, const char *fmt)
     64     : fmt::BasicArgFormatter<TestArgFormatter, char>(f, s, fmt) {}
     65 };
     66 
     67 TEST(OStreamTest, CustomArg) {
     68   fmt::MemoryWriter writer;
     69   typedef fmt::BasicFormatter<char, TestArgFormatter> Formatter;
     70   Formatter formatter(fmt::ArgList(), writer);
     71   fmt::FormatSpec spec;
     72   TestArgFormatter af(formatter, spec, "}");
     73   af.visit(fmt::internal::MakeArg<Formatter>(TestEnum()));
     74   EXPECT_EQ("TestEnum", writer.str());
     75 }
     76 
     77 TEST(OStreamTest, Format) {
     78   EXPECT_EQ("a string", format("{0}", TestString("a string")));
     79   std::string s = format("The date is {0}", Date(2012, 12, 9));
     80   EXPECT_EQ("The date is 2012-12-9", s);
     81   Date date(2012, 12, 9);
     82   EXPECT_EQ(L"The date is 2012-12-9",
     83             format(L"The date is {0}", Date(2012, 12, 9)));
     84 }
     85 
     86 TEST(OStreamTest, FormatSpecs) {
     87   EXPECT_EQ("def  ", format("{0:<5}", TestString("def")));
     88   EXPECT_EQ("  def", format("{0:>5}", TestString("def")));
     89   EXPECT_THROW_MSG(format("{0:=5}", TestString("def")),
     90       FormatError, "format specifier '=' requires numeric argument");
     91   EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
     92   EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
     93   EXPECT_THROW_MSG(format("{0:+}", TestString()),
     94       FormatError, "format specifier '+' requires numeric argument");
     95   EXPECT_THROW_MSG(format("{0:-}", TestString()),
     96       FormatError, "format specifier '-' requires numeric argument");
     97   EXPECT_THROW_MSG(format("{0: }", TestString()),
     98       FormatError, "format specifier ' ' requires numeric argument");
     99   EXPECT_THROW_MSG(format("{0:#}", TestString()),
    100       FormatError, "format specifier '#' requires numeric argument");
    101   EXPECT_THROW_MSG(format("{0:05}", TestString()),
    102       FormatError, "format specifier '0' requires numeric argument");
    103   EXPECT_EQ("test         ", format("{0:13}", TestString("test")));
    104   EXPECT_EQ("test         ", format("{0:{1}}", TestString("test"), 13));
    105   EXPECT_EQ("te", format("{0:.2}", TestString("test")));
    106   EXPECT_EQ("te", format("{0:.{1}}", TestString("test"), 2));
    107 }
    108 
    109 struct EmptyTest {};
    110 std::ostream &operator<<(std::ostream &os, EmptyTest) {
    111   return os << "";
    112 }
    113 
    114 TEST(OStreamTest, EmptyCustomOutput) {
    115   EXPECT_EQ("", fmt::format("{}", EmptyTest()));
    116 }
    117 
    118 TEST(OStreamTest, Print) {
    119   std::ostringstream os;
    120   fmt::print(os, "Don't {}!", "panic");
    121   EXPECT_EQ("Don't panic!", os.str());
    122 }
    123 
    124 TEST(OStreamTest, WriteToOStream) {
    125   std::ostringstream os;
    126   fmt::MemoryWriter w;
    127   w << "foo";
    128   fmt::internal::write(os, w);
    129   EXPECT_EQ("foo", os.str());
    130 }
    131 
    132 TEST(OStreamTest, WriteToOStreamMaxSize) {
    133   std::size_t max_size = std::numeric_limits<std::size_t>::max();
    134   std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max();
    135   if (max_size <= fmt::internal::to_unsigned(max_streamsize))
    136     return;
    137 
    138   class TestWriter : public fmt::BasicWriter<char> {
    139    private:
    140     struct TestBuffer : fmt::Buffer<char> {
    141       explicit TestBuffer(std::size_t size) { size_ = size; }
    142       void grow(std::size_t) {}
    143     } buffer_;
    144    public:
    145     explicit TestWriter(std::size_t size)
    146       : fmt::BasicWriter<char>(buffer_), buffer_(size) {}
    147   } w(max_size);
    148 
    149   struct MockStreamBuf : std::streambuf {
    150     MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
    151     std::streamsize xsputn(const char *s, std::streamsize n) {
    152       const void *v = s;
    153       return xsputn(v, n);
    154     }
    155   } buffer;
    156 
    157   struct TestOStream : std::ostream {
    158     explicit TestOStream(MockStreamBuf &buffer) : std::ostream(&buffer) {}
    159   } os(buffer);
    160 
    161   testing::InSequence sequence;
    162   const char *data = 0;
    163   std::size_t size = max_size;
    164   do {
    165     typedef fmt::internal::MakeUnsigned<std::streamsize>::Type UStreamSize;
    166     UStreamSize n = std::min<UStreamSize>(
    167           size, fmt::internal::to_unsigned(max_streamsize));
    168     EXPECT_CALL(buffer, xsputn(data, static_cast<std::streamsize>(n)))
    169         .WillOnce(testing::Return(max_streamsize));
    170     data += n;
    171     size -= static_cast<std::size_t>(n);
    172   } while (size != 0);
    173   fmt::internal::write(os, w);
    174 }
    175