Home | History | Annotate | Download | only in io
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // Author: kenton (at) google.com (Kenton Varda)
     32 //  Based on original Protocol Buffers design by
     33 //  Sanjay Ghemawat, Jeff Dean, and others.
     34 
     35 #include <vector>
     36 
     37 #include <google/protobuf/io/printer.h>
     38 #include <google/protobuf/io/zero_copy_stream_impl.h>
     39 
     40 #include <google/protobuf/stubs/common.h>
     41 #include <google/protobuf/testing/googletest.h>
     42 #include <gtest/gtest.h>
     43 
     44 namespace google {
     45 namespace protobuf {
     46 namespace io {
     47 namespace {
     48 
     49 // Each test repeats over several block sizes in order to test both cases
     50 // where particular writes cross a buffer boundary and cases where they do
     51 // not.
     52 
     53 TEST(Printer, EmptyPrinter) {
     54   char buffer[8192];
     55   const int block_size = 100;
     56   ArrayOutputStream output(buffer, GOOGLE_ARRAYSIZE(buffer), block_size);
     57   Printer printer(&output, '\0');
     58   EXPECT_TRUE(!printer.failed());
     59 }
     60 
     61 TEST(Printer, BasicPrinting) {
     62   char buffer[8192];
     63 
     64   for (int block_size = 1; block_size < 512; block_size *= 2) {
     65     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
     66 
     67     {
     68       Printer printer(&output, '\0');
     69 
     70       printer.Print("Hello World!");
     71       printer.Print("  This is the same line.\n");
     72       printer.Print("But this is a new one.\nAnd this is another one.");
     73 
     74       EXPECT_FALSE(printer.failed());
     75     }
     76 
     77     buffer[output.ByteCount()] = '\0';
     78 
     79     EXPECT_STREQ("Hello World!  This is the same line.\n"
     80                  "But this is a new one.\n"
     81                  "And this is another one.",
     82                  buffer);
     83   }
     84 }
     85 
     86 TEST(Printer, WriteRaw) {
     87   char buffer[8192];
     88 
     89   for (int block_size = 1; block_size < 512; block_size *= 2) {
     90     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
     91 
     92     {
     93       string string_obj = "From an object\n";
     94       Printer printer(&output, '$');
     95       printer.WriteRaw("Hello World!", 12);
     96       printer.PrintRaw("  This is the same line.\n");
     97       printer.PrintRaw("But this is a new one.\nAnd this is another one.");
     98       printer.WriteRaw("\n", 1);
     99       printer.PrintRaw(string_obj);
    100       EXPECT_FALSE(printer.failed());
    101     }
    102 
    103     buffer[output.ByteCount()] = '\0';
    104 
    105     EXPECT_STREQ("Hello World!  This is the same line.\n"
    106                  "But this is a new one.\n"
    107                  "And this is another one."
    108                  "\n"
    109                  "From an object\n",
    110                  buffer);
    111   }
    112 }
    113 
    114 TEST(Printer, VariableSubstitution) {
    115   char buffer[8192];
    116 
    117   for (int block_size = 1; block_size < 512; block_size *= 2) {
    118     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
    119 
    120     {
    121       Printer printer(&output, '$');
    122       map<string, string> vars;
    123 
    124       vars["foo"] = "World";
    125       vars["bar"] = "$foo$";
    126       vars["abcdefg"] = "1234";
    127 
    128       printer.Print(vars, "Hello $foo$!\nbar = $bar$\n");
    129       printer.PrintRaw("RawBit\n");
    130       printer.Print(vars, "$abcdefg$\nA literal dollar sign:  $$");
    131 
    132       vars["foo"] = "blah";
    133       printer.Print(vars, "\nNow foo = $foo$.");
    134 
    135       EXPECT_FALSE(printer.failed());
    136     }
    137 
    138     buffer[output.ByteCount()] = '\0';
    139 
    140     EXPECT_STREQ("Hello World!\n"
    141                  "bar = $foo$\n"
    142                  "RawBit\n"
    143                  "1234\n"
    144                  "A literal dollar sign:  $\n"
    145                  "Now foo = blah.",
    146                  buffer);
    147   }
    148 }
    149 
    150 TEST(Printer, InlineVariableSubstitution) {
    151   char buffer[8192];
    152 
    153   ArrayOutputStream output(buffer, sizeof(buffer));
    154 
    155   {
    156     Printer printer(&output, '$');
    157     printer.Print("Hello $foo$!\n", "foo", "World");
    158     printer.PrintRaw("RawBit\n");
    159     printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
    160     EXPECT_FALSE(printer.failed());
    161   }
    162 
    163   buffer[output.ByteCount()] = '\0';
    164 
    165   EXPECT_STREQ("Hello World!\n"
    166                "RawBit\n"
    167                "one two\n",
    168                buffer);
    169 }
    170 
    171 TEST(Printer, Indenting) {
    172   char buffer[8192];
    173 
    174   for (int block_size = 1; block_size < 512; block_size *= 2) {
    175     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
    176 
    177     {
    178       Printer printer(&output, '$');
    179       map<string, string> vars;
    180 
    181       vars["newline"] = "\n";
    182 
    183       printer.Print("This is not indented.\n");
    184       printer.Indent();
    185       printer.Print("This is indented\nAnd so is this\n");
    186       printer.Outdent();
    187       printer.Print("But this is not.");
    188       printer.Indent();
    189       printer.Print("  And this is still the same line.\n"
    190                     "But this is indented.\n");
    191       printer.PrintRaw("RawBit has indent at start\n");
    192       printer.PrintRaw("but not after a raw newline\n");
    193       printer.Print(vars, "Note that a newline in a variable will break "
    194                     "indenting, as we see$newline$here.\n");
    195       printer.Indent();
    196       printer.Print("And this");
    197       printer.Outdent();
    198       printer.Outdent();
    199       printer.Print(" is double-indented\nBack to normal.");
    200 
    201       EXPECT_FALSE(printer.failed());
    202     }
    203 
    204     buffer[output.ByteCount()] = '\0';
    205 
    206     EXPECT_STREQ(
    207       "This is not indented.\n"
    208       "  This is indented\n"
    209       "  And so is this\n"
    210       "But this is not.  And this is still the same line.\n"
    211       "  But this is indented.\n"
    212       "  RawBit has indent at start\n"
    213       "but not after a raw newline\n"
    214       "Note that a newline in a variable will break indenting, as we see\n"
    215       "here.\n"
    216       "    And this is double-indented\n"
    217       "Back to normal.",
    218       buffer);
    219   }
    220 }
    221 
    222 // Death tests do not work on Windows as of yet.
    223 #ifdef GTEST_HAS_DEATH_TEST
    224 TEST(Printer, Death) {
    225   char buffer[8192];
    226 
    227   ArrayOutputStream output(buffer, sizeof(buffer));
    228   Printer printer(&output, '$');
    229 
    230   EXPECT_DEBUG_DEATH(printer.Print("$nosuchvar$"), "Undefined variable");
    231   EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
    232   EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
    233 }
    234 #endif  // GTEST_HAS_DEATH_TEST
    235 
    236 TEST(Printer, WriteFailure) {
    237   char buffer[16];
    238 
    239   ArrayOutputStream output(buffer, sizeof(buffer));
    240   Printer printer(&output, '$');
    241 
    242   // Print 16 bytes to fill the buffer exactly (should not fail).
    243   printer.Print("0123456789abcdef");
    244   EXPECT_FALSE(printer.failed());
    245 
    246   // Try to print one more byte (should fail).
    247   printer.Print(" ");
    248   EXPECT_TRUE(printer.failed());
    249 
    250   // Should not crash
    251   printer.Print("blah");
    252   EXPECT_TRUE(printer.failed());
    253 
    254   // Buffer should contain the first 16 bytes written.
    255   EXPECT_EQ("0123456789abcdef", string(buffer, sizeof(buffer)));
    256 }
    257 
    258 }  // namespace
    259 }  // namespace io
    260 }  // namespace protobuf
    261 }  // namespace google
    262