Skip to content

Commit bb1d618

Browse files
Add test cases for Protobuf Editions (#225)
Whew! This one is a doozy. The vast majority of the work is fairly mechanical. In order to test the gauntlet of new semantics that might occur as a result of editions, a new set of test cases are created that mostly mirror the existing tests that already differ between proto2 and proto3. These test cases cover the existing tests that cover edge cases, with the possible set of field presence variants (implicit, explicit, and legacy-required; note that not all of these are valid in all cases) and with both default and expanded repeated field representation. Most of these changes are transparent or invisible even at the `protoreflect` level and mostly just ensure that protovalidate implementations are not tripping up over the wire format or resulting descriptors. One wrinkle is that getting a new enough version of the protobuf toolchain in Bazel for protobuf editions support is tricky; with upstream rules_proto, the latest toolchain you get does not support editions at all. I ran into a couple of very tricky issues getting a newer toolchain to work, but thankfully the resulting changes to work around those issues are relatively simple: - It seems like the `rules_python` repo needs to be defined for protobuf v27+, but the `protobuf_deps` function does not define it. We must define it ourselves. - For unknown reasons, it is necessary to specify both `--proto_compiler` and `--proto_toolchain_for_cc` (and presumably other `--proto_toolchain_for_*` options). The values specified were actually supposedly the default values for these options, so it is unclear why they need to be specified. I suspect this has something to do with refactoring of Bazel's protobuf rules but didn't want to spend more time investigating, as it took a fair bit of time to figure out that it worked in the first place.
1 parent 4f56342 commit bb1d618

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+9829
-649
lines changed

.bazelrc

+3-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
build --experimental_proto_descriptor_sets_include_source_info
1+
build --experimental_proto_descriptor_sets_include_source_info
2+
build --proto_compiler=@com_google_protobuf//:protoc
3+
build --proto_toolchain_for_cc=@com_google_protobuf//:cc_toolchain

WORKSPACE

+22-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@ workspace(name = "com_github_bufbuild_protovalidate")
22

33
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
44

5+
# This is needed due to an unresolved issue with protobuf v27+.
6+
# https://github.com/protocolbuffers/protobuf/issues/17200
7+
http_archive(
8+
name = "rules_python",
9+
sha256 = "0a8003b044294d7840ac7d9d73eef05d6ceb682d7516781a4ec62eeb34702578",
10+
strip_prefix = "rules_python-0.24.0",
11+
url = "https://github.com/bazelbuild/rules_python/releases/download/0.24.0/rules_python-0.24.0.tar.gz",
12+
)
13+
14+
# Use a newer protobuf toolchain for editions support.
15+
http_archive(
16+
name = "com_google_protobuf",
17+
sha256 = "e4ff2aeb767da6f4f52485c2e72468960ddfe5262483879ef6ad552e52757a77",
18+
strip_prefix = "protobuf-27.2",
19+
urls = ["https://github.com/protocolbuffers/protobuf/archive/v27.2.tar.gz"],
20+
)
21+
22+
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
23+
24+
protobuf_deps()
25+
526
http_archive(
627
name = "rules_buf",
728
sha256 = "523a4e06f0746661e092d083757263a249fedca535bd6dd819a8c50de074731a",
@@ -54,4 +75,4 @@ gazelle_dependencies()
5475

5576
load("@rules_buf//gazelle/buf:repositories.bzl", "gazelle_buf_dependencies")
5677

57-
gazelle_buf_dependencies()
78+
gazelle_buf_dependencies()

buf.gen.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ managed:
66
except:
77
- buf.build/envoyproxy/protoc-gen-validate
88
plugins:
9-
- plugin: buf.build/protocolbuffers/go:v1.31.0
9+
- plugin: buf.build/protocolbuffers/go:v1.34.2
1010
out: tools/internal/gen
1111
opt: paths=source_relative

proto/protovalidate-testing/buf/validate/conformance/cases/BUILD.bazel

+3
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ proto_library(
2424
"filename-with-dash.proto",
2525
"ignore_empty_proto2.proto",
2626
"ignore_empty_proto3.proto",
27+
"ignore_empty_proto_editions.proto",
2728
"ignore_proto2.proto",
2829
"ignore_proto3.proto",
30+
"ignore_proto_editions.proto",
2931
"kitchen_sink.proto",
3032
"maps.proto",
3133
"messages.proto",
@@ -34,6 +36,7 @@ proto_library(
3436
"repeated.proto",
3537
"required_field_proto2.proto",
3638
"required_field_proto3.proto",
39+
"required_field_proto_editions.proto",
3740
"strings.proto",
3841
"wkt_any.proto",
3942
"wkt_duration.proto",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright 2023 Buf Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
edition = "2023";
16+
17+
package buf.validate.conformance.cases;
18+
19+
import "buf/validate/validate.proto";
20+
21+
message IgnoreEmptyEditionsScalarExplicitPresence {
22+
int32 val = 1 [
23+
(buf.validate.field).ignore_empty = true,
24+
(buf.validate.field).int32.gt = 0
25+
];
26+
}
27+
28+
message IgnoreEmptyEditionsScalarExplicitPresenceWithDefault {
29+
int32 val = 1 [
30+
(buf.validate.field).ignore_empty = true,
31+
(buf.validate.field).int32.gt = 0,
32+
default = 42
33+
];
34+
}
35+
36+
message IgnoreEmptyEditionsScalarImplicitPresence {
37+
int32 val = 1 [
38+
features.field_presence = IMPLICIT,
39+
(buf.validate.field).ignore_empty = true,
40+
(buf.validate.field).int32.gt = 0
41+
];
42+
}
43+
44+
message IgnoreEmptyEditionsScalarLegacyRequired {
45+
int32 val = 1 [
46+
features.field_presence = LEGACY_REQUIRED,
47+
(buf.validate.field).ignore_empty = true,
48+
(buf.validate.field).int32.gt = 0
49+
];
50+
}
51+
52+
message IgnoreEmptyEditionsScalarLegacyRequiredWithDefault {
53+
int32 val = 1 [
54+
features.field_presence = LEGACY_REQUIRED,
55+
(buf.validate.field).ignore_empty = true,
56+
(buf.validate.field).int32.gt = 0,
57+
default = 42
58+
];
59+
}
60+
61+
message IgnoreEmptyEditionsMessageExplicitPresence {
62+
Msg val = 1 [
63+
(buf.validate.field).ignore_empty = true,
64+
(buf.validate.field).cel = {
65+
id: "ignore_empty.editions.message"
66+
message: "foobar"
67+
expression: "this.val == 'foo'"
68+
}
69+
];
70+
message Msg {
71+
string val = 1;
72+
}
73+
}
74+
75+
message IgnoreEmptyEditionsMessageExplicitPresenceDelimited {
76+
Msg val = 1 [
77+
features.message_encoding = DELIMITED,
78+
(buf.validate.field).ignore_empty = true,
79+
(buf.validate.field).cel = {
80+
id: "ignore_empty.editions.message"
81+
message: "foobar"
82+
expression: "this.val == 'foo'"
83+
}
84+
];
85+
message Msg {
86+
string val = 1;
87+
}
88+
}
89+
90+
message IgnoreEmptyEditionsMessageLegacyRequired {
91+
Msg val = 1 [
92+
features.field_presence = LEGACY_REQUIRED,
93+
(buf.validate.field).ignore_empty = true,
94+
(buf.validate.field).cel = {
95+
id: "ignore_empty.editions.message"
96+
message: "foobar"
97+
expression: "this.val == 'foo'"
98+
}
99+
];
100+
message Msg {
101+
string val = 1;
102+
}
103+
}
104+
105+
message IgnoreEmptyEditionsMessageLegacyRequiredDelimited {
106+
Msg val = 1 [
107+
features.message_encoding = DELIMITED,
108+
features.field_presence = LEGACY_REQUIRED,
109+
(buf.validate.field).ignore_empty = true,
110+
(buf.validate.field).cel = {
111+
id: "ignore_empty.editions.message"
112+
message: "foobar"
113+
expression: "this.val == 'foo'"
114+
}
115+
];
116+
message Msg {
117+
string val = 1;
118+
}
119+
}
120+
121+
message IgnoreEmptyEditionsOneof {
122+
oneof o {
123+
int32 val = 1 [
124+
(buf.validate.field).ignore_empty = true,
125+
(buf.validate.field).int32.gt = 0
126+
];
127+
}
128+
}
129+
130+
message IgnoreEmptyEditionsRepeated {
131+
repeated int32 val = 1 [
132+
(buf.validate.field).ignore_empty = true,
133+
(buf.validate.field).repeated.min_items = 3
134+
];
135+
}
136+
137+
message IgnoreEmptyEditionsRepeatedExpanded {
138+
repeated int32 val = 1 [
139+
features.repeated_field_encoding = EXPANDED,
140+
(buf.validate.field).ignore_empty = true,
141+
(buf.validate.field).repeated.min_items = 3
142+
];
143+
}
144+
145+
message IgnoreEmptyEditionsMap {
146+
map<int32, int32> val = 1 [
147+
(buf.validate.field).ignore_empty = true,
148+
(buf.validate.field).map.min_pairs = 3
149+
];
150+
}

0 commit comments

Comments
 (0)