• 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 //
10 // TODO:  Share code with the versions of this test in other languages?
11 //   It seemed like parameterizing it would add more complexity than it is
12 //   worth.
13 
14 #include <memory>
15 
16 #include "google/protobuf/testing/file.h"
17 #include "google/protobuf/testing/file.h"
18 #include "google/protobuf/compiler/cpp/generator.h"
19 #include "google/protobuf/compiler/command_line_interface.h"
20 #include <gtest/gtest.h>
21 #include "absl/log/absl_check.h"
22 #include "google/protobuf/io/printer.h"
23 #include "google/protobuf/io/zero_copy_stream.h"
24 
25 namespace google {
26 namespace protobuf {
27 namespace compiler {
28 namespace cpp {
29 namespace {
30 
31 class TestGenerator : public CodeGenerator {
32  public:
TestGenerator()33   TestGenerator() {}
~TestGenerator()34   ~TestGenerator() override {}
35 
Generate(const FileDescriptor * file,const std::string & parameter,GeneratorContext * context,std::string * error) const36   bool Generate(const FileDescriptor* file, const std::string& parameter,
37                 GeneratorContext* context, std::string* error) const override {
38     TryInsert("test.pb.h", "includes", context);
39     TryInsert("test.pb.h", "namespace_scope", context);
40     TryInsert("test.pb.h", "global_scope", context);
41     TryInsert("test.pb.h", "class_scope:foo.Bar", context);
42     TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", context);
43 
44     TryInsert("test.pb.cc", "includes", context);
45     TryInsert("test.pb.cc", "namespace_scope", context);
46     TryInsert("test.pb.cc", "global_scope", context);
47 
48     // Check field accessors for an optional int32:
49     TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context);
50     TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context);
51 
52     // Check field accessors for a repeated int32:
53     TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context);
54     TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context);
55 
56     // Check field accessors for a required string:
57     TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context);
58     TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context);
59     TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context);
60     TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString",
61               context);
62 
63     // Check field accessors for a repeated string:
64     TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context);
65     TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context);
66     TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context);
67 
68     // Check field accessors for an int inside oneof{}:
69     TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context);
70     TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context);
71 
72     // Check field accessors for a string inside oneof{}:
73     TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context);
74     TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context);
75     TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context);
76     TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context);
77 
78     // Check field accessors for an optional message:
79     TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context);
80     TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context);
81     TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context);
82 
83     // Check field accessors for a repeated message:
84     TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context);
85     TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context);
86     TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context);
87     TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context);
88     TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage",
89               context);
90 
91     // Check field accessors for a message inside oneof{}:
92     TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context);
93     TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context);
94     TryInsert("test.pb.cc", "field_set_allocated:foo.Bar.oneOfMessage",
95               context);
96 
97     // Check field accessors for an optional enum:
98     TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context);
99     TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context);
100 
101     // Check field accessors for a repeated enum:
102     TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context);
103     TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context);
104     TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context);
105     TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context);
106     TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context);
107 
108     // Check field accessors for an enum inside oneof{}:
109     TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context);
110     TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context);
111 
112     // Check field accessors for a required cord:
113     TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context);
114     TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context);
115     TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context);
116 
117     // Check field accessors for a repeated cord:
118     TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context);
119     TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context);
120     TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context);
121     TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context);
122     TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context);
123     TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context);
124 
125     // Check field accessors for a cord inside oneof{}:
126     TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context);
127     TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context);
128     TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context);
129 
130     return true;
131   }
132 
TryInsert(const std::string & filename,const std::string & insertion_point,GeneratorContext * context) const133   void TryInsert(const std::string& filename,
134                  const std::string& insertion_point,
135                  GeneratorContext* context) const {
136     std::unique_ptr<io::ZeroCopyOutputStream> output(
137         context->OpenForInsert(filename, insertion_point));
138     io::Printer printer(output.get(), '$');
139     printer.Print("// inserted $name$\n", "name", insertion_point);
140   }
141 };
142 
143 // This test verifies that all the expected insertion points exist.  It does
144 // not verify that they are correctly-placed; that would require actually
145 // compiling the output which is a bit more than I care to do for this test.
TEST(CppPluginTest,PluginTest)146 TEST(CppPluginTest, PluginTest) {
147   ABSL_CHECK_OK(
148       File::SetContents(absl::StrCat(::testing::TempDir(), "/test.proto"),
149                         "syntax = \"proto2\";\n"
150                         "package foo;\n"
151                         "\n"
152                         "enum Thud { VALUE = 0; }\n"
153                         "\n"
154                         "message Bar {\n"
155                         "  message Baz {}\n"
156                         "  optional int32 optInt = 1;\n"
157                         "  repeated int32 repeatedInt = 2;\n"
158                         "\n"
159                         "  required string requiredString = 3;\n"
160                         "  repeated string repeatedString = 4;\n"
161                         "\n"
162                         "  optional Baz optMessage = 6;\n"
163                         "  repeated Baz repeatedMessage = 7;\n"
164                         "\n"
165                         "  optional Thud optEnum = 8;\n"
166                         "  repeated Thud repeatedEnum = 9;\n"
167                         "\n"
168                         "  required string requiredCord = 10 [\n"
169                         "    ctype = CORD\n"
170                         "  ];\n"
171                         "  repeated string repeatedCord = 11 [\n"
172                         "    ctype = CORD\n"
173                         "  ];\n"
174                         "\n"
175                         "  oneof Moo {\n"
176                         "    int64 oneOfInt = 20;\n"
177                         "    string oneOfString = 21;\n"
178                         "    Baz oneOfMessage = 22;\n"
179                         "    Thud oneOfEnum = 23;"
180                         "    string oneOfCord = 24 [\n"
181                         "      ctype = CORD\n"
182                         "    ];\n"
183                         "  }\n"
184                         "}\n",
185                         true));
186 
187   CommandLineInterface cli;
188   cli.SetInputsAreProtoPathRelative(true);
189 
190   CppGenerator cpp_generator;
191   TestGenerator test_generator;
192   cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
193   cli.RegisterGenerator("--test_out", &test_generator, "");
194 
195   std::string proto_path = absl::StrCat("-I", ::testing::TempDir());
196   std::string cpp_out = absl::StrCat("--cpp_out=", ::testing::TempDir());
197   std::string test_out = absl::StrCat("--test_out=", ::testing::TempDir());
198 
199   const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(),
200                         test_out.c_str(), "test.proto"};
201 
202   EXPECT_EQ(0, cli.Run(5, argv));
203 }
204 
205 }  // namespace
206 }  // namespace cpp
207 }  // namespace compiler
208 }  // namespace protobuf
209 }  // namespace google
210