Commit 9cfb12bf authored by Joshua Haberman's avatar Joshua Haberman

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.
parent 969d245b
...@@ -1440,8 +1440,14 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, ...@@ -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, ...@@ -1475,7 +1481,6 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
} }
#undef T #undef T
} }
} }
......
...@@ -108,8 +108,12 @@ enum { ...@@ -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) { ...@@ -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, ...@@ -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); ...@@ -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, ...@@ -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,11 +1321,23 @@ module CommonTests ...@@ -1321,11 +1321,23 @@ 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
m = proto_module::Wrapper.new run_asserts = ->(m) {
m.double_as_value = 4.8 m.double_as_value = 4.8
assert_equal 4.8, m.double_as_value assert_equal 4.8, m.double_as_value
assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double
...@@ -1381,11 +1393,32 @@ module CommonTests ...@@ -1381,11 +1393,32 @@ module CommonTests
m.bytes_as_value = nil m.bytes_as_value = nil
assert_nil m.bytes assert_nil m.bytes
assert_nil m.bytes_as_value assert_nil m.bytes_as_value
end }
def test_wrapper_setters
m = proto_module::Wrapper.new m = proto_module::Wrapper.new
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)
serialized = proto_module::Wrapper::encode(m2)
m3 = proto_module::Wrapper::decode(serialized)
run_asserts.call(m3)
end
def test_wrapper_setters
run_asserts = ->(m) {
m.double = Google::Protobuf::DoubleValue.new(value: 4.8) m.double = Google::Protobuf::DoubleValue.new(value: 4.8)
assert_equal 4.8, m.double_as_value assert_equal 4.8, m.double_as_value
assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double
...@@ -1441,6 +1474,29 @@ module CommonTests ...@@ -1441,6 +1474,29 @@ module CommonTests
m.bytes = nil m.bytes = nil
assert_nil m.bytes assert_nil m.bytes
assert_nil m.bytes_as_value assert_nil m.bytes_as_value
}
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)
serialized = proto_module::Wrapper::encode(m2)
m3 = proto_module::Wrapper::decode(serialized)
run_asserts.call(m3)
end end
def test_wrappers_only def test_wrappers_only
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment