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@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
44namespace google {
45namespace protobuf {
46namespace io {
47namespace {
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
53TEST(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
61TEST(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
86TEST(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
114TEST(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
150TEST(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
171TEST(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
224TEST(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
236TEST(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