• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <google/protobuf/descriptor.pb.h>
40 
41 #include <google/protobuf/stubs/logging.h>
42 #include <google/protobuf/stubs/common.h>
43 #include <google/protobuf/testing/googletest.h>
44 #include <gtest/gtest.h>
45 
46 namespace google {
47 namespace protobuf {
48 namespace io {
49 namespace {
50 
51 // Each test repeats over several block sizes in order to test both cases
52 // where particular writes cross a buffer boundary and cases where they do
53 // not.
54 
TEST(Printer,EmptyPrinter)55 TEST(Printer, EmptyPrinter) {
56   char buffer[8192];
57   const int block_size = 100;
58   ArrayOutputStream output(buffer, GOOGLE_ARRAYSIZE(buffer), block_size);
59   Printer printer(&output, '\0');
60   EXPECT_TRUE(!printer.failed());
61 }
62 
TEST(Printer,BasicPrinting)63 TEST(Printer, BasicPrinting) {
64   char buffer[8192];
65 
66   for (int block_size = 1; block_size < 512; block_size *= 2) {
67     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
68 
69     {
70       Printer printer(&output, '\0');
71 
72       printer.Print("Hello World!");
73       printer.Print("  This is the same line.\n");
74       printer.Print("But this is a new one.\nAnd this is another one.");
75 
76       EXPECT_FALSE(printer.failed());
77     }
78 
79     buffer[output.ByteCount()] = '\0';
80 
81     EXPECT_STREQ("Hello World!  This is the same line.\n"
82                  "But this is a new one.\n"
83                  "And this is another one.",
84                  buffer);
85   }
86 }
87 
TEST(Printer,WriteRaw)88 TEST(Printer, WriteRaw) {
89   char buffer[8192];
90 
91   for (int block_size = 1; block_size < 512; block_size *= 2) {
92     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
93 
94     {
95       string string_obj = "From an object\n";
96       Printer printer(&output, '$');
97       printer.WriteRaw("Hello World!", 12);
98       printer.PrintRaw("  This is the same line.\n");
99       printer.PrintRaw("But this is a new one.\nAnd this is another one.");
100       printer.WriteRaw("\n", 1);
101       printer.PrintRaw(string_obj);
102       EXPECT_FALSE(printer.failed());
103     }
104 
105     buffer[output.ByteCount()] = '\0';
106 
107     EXPECT_STREQ("Hello World!  This is the same line.\n"
108                  "But this is a new one.\n"
109                  "And this is another one."
110                  "\n"
111                  "From an object\n",
112                  buffer);
113   }
114 }
115 
TEST(Printer,VariableSubstitution)116 TEST(Printer, VariableSubstitution) {
117   char buffer[8192];
118 
119   for (int block_size = 1; block_size < 512; block_size *= 2) {
120     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
121 
122     {
123       Printer printer(&output, '$');
124       map<string, string> vars;
125 
126       vars["foo"] = "World";
127       vars["bar"] = "$foo$";
128       vars["abcdefg"] = "1234";
129 
130       printer.Print(vars, "Hello $foo$!\nbar = $bar$\n");
131       printer.PrintRaw("RawBit\n");
132       printer.Print(vars, "$abcdefg$\nA literal dollar sign:  $$");
133 
134       vars["foo"] = "blah";
135       printer.Print(vars, "\nNow foo = $foo$.");
136 
137       EXPECT_FALSE(printer.failed());
138     }
139 
140     buffer[output.ByteCount()] = '\0';
141 
142     EXPECT_STREQ("Hello World!\n"
143                  "bar = $foo$\n"
144                  "RawBit\n"
145                  "1234\n"
146                  "A literal dollar sign:  $\n"
147                  "Now foo = blah.",
148                  buffer);
149   }
150 }
151 
TEST(Printer,InlineVariableSubstitution)152 TEST(Printer, InlineVariableSubstitution) {
153   char buffer[8192];
154 
155   ArrayOutputStream output(buffer, sizeof(buffer));
156 
157   {
158     Printer printer(&output, '$');
159     printer.Print("Hello $foo$!\n", "foo", "World");
160     printer.PrintRaw("RawBit\n");
161     printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
162     EXPECT_FALSE(printer.failed());
163   }
164 
165   buffer[output.ByteCount()] = '\0';
166 
167   EXPECT_STREQ("Hello World!\n"
168                "RawBit\n"
169                "one two\n",
170                buffer);
171 }
172 
173 // MockDescriptorFile defines only those members that Printer uses to write out
174 // annotations.
175 class MockDescriptorFile {
176  public:
MockDescriptorFile(const string & file)177   explicit MockDescriptorFile(const string& file) : file_(file) {}
178 
179   // The mock filename for this file.
name() const180   const string& name() const { return file_; }
181 
182  private:
183   string file_;
184 };
185 
186 // MockDescriptor defines only those members that Printer uses to write out
187 // annotations.
188 class MockDescriptor {
189  public:
MockDescriptor(const string & file,const vector<int> & path)190   MockDescriptor(const string& file, const vector<int>& path)
191       : file_(file), path_(path) {}
192 
193   // The mock file in which this descriptor was defined.
file() const194   const MockDescriptorFile* file() const { return &file_; }
195 
196  private:
197   // Allows access to GetLocationPath.
198   friend class ::google::protobuf::io::Printer;
199 
200   // Copies the pre-stored path to output.
GetLocationPath(std::vector<int> * output) const201   void GetLocationPath(std::vector<int>* output) const { *output = path_; }
202 
203   MockDescriptorFile file_;
204   vector<int> path_;
205 };
206 
TEST(Printer,AnnotateMap)207 TEST(Printer, AnnotateMap) {
208   char buffer[8192];
209   ArrayOutputStream output(buffer, sizeof(buffer));
210   GeneratedCodeInfo info;
211   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
212   {
213     Printer printer(&output, '$', &info_collector);
214     map<string, string> vars;
215     vars["foo"] = "3";
216     vars["bar"] = "5";
217     printer.Print(vars, "012$foo$4$bar$\n");
218     vector<int> path_1;
219     path_1.push_back(33);
220     vector<int> path_2;
221     path_2.push_back(11);
222     path_2.push_back(22);
223     MockDescriptor descriptor_1("path_1", path_1);
224     MockDescriptor descriptor_2("path_2", path_2);
225     printer.Annotate("foo", "foo", &descriptor_1);
226     printer.Annotate("bar", "bar", &descriptor_2);
227   }
228   buffer[output.ByteCount()] = '\0';
229   EXPECT_STREQ("012345\n", buffer);
230   ASSERT_EQ(2, info.annotation_size());
231   const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1
232                                                  ? &info.annotation(0)
233                                                  : &info.annotation(1);
234   const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1
235                                                  ? &info.annotation(1)
236                                                  : &info.annotation(0);
237   ASSERT_EQ(1, foo->path_size());
238   ASSERT_EQ(2, bar->path_size());
239   EXPECT_EQ(33, foo->path(0));
240   EXPECT_EQ(11, bar->path(0));
241   EXPECT_EQ(22, bar->path(1));
242   EXPECT_EQ("path_1", foo->source_file());
243   EXPECT_EQ("path_2", bar->source_file());
244   EXPECT_EQ(3, foo->begin());
245   EXPECT_EQ(4, foo->end());
246   EXPECT_EQ(5, bar->begin());
247   EXPECT_EQ(6, bar->end());
248 }
249 
TEST(Printer,AnnotateInline)250 TEST(Printer, AnnotateInline) {
251   char buffer[8192];
252   ArrayOutputStream output(buffer, sizeof(buffer));
253   GeneratedCodeInfo info;
254   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
255   {
256     Printer printer(&output, '$', &info_collector);
257     printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
258     vector<int> path_1;
259     path_1.push_back(33);
260     vector<int> path_2;
261     path_2.push_back(11);
262     path_2.push_back(22);
263     MockDescriptor descriptor_1("path_1", path_1);
264     MockDescriptor descriptor_2("path_2", path_2);
265     printer.Annotate("foo", "foo", &descriptor_1);
266     printer.Annotate("bar", "bar", &descriptor_2);
267   }
268   buffer[output.ByteCount()] = '\0';
269   EXPECT_STREQ("012345\n", buffer);
270   ASSERT_EQ(2, info.annotation_size());
271   const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1
272                                                  ? &info.annotation(0)
273                                                  : &info.annotation(1);
274   const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1
275                                                  ? &info.annotation(1)
276                                                  : &info.annotation(0);
277   ASSERT_EQ(1, foo->path_size());
278   ASSERT_EQ(2, bar->path_size());
279   EXPECT_EQ(33, foo->path(0));
280   EXPECT_EQ(11, bar->path(0));
281   EXPECT_EQ(22, bar->path(1));
282   EXPECT_EQ("path_1", foo->source_file());
283   EXPECT_EQ("path_2", bar->source_file());
284   EXPECT_EQ(3, foo->begin());
285   EXPECT_EQ(4, foo->end());
286   EXPECT_EQ(5, bar->begin());
287   EXPECT_EQ(6, bar->end());
288 }
289 
TEST(Printer,AnnotateRange)290 TEST(Printer, AnnotateRange) {
291   char buffer[8192];
292   ArrayOutputStream output(buffer, sizeof(buffer));
293   GeneratedCodeInfo info;
294   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
295   {
296     Printer printer(&output, '$', &info_collector);
297     printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
298     vector<int> path;
299     path.push_back(33);
300     MockDescriptor descriptor("path", path);
301     printer.Annotate("foo", "bar", &descriptor);
302   }
303   buffer[output.ByteCount()] = '\0';
304   EXPECT_STREQ("012345\n", buffer);
305   ASSERT_EQ(1, info.annotation_size());
306   const GeneratedCodeInfo::Annotation* foobar = &info.annotation(0);
307   ASSERT_EQ(1, foobar->path_size());
308   EXPECT_EQ(33, foobar->path(0));
309   EXPECT_EQ("path", foobar->source_file());
310   EXPECT_EQ(3, foobar->begin());
311   EXPECT_EQ(6, foobar->end());
312 }
313 
TEST(Printer,AnnotateEmptyRange)314 TEST(Printer, AnnotateEmptyRange) {
315   char buffer[8192];
316   ArrayOutputStream output(buffer, sizeof(buffer));
317   GeneratedCodeInfo info;
318   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
319   {
320     Printer printer(&output, '$', &info_collector);
321     printer.Print("012$foo$4$baz$$bam$$bar$\n", "foo", "3", "bar", "5", "baz",
322                   "", "bam", "");
323     vector<int> path;
324     path.push_back(33);
325     MockDescriptor descriptor("path", path);
326     printer.Annotate("baz", "bam", &descriptor);
327   }
328   buffer[output.ByteCount()] = '\0';
329   EXPECT_STREQ("012345\n", buffer);
330   ASSERT_EQ(1, info.annotation_size());
331   const GeneratedCodeInfo::Annotation* bazbam = &info.annotation(0);
332   ASSERT_EQ(1, bazbam->path_size());
333   EXPECT_EQ(33, bazbam->path(0));
334   EXPECT_EQ("path", bazbam->source_file());
335   EXPECT_EQ(5, bazbam->begin());
336   EXPECT_EQ(5, bazbam->end());
337 }
338 
TEST(Printer,AnnotateDespiteUnrelatedMultipleUses)339 TEST(Printer, AnnotateDespiteUnrelatedMultipleUses) {
340   char buffer[8192];
341   ArrayOutputStream output(buffer, sizeof(buffer));
342   GeneratedCodeInfo info;
343   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
344   {
345     Printer printer(&output, '$', &info_collector);
346     printer.Print("012$foo$4$foo$$bar$\n", "foo", "3", "bar", "5");
347     vector<int> path;
348     path.push_back(33);
349     MockDescriptor descriptor("path", path);
350     printer.Annotate("bar", "bar", &descriptor);
351   }
352   buffer[output.ByteCount()] = '\0';
353   EXPECT_STREQ("0123435\n", buffer);
354   ASSERT_EQ(1, info.annotation_size());
355   const GeneratedCodeInfo::Annotation* bar = &info.annotation(0);
356   ASSERT_EQ(1, bar->path_size());
357   EXPECT_EQ(33, bar->path(0));
358   EXPECT_EQ("path", bar->source_file());
359   EXPECT_EQ(6, bar->begin());
360   EXPECT_EQ(7, bar->end());
361 }
362 
TEST(Printer,Indenting)363 TEST(Printer, Indenting) {
364   char buffer[8192];
365 
366   for (int block_size = 1; block_size < 512; block_size *= 2) {
367     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
368 
369     {
370       Printer printer(&output, '$');
371       map<string, string> vars;
372 
373       vars["newline"] = "\n";
374 
375       printer.Print("This is not indented.\n");
376       printer.Indent();
377       printer.Print("This is indented\nAnd so is this\n");
378       printer.Outdent();
379       printer.Print("But this is not.");
380       printer.Indent();
381       printer.Print("  And this is still the same line.\n"
382                     "But this is indented.\n");
383       printer.PrintRaw("RawBit has indent at start\n");
384       printer.PrintRaw("but not after a raw newline\n");
385       printer.Print(vars, "Note that a newline in a variable will break "
386                     "indenting, as we see$newline$here.\n");
387       printer.Indent();
388       printer.Print("And this");
389       printer.Outdent();
390       printer.Outdent();
391       printer.Print(" is double-indented\nBack to normal.");
392 
393       EXPECT_FALSE(printer.failed());
394     }
395 
396     buffer[output.ByteCount()] = '\0';
397 
398     EXPECT_STREQ(
399       "This is not indented.\n"
400       "  This is indented\n"
401       "  And so is this\n"
402       "But this is not.  And this is still the same line.\n"
403       "  But this is indented.\n"
404       "  RawBit has indent at start\n"
405       "but not after a raw newline\n"
406       "Note that a newline in a variable will break indenting, as we see\n"
407       "here.\n"
408       "    And this is double-indented\n"
409       "Back to normal.",
410       buffer);
411   }
412 }
413 
414 // Death tests do not work on Windows as of yet.
415 #ifdef PROTOBUF_HAS_DEATH_TEST
TEST(Printer,Death)416 TEST(Printer, Death) {
417   char buffer[8192];
418 
419   ArrayOutputStream output(buffer, sizeof(buffer));
420   Printer printer(&output, '$');
421 
422   EXPECT_DEBUG_DEATH(printer.Print("$nosuchvar$"), "Undefined variable");
423   EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
424   EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
425 }
426 
TEST(Printer,AnnotateMultipleUsesDeath)427 TEST(Printer, AnnotateMultipleUsesDeath) {
428   char buffer[8192];
429   ArrayOutputStream output(buffer, sizeof(buffer));
430   GeneratedCodeInfo info;
431   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
432   {
433     Printer printer(&output, '$', &info_collector);
434     printer.Print("012$foo$4$foo$\n", "foo", "3");
435     vector<int> path;
436     path.push_back(33);
437     MockDescriptor descriptor("path", path);
438     EXPECT_DEBUG_DEATH(printer.Annotate("foo", "foo", &descriptor), "multiple");
439   }
440 }
441 
TEST(Printer,AnnotateNegativeLengthDeath)442 TEST(Printer, AnnotateNegativeLengthDeath) {
443   char buffer[8192];
444   ArrayOutputStream output(buffer, sizeof(buffer));
445   GeneratedCodeInfo info;
446   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
447   {
448     Printer printer(&output, '$', &info_collector);
449     printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
450     vector<int> path;
451     path.push_back(33);
452     MockDescriptor descriptor("path", path);
453     EXPECT_DEBUG_DEATH(printer.Annotate("bar", "foo", &descriptor), "negative");
454   }
455 }
456 
TEST(Printer,AnnotateUndefinedDeath)457 TEST(Printer, AnnotateUndefinedDeath) {
458   char buffer[8192];
459   ArrayOutputStream output(buffer, sizeof(buffer));
460   GeneratedCodeInfo info;
461   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
462   {
463     Printer printer(&output, '$', &info_collector);
464     printer.Print("012$foo$4$foo$\n", "foo", "3");
465     vector<int> path;
466     path.push_back(33);
467     MockDescriptor descriptor("path", path);
468     EXPECT_DEBUG_DEATH(printer.Annotate("bar", "bar", &descriptor),
469                        "Undefined");
470   }
471 }
472 #endif  // PROTOBUF_HAS_DEATH_TEST
473 
TEST(Printer,WriteFailurePartial)474 TEST(Printer, WriteFailurePartial) {
475   char buffer[17];
476 
477   ArrayOutputStream output(buffer, sizeof(buffer));
478   Printer printer(&output, '$');
479 
480   // Print 16 bytes to almost fill the buffer (should not fail).
481   printer.Print("0123456789abcdef");
482   EXPECT_FALSE(printer.failed());
483 
484   // Try to print 2 chars. Only one fits.
485   printer.Print("<>");
486   EXPECT_TRUE(printer.failed());
487 
488   // Anything else should fail too.
489   printer.Print(" ");
490   EXPECT_TRUE(printer.failed());
491   printer.Print("blah");
492   EXPECT_TRUE(printer.failed());
493 
494   // Buffer should contain the first 17 bytes written.
495   EXPECT_EQ("0123456789abcdef<", string(buffer, sizeof(buffer)));
496 }
497 
TEST(Printer,WriteFailureExact)498 TEST(Printer, WriteFailureExact) {
499   char buffer[16];
500 
501   ArrayOutputStream output(buffer, sizeof(buffer));
502   Printer printer(&output, '$');
503 
504   // Print 16 bytes to fill the buffer exactly (should not fail).
505   printer.Print("0123456789abcdef");
506   EXPECT_FALSE(printer.failed());
507 
508   // Try to print one more byte (should fail).
509   printer.Print(" ");
510   EXPECT_TRUE(printer.failed());
511 
512   // Should not crash
513   printer.Print("blah");
514   EXPECT_TRUE(printer.failed());
515 
516   // Buffer should contain the first 16 bytes written.
517   EXPECT_EQ("0123456789abcdef", string(buffer, sizeof(buffer)));
518 }
519 
520 }  // namespace
521 }  // namespace io
522 }  // namespace protobuf
523 }  // namespace google
524