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