• 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 
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 
TEST(Printer,EmptyPrinter)54 TEST(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 
TEST(Printer,BasicPrinting)62 TEST(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 
80     EXPECT_STREQ(
81         "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       std::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(
108         "Hello World!  This is the same line.\n"
109         "But this is a new one.\n"
110         "And this is another one."
111         "\n"
112         "From an object\n",
113         buffer);
114   }
115 }
116 
TEST(Printer,VariableSubstitution)117 TEST(Printer, VariableSubstitution) {
118   char buffer[8192];
119 
120   for (int block_size = 1; block_size < 512; block_size *= 2) {
121     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
122 
123     {
124       Printer printer(&output, '$');
125       std::map<std::string, std::string> vars;
126 
127       vars["foo"] = "World";
128       vars["bar"] = "$foo$";
129       vars["abcdefg"] = "1234";
130 
131       printer.Print(vars, "Hello $foo$!\nbar = $bar$\n");
132       printer.PrintRaw("RawBit\n");
133       printer.Print(vars, "$abcdefg$\nA literal dollar sign:  $$");
134 
135       vars["foo"] = "blah";
136       printer.Print(vars, "\nNow foo = $foo$.");
137 
138       EXPECT_FALSE(printer.failed());
139     }
140 
141     buffer[output.ByteCount()] = '\0';
142 
143     EXPECT_STREQ(
144         "Hello World!\n"
145         "bar = $foo$\n"
146         "RawBit\n"
147         "1234\n"
148         "A literal dollar sign:  $\n"
149         "Now foo = blah.",
150         buffer);
151   }
152 }
153 
TEST(Printer,InlineVariableSubstitution)154 TEST(Printer, InlineVariableSubstitution) {
155   char buffer[8192];
156 
157   ArrayOutputStream output(buffer, sizeof(buffer));
158 
159   {
160     Printer printer(&output, '$');
161     printer.Print("Hello $foo$!\n", "foo", "World");
162     printer.PrintRaw("RawBit\n");
163     printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
164     EXPECT_FALSE(printer.failed());
165   }
166 
167   buffer[output.ByteCount()] = '\0';
168 
169   EXPECT_STREQ(
170       "Hello World!\n"
171       "RawBit\n"
172       "one two\n",
173       buffer);
174 }
175 
176 // MockDescriptorFile defines only those members that Printer uses to write out
177 // annotations.
178 class MockDescriptorFile {
179  public:
MockDescriptorFile(const std::string & file)180   explicit MockDescriptorFile(const std::string& file) : file_(file) {}
181 
182   // The mock filename for this file.
name() const183   const std::string& name() const { return file_; }
184 
185  private:
186   std::string file_;
187 };
188 
189 // MockDescriptor defines only those members that Printer uses to write out
190 // annotations.
191 class MockDescriptor {
192  public:
MockDescriptor(const std::string & file,const std::vector<int> & path)193   MockDescriptor(const std::string& file, const std::vector<int>& path)
194       : file_(file), path_(path) {}
195 
196   // The mock file in which this descriptor was defined.
file() const197   const MockDescriptorFile* file() const { return &file_; }
198 
199  private:
200   // Allows access to GetLocationPath.
201   friend class Printer;
202 
203   // Copies the pre-stored path to output.
GetLocationPath(std::vector<int> * output) const204   void GetLocationPath(std::vector<int>* output) const { *output = path_; }
205 
206   MockDescriptorFile file_;
207   std::vector<int> path_;
208 };
209 
TEST(Printer,AnnotateMap)210 TEST(Printer, AnnotateMap) {
211   char buffer[8192];
212   ArrayOutputStream output(buffer, sizeof(buffer));
213   GeneratedCodeInfo info;
214   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
215   {
216     Printer printer(&output, '$', &info_collector);
217     std::map<std::string, std::string> vars;
218     vars["foo"] = "3";
219     vars["bar"] = "5";
220     printer.Print(vars, "012$foo$4$bar$\n");
221     std::vector<int> path_1;
222     path_1.push_back(33);
223     std::vector<int> path_2;
224     path_2.push_back(11);
225     path_2.push_back(22);
226     MockDescriptor descriptor_1("path_1", path_1);
227     MockDescriptor descriptor_2("path_2", path_2);
228     printer.Annotate("foo", "foo", &descriptor_1);
229     printer.Annotate("bar", "bar", &descriptor_2);
230   }
231   buffer[output.ByteCount()] = '\0';
232   EXPECT_STREQ("012345\n", buffer);
233   ASSERT_EQ(2, info.annotation_size());
234   const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1
235                                                  ? &info.annotation(0)
236                                                  : &info.annotation(1);
237   const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1
238                                                  ? &info.annotation(1)
239                                                  : &info.annotation(0);
240   ASSERT_EQ(1, foo->path_size());
241   ASSERT_EQ(2, bar->path_size());
242   EXPECT_EQ(33, foo->path(0));
243   EXPECT_EQ(11, bar->path(0));
244   EXPECT_EQ(22, bar->path(1));
245   EXPECT_EQ("path_1", foo->source_file());
246   EXPECT_EQ("path_2", bar->source_file());
247   EXPECT_EQ(3, foo->begin());
248   EXPECT_EQ(4, foo->end());
249   EXPECT_EQ(5, bar->begin());
250   EXPECT_EQ(6, bar->end());
251 }
252 
TEST(Printer,AnnotateInline)253 TEST(Printer, AnnotateInline) {
254   char buffer[8192];
255   ArrayOutputStream output(buffer, sizeof(buffer));
256   GeneratedCodeInfo info;
257   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
258   {
259     Printer printer(&output, '$', &info_collector);
260     printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
261     std::vector<int> path_1;
262     path_1.push_back(33);
263     std::vector<int> path_2;
264     path_2.push_back(11);
265     path_2.push_back(22);
266     MockDescriptor descriptor_1("path_1", path_1);
267     MockDescriptor descriptor_2("path_2", path_2);
268     printer.Annotate("foo", "foo", &descriptor_1);
269     printer.Annotate("bar", "bar", &descriptor_2);
270   }
271   buffer[output.ByteCount()] = '\0';
272   EXPECT_STREQ("012345\n", buffer);
273   ASSERT_EQ(2, info.annotation_size());
274   const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1
275                                                  ? &info.annotation(0)
276                                                  : &info.annotation(1);
277   const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1
278                                                  ? &info.annotation(1)
279                                                  : &info.annotation(0);
280   ASSERT_EQ(1, foo->path_size());
281   ASSERT_EQ(2, bar->path_size());
282   EXPECT_EQ(33, foo->path(0));
283   EXPECT_EQ(11, bar->path(0));
284   EXPECT_EQ(22, bar->path(1));
285   EXPECT_EQ("path_1", foo->source_file());
286   EXPECT_EQ("path_2", bar->source_file());
287   EXPECT_EQ(3, foo->begin());
288   EXPECT_EQ(4, foo->end());
289   EXPECT_EQ(5, bar->begin());
290   EXPECT_EQ(6, bar->end());
291 }
292 
TEST(Printer,AnnotateRange)293 TEST(Printer, AnnotateRange) {
294   char buffer[8192];
295   ArrayOutputStream output(buffer, sizeof(buffer));
296   GeneratedCodeInfo info;
297   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
298   {
299     Printer printer(&output, '$', &info_collector);
300     printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
301     std::vector<int> path;
302     path.push_back(33);
303     MockDescriptor descriptor("path", path);
304     printer.Annotate("foo", "bar", &descriptor);
305   }
306   buffer[output.ByteCount()] = '\0';
307   EXPECT_STREQ("012345\n", buffer);
308   ASSERT_EQ(1, info.annotation_size());
309   const GeneratedCodeInfo::Annotation* foobar = &info.annotation(0);
310   ASSERT_EQ(1, foobar->path_size());
311   EXPECT_EQ(33, foobar->path(0));
312   EXPECT_EQ("path", foobar->source_file());
313   EXPECT_EQ(3, foobar->begin());
314   EXPECT_EQ(6, foobar->end());
315 }
316 
TEST(Printer,AnnotateEmptyRange)317 TEST(Printer, AnnotateEmptyRange) {
318   char buffer[8192];
319   ArrayOutputStream output(buffer, sizeof(buffer));
320   GeneratedCodeInfo info;
321   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
322   {
323     Printer printer(&output, '$', &info_collector);
324     printer.Print("012$foo$4$baz$$bam$$bar$\n", "foo", "3", "bar", "5", "baz",
325                   "", "bam", "");
326     std::vector<int> path;
327     path.push_back(33);
328     MockDescriptor descriptor("path", path);
329     printer.Annotate("baz", "bam", &descriptor);
330   }
331   buffer[output.ByteCount()] = '\0';
332   EXPECT_STREQ("012345\n", buffer);
333   ASSERT_EQ(1, info.annotation_size());
334   const GeneratedCodeInfo::Annotation* bazbam = &info.annotation(0);
335   ASSERT_EQ(1, bazbam->path_size());
336   EXPECT_EQ(33, bazbam->path(0));
337   EXPECT_EQ("path", bazbam->source_file());
338   EXPECT_EQ(5, bazbam->begin());
339   EXPECT_EQ(5, bazbam->end());
340 }
341 
TEST(Printer,AnnotateDespiteUnrelatedMultipleUses)342 TEST(Printer, AnnotateDespiteUnrelatedMultipleUses) {
343   char buffer[8192];
344   ArrayOutputStream output(buffer, sizeof(buffer));
345   GeneratedCodeInfo info;
346   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
347   {
348     Printer printer(&output, '$', &info_collector);
349     printer.Print("012$foo$4$foo$$bar$\n", "foo", "3", "bar", "5");
350     std::vector<int> path;
351     path.push_back(33);
352     MockDescriptor descriptor("path", path);
353     printer.Annotate("bar", "bar", &descriptor);
354   }
355   buffer[output.ByteCount()] = '\0';
356   EXPECT_STREQ("0123435\n", buffer);
357   ASSERT_EQ(1, info.annotation_size());
358   const GeneratedCodeInfo::Annotation* bar = &info.annotation(0);
359   ASSERT_EQ(1, bar->path_size());
360   EXPECT_EQ(33, bar->path(0));
361   EXPECT_EQ("path", bar->source_file());
362   EXPECT_EQ(6, bar->begin());
363   EXPECT_EQ(7, bar->end());
364 }
365 
TEST(Printer,AnnotateIndent)366 TEST(Printer, AnnotateIndent) {
367   char buffer[8192];
368   ArrayOutputStream output(buffer, sizeof(buffer));
369   GeneratedCodeInfo info;
370   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
371   {
372     Printer printer(&output, '$', &info_collector);
373     printer.Print("0\n");
374     printer.Indent();
375     printer.Print("$foo$", "foo", "4");
376     std::vector<int> path;
377     path.push_back(44);
378     MockDescriptor descriptor("path", path);
379     printer.Annotate("foo", &descriptor);
380     printer.Print(",\n");
381     printer.Print("$bar$", "bar", "9");
382     path[0] = 99;
383     MockDescriptor descriptor_two("path", path);
384     printer.Annotate("bar", &descriptor_two);
385     printer.Print("\n${$$D$$}$\n", "{", "", "}", "", "D", "d");
386     path[0] = 1313;
387     MockDescriptor descriptor_three("path", path);
388     printer.Annotate("{", "}", &descriptor_three);
389     printer.Outdent();
390     printer.Print("\n");
391   }
392   buffer[output.ByteCount()] = '\0';
393   EXPECT_STREQ("0\n  4,\n  9\n  d\n\n", buffer);
394   ASSERT_EQ(3, info.annotation_size());
395   const GeneratedCodeInfo::Annotation* foo = &info.annotation(0);
396   ASSERT_EQ(1, foo->path_size());
397   EXPECT_EQ(44, foo->path(0));
398   EXPECT_EQ("path", foo->source_file());
399   EXPECT_EQ(4, foo->begin());
400   EXPECT_EQ(5, foo->end());
401   const GeneratedCodeInfo::Annotation* bar = &info.annotation(1);
402   ASSERT_EQ(1, bar->path_size());
403   EXPECT_EQ(99, bar->path(0));
404   EXPECT_EQ("path", bar->source_file());
405   EXPECT_EQ(9, bar->begin());
406   EXPECT_EQ(10, bar->end());
407   const GeneratedCodeInfo::Annotation* braces = &info.annotation(2);
408   ASSERT_EQ(1, braces->path_size());
409   EXPECT_EQ(1313, braces->path(0));
410   EXPECT_EQ("path", braces->source_file());
411   EXPECT_EQ(13, braces->begin());
412   EXPECT_EQ(14, braces->end());
413 }
414 
TEST(Printer,AnnotateIndentNewline)415 TEST(Printer, AnnotateIndentNewline) {
416   char buffer[8192];
417   ArrayOutputStream output(buffer, sizeof(buffer));
418   GeneratedCodeInfo info;
419   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
420   {
421     Printer printer(&output, '$', &info_collector);
422     printer.Indent();
423     printer.Print("$A$$N$$B$C\n", "A", "", "N", "\nz", "B", "");
424     std::vector<int> path;
425     path.push_back(0);
426     MockDescriptor descriptor("path", path);
427     printer.Annotate("A", "B", &descriptor);
428     printer.Outdent();
429     printer.Print("\n");
430   }
431   buffer[output.ByteCount()] = '\0';
432   EXPECT_STREQ("\nz  C\n\n", buffer);
433   ASSERT_EQ(1, info.annotation_size());
434   const GeneratedCodeInfo::Annotation* ab = &info.annotation(0);
435   ASSERT_EQ(1, ab->path_size());
436   EXPECT_EQ(0, ab->path(0));
437   EXPECT_EQ("path", ab->source_file());
438   EXPECT_EQ(0, ab->begin());
439   EXPECT_EQ(4, ab->end());
440 }
441 
TEST(Printer,Indenting)442 TEST(Printer, Indenting) {
443   char buffer[8192];
444 
445   for (int block_size = 1; block_size < 512; block_size *= 2) {
446     ArrayOutputStream output(buffer, sizeof(buffer), block_size);
447 
448     {
449       Printer printer(&output, '$');
450       std::map<std::string, std::string> vars;
451 
452       vars["newline"] = "\n";
453 
454       printer.Print("This is not indented.\n");
455       printer.Indent();
456       printer.Print("This is indented\nAnd so is this\n");
457       printer.Outdent();
458       printer.Print("But this is not.");
459       printer.Indent();
460       printer.Print(
461           "  And this is still the same line.\n"
462           "But this is indented.\n");
463       printer.PrintRaw("RawBit has indent at start\n");
464       printer.PrintRaw("but not after a raw newline\n");
465       printer.Print(vars,
466                     "Note that a newline in a variable will break "
467                     "indenting, as we see$newline$here.\n");
468       printer.Indent();
469       printer.Print("And this");
470       printer.Outdent();
471       printer.Outdent();
472       printer.Print(" is double-indented\nBack to normal.");
473 
474       EXPECT_FALSE(printer.failed());
475     }
476 
477     buffer[output.ByteCount()] = '\0';
478 
479     EXPECT_STREQ(
480         "This is not indented.\n"
481         "  This is indented\n"
482         "  And so is this\n"
483         "But this is not.  And this is still the same line.\n"
484         "  But this is indented.\n"
485         "  RawBit has indent at start\n"
486         "but not after a raw newline\n"
487         "Note that a newline in a variable will break indenting, as we see\n"
488         "here.\n"
489         "    And this is double-indented\n"
490         "Back to normal.",
491         buffer);
492   }
493 }
494 
495 // Death tests do not work on Windows as of yet.
496 #ifdef PROTOBUF_HAS_DEATH_TEST
TEST(Printer,Death)497 TEST(Printer, Death) {
498   char buffer[8192];
499 
500   ArrayOutputStream output(buffer, sizeof(buffer));
501   Printer printer(&output, '$');
502 
503   EXPECT_DEBUG_DEATH(printer.Print("$nosuchvar$"), "Undefined variable");
504   EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
505   EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
506 }
507 
TEST(Printer,AnnotateMultipleUsesDeath)508 TEST(Printer, AnnotateMultipleUsesDeath) {
509   char buffer[8192];
510   ArrayOutputStream output(buffer, sizeof(buffer));
511   GeneratedCodeInfo info;
512   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
513   {
514     Printer printer(&output, '$', &info_collector);
515     printer.Print("012$foo$4$foo$\n", "foo", "3");
516     std::vector<int> path;
517     path.push_back(33);
518     MockDescriptor descriptor("path", path);
519     EXPECT_DEBUG_DEATH(printer.Annotate("foo", "foo", &descriptor), "multiple");
520   }
521 }
522 
TEST(Printer,AnnotateNegativeLengthDeath)523 TEST(Printer, AnnotateNegativeLengthDeath) {
524   char buffer[8192];
525   ArrayOutputStream output(buffer, sizeof(buffer));
526   GeneratedCodeInfo info;
527   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
528   {
529     Printer printer(&output, '$', &info_collector);
530     printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
531     std::vector<int> path;
532     path.push_back(33);
533     MockDescriptor descriptor("path", path);
534     EXPECT_DEBUG_DEATH(printer.Annotate("bar", "foo", &descriptor), "negative");
535   }
536 }
537 
TEST(Printer,AnnotateUndefinedDeath)538 TEST(Printer, AnnotateUndefinedDeath) {
539   char buffer[8192];
540   ArrayOutputStream output(buffer, sizeof(buffer));
541   GeneratedCodeInfo info;
542   AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
543   {
544     Printer printer(&output, '$', &info_collector);
545     printer.Print("012$foo$4$foo$\n", "foo", "3");
546     std::vector<int> path;
547     path.push_back(33);
548     MockDescriptor descriptor("path", path);
549     EXPECT_DEBUG_DEATH(printer.Annotate("bar", "bar", &descriptor),
550                        "Undefined");
551   }
552 }
553 #endif  // PROTOBUF_HAS_DEATH_TEST
554 
TEST(Printer,WriteFailurePartial)555 TEST(Printer, WriteFailurePartial) {
556   char buffer[17];
557 
558   ArrayOutputStream output(buffer, sizeof(buffer));
559   Printer printer(&output, '$');
560 
561   // Print 16 bytes to almost fill the buffer (should not fail).
562   printer.Print("0123456789abcdef");
563   EXPECT_FALSE(printer.failed());
564 
565   // Try to print 2 chars. Only one fits.
566   printer.Print("<>");
567   EXPECT_TRUE(printer.failed());
568 
569   // Anything else should fail too.
570   printer.Print(" ");
571   EXPECT_TRUE(printer.failed());
572   printer.Print("blah");
573   EXPECT_TRUE(printer.failed());
574 
575   // Buffer should contain the first 17 bytes written.
576   EXPECT_EQ("0123456789abcdef<", string(buffer, sizeof(buffer)));
577 }
578 
TEST(Printer,WriteFailureExact)579 TEST(Printer, WriteFailureExact) {
580   char buffer[16];
581 
582   ArrayOutputStream output(buffer, sizeof(buffer));
583   Printer printer(&output, '$');
584 
585   // Print 16 bytes to fill the buffer exactly (should not fail).
586   printer.Print("0123456789abcdef");
587   EXPECT_FALSE(printer.failed());
588 
589   // Try to print one more byte (should fail).
590   printer.Print(" ");
591   EXPECT_TRUE(printer.failed());
592 
593   // Should not crash
594   printer.Print("blah");
595   EXPECT_TRUE(printer.failed());
596 
597   // Buffer should contain the first 16 bytes written.
598   EXPECT_EQ("0123456789abcdef", string(buffer, sizeof(buffer)));
599 }
600 
TEST(Printer,FormatInternal)601 TEST(Printer, FormatInternal) {
602   std::vector<std::string> args{"arg1", "arg2"};
603   std::map<std::string, std::string> vars{
604       {"foo", "bar"}, {"baz", "bla"}, {"empty", ""}};
605   // Substitution tests
606   {
607     // Direct arg substitution
608     std::string s;
609     {
610       StringOutputStream output(&s);
611       Printer printer(&output, '$');
612       printer.FormatInternal(args, vars, "$1$ $2$");
613     }
614     EXPECT_EQ("arg1 arg2", s);
615   }
616   {
617     // Variable substitution including spaces left
618     std::string s;
619     {
620       StringOutputStream output(&s);
621       Printer printer(&output, '$');
622       printer.FormatInternal({}, vars, "$foo$$ baz$$ empty$");
623     }
624     EXPECT_EQ("bar bla", s);
625   }
626   {
627     // Variable substitution including spaces right
628     std::string s;
629     {
630       StringOutputStream output(&s);
631       Printer printer(&output, '$');
632       printer.FormatInternal({}, vars, "$empty $$foo $$baz$");
633     }
634     EXPECT_EQ("bar bla", s);
635   }
636   {
637     // Mixed variable substitution
638     std::string s;
639     {
640       StringOutputStream output(&s);
641       Printer printer(&output, '$');
642       printer.FormatInternal(args, vars, "$empty $$1$ $foo $$2$ $baz$");
643     }
644     EXPECT_EQ("arg1 bar arg2 bla", s);
645   }
646 
647   // Indentation tests
648   {
649     // Empty lines shouldn't indent.
650     std::string s;
651     {
652       StringOutputStream output(&s);
653       Printer printer(&output, '$');
654       printer.Indent();
655       printer.FormatInternal(args, vars, "$empty $\n\n$1$ $foo $$2$\n$baz$");
656       printer.Outdent();
657     }
658     EXPECT_EQ("\n\n  arg1 bar arg2\n  bla", s);
659   }
660   {
661     // Annotations should respect indentation.
662     std::string s;
663     GeneratedCodeInfo info;
664     {
665       StringOutputStream output(&s);
666       AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
667       Printer printer(&output, '$', &info_collector);
668       printer.Indent();
669       GeneratedCodeInfo::Annotation annotation;
670       annotation.set_source_file("file.proto");
671       annotation.add_path(33);
672       std::vector<std::string> args{annotation.SerializeAsString(), "arg1",
673                                     "arg2"};
674       printer.FormatInternal(args, vars, "$empty $\n\n${1$$2$$}$ $3$\n$baz$");
675       printer.Outdent();
676     }
677     EXPECT_EQ("\n\n  arg1 arg2\n  bla", s);
678     ASSERT_EQ(1, info.annotation_size());
679     const GeneratedCodeInfo::Annotation* arg1 = &info.annotation(0);
680     ASSERT_EQ(1, arg1->path_size());
681     EXPECT_EQ(33, arg1->path(0));
682     EXPECT_EQ("file.proto", arg1->source_file());
683     EXPECT_EQ(4, arg1->begin());
684     EXPECT_EQ(8, arg1->end());
685   }
686 #ifdef PROTOBUF_HAS_DEATH_TEST
687   // Death tests in case of illegal format strings.
688   {
689     // Unused arguments
690     std::string s;
691     StringOutputStream output(&s);
692     Printer printer(&output, '$');
693     EXPECT_DEATH(printer.FormatInternal(args, vars, "$empty $$1$"), "Unused");
694   }
695   {
696     // Wrong order arguments
697     std::string s;
698     StringOutputStream output(&s);
699     Printer printer(&output, '$');
700     EXPECT_DEATH(printer.FormatInternal(args, vars, "$2$ $1$"), "order");
701   }
702   {
703     // Zero is illegal argument
704     std::string s;
705     StringOutputStream output(&s);
706     Printer printer(&output, '$');
707     EXPECT_DEATH(printer.FormatInternal(args, vars, "$0$"), "failed");
708   }
709   {
710     // Argument out of bounds
711     std::string s;
712     StringOutputStream output(&s);
713     Printer printer(&output, '$');
714     EXPECT_DEATH(printer.FormatInternal(args, vars, "$1$ $2$ $3$"), "bounds");
715   }
716   {
717     // Unknown variable
718     std::string s;
719     StringOutputStream output(&s);
720     Printer printer(&output, '$');
721     EXPECT_DEATH(printer.FormatInternal(args, vars, "$huh$ $1$$2$"), "Unknown");
722   }
723   {
724     // Illegal variable
725     std::string s;
726     StringOutputStream output(&s);
727     Printer printer(&output, '$');
728     EXPECT_DEATH(printer.FormatInternal({}, vars, "$ $"), "Empty");
729   }
730 #endif  // PROTOBUF_HAS_DEATH_TEST
731 }
732 
733 }  // namespace io
734 }  // namespace protobuf
735 }  // namespace google
736