• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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