1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
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
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
TEST(Printer,EmptyPrinter)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
TEST(Printer,BasicPrinting)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
TEST(Printer,WriteRaw)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
TEST(Printer,VariableSubstitution)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
TEST(Printer,InlineVariableSubstitution)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
TEST(Printer,Indenting)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 PROTOBUF_HAS_DEATH_TEST
TEST(Printer,Death)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 // PROTOBUF_HAS_DEATH_TEST
235
TEST(Printer,WriteFailurePartial)236 TEST(Printer, WriteFailurePartial) {
237 char buffer[17];
238
239 ArrayOutputStream output(buffer, sizeof(buffer));
240 Printer printer(&output, '$');
241
242 // Print 16 bytes to almost fill the buffer (should not fail).
243 printer.Print("0123456789abcdef");
244 EXPECT_FALSE(printer.failed());
245
246 // Try to print 2 chars. Only one fits.
247 printer.Print("<>");
248 EXPECT_TRUE(printer.failed());
249
250 // Anything else should fail too.
251 printer.Print(" ");
252 EXPECT_TRUE(printer.failed());
253 printer.Print("blah");
254 EXPECT_TRUE(printer.failed());
255
256 // Buffer should contain the first 17 bytes written.
257 EXPECT_EQ("0123456789abcdef<", string(buffer, sizeof(buffer)));
258 }
259
TEST(Printer,WriteFailureExact)260 TEST(Printer, WriteFailureExact) {
261 char buffer[16];
262
263 ArrayOutputStream output(buffer, sizeof(buffer));
264 Printer printer(&output, '$');
265
266 // Print 16 bytes to fill the buffer exactly (should not fail).
267 printer.Print("0123456789abcdef");
268 EXPECT_FALSE(printer.failed());
269
270 // Try to print one more byte (should fail).
271 printer.Print(" ");
272 EXPECT_TRUE(printer.failed());
273
274 // Should not crash
275 printer.Print("blah");
276 EXPECT_TRUE(printer.failed());
277
278 // Buffer should contain the first 16 bytes written.
279 EXPECT_EQ("0123456789abcdef", string(buffer, sizeof(buffer)));
280 }
281
282 } // namespace
283 } // namespace io
284 } // namespace protobuf
285 } // namespace google
286