• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 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 #include "google/protobuf/compiler/cpp/generator.h"
9 
10 #include <memory>
11 
12 #include "google/protobuf/descriptor.pb.h"
13 #include <gtest/gtest.h>
14 #include "google/protobuf/compiler/command_line_interface_tester.h"
15 #include "google/protobuf/cpp_features.pb.h"
16 
17 namespace google {
18 namespace protobuf {
19 namespace compiler {
20 namespace cpp {
21 namespace {
22 
23 class CppGeneratorTest : public CommandLineInterfaceTester {
24  protected:
CppGeneratorTest()25   CppGeneratorTest() {
26     RegisterGenerator("--cpp_out", "--cpp_opt",
27                       std::make_unique<CppGenerator>(), "C++ test generator");
28 
29     // Generate built-in protos.
30     CreateTempFile(
31         "google/protobuf/descriptor.proto",
32         google::protobuf::DescriptorProto::descriptor()->file()->DebugString());
33     CreateTempFile("google/protobuf/cpp_features.proto",
34                    pb::CppFeatures::descriptor()->file()->DebugString());
35   }
36 };
37 
TEST_F(CppGeneratorTest,Basic)38 TEST_F(CppGeneratorTest, Basic) {
39   CreateTempFile("foo.proto",
40                  R"schema(
41     syntax = "proto2";
42     message Foo {
43       optional int32 bar = 1;
44     })schema");
45 
46   RunProtoc(
47       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
48 
49   ExpectNoErrors();
50 }
51 
TEST_F(CppGeneratorTest,BasicError)52 TEST_F(CppGeneratorTest, BasicError) {
53   CreateTempFile("foo.proto",
54                  R"schema(
55     syntax = "proto2";
56     message Foo {
57       int32 bar = 1;
58     })schema");
59 
60   RunProtoc(
61       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
62 
63   ExpectErrorSubstring(
64       "foo.proto:4:7: Expected \"required\", \"optional\", or \"repeated\"");
65 }
66 
TEST_F(CppGeneratorTest,LegacyClosedEnumOnNonEnumField)67 TEST_F(CppGeneratorTest, LegacyClosedEnumOnNonEnumField) {
68   CreateTempFile("foo.proto",
69                  R"schema(
70     edition = "2023";
71     import "google/protobuf/cpp_features.proto";
72 
73     message Foo {
74       int32 bar = 1 [features.(pb.cpp).legacy_closed_enum = true];
75     })schema");
76 
77   RunProtoc(
78       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
79 
80   ExpectErrorSubstring(
81       "Field Foo.bar specifies the legacy_closed_enum feature but has non-enum "
82       "type.");
83 }
84 
TEST_F(CppGeneratorTest,LegacyClosedEnum)85 TEST_F(CppGeneratorTest, LegacyClosedEnum) {
86   CreateTempFile("foo.proto",
87                  R"schema(
88     edition = "2023";
89     import "google/protobuf/cpp_features.proto";
90 
91     enum TestEnum {
92       TEST_ENUM_UNKNOWN = 0;
93     }
94     message Foo {
95       TestEnum bar = 1 [features.(pb.cpp).legacy_closed_enum = true];
96     })schema");
97 
98   RunProtoc(
99       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
100 
101   ExpectWarningSubstring(
102       "foo.proto:9:16: warning: Feature pb.CppFeatures.legacy_closed_enum has "
103       "been deprecated in edition 2023");
104 }
105 
TEST_F(CppGeneratorTest,LegacyClosedEnumInherited)106 TEST_F(CppGeneratorTest, LegacyClosedEnumInherited) {
107   CreateTempFile("foo.proto",
108                  R"schema(
109     edition = "2023";
110     import "google/protobuf/cpp_features.proto";
111     option features.(pb.cpp).legacy_closed_enum = true;
112 
113     enum TestEnum {
114       TEST_ENUM_UNKNOWN = 0;
115     }
116     message Foo {
117       TestEnum bar = 1;
118       int32 baz = 2;
119     })schema");
120 
121   RunProtoc(
122       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
123 
124   ExpectWarningSubstring(
125       "foo.proto: warning: Feature pb.CppFeatures.legacy_closed_enum has "
126       "been deprecated in edition 2023");
127 }
128 
TEST_F(CppGeneratorTest,LegacyClosedEnumImplicit)129 TEST_F(CppGeneratorTest, LegacyClosedEnumImplicit) {
130   CreateTempFile("foo.proto", R"schema(
131     edition = "2023";
132     import "google/protobuf/cpp_features.proto";
133     option features.(pb.cpp).legacy_closed_enum = true;
134 
135     enum TestEnum {
136       TEST_ENUM_UNKNOWN = 0;
137     }
138     message Foo {
139       TestEnum bar = 1 [features.field_presence = IMPLICIT];
140       int32 baz = 2;
141     }
142   )schema");
143 
144   RunProtoc(
145       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
146 
147   ExpectErrorSubstring(
148       "Field Foo.bar has a closed enum type with implicit presence.");
149 }
150 
TEST_F(CppGeneratorTest,AllowStringTypeForEdition2023)151 TEST_F(CppGeneratorTest, AllowStringTypeForEdition2023) {
152   CreateTempFile("foo.proto", R"schema(
153     edition = "2023";
154     import "google/protobuf/cpp_features.proto";
155 
156     message Foo {
157       int32 bar = 1;
158       bytes baz = 2 [features.(pb.cpp).string_type = CORD];
159     }
160   )schema");
161 
162   RunProtoc(
163       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
164 
165   ExpectNoErrors();
166 }
167 
TEST_F(CppGeneratorTest,ErrorsOnBothStringTypeAndCtype)168 TEST_F(CppGeneratorTest, ErrorsOnBothStringTypeAndCtype) {
169   CreateTempFile("foo.proto", R"schema(
170     edition = "2023";
171     import "google/protobuf/cpp_features.proto";
172 
173     message Foo {
174       int32 bar = 1;
175       bytes baz = 2 [ctype = CORD, features.(pb.cpp).string_type = VIEW];
176     }
177   )schema");
178 
179   RunProtoc(
180       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
181 
182   ExpectErrorSubstring(
183       "Foo.baz specifies both string_type and ctype which is not supported.");
184 }
185 
TEST_F(CppGeneratorTest,StringTypeForCord)186 TEST_F(CppGeneratorTest, StringTypeForCord) {
187   CreateTempFile("foo.proto", R"schema(
188     edition = "2024";
189     import "google/protobuf/cpp_features.proto";
190 
191     message Foo {
192       int32 bar = 1;
193       bytes baz = 2 [features.(pb.cpp).string_type = CORD];
194     }
195   )schema");
196 
197   RunProtoc(
198       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir "
199       "--experimental_editions foo.proto");
200 
201   ExpectNoErrors();
202 }
203 
TEST_F(CppGeneratorTest,CtypeForCord)204 TEST_F(CppGeneratorTest, CtypeForCord) {
205   CreateTempFile("foo.proto", R"schema(
206     edition = "2023";
207 
208     message Foo {
209       int32 bar = 1;
210       bytes baz = 2 [ctype = CORD];
211     }
212   )schema");
213 
214   RunProtoc(
215       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
216 
217   ExpectNoErrors();
218 }
219 
TEST_F(CppGeneratorTest,StringTypeForStringFieldsOnly)220 TEST_F(CppGeneratorTest, StringTypeForStringFieldsOnly) {
221   CreateTempFile("foo.proto", R"schema(
222     edition = "2024";
223     import "google/protobuf/cpp_features.proto";
224 
225     message Foo {
226       int32 bar = 1;
227       int32 baz = 2 [features.(pb.cpp).string_type = CORD];
228     }
229   )schema");
230 
231   RunProtoc(
232       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir "
233       "--experimental_editions foo.proto");
234 
235   ExpectErrorSubstring(
236       "Field Foo.baz specifies string_type, but is not a string nor bytes "
237       "field.");
238 }
239 
TEST_F(CppGeneratorTest,StringTypeCordNotForExtension)240 TEST_F(CppGeneratorTest, StringTypeCordNotForExtension) {
241   CreateTempFile("foo.proto", R"schema(
242     edition = "2024";
243     import "google/protobuf/cpp_features.proto";
244 
245     message Foo {
246       extensions 1 to max;
247     }
248     extend Foo {
249       bytes bar = 1 [features.(pb.cpp).string_type = CORD];
250     }
251   )schema");
252 
253   RunProtoc(
254       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir "
255       "--experimental_editions foo.proto");
256 
257   ExpectErrorSubstring(
258       "Extension bar specifies Cord type which is not supported for "
259       "extensions.");
260 }
261 
TEST_F(CppGeneratorTest,InheritedStringTypeCordNotForExtension)262 TEST_F(CppGeneratorTest, InheritedStringTypeCordNotForExtension) {
263   CreateTempFile("foo.proto", R"schema(
264     edition = "2024";
265     import "google/protobuf/cpp_features.proto";
266     option features.(pb.cpp).string_type = CORD;
267 
268     message Foo {
269       extensions 1 to max;
270     }
271     extend Foo {
272       bytes bar = 1;
273     }
274   )schema");
275 
276   RunProtoc(
277       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir "
278       "--experimental_editions foo.proto");
279 
280   ExpectNoErrors();
281 }
282 
TEST_F(CppGeneratorTest,CtypeOnNoneStringFieldTest)283 TEST_F(CppGeneratorTest, CtypeOnNoneStringFieldTest) {
284   CreateTempFile("foo.proto",
285                  R"schema(
286     edition = "2023";
287     message Foo {
288       int32 bar = 1 [ctype=STRING];
289     })schema");
290   RunProtoc(
291       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
292   ExpectErrorSubstring(
293       "Field Foo.bar specifies ctype, but is not "
294       "a string nor bytes field.");
295 }
296 
TEST_F(CppGeneratorTest,CtypeOnExtensionTest)297 TEST_F(CppGeneratorTest, CtypeOnExtensionTest) {
298   CreateTempFile("foo.proto",
299                  R"schema(
300     edition = "2023";
301     message Foo {
302       extensions 1 to max;
303     }
304     extend Foo {
305       bytes bar = 1 [ctype=CORD];
306     })schema");
307   RunProtoc(
308       "protocol_compiler --proto_path=$tmpdir --cpp_out=$tmpdir foo.proto");
309   ExpectErrorSubstring(
310       "Extension bar specifies Cord type which is "
311       "not supported for extensions.");
312 }
313 }  // namespace
314 }  // namespace cpp
315 }  // namespace compiler
316 }  // namespace protobuf
317 }  // namespace google
318