printer_unittest.cc revision fbaaef999ba563838ebd00874ed8a1c01fbf286d
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(buffer,
80      "Hello World!  This is the same line.\n"
81      "But this is a new one.\n"
82      "And this is another one.");
83  }
84}
85
86TEST(Printer, VariableSubstitution) {
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      Printer printer(&output, '$');
94      map<string, string> vars;
95
96      vars["foo"] = "World";
97      vars["bar"] = "$foo$";
98      vars["abcdefg"] = "1234";
99
100      printer.Print(vars, "Hello $foo$!\nbar = $bar$\n");
101      printer.Print(vars, "$abcdefg$\nA literal dollar sign:  $$");
102
103      vars["foo"] = "blah";
104      printer.Print(vars, "\nNow foo = $foo$.");
105
106      EXPECT_FALSE(printer.failed());
107    }
108
109    buffer[output.ByteCount()] = '\0';
110
111    EXPECT_STREQ(buffer,
112      "Hello World!\n"
113      "bar = $foo$\n"
114      "1234\n"
115      "A literal dollar sign:  $\n"
116      "Now foo = blah.");
117  }
118}
119
120TEST(Printer, InlineVariableSubstitution) {
121  char buffer[8192];
122
123  ArrayOutputStream output(buffer, sizeof(buffer));
124
125  {
126    Printer printer(&output, '$');
127    printer.Print("Hello $foo$!\n", "foo", "World");
128    printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
129    EXPECT_FALSE(printer.failed());
130  }
131
132  buffer[output.ByteCount()] = '\0';
133
134  EXPECT_STREQ(buffer,
135    "Hello World!\n"
136    "one two\n");
137}
138
139TEST(Printer, Indenting) {
140  char buffer[8192];
141
142  for (int block_size = 1; block_size < 512; block_size *= 2) {
143    ArrayOutputStream output(buffer, sizeof(buffer), block_size);
144
145    {
146      Printer printer(&output, '$');
147      map<string, string> vars;
148
149      vars["newline"] = "\n";
150
151      printer.Print("This is not indented.\n");
152      printer.Indent();
153      printer.Print("This is indented\nAnd so is this\n");
154      printer.Outdent();
155      printer.Print("But this is not.");
156      printer.Indent();
157      printer.Print("  And this is still the same line.\n"
158                    "But this is indented.\n");
159      printer.Print(vars, "Note that a newline in a variable will break "
160                    "indenting, as we see$newline$here.\n");
161      printer.Indent();
162      printer.Print("And this");
163      printer.Outdent();
164      printer.Outdent();
165      printer.Print(" is double-indented\nBack to normal.");
166
167      EXPECT_FALSE(printer.failed());
168    }
169
170    buffer[output.ByteCount()] = '\0';
171
172    EXPECT_STREQ(buffer,
173      "This is not indented.\n"
174      "  This is indented\n"
175      "  And so is this\n"
176      "But this is not.  And this is still the same line.\n"
177      "  But this is indented.\n"
178      "  Note that a newline in a variable will break indenting, as we see\n"
179      "here.\n"
180      "    And this is double-indented\n"
181      "Back to normal.");
182  }
183}
184
185// Death tests do not work on Windows as of yet.
186#ifdef GTEST_HAS_DEATH_TEST
187TEST(Printer, Death) {
188  char buffer[8192];
189
190  ArrayOutputStream output(buffer, sizeof(buffer));
191  Printer printer(&output, '$');
192
193  EXPECT_DEBUG_DEATH(printer.Print("$nosuchvar$"), "Undefined variable");
194  EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
195  EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
196}
197#endif  // GTEST_HAS_DEATH_TEST
198
199TEST(Printer, WriteFailure) {
200  char buffer[16];
201
202  ArrayOutputStream output(buffer, sizeof(buffer));
203  Printer printer(&output, '$');
204
205  // Print 16 bytes to fill the buffer exactly (should not fail).
206  printer.Print("0123456789abcdef");
207  EXPECT_FALSE(printer.failed());
208
209  // Try to print one more byte (should fail).
210  printer.Print(" ");
211  EXPECT_TRUE(printer.failed());
212
213  // Should not crash
214  printer.Print("blah");
215  EXPECT_TRUE(printer.failed());
216
217  // Buffer should contain the first 16 bytes written.
218  EXPECT_EQ("0123456789abcdef", string(buffer, sizeof(buffer)));
219}
220
221}  // namespace
222}  // namespace io
223}  // namespace protobuf
224}  // namespace google
225