Tests pass for all common operations.

A few things that don't work or aren't tested yet:
- wrappers at the top level
- equality checking for not-yet-expanded wrappers.
pull/6797/head
Joshua Haberman 5 years ago
parent 969d245bd3
commit 9cfb12bf0a
  1. 11
      ruby/ext/google/protobuf_c/encode_decode.c
  2. 13
      ruby/ext/google/protobuf_c/message.c
  3. 4
      ruby/ext/google/protobuf_c/protobuf.h
  4. 11
      ruby/ext/google/protobuf_c/storage.c
  5. 276
      ruby/tests/common_tests.rb

@ -1440,8 +1440,14 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
putstr(str, f, sink); putstr(str, f, sink);
} }
} else if (upb_fielddef_issubmsg(f)) { } else if (upb_fielddef_issubmsg(f)) {
putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth, VALUE val = DEREF(msg, offset, VALUE);
emit_defaults, is_json); int type = TYPE(val);
if (type != T_DATA && type != T_NIL && is_wrapper_type_field(f)) {
// OPT: could try to avoid expanding the wrapper here.
val = ruby_wrapper_type(desc->layout, f, val);
DEREF(msg, offset, VALUE) = val;
}
putsubmsg(val, f, sink, depth, emit_defaults, is_json);
} else { } else {
upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
@ -1475,7 +1481,6 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
} }
#undef T #undef T
} }
} }

@ -108,8 +108,12 @@ enum {
}; };
// Check if the field is a well known wrapper type // Check if the field is a well known wrapper type
static bool is_wrapper_type_field(const upb_fielddef* field) { bool is_wrapper_type_field(const upb_fielddef* field) {
const upb_msgdef *m = upb_fielddef_msgsubdef(field); const upb_msgdef *m;
if (upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
return false;
}
m = upb_fielddef_msgsubdef(field);
switch (upb_msgdef_wellknowntype(m)) { switch (upb_msgdef_wellknowntype(m)) {
case UPB_WELLKNOWN_DOUBLEVALUE: case UPB_WELLKNOWN_DOUBLEVALUE:
case UPB_WELLKNOWN_FLOATVALUE: case UPB_WELLKNOWN_FLOATVALUE:
@ -127,8 +131,8 @@ static bool is_wrapper_type_field(const upb_fielddef* field) {
} }
// Get a new Ruby wrapper type and set the initial value // Get a new Ruby wrapper type and set the initial value
static VALUE ruby_wrapper_type(const MessageLayout* layout, VALUE ruby_wrapper_type(const MessageLayout* layout, const upb_fielddef* field,
const upb_fielddef* field, const VALUE value) { const VALUE value) {
if (is_wrapper_type_field(field) && value != Qnil) { if (is_wrapper_type_field(field) && value != Qnil) {
VALUE hash = rb_hash_new(); VALUE hash = rb_hash_new();
rb_hash_aset(hash, rb_str_new2("value"), value); rb_hash_aset(hash, rb_str_new2("value"), value);
@ -195,7 +199,6 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
// Check if field exists and is a wrapper type // Check if field exists and is a wrapper type
if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name, if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name,
name_len - 9, &test_f_wrapper, &test_o_wrapper) && name_len - 9, &test_f_wrapper, &test_o_wrapper) &&
upb_fielddef_type(test_f_wrapper) == UPB_TYPE_MESSAGE &&
is_wrapper_type_field(test_f_wrapper)) { is_wrapper_type_field(test_f_wrapper)) {
// It does exist! // It does exist!
has_field = true; has_field = true;

@ -556,6 +556,10 @@ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2);
VALUE layout_hash(MessageLayout* layout, void* storage); VALUE layout_hash(MessageLayout* layout, void* storage);
VALUE layout_inspect(MessageLayout* layout, void* storage); VALUE layout_inspect(MessageLayout* layout, void* storage);
bool is_wrapper_type_field(const upb_fielddef* field);
VALUE ruby_wrapper_type(const MessageLayout* layout, const upb_fielddef* field,
const VALUE value);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Message class creation. // Message class creation.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

@ -843,8 +843,15 @@ VALUE layout_get(MessageLayout* layout,
} else if (!field_set) { } else if (!field_set) {
return layout_get_default(field); return layout_get_default(field);
} else { } else {
return native_slot_get(upb_fielddef_type(field), VALUE type_class = field_type_class(layout, field);
field_type_class(layout, field), memory); VALUE val = native_slot_get(upb_fielddef_type(field), type_class, memory);
int type = TYPE(val);
if (type != T_DATA && type != T_NIL && is_wrapper_type_field(field)) {
val = ruby_wrapper_type(layout, field, val);
native_slot_set(upb_fielddef_name(field), upb_fielddef_type(field),
type_class, memory, val);
}
return val;
} }
} }

@ -1321,126 +1321,182 @@ module CommonTests
serialized = proto_module::Wrapper::encode(m) serialized = proto_module::Wrapper::encode(m)
m2 = proto_module::Wrapper::decode(serialized) m2 = proto_module::Wrapper::decode(serialized)
run_asserts.call(m2) run_asserts.call(m2)
# Test the case where we are serializing directly from the parsed form
# (before anything lazy is materialized).
m3 = proto_module::Wrapper::decode(serialized)
serialized2 = proto_module::Wrapper::encode(m3)
m4 = proto_module::Wrapper::decode(serialized2)
run_asserts.call(m4)
# Test that the lazy form compares equal to the expanded form.
m5 = proto_module::Wrapper::decode(serialized2)
# This doesn't work yet.
# assert_equal m5, m
end end
def test_wrapper_setters_as_value def test_wrapper_setters_as_value
run_asserts = ->(m) {
m.double_as_value = 4.8
assert_equal 4.8, m.double_as_value
assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double
m.float_as_value = 2.4
assert_in_delta 2.4, m.float_as_value
assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value
m.int32_as_value = 5
assert_equal 5, m.int32_as_value
assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32
m.int64_as_value = 15
assert_equal 15, m.int64_as_value
assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64
m.uint32_as_value = 50
assert_equal 50, m.uint32_as_value
assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32
m.uint64_as_value = 500
assert_equal 500, m.uint64_as_value
assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64
m.bool_as_value = false
assert_equal false, m.bool_as_value
assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool
m.string_as_value = 'xy'
assert_equal 'xy', m.string_as_value
assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string
m.bytes_as_value = '123'
assert_equal '123', m.bytes_as_value
assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes
m.double_as_value = nil
assert_nil m.double
assert_nil m.double_as_value
m.float_as_value = nil
assert_nil m.float
assert_nil m.float_as_value
m.int32_as_value = nil
assert_nil m.int32
assert_nil m.int32_as_value
m.int64_as_value = nil
assert_nil m.int64
assert_nil m.int64_as_value
m.uint32_as_value = nil
assert_nil m.uint32
assert_nil m.uint32_as_value
m.uint64_as_value = nil
assert_nil m.uint64
assert_nil m.uint64_as_value
m.bool_as_value = nil
assert_nil m.bool
assert_nil m.bool_as_value
m.string_as_value = nil
assert_nil m.string
assert_nil m.string_as_value
m.bytes_as_value = nil
assert_nil m.bytes
assert_nil m.bytes_as_value
}
m = proto_module::Wrapper.new m = proto_module::Wrapper.new
m.double_as_value = 4.8 m2 = proto_module::Wrapper.new(
assert_equal 4.8, m.double_as_value double: Google::Protobuf::DoubleValue.new(value: 2.0),
assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double float: Google::Protobuf::FloatValue.new(value: 4.0),
m.float_as_value = 2.4 int32: Google::Protobuf::Int32Value.new(value: 3),
assert_in_delta 2.4, m.float_as_value int64: Google::Protobuf::Int64Value.new(value: 4),
assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value uint32: Google::Protobuf::UInt32Value.new(value: 5),
m.int32_as_value = 5 uint64: Google::Protobuf::UInt64Value.new(value: 6),
assert_equal 5, m.int32_as_value bool: Google::Protobuf::BoolValue.new(value: true),
assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32 string: Google::Protobuf::StringValue.new(value: 'str'),
m.int64_as_value = 15 bytes: Google::Protobuf::BytesValue.new(value: 'fun'),
assert_equal 15, m.int64_as_value real_string: '100'
assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64 )
m.uint32_as_value = 50
assert_equal 50, m.uint32_as_value run_asserts.call(m2)
assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32
m.uint64_as_value = 500 serialized = proto_module::Wrapper::encode(m2)
assert_equal 500, m.uint64_as_value m3 = proto_module::Wrapper::decode(serialized)
assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64 run_asserts.call(m3)
m.bool_as_value = false
assert_equal false, m.bool_as_value
assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool
m.string_as_value = 'xy'
assert_equal 'xy', m.string_as_value
assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string
m.bytes_as_value = '123'
assert_equal '123', m.bytes_as_value
assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes
m.double_as_value = nil
assert_nil m.double
assert_nil m.double_as_value
m.float_as_value = nil
assert_nil m.float
assert_nil m.float_as_value
m.int32_as_value = nil
assert_nil m.int32
assert_nil m.int32_as_value
m.int64_as_value = nil
assert_nil m.int64
assert_nil m.int64_as_value
m.uint32_as_value = nil
assert_nil m.uint32
assert_nil m.uint32_as_value
m.uint64_as_value = nil
assert_nil m.uint64
assert_nil m.uint64_as_value
m.bool_as_value = nil
assert_nil m.bool
assert_nil m.bool_as_value
m.string_as_value = nil
assert_nil m.string
assert_nil m.string_as_value
m.bytes_as_value = nil
assert_nil m.bytes
assert_nil m.bytes_as_value
end end
def test_wrapper_setters def test_wrapper_setters
run_asserts = ->(m) {
m.double = Google::Protobuf::DoubleValue.new(value: 4.8)
assert_equal 4.8, m.double_as_value
assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double
m.float = Google::Protobuf::FloatValue.new(value: 2.4)
assert_in_delta 2.4, m.float_as_value
assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value
m.int32 = Google::Protobuf::Int32Value.new(value: 5)
assert_equal 5, m.int32_as_value
assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32
m.int64 = Google::Protobuf::Int64Value.new(value: 15)
assert_equal 15, m.int64_as_value
assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64
m.uint32 = Google::Protobuf::UInt32Value.new(value: 50)
assert_equal 50, m.uint32_as_value
assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32
m.uint64 = Google::Protobuf::UInt64Value.new(value: 500)
assert_equal 500, m.uint64_as_value
assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64
m.bool = Google::Protobuf::BoolValue.new(value: false)
assert_equal false, m.bool_as_value
assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool
m.string = Google::Protobuf::StringValue.new(value: 'xy')
assert_equal 'xy', m.string_as_value
assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string
m.bytes = Google::Protobuf::BytesValue.new(value: '123')
assert_equal '123', m.bytes_as_value
assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes
m.double = nil
assert_nil m.double
assert_nil m.double_as_value
m.float = nil
assert_nil m.float
assert_nil m.float_as_value
m.int32 = nil
assert_nil m.int32
assert_nil m.int32_as_value
m.int64 = nil
assert_nil m.int64
assert_nil m.int64_as_value
m.uint32 = nil
assert_nil m.uint32
assert_nil m.uint32_as_value
m.uint64 = nil
assert_nil m.uint64
assert_nil m.uint64_as_value
m.bool = nil
assert_nil m.bool
assert_nil m.bool_as_value
m.string = nil
assert_nil m.string
assert_nil m.string_as_value
m.bytes = nil
assert_nil m.bytes
assert_nil m.bytes_as_value
}
m = proto_module::Wrapper.new m = proto_module::Wrapper.new
run_asserts.call(m)
m2 = proto_module::Wrapper.new(
double: Google::Protobuf::DoubleValue.new(value: 2.0),
float: Google::Protobuf::FloatValue.new(value: 4.0),
int32: Google::Protobuf::Int32Value.new(value: 3),
int64: Google::Protobuf::Int64Value.new(value: 4),
uint32: Google::Protobuf::UInt32Value.new(value: 5),
uint64: Google::Protobuf::UInt64Value.new(value: 6),
bool: Google::Protobuf::BoolValue.new(value: true),
string: Google::Protobuf::StringValue.new(value: 'str'),
bytes: Google::Protobuf::BytesValue.new(value: 'fun'),
real_string: '100'
)
run_asserts.call(m2)
m.double = Google::Protobuf::DoubleValue.new(value: 4.8) serialized = proto_module::Wrapper::encode(m2)
assert_equal 4.8, m.double_as_value m3 = proto_module::Wrapper::decode(serialized)
assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double run_asserts.call(m3)
m.float = Google::Protobuf::FloatValue.new(value: 2.4)
assert_in_delta 2.4, m.float_as_value
assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value
m.int32 = Google::Protobuf::Int32Value.new(value: 5)
assert_equal 5, m.int32_as_value
assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32
m.int64 = Google::Protobuf::Int64Value.new(value: 15)
assert_equal 15, m.int64_as_value
assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64
m.uint32 = Google::Protobuf::UInt32Value.new(value: 50)
assert_equal 50, m.uint32_as_value
assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32
m.uint64 = Google::Protobuf::UInt64Value.new(value: 500)
assert_equal 500, m.uint64_as_value
assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64
m.bool = Google::Protobuf::BoolValue.new(value: false)
assert_equal false, m.bool_as_value
assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool
m.string = Google::Protobuf::StringValue.new(value: 'xy')
assert_equal 'xy', m.string_as_value
assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string
m.bytes = Google::Protobuf::BytesValue.new(value: '123')
assert_equal '123', m.bytes_as_value
assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes
m.double = nil
assert_nil m.double
assert_nil m.double_as_value
m.float = nil
assert_nil m.float
assert_nil m.float_as_value
m.int32 = nil
assert_nil m.int32
assert_nil m.int32_as_value
m.int64 = nil
assert_nil m.int64
assert_nil m.int64_as_value
m.uint32 = nil
assert_nil m.uint32
assert_nil m.uint32_as_value
m.uint64 = nil
assert_nil m.uint64
assert_nil m.uint64_as_value
m.bool = nil
assert_nil m.bool
assert_nil m.bool_as_value
m.string = nil
assert_nil m.string
assert_nil m.string_as_value
m.bytes = nil
assert_nil m.bytes
assert_nil m.bytes_as_value
end end
def test_wrappers_only def test_wrappers_only

Loading…
Cancel
Save