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