1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 // Author: kenton@google.com (Kenton Varda)
9 // Based on original Protocol Buffers design by
10 // Sanjay Ghemawat, Jeff Dean, and others.
11
12 #include "google/protobuf/io/printer.h"
13
14 #include <ostream>
15 #include <string>
16 #include <tuple>
17 #include <vector>
18
19 #include "google/protobuf/descriptor.pb.h"
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include "absl/container/flat_hash_map.h"
23 #include "absl/log/absl_check.h"
24 #include "absl/strings/str_join.h"
25 #include "absl/strings/string_view.h"
26 #include "absl/types/optional.h"
27 #include "google/protobuf/io/zero_copy_stream.h"
28 #include "google/protobuf/io/zero_copy_stream_impl_lite.h"
29
30 namespace google {
31 namespace protobuf {
32 namespace io {
33 namespace {
34 using ::testing::AllOf;
35 using ::testing::ElementsAre;
36 using ::testing::Field;
37 using ::testing::IsEmpty;
38 using ::testing::MatchesRegex;
39
40 class PrinterTest : public testing::Test {
41 protected:
output()42 ZeroCopyOutputStream* output() {
43 ABSL_CHECK(stream_.has_value());
44 return &*stream_;
45 }
written()46 absl::string_view written() {
47 stream_.reset();
48 return out_;
49 }
50
51 std::string out_;
52 absl::optional<StringOutputStream> stream_{&out_};
53 };
54
TEST_F(PrinterTest,EmptyPrinter)55 TEST_F(PrinterTest, EmptyPrinter) {
56 Printer printer(output(), '\0');
57 EXPECT_FALSE(printer.failed());
58 }
59
TEST_F(PrinterTest,BasicPrinting)60 TEST_F(PrinterTest, BasicPrinting) {
61 {
62 Printer printer(output(), '\0');
63
64 printer.Print("Hello World!");
65 printer.Print(" This is the same line.\n");
66 printer.Print("But this is a new one.\nAnd this is another one.");
67 EXPECT_FALSE(printer.failed());
68 }
69
70 EXPECT_EQ(written(),
71 "Hello World! This is the same line.\n"
72 "But this is a new one.\n"
73 "And this is another one.");
74 }
75
TEST_F(PrinterTest,WriteRaw)76 TEST_F(PrinterTest, WriteRaw) {
77 {
78 absl::string_view string_obj = "From an object\n";
79 Printer printer(output(), '$');
80 printer.WriteRaw("Hello World!", 12);
81 printer.PrintRaw(" This is the same line.\n");
82 printer.PrintRaw("But this is a new one.\nAnd this is another one.");
83 printer.WriteRaw("\n", 1);
84 printer.PrintRaw(string_obj);
85 EXPECT_FALSE(printer.failed());
86 }
87
88 EXPECT_EQ(written(),
89 "Hello World! This is the same line.\n"
90 "But this is a new one.\n"
91 "And this is another one."
92 "\n"
93 "From an object\n");
94 }
95
TEST_F(PrinterTest,VariableSubstitution)96 TEST_F(PrinterTest, VariableSubstitution) {
97 {
98 Printer printer(output(), '$');
99
100 absl::flat_hash_map<std::string, std::string> vars{
101 {"foo", "World"},
102 {"bar", "$foo$"},
103 {"abcdefg", "1234"},
104 };
105
106 printer.Print(vars, "Hello $foo$!\nbar = $bar$\n");
107 printer.PrintRaw("RawBit\n");
108 printer.Print(vars, "$abcdefg$\nA literal dollar sign: $$");
109
110 vars["foo"] = "blah";
111 printer.Print(vars, "\nNow foo = $foo$.");
112
113 EXPECT_FALSE(printer.failed());
114 }
115
116 EXPECT_EQ(written(),
117 "Hello World!\n"
118 "bar = $foo$\n"
119 "RawBit\n"
120 "1234\n"
121 "A literal dollar sign: $\n"
122 "Now foo = blah.");
123 }
124
TEST_F(PrinterTest,InlineVariableSubstitution)125 TEST_F(PrinterTest, InlineVariableSubstitution) {
126 {
127 Printer printer(output(), '$');
128 printer.Print("Hello $foo$!\n", "foo", "World");
129 printer.PrintRaw("RawBit\n");
130 printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
131 EXPECT_FALSE(printer.failed());
132 }
133
134 EXPECT_EQ(written(),
135 "Hello World!\n"
136 "RawBit\n"
137 "one two\n");
138 }
139
140 // FakeDescriptorFile defines only those members that Printer uses to write out
141 // annotations.
142 struct FakeDescriptorFile {
namegoogle::protobuf::io::__anonc5ec69450111::FakeDescriptorFile143 const std::string& name() const { return filename; }
144 std::string filename;
145 };
146
147 // FakeDescriptor defines only those members that Printer uses to write out
148 // annotations.
149 struct FakeDescriptor {
filegoogle::protobuf::io::__anonc5ec69450111::FakeDescriptor150 const FakeDescriptorFile* file() const { return &fake_file; }
GetLocationPathgoogle::protobuf::io::__anonc5ec69450111::FakeDescriptor151 void GetLocationPath(std::vector<int>* output) const { *output = path; }
152
153 FakeDescriptorFile fake_file;
154 std::vector<int> path;
155 };
156
157 class FakeAnnotationCollector : public AnnotationCollector {
158 public:
159 ~FakeAnnotationCollector() override = default;
160
161 // Records that the bytes in file_path beginning with begin_offset and ending
162 // before end_offset are associated with the SourceCodeInfo-style path.
AddAnnotation(size_t begin_offset,size_t end_offset,const std::string & file_path,const std::vector<int> & path)163 void AddAnnotation(size_t begin_offset, size_t end_offset,
164 const std::string& file_path,
165 const std::vector<int>& path) override {
166 annotations_.emplace_back(
167 Record{begin_offset, end_offset, file_path, path});
168 }
169
AddAnnotation(size_t begin_offset,size_t end_offset,const std::string & file_path,const std::vector<int> & path,absl::optional<Semantic> semantic)170 void AddAnnotation(size_t begin_offset, size_t end_offset,
171 const std::string& file_path, const std::vector<int>& path,
172 absl::optional<Semantic> semantic) override {
173 annotations_.emplace_back(
174 Record{begin_offset, end_offset, file_path, path, semantic});
175 }
176
AddAnnotationNew(Annotation & a)177 void AddAnnotationNew(Annotation& a) override {
178 GeneratedCodeInfo::Annotation annotation;
179 annotation.ParseFromString(a.second);
180
181 Record r{a.first.first, a.first.second, annotation.source_file(), {}};
182 for (int i : annotation.path()) {
183 r.path.push_back(i);
184 }
185
186 annotations_.emplace_back(r);
187 }
188
189 struct Record {
190 size_t start = 0;
191 size_t end = 0;
192 std::string file_path;
193 std::vector<int> path;
194 absl::optional<Semantic> semantic;
195
operator <<(std::ostream & out,const Record & record)196 friend std::ostream& operator<<(std::ostream& out, const Record& record) {
197 return out << "Record{" << record.start << ", " << record.end << ", \""
198 << record.file_path << "\", ["
199 << absl::StrJoin(record.path, ", ") << "], "
200 << record.semantic.value_or(kNone) << "}";
201 }
202 };
203
Get() const204 absl::Span<const Record> Get() const { return annotations_; }
205
206 private:
207 std::vector<Record> annotations_;
208 };
209
210 template <typename Start, typename End, typename FilePath, typename Path,
211 typename Semantic = absl::optional<AnnotationCollector::Semantic>>
Annotation(Start start,End end,FilePath file_path,Path path,Semantic semantic=absl::nullopt)212 testing::Matcher<FakeAnnotationCollector::Record> Annotation(
213 Start start, End end, FilePath file_path, Path path,
214 Semantic semantic = absl::nullopt) {
215 return AllOf(
216 Field("start", &FakeAnnotationCollector::Record::start, start),
217 Field("end", &FakeAnnotationCollector::Record::end, end),
218 Field("file_path", &FakeAnnotationCollector::Record::file_path,
219 file_path),
220 Field("path", &FakeAnnotationCollector::Record::path, path),
221 Field("semantic", &FakeAnnotationCollector::Record::semantic, semantic));
222 }
223
TEST_F(PrinterTest,AnnotateMap)224 TEST_F(PrinterTest, AnnotateMap) {
225 FakeAnnotationCollector collector;
226 {
227 Printer printer(output(), '$', &collector);
228 absl::flat_hash_map<std::string, std::string> vars = {{"foo", "3"},
229 {"bar", "5"}};
230 printer.Print(vars, "012$foo$4$bar$\n");
231
232 FakeDescriptor descriptor_1{{"path_1"}, {33}};
233 FakeDescriptor descriptor_2{{"path_2"}, {11, 22}};
234 printer.Annotate("foo", "foo", &descriptor_1);
235 printer.Annotate("bar", "bar", &descriptor_2);
236 }
237
238 EXPECT_EQ(written(), "012345\n");
239 EXPECT_THAT(collector.Get(),
240 ElementsAre(Annotation(3, 4, "path_1", ElementsAre(33)),
241 Annotation(5, 6, "path_2", ElementsAre(11, 22))));
242 }
243
TEST_F(PrinterTest,AnnotateInline)244 TEST_F(PrinterTest, AnnotateInline) {
245 FakeAnnotationCollector collector;
246 {
247 Printer printer(output(), '$', &collector);
248 printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
249
250 FakeDescriptor descriptor_1{{"path_1"}, {33}};
251 FakeDescriptor descriptor_2{{"path_2"}, {11, 22}};
252 printer.Annotate("foo", "foo", &descriptor_1);
253 printer.Annotate("bar", "bar", &descriptor_2);
254 }
255
256 EXPECT_EQ(written(), "012345\n");
257 EXPECT_THAT(collector.Get(),
258 ElementsAre(Annotation(3, 4, "path_1", ElementsAre(33)),
259 Annotation(5, 6, "path_2", ElementsAre(11, 22))));
260 }
261
TEST_F(PrinterTest,AnnotateRange)262 TEST_F(PrinterTest, AnnotateRange) {
263 FakeAnnotationCollector collector;
264 {
265 Printer printer(output(), '$', &collector);
266 printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
267
268 FakeDescriptor descriptor{{"path"}, {33}};
269 printer.Annotate("foo", "bar", &descriptor);
270 }
271
272 EXPECT_EQ(written(), "012345\n");
273 EXPECT_THAT(collector.Get(),
274 ElementsAre(Annotation(3, 6, "path", ElementsAre(33))));
275 }
276
TEST_F(PrinterTest,AnnotateEmptyRange)277 TEST_F(PrinterTest, AnnotateEmptyRange) {
278 FakeAnnotationCollector collector;
279 {
280 Printer printer(output(), '$', &collector);
281 printer.Print("012$foo$4$baz$$bam$$bar$\n", "foo", "3", "bar", "5", "baz",
282 "", "bam", "");
283
284 FakeDescriptor descriptor{{"path"}, {33}};
285 printer.Annotate("baz", "bam", &descriptor);
286 }
287
288 EXPECT_EQ(written(), "012345\n");
289 EXPECT_THAT(collector.Get(),
290 ElementsAre(Annotation(5, 5, "path", ElementsAre(33))));
291 }
292
TEST_F(PrinterTest,AnnotateDespiteUnrelatedMultipleUses)293 TEST_F(PrinterTest, AnnotateDespiteUnrelatedMultipleUses) {
294 FakeAnnotationCollector collector;
295 {
296 Printer printer(output(), '$', &collector);
297 printer.Print("012$foo$4$foo$$bar$\n", "foo", "3", "bar", "5");
298
299 FakeDescriptor descriptor{{"path"}, {33}};
300 printer.Annotate("bar", "bar", &descriptor);
301 }
302
303 EXPECT_EQ(written(), "0123435\n");
304 EXPECT_THAT(collector.Get(),
305 ElementsAre(Annotation(6, 7, "path", ElementsAre(33))));
306 }
307
TEST_F(PrinterTest,AnnotateIndent)308 TEST_F(PrinterTest, AnnotateIndent) {
309 FakeAnnotationCollector collector;
310 {
311 Printer printer(output(), '$', &collector);
312 printer.Print("0\n");
313 printer.Indent();
314
315 printer.Print("$foo$", "foo", "4");
316 FakeDescriptor descriptor1{{"path"}, {44}};
317 printer.Annotate("foo", &descriptor1);
318
319 printer.Print(",\n");
320 printer.Print("$bar$", "bar", "9");
321 FakeDescriptor descriptor2{{"path"}, {99}};
322 printer.Annotate("bar", &descriptor2);
323
324 printer.Print("\n${$$D$$}$\n", "{", "", "}", "", "D", "d");
325 FakeDescriptor descriptor3{{"path"}, {1313}};
326 printer.Annotate("{", "}", &descriptor3);
327
328 printer.Outdent();
329 printer.Print("\n");
330 }
331
332 EXPECT_EQ(written(), "0\n 4,\n 9\n d\n\n");
333 EXPECT_THAT(collector.Get(),
334 ElementsAre(Annotation(4, 5, "path", ElementsAre(44)),
335 Annotation(9, 10, "path", ElementsAre(99)),
336 Annotation(13, 14, "path", ElementsAre(1313))));
337 }
338
TEST_F(PrinterTest,AnnotateIndentNewline)339 TEST_F(PrinterTest, AnnotateIndentNewline) {
340 FakeAnnotationCollector collector;
341 {
342 Printer printer(output(), '$', &collector);
343 printer.Indent();
344
345 printer.Print("$A$$N$$B$C\n", "A", "", "N", "\nz", "B", "");
346 FakeDescriptor descriptor{{"path"}, {0}};
347 printer.Annotate("A", "B", &descriptor);
348
349 printer.Outdent();
350 printer.Print("\n");
351 }
352 EXPECT_EQ(written(), "\nz C\n\n");
353
354 EXPECT_THAT(collector.Get(),
355 ElementsAre(Annotation(0, 4, "path", ElementsAre(0))));
356 }
357
TEST_F(PrinterTest,Indenting)358 TEST_F(PrinterTest, Indenting) {
359 {
360 Printer printer(output(), '$');
361 absl::flat_hash_map<std::string, std::string> vars = {{"newline", "\n"}};
362
363 printer.Print("This is not indented.\n");
364 printer.Indent();
365 printer.Print("This is indented\nAnd so is this\n");
366 printer.Outdent();
367 printer.Print("But this is not.");
368 printer.Indent();
369 printer.Print(
370 " And this is still the same line.\n"
371 "But this is indented.\n");
372 printer.PrintRaw("RawBit has indent at start\n");
373 printer.PrintRaw("but not after a raw newline\n");
374 printer.Print(vars,
375 "Note that a newline in a variable will break "
376 "indenting, as we see$newline$here.\n");
377 printer.Indent();
378 printer.Print("And this");
379 printer.Outdent();
380 printer.Outdent();
381 printer.Print(" is double-indented\nBack to normal.");
382
383 EXPECT_FALSE(printer.failed());
384 }
385
386 EXPECT_EQ(
387 written(),
388 "This is not indented.\n"
389 " This is indented\n"
390 " And so is this\n"
391 "But this is not. And this is still the same line.\n"
392 " But this is indented.\n"
393 " RawBit has indent at start\n"
394 "but not after a raw newline\n"
395 "Note that a newline in a variable will break indenting, as we see\n"
396 "here.\n"
397 " And this is double-indented\n"
398 "Back to normal.");
399 }
400
TEST_F(PrinterTest,WriteFailurePartial)401 TEST_F(PrinterTest, WriteFailurePartial) {
402 std::string buffer(17, '\xaa');
403 ArrayOutputStream output(&buffer[0], buffer.size());
404 Printer printer(&output, '$');
405
406 // Print 16 bytes to almost fill the buffer (should not fail).
407 printer.Print("0123456789abcdef");
408 EXPECT_FALSE(printer.failed());
409
410 // Try to print 2 chars. Only one fits.
411 printer.Print("<>");
412 EXPECT_TRUE(printer.failed());
413
414 // Anything else should fail too.
415 printer.Print(" ");
416 EXPECT_TRUE(printer.failed());
417 printer.Print("blah");
418 EXPECT_TRUE(printer.failed());
419
420 // Buffer should contain the first 17 bytes written.
421 EXPECT_EQ(buffer, "0123456789abcdef<");
422 }
423
TEST_F(PrinterTest,WriteFailureExact)424 TEST_F(PrinterTest, WriteFailureExact) {
425 std::string buffer(16, '\xaa');
426 ArrayOutputStream output(&buffer[0], buffer.size());
427 Printer printer(&output, '$');
428
429 // Print 16 bytes to fill the buffer exactly (should not fail).
430 printer.Print("0123456789abcdef");
431 EXPECT_FALSE(printer.failed());
432
433 // Try to print one more byte (should fail).
434 printer.Print(" ");
435 EXPECT_TRUE(printer.failed());
436
437 // Should not crash
438 printer.Print("blah");
439 EXPECT_TRUE(printer.failed());
440
441 // Buffer should contain the first 16 bytes written.
442 EXPECT_EQ(buffer, "0123456789abcdef");
443 }
444
TEST_F(PrinterTest,FormatInternalDirectSub)445 TEST_F(PrinterTest, FormatInternalDirectSub) {
446 {
447 Printer printer(output(), '$');
448 printer.FormatInternal({"arg1", "arg2"}, {}, "$1$ $2$");
449 }
450 EXPECT_EQ(written(), "arg1 arg2");
451 }
452
TEST_F(PrinterTest,FormatInternalSubWithSpacesLeft)453 TEST_F(PrinterTest, FormatInternalSubWithSpacesLeft) {
454 {
455 Printer printer(output(), '$');
456 printer.FormatInternal({}, {{"foo", "bar"}, {"baz", "bla"}, {"empty", ""}},
457 "$foo$$ baz$$ empty$");
458 }
459 EXPECT_EQ(written(), "bar bla");
460 }
461
TEST_F(PrinterTest,FormatInternalSubWithSpacesRight)462 TEST_F(PrinterTest, FormatInternalSubWithSpacesRight) {
463 {
464 Printer printer(output(), '$');
465 printer.FormatInternal({}, {{"foo", "bar"}, {"baz", "bla"}, {"empty", ""}},
466 "$empty $$foo $$baz$");
467 }
468 EXPECT_EQ(written(), "bar bla");
469 }
470
TEST_F(PrinterTest,FormatInternalSubMixed)471 TEST_F(PrinterTest, FormatInternalSubMixed) {
472 {
473 Printer printer(output(), '$');
474 printer.FormatInternal({"arg1", "arg2"},
475 {{"foo", "bar"}, {"baz", "bla"}, {"empty", ""}},
476 "$empty $$1$ $foo $$2$ $baz$");
477 }
478 EXPECT_EQ(written(), "arg1 bar arg2 bla");
479 }
480
TEST_F(PrinterTest,FormatInternalIndent)481 TEST_F(PrinterTest, FormatInternalIndent) {
482 {
483 Printer printer(output(), '$');
484 printer.Indent();
485 printer.FormatInternal({"arg1", "arg2"},
486 {{"foo", "bar"}, {"baz", "bla"}, {"empty", ""}},
487 "$empty $\n\n$1$ $foo $$2$\n$baz$");
488 printer.Outdent();
489 }
490 EXPECT_EQ(written(), "\n\n arg1 bar arg2\n bla");
491 }
492
TEST_F(PrinterTest,FormatInternalAnnotations)493 TEST_F(PrinterTest, FormatInternalAnnotations) {
494 FakeAnnotationCollector collector;
495 {
496 Printer printer(output(), '$', &collector);
497
498 printer.Indent();
499 GeneratedCodeInfo::Annotation annotation;
500 annotation.set_source_file("file.proto");
501 annotation.add_path(33);
502
503 printer.FormatInternal({annotation.SerializeAsString(), "arg1", "arg2"},
504 {{"foo", "bar"}, {"baz", "bla"}, {"empty", ""}},
505 "$empty $\n\n${1$$2$$}$ $3$\n$baz$");
506 printer.Outdent();
507 }
508
509 EXPECT_EQ(written(), "\n\n arg1 arg2\n bla");
510 EXPECT_THAT(collector.Get(),
511 ElementsAre(Annotation(4, 8, "file.proto", ElementsAre(33))));
512 }
513
TEST_F(PrinterTest,Emit)514 TEST_F(PrinterTest, Emit) {
515 {
516 Printer printer(output());
517 printer.Emit(R"cc(
518 class Foo {
519 int x, y, z;
520 };
521 )cc");
522 printer.Emit(R"java(
523 public final class Bar {
524 Bar() {}
525 }
526 )java");
527 }
528
529 EXPECT_EQ(written(),
530 "class Foo {\n"
531 " int x, y, z;\n"
532 "};\n"
533 "public final class Bar {\n"
534 " Bar() {}\n"
535 "}\n");
536 }
537
TEST_F(PrinterTest,EmitWithSubs)538 TEST_F(PrinterTest, EmitWithSubs) {
539 {
540 Printer printer(output());
541 printer.Emit(
542 {{"class", "Foo"}, {"f1", "x"}, {"f2", "y"}, {"f3", "z"}, {"init", 42}},
543 R"cc(
544 class $class$ {
545 int $f1$, $f2$, $f3$ = $init$;
546 };
547 )cc");
548 }
549
550 EXPECT_EQ(written(),
551 "class Foo {\n"
552 " int x, y, z = 42;\n"
553 "};\n");
554 }
555
TEST_F(PrinterTest,EmitComments)556 TEST_F(PrinterTest, EmitComments) {
557 {
558 Printer printer(output());
559 printer.Emit(R"cc(
560 // Yes.
561 //~ No.
562 )cc");
563 printer.Emit("//~ Not a raw string.");
564 }
565
566 EXPECT_EQ(written(), "// Yes.\n//~ Not a raw string.");
567 }
568
TEST_F(PrinterTest,EmitWithVars)569 TEST_F(PrinterTest, EmitWithVars) {
570 {
571 Printer printer(output());
572 auto v = printer.WithVars({
573 {"class", "Foo"},
574 {"f1", "x"},
575 {"f2", "y"},
576 {"f3", "z"},
577 {"init", 42},
578 });
579 printer.Emit(R"cc(
580 class $class$ {
581 int $f1$, $f2$, $f3$ = $init$;
582 };
583 )cc");
584 }
585
586 EXPECT_EQ(written(),
587 "class Foo {\n"
588 " int x, y, z = 42;\n"
589 "};\n");
590 }
591
TEST_F(PrinterTest,EmitConsumeAfter)592 TEST_F(PrinterTest, EmitConsumeAfter) {
593 {
594 Printer printer(output());
595 printer.Emit(
596 {
597 {"class", "Foo"},
598 Printer::Sub{"var", "int x;"}.WithSuffix(";"),
599 },
600 R"cc(
601 class $class$ {
602 $var$;
603 };
604 )cc");
605 }
606
607 EXPECT_EQ(written(),
608 "class Foo {\n"
609 " int x;\n"
610 "};\n");
611 }
612
TEST_F(PrinterTest,EmitWithSubstitutionListener)613 TEST_F(PrinterTest, EmitWithSubstitutionListener) {
614 std::vector<std::string> seen;
615 Printer printer(output());
616 const auto emit = [&] {
617 printer.Emit(
618 {
619 {"class", "Foo"},
620 Printer::Sub{"var", "int x;"}.WithSuffix(";"),
621 },
622 R"cc(
623 void $class$::foo() { $var$; }
624 void $class$::set_foo() { $var$; }
625 )cc");
626 };
627 emit();
628 EXPECT_THAT(seen, ElementsAre());
629 {
630 auto listener = printer.WithSubstitutionListener(
631 [&](auto label, auto loc) { seen.emplace_back(label); });
632 emit();
633 }
634 EXPECT_THAT(seen, ElementsAre("class", "var", "class", "var"));
635
636 // Still works after the listener is disconnected.
637 seen.clear();
638 emit();
639 EXPECT_THAT(seen, ElementsAre());
640 }
641
TEST_F(PrinterTest,EmitConditionalFunctionCall)642 TEST_F(PrinterTest, EmitConditionalFunctionCall) {
643 {
644 Printer printer(output());
645 printer.Emit(
646 {
647 Printer::Sub{"weak_cast", ""}.ConditionalFunctionCall(),
648 Printer::Sub{"strong_cast", "static_cast<void*>"}
649 .ConditionalFunctionCall(),
650 },
651 R"cc(
652 $weak_cast$(weak);
653 $weak_cast$(weak + (1234 * 89) + zomg);
654 $strong_cast$(strong);
655 $weak_cast$($strong_cast$($weak_cast$(1 + 2)));
656 $weak_cast$(boy_this_expression_got_really_long +
657 what_kind_of_monster_does_this);
658 )cc");
659 }
660
661 EXPECT_EQ(written(),
662 "weak;\n"
663 "weak + (1234 * 89) + zomg;\n"
664 "static_cast<void*>(strong);\n"
665 "static_cast<void*>(1 + 2);\n"
666 "boy_this_expression_got_really_long +\n"
667 " what_kind_of_monster_does_this;\n");
668 }
669
TEST_F(PrinterTest,EmitWithSpacedVars)670 TEST_F(PrinterTest, EmitWithSpacedVars) {
671 {
672 Printer printer(output());
673 auto v = printer.WithVars({
674 {"is_final", "final"},
675 {"isnt_final", ""},
676 {"class", "Foo"},
677 });
678 printer.Emit(R"java(
679 public $is_final $class $class$ {
680 // Stuff.
681 }
682 )java");
683 printer.Emit(R"java(
684 public $isnt_final $class $class$ {
685 // Stuff.
686 }
687 )java");
688 }
689
690 EXPECT_EQ(written(),
691 "public final class Foo {\n"
692 " // Stuff.\n"
693 "}\n"
694 "public class Foo {\n"
695 " // Stuff.\n"
696 "}\n");
697 }
698
TEST_F(PrinterTest,EmitWithIndent)699 TEST_F(PrinterTest, EmitWithIndent) {
700 {
701 Printer printer(output());
702 auto v = printer.WithIndent();
703 printer.Emit({{"f1", "x"}, {"f2", "y"}, {"f3", "z"}}, R"cc(
704 class Foo {
705 int $f1$, $f2$, $f3$;
706 };
707 )cc");
708 }
709
710 EXPECT_EQ(written(),
711 " class Foo {\n"
712 " int x, y, z;\n"
713 " };\n");
714 }
715
TEST_F(PrinterTest,EmitWithPreprocessor)716 TEST_F(PrinterTest, EmitWithPreprocessor) {
717 {
718 Printer printer(output());
719 auto v = printer.WithIndent();
720 printer.Emit({{"value",
721 [&] {
722 printer.Emit(R"cc(
723 #if FOO
724 0,
725 #else
726 1,
727 #endif
728 )cc");
729 }},
730 {"on_new_line",
731 [&] {
732 printer.Emit(R"cc(
733 #pragma foo
734 )cc");
735 }}},
736 R"cc(
737 int val = ($value$, 0);
738 $on_new_line$;
739 )cc");
740 }
741
742 EXPECT_EQ(written(),
743 R"( int val = (
744 #if FOO
745 0,
746 #else
747 1,
748 #endif
749 0);
750 #pragma foo
751 )");
752 }
753
754
TEST_F(PrinterTest,EmitSameNameAnnotation)755 TEST_F(PrinterTest, EmitSameNameAnnotation) {
756 FakeAnnotationCollector collector;
757 {
758 Printer printer(output(), '$', &collector);
759 FakeDescriptor descriptor{{"file.proto"}, {33}};
760 auto v = printer.WithVars({{"class", "Foo"}});
761 auto a = printer.WithAnnotations({{"class", &descriptor}});
762
763 printer.Emit({{"f1", "x"}, {"f2", "y"}, {"f3", "z"}}, R"cc(
764 class $class$ {
765 int $f1$, $f2$, $f3$;
766 };
767 )cc");
768 }
769
770 EXPECT_EQ(written(),
771 "class Foo {\n"
772 " int x, y, z;\n"
773 "};\n");
774
775 EXPECT_THAT(collector.Get(),
776 ElementsAre(Annotation(6, 9, "file.proto", ElementsAre(33))));
777 }
778
TEST_F(PrinterTest,EmitSameNameAnnotationWithSemantic)779 TEST_F(PrinterTest, EmitSameNameAnnotationWithSemantic) {
780 FakeAnnotationCollector collector;
781 {
782 Printer printer(output(), '$', &collector);
783 FakeDescriptor descriptor{{"file.proto"}, {33}};
784 auto v = printer.WithVars({{"class", "Foo"}});
785 auto a = printer.WithAnnotations(
786 {{"class", {&descriptor, AnnotationCollector::kSet}}});
787
788 printer.Emit({{"f1", "x"}, {"f2", "y"}, {"f3", "z"}}, R"cc(
789 class $class$ {
790 int $f1$, $f2$, $f3$;
791 };
792 )cc");
793 }
794
795 EXPECT_EQ(written(),
796 "class Foo {\n"
797 " int x, y, z;\n"
798 "};\n");
799
800 EXPECT_THAT(collector.Get(),
801 ElementsAre(Annotation(6, 9, "file.proto", ElementsAre(33),
802 AnnotationCollector::kSet)));
803 }
804
TEST_F(PrinterTest,EmitSameNameAnnotationFileNameOnly)805 TEST_F(PrinterTest, EmitSameNameAnnotationFileNameOnly) {
806 FakeAnnotationCollector collector;
807 {
808 Printer printer(output(), '$', &collector);
809 auto v = printer.WithVars({{"class", "Foo"}});
810 auto a = printer.WithAnnotations({{"class", "file.proto"}});
811
812 printer.Emit({{"f1", "x"}, {"f2", "y"}, {"f3", "z"}}, R"cc(
813 class $class$ {
814 int $f1$, $f2$, $f3$;
815 };
816 )cc");
817 }
818
819 EXPECT_EQ(written(),
820 "class Foo {\n"
821 " int x, y, z;\n"
822 "};\n");
823
824 EXPECT_THAT(collector.Get(),
825 ElementsAre(Annotation(6, 9, "file.proto", IsEmpty())));
826 }
827
TEST_F(PrinterTest,EmitThreeArgWithVars)828 TEST_F(PrinterTest, EmitThreeArgWithVars) {
829 FakeAnnotationCollector collector;
830 {
831 Printer printer(output(), '$', &collector);
832 auto v = printer.WithVars({
833 Printer::Sub("class", "Foo").AnnotatedAs("file.proto"),
834 });
835
836 printer.Emit({{"f1", "x"}, {"f2", "y"}, {"f3", "z"}}, R"cc(
837 class $class$ {
838 int $f1$, $f2$, $f3$;
839 };
840 )cc");
841 }
842
843 EXPECT_EQ(written(),
844 "class Foo {\n"
845 " int x, y, z;\n"
846 "};\n");
847
848 EXPECT_THAT(collector.Get(),
849 ElementsAre(Annotation(6, 9, "file.proto", IsEmpty())));
850 }
851
TEST_F(PrinterTest,EmitRangeAnnotation)852 TEST_F(PrinterTest, EmitRangeAnnotation) {
853 FakeAnnotationCollector collector;
854 {
855 Printer printer(output(), '$', &collector);
856 FakeDescriptor descriptor1{{"file1.proto"}, {33}};
857 FakeDescriptor descriptor2{{"file2.proto"}, {11, 22}};
858 auto v = printer.WithVars({{"class", "Foo"}});
859 auto a = printer.WithAnnotations({
860 {"message", &descriptor1},
861 {"field", &descriptor2},
862 });
863
864 printer.Emit({{"f1", "x"}, {"f2", "y"}, {"f3", "z"}}, R"cc(
865 $_start$message$ class $class$ {
866 $_start$field$ int $f1$, $f2$, $f3$;
867 $_end$field$
868 };
869 $_end$message$
870 )cc");
871 }
872
873 EXPECT_EQ(written(),
874 "class Foo {\n"
875 " int x, y, z;\n"
876 "};\n");
877
878 EXPECT_THAT(
879 collector.Get(),
880 ElementsAre(Annotation(14, 27, "file2.proto", ElementsAre(11, 22)),
881 Annotation(0, 30, "file1.proto", ElementsAre(33))));
882 }
883
TEST_F(PrinterTest,EmitCallbacks)884 TEST_F(PrinterTest, EmitCallbacks) {
885 {
886 Printer printer(output());
887 printer.Emit(
888 {
889 {"class", "Foo"},
890 {"method", "bar"},
891 {"methods",
892 [&] {
893 printer.Emit(R"cc(
894 int $method$() { return 42; }
895 )cc");
896 }},
897 {"fields",
898 [&] {
899 printer.Emit(R"cc(
900 int $method$_;
901 )cc");
902 }},
903 },
904 R"cc(
905 class $class$ {
906 public:
907 $methods$;
908
909 private:
910 $fields$;
911 };
912 )cc");
913 }
914
915 EXPECT_EQ(written(),
916 "class Foo {\n"
917 " public:\n"
918 " int bar() { return 42; }\n"
919 "\n"
920 " private:\n"
921 " int bar_;\n"
922 "};\n");
923 }
924
TEST_F(PrinterTest,PreserveNewlinesThroughEmits)925 TEST_F(PrinterTest, PreserveNewlinesThroughEmits) {
926 {
927 Printer printer(output());
928 const std::vector<std::string> insertion_lines = {"// line 1", "// line 2"};
929 printer.Emit(
930 {
931 {"insert_lines",
932 [&] {
933 for (const auto& line : insertion_lines) {
934 printer.Emit({{"line", line}}, R"cc(
935 $line$
936 )cc");
937 }
938 }},
939 },
940 R"cc(
941 // one
942 // two
943
944 $insert_lines$;
945
946 // three
947 // four
948 )cc");
949 }
950 EXPECT_EQ(written(),
951 "// one\n"
952 "// two\n"
953 "\n"
954 "// line 1\n"
955 "// line 2\n"
956 "\n"
957 "// three\n"
958 "// four\n");
959 }
960
961 } // namespace
962 } // namespace io
963 } // namespace protobuf
964 } // namespace google
965