Skip to content

Commit bca8fb6

Browse files
mkruskal-googlecopybara-github
authored andcommitted
Implement edition 2023 support in all Ruby runtimes.
Three of these runtimes are based on upb, and the fourth is based on the Java runtime. Both of these already have editions support, so this was mostly just a matter of: - Advertising support to allow editions codegen - Stripping features from the runtime options - Hooking up conformance tests - Adding some lightweight editions tests There are also a few minor orthogonal fixes included here: - Ruby's upb hack for treating all enums as open enums needed tweaking - The `enable_editions` flag is no longer needed in our internal proto rules PiperOrigin-RevId: 616256211
1 parent 9ca36df commit bca8fb6

30 files changed

+388
-57
lines changed

bazel/amalgamate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def amalgamate(self, h_files, c_files):
5454
self.output_c.write('#include "%s"\n' % (self.h_out))
5555
if self.h_out == "ruby-upb.h":
5656
self.output_h.write("// Ruby is still using proto3 enum semantics for proto2\n")
57-
self.output_h.write("#define UPB_DISABLE_PROTO2_ENUM_CHECKING\n")
57+
self.output_h.write("#define UPB_DISABLE_CLOSED_ENUM_CHECKING\n")
5858

5959
self.output_h.write("/* Amalgamated source file */\n")
6060

conformance/BUILD.bazel

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ exports_files([
3636
"text_format_failure_list_python.txt",
3737
"text_format_failure_list_python_cpp.txt",
3838
"text_format_failure_list_python_upb.txt",
39-
"text_format_failure_list_ruby.txt",
40-
"text_format_failure_list_jruby.txt",
41-
"text_format_failure_list_jruby_ffi.txt",
4239
])
4340

4441
cc_proto_library(
@@ -377,6 +374,7 @@ ruby_binary(
377374
deps = [
378375
":conformance_ruby_proto",
379376
"//ruby:conformance_test_ruby_proto",
377+
"//ruby:protobuf",
380378
],
381379
)
382380

conformance/conformance_ruby.rb

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
# https://developers.google.com/open-source/licenses/bsd
99

1010
require 'conformance/conformance_pb'
11+
require 'google/protobuf'
1112
require 'google/protobuf/test_messages_proto3_pb'
1213
require 'google/protobuf/test_messages_proto2_pb'
14+
require 'google/protobuf/editions/golden/test_messages_proto2_editions_pb'
15+
require 'google/protobuf/editions/golden/test_messages_proto3_editions_pb'
1316

1417
$test_count = 0
1518
$verbose = false
@@ -20,7 +23,12 @@ def do_test(request)
2023
descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(request.message_type)
2124

2225
unless descriptor
23-
response.skipped = "Unknown message type: " + request.message_type
26+
response.runtime_error = "Unknown message type: " + request.message_type
27+
end
28+
29+
if request.test_category == :TEXT_FORMAT_TEST
30+
response.skipped = "Ruby doesn't support text format"
31+
return response
2432
end
2533

2634
begin
@@ -45,12 +53,6 @@ def do_test(request)
4553
return response
4654
end
4755

48-
when :text_payload
49-
begin
50-
response.skipped = "Ruby doesn't support text format"
51-
return response
52-
end
53-
5456
when nil
5557
fail "Request didn't have payload"
5658
end

conformance/failure_list_jruby.txt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,74 @@ Required.Proto3.JsonInput.Int32FieldPlusSign
6969
Required.Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
7070
Required.Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
7171
Required.Proto3.JsonInput.StringFieldNotAString
72+
Recommended.Editions_Proto3.FieldMaskNumbersDontRoundTrip.JsonOutput
73+
Recommended.Editions_Proto3.FieldMaskPathsDontRoundTrip.JsonOutput
74+
Recommended.Editions_Proto3.FieldMaskTooManyUnderscore.JsonOutput
75+
Recommended.Editions_Proto2.JsonInput.BoolFieldAllCapitalFalse
76+
Recommended.Editions_Proto2.JsonInput.BoolFieldAllCapitalTrue
77+
Recommended.Editions_Proto2.JsonInput.BoolFieldCamelCaseFalse
78+
Recommended.Editions_Proto2.JsonInput.BoolFieldCamelCaseTrue
79+
Recommended.Editions_Proto2.JsonInput.BoolFieldDoubleQuotedFalse
80+
Recommended.Editions_Proto2.JsonInput.BoolFieldDoubleQuotedTrue
81+
Recommended.Editions_Proto2.JsonInput.BoolMapFieldKeyNotQuoted
82+
Recommended.Editions_Proto2.JsonInput.DoubleFieldInfinityNotQuoted
83+
Recommended.Editions_Proto2.JsonInput.DoubleFieldNanNotQuoted
84+
Recommended.Editions_Proto2.JsonInput.DoubleFieldNegativeInfinityNotQuoted
85+
Recommended.Editions_Proto2.JsonInput.FieldNameDuplicate
86+
Recommended.Editions_Proto2.JsonInput.FieldNameExtension.Validator
87+
Recommended.Editions_Proto2.JsonInput.FieldNameNotQuoted
88+
Recommended.Editions_Proto2.JsonInput.FloatFieldInfinityNotQuoted
89+
Recommended.Editions_Proto2.JsonInput.FloatFieldNanNotQuoted
90+
Recommended.Editions_Proto2.JsonInput.FloatFieldNegativeInfinityNotQuoted
91+
Recommended.Editions_Proto2.JsonInput.Int32MapFieldKeyNotQuoted
92+
Recommended.Editions_Proto2.JsonInput.Int64MapFieldKeyNotQuoted
93+
Recommended.Editions_Proto2.JsonInput.JsonWithComments
94+
Recommended.Editions_Proto2.JsonInput.StringFieldSingleQuoteBoth
95+
Recommended.Editions_Proto2.JsonInput.StringFieldSingleQuoteKey
96+
Recommended.Editions_Proto2.JsonInput.StringFieldSingleQuoteValue
97+
Recommended.Editions_Proto2.JsonInput.StringFieldSurrogateInWrongOrder
98+
Recommended.Editions_Proto2.JsonInput.StringFieldUnpairedHighSurrogate
99+
Recommended.Editions_Proto2.JsonInput.StringFieldUnpairedLowSurrogate
100+
Recommended.Editions_Proto2.JsonInput.Uint32MapFieldKeyNotQuoted
101+
Recommended.Editions_Proto2.JsonInput.Uint64MapFieldKeyNotQuoted
102+
Recommended.Editions_Proto3.JsonInput.BoolFieldAllCapitalFalse
103+
Recommended.Editions_Proto3.JsonInput.BoolFieldAllCapitalTrue
104+
Recommended.Editions_Proto3.JsonInput.BoolFieldCamelCaseFalse
105+
Recommended.Editions_Proto3.JsonInput.BoolFieldCamelCaseTrue
106+
Recommended.Editions_Proto3.JsonInput.BoolFieldDoubleQuotedFalse
107+
Recommended.Editions_Proto3.JsonInput.BoolFieldDoubleQuotedTrue
108+
Recommended.Editions_Proto3.JsonInput.BoolMapFieldKeyNotQuoted
109+
Recommended.Editions_Proto3.JsonInput.DoubleFieldInfinityNotQuoted
110+
Recommended.Editions_Proto3.JsonInput.DoubleFieldNanNotQuoted
111+
Recommended.Editions_Proto3.JsonInput.DoubleFieldNegativeInfinityNotQuoted
112+
Recommended.Editions_Proto3.JsonInput.FieldMaskInvalidCharacter
113+
Recommended.Editions_Proto3.JsonInput.FieldNameDuplicate
114+
Recommended.Editions_Proto3.JsonInput.FieldNameNotQuoted
115+
Recommended.Editions_Proto3.JsonInput.FloatFieldInfinityNotQuoted
116+
Recommended.Editions_Proto3.JsonInput.FloatFieldNanNotQuoted
117+
Recommended.Editions_Proto3.JsonInput.FloatFieldNegativeInfinityNotQuoted
118+
Recommended.Editions_Proto3.JsonInput.Int32MapFieldKeyNotQuoted
119+
Recommended.Editions_Proto3.JsonInput.Int64MapFieldKeyNotQuoted
120+
Recommended.Editions_Proto3.JsonInput.JsonWithComments
121+
Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteBoth
122+
Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteKey
123+
Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteValue
124+
Recommended.Editions_Proto3.JsonInput.StringFieldSurrogateInWrongOrder
125+
Recommended.Editions_Proto3.JsonInput.StringFieldUnpairedHighSurrogate
126+
Recommended.Editions_Proto3.JsonInput.StringFieldUnpairedLowSurrogate
127+
Recommended.Editions_Proto3.JsonInput.Uint32MapFieldKeyNotQuoted
128+
Recommended.Editions_Proto3.JsonInput.Uint64MapFieldKeyNotQuoted
129+
Required.Editions_Proto2.JsonInput.EnumFieldNotQuoted
130+
Required.Editions_Proto2.JsonInput.Int32FieldLeadingZero
131+
Required.Editions_Proto2.JsonInput.Int32FieldNegativeWithLeadingZero
132+
Required.Editions_Proto2.JsonInput.Int32FieldPlusSign
133+
Required.Editions_Proto2.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
134+
Required.Editions_Proto2.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
135+
Required.Editions_Proto2.JsonInput.StringFieldNotAString
136+
Required.Editions_Proto3.JsonInput.EnumFieldNotQuoted
137+
Required.Editions_Proto3.JsonInput.Int32FieldLeadingZero
138+
Required.Editions_Proto3.JsonInput.Int32FieldNegativeWithLeadingZero
139+
Required.Editions_Proto3.JsonInput.Int32FieldPlusSign
140+
Required.Editions_Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
141+
Required.Editions_Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
142+
Required.Editions_Proto3.JsonInput.StringFieldNotAString

conformance/text_format_failure_list_jruby.txt

Lines changed: 0 additions & 8 deletions
This file was deleted.

conformance/text_format_failure_list_ruby.txt

Lines changed: 0 additions & 8 deletions
This file was deleted.

ruby/BUILD.bazel

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ internal_copy_files(
113113
srcs = [
114114
"//src/google/protobuf:test_messages_proto2.proto",
115115
"//src/google/protobuf:test_messages_proto3.proto",
116+
"//src/google/protobuf/editions:golden/test_messages_proto2_editions.proto",
117+
"//src/google/protobuf/editions:golden/test_messages_proto3_editions.proto",
116118
],
117119
strip_prefix = "src",
118120
)
@@ -232,12 +234,12 @@ filegroup(
232234
conformance_test(
233235
name = "conformance_test",
234236
failure_list = "//conformance:failure_list_ruby.txt",
237+
maximum_edition = "2023",
235238
target_compatible_with = select({
236239
":ruby_native": [],
237240
"//conditions:default": ["@platforms//:incompatible"],
238241
}),
239242
testee = "//conformance:conformance_ruby",
240-
text_format_failure_list = "//conformance:text_format_failure_list_ruby.txt",
241243
)
242244

243245
conformance_test(
@@ -246,23 +248,23 @@ conformance_test(
246248
"PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION": "ffi",
247249
},
248250
failure_list = "//conformance:failure_list_ruby.txt",
251+
maximum_edition = "2023",
249252
target_compatible_with = select({
250253
":ruby_ffi": [],
251254
"//conditions:default": ["@platforms//:incompatible"],
252255
}),
253256
testee = "//conformance:conformance_ruby",
254-
text_format_failure_list = "//conformance:text_format_failure_list_ruby.txt",
255257
)
256258

257259
conformance_test(
258260
name = "conformance_test_jruby",
259261
failure_list = "//conformance:failure_list_jruby.txt",
262+
maximum_edition = "2023",
260263
target_compatible_with = select({
261264
":jruby_native": [],
262265
"//conditions:default": ["@platforms//:incompatible"],
263266
}),
264267
testee = "//conformance:conformance_ruby",
265-
text_format_failure_list = "//conformance:text_format_failure_list_jruby.txt",
266268
)
267269

268270
conformance_test(
@@ -271,12 +273,12 @@ conformance_test(
271273
"PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION": "ffi",
272274
},
273275
failure_list = "//conformance:failure_list_jruby_ffi.txt",
276+
maximum_edition = "2023",
274277
target_compatible_with = select({
275278
":jruby_ffi": [],
276279
"//conditions:default": ["@platforms//:incompatible"],
277280
}),
278281
testee = "//conformance:conformance_ruby",
279-
text_format_failure_list = "//conformance:text_format_failure_list_jruby.txt",
280282
)
281283

282284
################################################################################

ruby/Rakefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ well_known_protos = %w[
2222

2323
test_protos = %w[
2424
tests/basic_test.proto
25+
tests/basic_test_features.proto
2526
tests/basic_test_proto2.proto
2627
tests/generated_code.proto
2728
tests/generated_code_proto2.proto
29+
tests/generated_code_editions.proto
2830
tests/multi_level_nesting_test.proto
2931
tests/repeated_field_test.proto
3032
tests/stress.proto

ruby/ext/google/protobuf_c/defs.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,20 @@ static VALUE decode_options(VALUE self, const char* option_type, int size,
257257
VALUE desc_rb = get_msgdef_obj(descriptor_pool, msgdef);
258258
const Descriptor* desc = ruby_to_Descriptor(desc_rb);
259259

260-
options_rb = Message_decode_bytes(size, bytes, 0, desc->klass, true);
260+
options_rb = Message_decode_bytes(size, bytes, 0, desc->klass, false);
261+
262+
// Strip features from the options proto to keep it internal.
263+
const upb_MessageDef* decoded_desc = NULL;
264+
upb_Message* options = Message_GetMutable(options_rb, &decoded_desc);
265+
PBRUBY_ASSERT(options != NULL);
266+
PBRUBY_ASSERT(decoded_desc == msgdef);
267+
const upb_FieldDef* field =
268+
upb_MessageDef_FindFieldByName(decoded_desc, "features");
269+
PBRUBY_ASSERT(field != NULL);
270+
upb_Message_ClearFieldByDef(options, field);
271+
272+
Message_freeze(options_rb);
273+
261274
rb_ivar_set(self, options_instancevar_interned, options_rb);
262275
return options_rb;
263276
}

ruby/lib/google/protobuf/ffi/descriptor.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ def options
100100
size_ptr = ::FFI::MemoryPointer.new(:size_t, 1)
101101
temporary_arena = Google::Protobuf::FFI.create_arena
102102
buffer = Google::Protobuf::FFI.message_options(self, size_ptr, temporary_arena)
103-
Google::Protobuf::MessageOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).freeze
103+
opts = Google::Protobuf::MessageOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze)
104+
opts.clear_features()
105+
opts.freeze
104106
end
105107
end
106108

0 commit comments

Comments
 (0)