blob: 258dd9861f7d2c062c7860ccd69a65fcd44ea86e [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
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
Feng Xiaoeee38b02015-08-22 18:25:48 -070040#include <google/protobuf/stubs/logging.h>
temporal40ee5512008-07-10 02:12:20 +000041#include <google/protobuf/stubs/common.h>
42#include <google/protobuf/testing/googletest.h>
43#include <gtest/gtest.h>
44
45namespace google {
46namespace protobuf {
47namespace io {
48namespace {
49
50// Each test repeats over several block sizes in order to test both cases
51// where particular writes cross a buffer boundary and cases where they do
52// not.
53
54TEST(Printer, EmptyPrinter) {
55 char buffer[8192];
56 const int block_size = 100;
57 ArrayOutputStream output(buffer, GOOGLE_ARRAYSIZE(buffer), block_size);
58 Printer printer(&output, '\0');
59 EXPECT_TRUE(!printer.failed());
60}
61
62TEST(Printer, BasicPrinting) {
63 char buffer[8192];
64
65 for (int block_size = 1; block_size < 512; block_size *= 2) {
66 ArrayOutputStream output(buffer, sizeof(buffer), block_size);
67
68 {
69 Printer printer(&output, '\0');
70
71 printer.Print("Hello World!");
72 printer.Print(" This is the same line.\n");
73 printer.Print("But this is a new one.\nAnd this is another one.");
74
75 EXPECT_FALSE(printer.failed());
76 }
77
78 buffer[output.ByteCount()] = '\0';
79
kenton@google.comfccb1462009-12-18 02:11:36 +000080 EXPECT_STREQ("Hello World! This is the same line.\n"
81 "But this is a new one.\n"
82 "And this is another one.",
83 buffer);
84 }
85}
86
87TEST(Printer, WriteRaw) {
88 char buffer[8192];
89
90 for (int block_size = 1; block_size < 512; block_size *= 2) {
91 ArrayOutputStream output(buffer, sizeof(buffer), block_size);
92
93 {
94 string string_obj = "From an object\n";
95 Printer printer(&output, '$');
96 printer.WriteRaw("Hello World!", 12);
97 printer.PrintRaw(" This is the same line.\n");
98 printer.PrintRaw("But this is a new one.\nAnd this is another one.");
99 printer.WriteRaw("\n", 1);
100 printer.PrintRaw(string_obj);
101 EXPECT_FALSE(printer.failed());
102 }
103
104 buffer[output.ByteCount()] = '\0';
105
106 EXPECT_STREQ("Hello World! This is the same line.\n"
107 "But this is a new one.\n"
108 "And this is another one."
109 "\n"
110 "From an object\n",
111 buffer);
temporal40ee5512008-07-10 02:12:20 +0000112 }
113}
114
115TEST(Printer, VariableSubstitution) {
116 char buffer[8192];
117
118 for (int block_size = 1; block_size < 512; block_size *= 2) {
119 ArrayOutputStream output(buffer, sizeof(buffer), block_size);
120
121 {
122 Printer printer(&output, '$');
123 map<string, string> vars;
124
125 vars["foo"] = "World";
126 vars["bar"] = "$foo$";
127 vars["abcdefg"] = "1234";
128
129 printer.Print(vars, "Hello $foo$!\nbar = $bar$\n");
kenton@google.comfccb1462009-12-18 02:11:36 +0000130 printer.PrintRaw("RawBit\n");
temporal40ee5512008-07-10 02:12:20 +0000131 printer.Print(vars, "$abcdefg$\nA literal dollar sign: $$");
132
133 vars["foo"] = "blah";
134 printer.Print(vars, "\nNow foo = $foo$.");
135
136 EXPECT_FALSE(printer.failed());
137 }
138
139 buffer[output.ByteCount()] = '\0';
140
kenton@google.comfccb1462009-12-18 02:11:36 +0000141 EXPECT_STREQ("Hello World!\n"
142 "bar = $foo$\n"
143 "RawBit\n"
144 "1234\n"
145 "A literal dollar sign: $\n"
146 "Now foo = blah.",
147 buffer);
temporal40ee5512008-07-10 02:12:20 +0000148 }
149}
150
151TEST(Printer, InlineVariableSubstitution) {
152 char buffer[8192];
153
154 ArrayOutputStream output(buffer, sizeof(buffer));
155
156 {
157 Printer printer(&output, '$');
158 printer.Print("Hello $foo$!\n", "foo", "World");
kenton@google.comfccb1462009-12-18 02:11:36 +0000159 printer.PrintRaw("RawBit\n");
temporal40ee5512008-07-10 02:12:20 +0000160 printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
161 EXPECT_FALSE(printer.failed());
162 }
163
164 buffer[output.ByteCount()] = '\0';
165
kenton@google.comfccb1462009-12-18 02:11:36 +0000166 EXPECT_STREQ("Hello World!\n"
167 "RawBit\n"
168 "one two\n",
169 buffer);
temporal40ee5512008-07-10 02:12:20 +0000170}
171
172TEST(Printer, Indenting) {
173 char buffer[8192];
174
175 for (int block_size = 1; block_size < 512; block_size *= 2) {
176 ArrayOutputStream output(buffer, sizeof(buffer), block_size);
177
178 {
179 Printer printer(&output, '$');
180 map<string, string> vars;
181
182 vars["newline"] = "\n";
183
184 printer.Print("This is not indented.\n");
185 printer.Indent();
186 printer.Print("This is indented\nAnd so is this\n");
187 printer.Outdent();
188 printer.Print("But this is not.");
189 printer.Indent();
190 printer.Print(" And this is still the same line.\n"
191 "But this is indented.\n");
kenton@google.comfccb1462009-12-18 02:11:36 +0000192 printer.PrintRaw("RawBit has indent at start\n");
193 printer.PrintRaw("but not after a raw newline\n");
temporal40ee5512008-07-10 02:12:20 +0000194 printer.Print(vars, "Note that a newline in a variable will break "
195 "indenting, as we see$newline$here.\n");
196 printer.Indent();
197 printer.Print("And this");
198 printer.Outdent();
199 printer.Outdent();
200 printer.Print(" is double-indented\nBack to normal.");
201
202 EXPECT_FALSE(printer.failed());
203 }
204
205 buffer[output.ByteCount()] = '\0';
206
kenton@google.comfccb1462009-12-18 02:11:36 +0000207 EXPECT_STREQ(
temporal40ee5512008-07-10 02:12:20 +0000208 "This is not indented.\n"
209 " This is indented\n"
210 " And so is this\n"
211 "But this is not. And this is still the same line.\n"
212 " But this is indented.\n"
kenton@google.comfccb1462009-12-18 02:11:36 +0000213 " RawBit has indent at start\n"
214 "but not after a raw newline\n"
215 "Note that a newline in a variable will break indenting, as we see\n"
temporal40ee5512008-07-10 02:12:20 +0000216 "here.\n"
217 " And this is double-indented\n"
kenton@google.comfccb1462009-12-18 02:11:36 +0000218 "Back to normal.",
219 buffer);
temporal40ee5512008-07-10 02:12:20 +0000220 }
221}
222
223// Death tests do not work on Windows as of yet.
liujisi@google.comf5d5b4d2012-12-05 05:54:48 +0000224#ifdef PROTOBUF_HAS_DEATH_TEST
temporal40ee5512008-07-10 02:12:20 +0000225TEST(Printer, Death) {
226 char buffer[8192];
227
228 ArrayOutputStream output(buffer, sizeof(buffer));
229 Printer printer(&output, '$');
230
231 EXPECT_DEBUG_DEATH(printer.Print("$nosuchvar$"), "Undefined variable");
232 EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
233 EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
234}
jieluo@google.com4de8f552014-07-18 00:47:59 +0000235#endif // PROTOBUF_HAS_DEATH_TEST
temporal40ee5512008-07-10 02:12:20 +0000236
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000237TEST(Printer, WriteFailurePartial) {
238 char buffer[17];
239
240 ArrayOutputStream output(buffer, sizeof(buffer));
241 Printer printer(&output, '$');
242
243 // Print 16 bytes to almost fill the buffer (should not fail).
244 printer.Print("0123456789abcdef");
245 EXPECT_FALSE(printer.failed());
246
247 // Try to print 2 chars. Only one fits.
248 printer.Print("<>");
249 EXPECT_TRUE(printer.failed());
250
251 // Anything else should fail too.
252 printer.Print(" ");
253 EXPECT_TRUE(printer.failed());
254 printer.Print("blah");
255 EXPECT_TRUE(printer.failed());
256
257 // Buffer should contain the first 17 bytes written.
258 EXPECT_EQ("0123456789abcdef<", string(buffer, sizeof(buffer)));
259}
260
261TEST(Printer, WriteFailureExact) {
temporal40ee5512008-07-10 02:12:20 +0000262 char buffer[16];
263
264 ArrayOutputStream output(buffer, sizeof(buffer));
265 Printer printer(&output, '$');
266
267 // Print 16 bytes to fill the buffer exactly (should not fail).
268 printer.Print("0123456789abcdef");
269 EXPECT_FALSE(printer.failed());
270
271 // Try to print one more byte (should fail).
272 printer.Print(" ");
273 EXPECT_TRUE(printer.failed());
274
275 // Should not crash
276 printer.Print("blah");
277 EXPECT_TRUE(printer.failed());
278
279 // Buffer should contain the first 16 bytes written.
280 EXPECT_EQ("0123456789abcdef", string(buffer, sizeof(buffer)));
281}
282
283} // namespace
284} // namespace io
285} // namespace protobuf
286} // namespace google