aboutsummaryrefslogtreecommitdiffhomepage
path: root/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'ruby')
-rw-r--r--ruby/compatibility_tests/v3.0.0/tests/basic.rb159
-rw-r--r--ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb2
-rw-r--r--ruby/ext/google/protobuf_c/defs.c10
-rw-r--r--ruby/ext/google/protobuf_c/encode_decode.c4
-rw-r--r--ruby/ext/google/protobuf_c/message.c6
-rw-r--r--ruby/ext/google/protobuf_c/protobuf.c2
-rw-r--r--ruby/ext/google/protobuf_c/protobuf.h1
-rw-r--r--ruby/ext/google/protobuf_c/storage.c38
-rw-r--r--ruby/lib/google/protobuf.rb1
-rw-r--r--ruby/lib/google/protobuf/well_known_types.rb12
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java2
-rw-r--r--ruby/tests/basic.rb64
-rw-r--r--ruby/tests/repeated_field_test.rb2
-rw-r--r--ruby/tests/well_known_types_test.rb14
14 files changed, 235 insertions, 82 deletions
diff --git a/ruby/compatibility_tests/v3.0.0/tests/basic.rb b/ruby/compatibility_tests/v3.0.0/tests/basic.rb
index 05fe0278..e2559036 100644
--- a/ruby/compatibility_tests/v3.0.0/tests/basic.rb
+++ b/ruby/compatibility_tests/v3.0.0/tests/basic.rb
@@ -222,33 +222,55 @@ module BasicTest
def test_type_errors
m = TestMessage.new
- assert_raise TypeError do
+
+ # Use rescue to allow subclasses of error
+ success = false
+ begin
m.optional_int32 = "hello"
+ rescue TypeError
+ success = true
end
- assert_raise TypeError do
- m.optional_string = 42
- end
- assert_raise TypeError do
+ assert(success)
+
+ success = false
+ begin
m.optional_string = nil
+ rescue TypeError
+ success = true
end
- assert_raise TypeError do
+ assert(success)
+
+ success = false
+ begin
m.optional_bool = 42
+ rescue TypeError
+ success = true
end
- assert_raise TypeError do
+ assert(success)
+
+ success = false
+ begin
m.optional_msg = TestMessage.new # expects TestMessage2
+ rescue TypeError
+ success = true
end
+ assert(success)
- assert_raise TypeError do
+ success = false
+ begin
m.repeated_int32 = [] # needs RepeatedField
+ rescue TypeError
+ success = true
end
+ assert(success)
- assert_raise TypeError do
- m.repeated_int32.push "hello"
- end
-
- assert_raise TypeError do
+ success = false
+ begin
m.repeated_msg.push TestMessage.new
+ rescue TypeError
+ success = true
end
+ assert(success)
end
def test_string_encoding
@@ -275,7 +297,7 @@ module BasicTest
# strings are immutable so we can't do this, but serialize should catch it.
m.optional_string = "asdf".encode!('UTF-8')
- assert_raise RuntimeError do
+ assert_raise do
m.optional_string.encode!('ASCII-8BIT')
end
end
@@ -312,10 +334,14 @@ module BasicTest
assert l.pop == 9
assert l == [5, 2, 3, 4, 7, 8]
- assert_raise TypeError do
+ success = false
+ begin
m = TestMessage.new
l.push m
+ rescue TypeError
+ success = true
end
+ assert(success)
m = TestMessage.new
m.repeated_int32 = l
@@ -362,12 +388,22 @@ module BasicTest
l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
l.push TestMessage.new
assert l.count == 1
- assert_raise TypeError do
+
+ success = false
+ begin
l.push TestMessage2.new
+ rescue TypeError
+ success = true
end
- assert_raise TypeError do
+ assert(success)
+
+ success = false
+ begin
l.push 42
+ rescue TypeError
+ success = true
end
+ assert(success)
l2 = l.dup
assert l2[0] == l[0]
@@ -493,9 +529,14 @@ module BasicTest
assert m.length == 0
assert m == {}
- assert_raise TypeError do
+ success = false
+ begin
m[1] = 1
+ rescue TypeError
+ success = true
end
+ assert(success)
+
assert_raise RangeError do
m["asdf"] = 0x1_0000_0000
end
@@ -514,18 +555,28 @@ module BasicTest
assert_raise RangeError do
m[0x8000_0000] = 1
end
- assert_raise TypeError do
+
+ success = false
+ begin
m["asdf"] = 1
+ rescue TypeError
+ success = true
end
+ assert(success)
m = Google::Protobuf::Map.new(:int64, :int32)
m[0x1000_0000_0000_0000] = 1
assert_raise RangeError do
m[0x1_0000_0000_0000_0000] = 1
end
- assert_raise TypeError do
+
+ success = false
+ begin
m["asdf"] = 1
+ rescue TypeError
+ success = true
end
+ assert(success)
m = Google::Protobuf::Map.new(:uint32, :int32)
m[0x8000_0000] = 1
@@ -548,18 +599,32 @@ module BasicTest
m = Google::Protobuf::Map.new(:bool, :int32)
m[true] = 1
m[false] = 2
- assert_raise TypeError do
+
+ success = false
+ begin
m[1] = 1
+ rescue TypeError
+ success = true
end
- assert_raise TypeError do
+ assert(success)
+
+ success = false
+ begin
m["asdf"] = 1
+ rescue TypeError
+ success = true
end
+ assert(success)
m = Google::Protobuf::Map.new(:string, :int32)
m["asdf"] = 1
- assert_raise TypeError do
+ success = false
+ begin
m[1] = 1
+ rescue TypeError
+ success = true
end
+ assert(success)
assert_raise Encoding::UndefinedConversionError do
bytestring = ["FFFF"].pack("H*")
m[bytestring] = 1
@@ -570,17 +635,25 @@ module BasicTest
m[bytestring] = 1
# Allowed -- we will automatically convert to ASCII-8BIT.
m["asdf"] = 1
- assert_raise TypeError do
+ success = false
+ begin
m[1] = 1
+ rescue TypeError
+ success = true
end
+ assert(success)
end
def test_map_msg_enum_valuetypes
m = Google::Protobuf::Map.new(:string, :message, TestMessage)
m["asdf"] = TestMessage.new
- assert_raise TypeError do
+ success = false
+ begin
m["jkl;"] = TestMessage2.new
+ rescue TypeError
+ success = true
end
+ assert(success)
m = Google::Protobuf::Map.new(
:string, :message, TestMessage,
@@ -645,23 +718,39 @@ module BasicTest
m.map_string_msg.delete("c")
assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
- assert_raise TypeError do
+ success = false
+ begin
m.map_string_msg["e"] = TestMessage.new # wrong value type
+ rescue TypeError
+ success = true
end
+ assert(success)
# ensure nothing was added by the above
assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
- assert_raise TypeError do
+ success = false
+ begin
m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
+ rescue TypeError
+ success = true
end
- assert_raise TypeError do
+ assert(success)
+ success = false
+ begin
m.map_string_int32 = {}
+ rescue TypeError
+ success = true
end
+ assert(success)
- assert_raise TypeError do
+ success = false
+ begin
m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
+ rescue TypeError
+ success = true
end
+ assert(success)
end
def test_map_encode_decode
@@ -922,22 +1011,30 @@ module BasicTest
def test_def_errors
s = Google::Protobuf::DescriptorPool.new
- assert_raise TypeError do
+ success = false
+ begin
s.build do
# enum with no default (integer value 0)
add_enum "MyEnum" do
value :A, 1
end
end
+ rescue TypeError
+ success = true
end
- assert_raise TypeError do
+ assert(success)
+ success = false
+ begin
s.build do
# message with required field (unsupported in proto3)
add_message "MyMessage" do
required :foo, :int32, 1
end
end
+ rescue TypeError
+ success = true
end
+ assert(success)
end
def test_corecursive
diff --git a/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb b/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb
index 25727b7b..201fe36b 100644
--- a/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb
+++ b/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb
@@ -18,7 +18,7 @@ class RepeatedFieldTest < Test::Unit::TestCase
# jRuby additions to the Array class that we can ignore
arr_methods -= [ :indices, :iter_for_each, :iter_for_each_index,
:iter_for_each_with_index, :dimensions, :copy_data, :copy_data_simple,
- :nitems, :iter_for_reverse_each, :indexes]
+ :nitems, :iter_for_reverse_each, :indexes, :append, :prepend]
arr_methods.each do |method_name|
assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
end
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
index d9d2ebac..9fe04503 100644
--- a/ruby/ext/google/protobuf_c/defs.c
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -812,7 +812,7 @@ VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value) {
upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
const char* str = get_str(value);
if (!upb_fielddef_hassubdef(self->fielddef)) {
- rb_raise(rb_eTypeError, "FieldDescriptor does not have subdef.");
+ rb_raise(cTypeError, "FieldDescriptor does not have subdef.");
}
CHECK_UPB(upb_fielddef_setsubdefname(mut_def, str, &status),
"Error setting submessage name");
@@ -854,7 +854,7 @@ VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
MessageHeader* msg;
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
- rb_raise(rb_eTypeError, "get method called on wrong message type");
+ rb_raise(cTypeError, "get method called on wrong message type");
}
return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
}
@@ -872,7 +872,7 @@ VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
MessageHeader* msg;
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
- rb_raise(rb_eTypeError, "set method called on wrong message type");
+ rb_raise(cTypeError, "set method called on wrong message type");
}
layout_set(msg->descriptor->layout, Message_data(msg), self->fielddef, value);
return Qnil;
@@ -1713,7 +1713,7 @@ static void validate_msgdef(const upb_msgdef* msgdef) {
upb_msg_field_next(&it)) {
const upb_fielddef* field = upb_msg_iter_field(&it);
if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
- rb_raise(rb_eTypeError, "Required fields are unsupported in proto3.");
+ rb_raise(cTypeError, "Required fields are unsupported in proto3.");
}
}
}
@@ -1723,7 +1723,7 @@ static void validate_enumdef(const upb_enumdef* enumdef) {
// value.)
const char* lookup = upb_enumdef_iton(enumdef, 0);
if (lookup == NULL) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Enum definition does not contain a value for '0'.");
}
}
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
index 12080d03..8c6ded64 100644
--- a/ruby/ext/google/protobuf_c/encode_decode.c
+++ b/ruby/ext/google/protobuf_c/encode_decode.c
@@ -963,13 +963,15 @@ static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
if (ary == Qnil) return;
+ size = NUM2INT(RepeatedField_length(ary));
+ if (size == 0 && !emit_defaults) return;
+
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
if (upb_fielddef_isprimitive(f)) {
sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
}
- size = NUM2INT(RepeatedField_length(ary));
for (int i = 0; i < size; i++) {
void* memory = RepeatedField_index_native(ary, i);
switch (type) {
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index 63a61baf..721c1112 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -256,6 +256,10 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
"Unknown field name '%s' in initialization map entry.", name);
}
+ if (TYPE(val) == T_NIL) {
+ return 0;
+ }
+
if (is_map_field(f)) {
VALUE map;
@@ -631,7 +635,7 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
const char* name = upb_enum_iter_name(&it);
int32_t value = upb_enum_iter_number(&it);
if (name[0] < 'A' || name[0] > 'Z') {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Enum value '%s' does not start with an uppercase letter "
"as is required for Ruby constants.",
name);
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
index db696426..fe6bb406 100644
--- a/ruby/ext/google/protobuf_c/protobuf.c
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -41,6 +41,7 @@ VALUE upb_def_to_ruby_obj_map;
VALUE cError;
VALUE cParseError;
+VALUE cTypeError;
void add_def_obj(const void* def, VALUE value) {
rb_hash_aset(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def), value);
@@ -102,6 +103,7 @@ void Init_protobuf_c() {
cError = rb_const_get(protobuf, rb_intern("Error"));
cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
+ cTypeError = rb_const_get(protobuf, rb_intern("TypeError"));
rb_define_singleton_method(protobuf, "discard_unknown",
Google_Protobuf_discard_unknown, 1);
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
index 5266aa8d..3e5c0520 100644
--- a/ruby/ext/google/protobuf_c/protobuf.h
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -161,6 +161,7 @@ extern VALUE cBuilder;
extern VALUE cError;
extern VALUE cParseError;
+extern VALUE cTypeError;
// We forward-declare all of the Ruby method implementations here because we
// sometimes call the methods directly across .c files, rather than going
diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c
index 1437c0b5..163b2f81 100644
--- a/ruby/ext/google/protobuf_c/storage.c
+++ b/ruby/ext/google/protobuf_c/storage.c
@@ -96,7 +96,7 @@ static bool is_ruby_num(VALUE value) {
void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
if (!is_ruby_num(val)) {
- rb_raise(rb_eTypeError, "Expected number type for integral field.");
+ rb_raise(cTypeError, "Expected number type for integral field.");
}
// NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
@@ -153,13 +153,13 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
switch (type) {
case UPB_TYPE_FLOAT:
if (!is_ruby_num(value)) {
- rb_raise(rb_eTypeError, "Expected number type for float field.");
+ rb_raise(cTypeError, "Expected number type for float field.");
}
DEREF(memory, float) = NUM2DBL(value);
break;
case UPB_TYPE_DOUBLE:
if (!is_ruby_num(value)) {
- rb_raise(rb_eTypeError, "Expected number type for double field.");
+ rb_raise(cTypeError, "Expected number type for double field.");
}
DEREF(memory, double) = NUM2DBL(value);
break;
@@ -170,16 +170,16 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
} else if (value == Qfalse) {
val = 0;
} else {
- rb_raise(rb_eTypeError, "Invalid argument for boolean field.");
+ rb_raise(cTypeError, "Invalid argument for boolean field.");
}
DEREF(memory, int8_t) = val;
break;
}
case UPB_TYPE_STRING:
if (CLASS_OF(value) == rb_cSymbol) {
- value = rb_funcall(value, rb_intern("to_s"), 0, NULL);
+ value = rb_funcall(value, rb_intern("to_s"), 0);
} else if (CLASS_OF(value) != rb_cString) {
- rb_raise(rb_eTypeError, "Invalid argument for string field.");
+ rb_raise(cTypeError, "Invalid argument for string field.");
}
DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
@@ -187,7 +187,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
case UPB_TYPE_BYTES: {
if (CLASS_OF(value) != rb_cString) {
- rb_raise(rb_eTypeError, "Invalid argument for string field.");
+ rb_raise(cTypeError, "Invalid argument for string field.");
}
DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
@@ -197,7 +197,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
if (CLASS_OF(value) == CLASS_OF(Qnil)) {
value = Qnil;
} else if (CLASS_OF(value) != type_class) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Invalid type %s to assign to submessage field.",
rb_class2name(CLASS_OF(value)));
}
@@ -207,9 +207,9 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
case UPB_TYPE_ENUM: {
int32_t int_val = 0;
if (TYPE(value) == T_STRING) {
- value = rb_funcall(value, rb_intern("to_sym"), 0, NULL);
+ value = rb_funcall(value, rb_intern("to_sym"), 0);
} else if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Expected number or symbol type for enum field.");
}
if (TYPE(value) == T_SYMBOL) {
@@ -598,18 +598,18 @@ static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
- rb_raise(rb_eTypeError, "Expected repeated field array");
+ rb_raise(cTypeError, "Expected repeated field array");
}
self = ruby_to_RepeatedField(val);
if (self->field_type != upb_fielddef_type(field)) {
- rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
+ rb_raise(cTypeError, "Repeated field array has wrong element type");
}
- if (self->field_type == UPB_TYPE_MESSAGE) {
+ if (self->field_type == UPB_TYPE_MESSAGE) {
if (self->field_type_class !=
Descriptor_msgclass(get_def_obj(upb_fielddef_subdef(field)))) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Repeated field array has wrong message class");
}
}
@@ -618,7 +618,7 @@ static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
if (self->field_type == UPB_TYPE_ENUM) {
if (self->field_type_class !=
EnumDescriptor_enummodule(get_def_obj(upb_fielddef_subdef(field)))) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Repeated field array has wrong enum class");
}
}
@@ -631,21 +631,21 @@ static void check_map_field_type(VALUE val, const upb_fielddef* field) {
if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
RTYPEDDATA_TYPE(val) != &Map_type) {
- rb_raise(rb_eTypeError, "Expected Map instance");
+ rb_raise(cTypeError, "Expected Map instance");
}
self = ruby_to_Map(val);
if (self->key_type != upb_fielddef_type(key_field)) {
- rb_raise(rb_eTypeError, "Map key type does not match field's key type");
+ rb_raise(cTypeError, "Map key type does not match field's key type");
}
if (self->value_type != upb_fielddef_type(value_field)) {
- rb_raise(rb_eTypeError, "Map value type does not match field's value type");
+ rb_raise(cTypeError, "Map value type does not match field's value type");
}
if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
if (self->value_type_class !=
get_def_obj(upb_fielddef_subdef(value_field))) {
- rb_raise(rb_eTypeError,
+ rb_raise(cTypeError,
"Map value type has wrong message/enum class");
}
}
diff --git a/ruby/lib/google/protobuf.rb b/ruby/lib/google/protobuf.rb
index 4a805e88..e20a584e 100644
--- a/ruby/lib/google/protobuf.rb
+++ b/ruby/lib/google/protobuf.rb
@@ -37,6 +37,7 @@ module Google
module Protobuf
class Error < StandardError; end
class ParseError < Error; end
+ class TypeError < ::TypeError; end
end
end
diff --git a/ruby/lib/google/protobuf/well_known_types.rb b/ruby/lib/google/protobuf/well_known_types.rb
index 921ddbc0..2ee65bc2 100644
--- a/ruby/lib/google/protobuf/well_known_types.rb
+++ b/ruby/lib/google/protobuf/well_known_types.rb
@@ -39,6 +39,12 @@ module Google
module Protobuf
Any.class_eval do
+ def self.pack(msg, type_url_prefix='type.googleapis.com/')
+ any = self.new
+ any.pack(msg, type_url_prefix)
+ any
+ end
+
def pack(msg, type_url_prefix='type.googleapis.com/')
if type_url_prefix.empty? or type_url_prefix[-1] != '/' then
self.type_url = "#{type_url_prefix}/#{msg.class.descriptor.name}"
@@ -149,6 +155,8 @@ module Google
Struct.class_eval do
def [](key)
self.fields[key].to_ruby
+ rescue NoMethodError
+ nil
end
def []=(key, value)
@@ -170,6 +178,10 @@ module Google
hash.each { |key, val| ret[key] = val }
ret
end
+
+ def has_key?(key)
+ self.fields.has_key?(key)
+ end
end
ListValue.class_eval do
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
index 07558fbc..c3a0d81c 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
@@ -86,6 +86,8 @@ public class RubyMessage extends RubyObject {
throw runtime.newTypeError("Expected string or symbols as hash keys in initialization map.");
final Descriptors.FieldDescriptor fieldDescriptor = findField(context, key);
+ if (value.isNil()) return;
+
if (Utils.isMapEntry(fieldDescriptor)) {
if (!(value instanceof RubyHash))
throw runtime.newArgumentError("Expected Hash object as initializer value for map field '" + key.asJavaString() + "'.");
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
index ad34d53d..f174402b 100644
--- a/ruby/tests/basic.rb
+++ b/ruby/tests/basic.rb
@@ -212,6 +212,15 @@ module BasicTest
assert_equal ['foo', 'bar'], m.repeated_string
end
+ def test_ctor_nil_args
+ m = TestMessage.new(:optional_enum => nil, :optional_int32 => nil, :optional_string => nil, :optional_msg => nil)
+
+ assert_equal :Default, m.optional_enum
+ assert_equal 0, m.optional_int32
+ assert_equal "", m.optional_string
+ assert_nil m.optional_msg
+ end
+
def test_embeddedmsg_hash_init
m = TestEmbeddedMessageParent.new(:child_msg => {sub_child: {optional_int32: 1}},
:number => 2,
@@ -283,31 +292,36 @@ module BasicTest
def test_type_errors
m = TestMessage.new
- assert_raise TypeError do
+ e = assert_raise Google::Protobuf::TypeError do
m.optional_int32 = "hello"
end
- assert_raise TypeError do
+
+ # Google::Protobuf::TypeError should inherit from TypeError for backwards compatibility
+ # TODO: This can be removed when we can safely migrate to Google::Protobuf::TypeError
+ assert_true e.is_a?(::TypeError)
+
+ assert_raise Google::Protobuf::TypeError do
m.optional_string = 42
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.optional_string = nil
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.optional_bool = 42
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.optional_msg = TestMessage.new # expects TestMessage2
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.repeated_int32 = [] # needs RepeatedField
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.repeated_int32.push "hello"
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.repeated_msg.push TestMessage.new
end
end
@@ -336,7 +350,9 @@ module BasicTest
# strings are immutable so we can't do this, but serialize should catch it.
m.optional_string = "asdf".encode!('UTF-8')
- assert_raise RuntimeError do
+ # Ruby 2.5 changed to raise FrozenError. However, assert_raise don't
+ # accept subclass. Don't specify type here.
+ assert_raise do
m.optional_string.encode!('ASCII-8BIT')
end
end
@@ -373,7 +389,7 @@ module BasicTest
assert l.pop == 9
assert l == [5, 2, 3, 4, 7, 8]
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m = TestMessage.new
l.push m
end
@@ -423,10 +439,10 @@ module BasicTest
l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
l.push TestMessage.new
assert l.count == 1
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
l.push TestMessage2.new
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
l.push 42
end
@@ -575,7 +591,7 @@ module BasicTest
assert_raise RangeError do
m[0x8000_0000] = 1
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m["asdf"] = 1
end
@@ -584,7 +600,7 @@ module BasicTest
assert_raise RangeError do
m[0x1_0000_0000_0000_0000] = 1
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m["asdf"] = 1
end
@@ -609,10 +625,10 @@ module BasicTest
m = Google::Protobuf::Map.new(:bool, :int32)
m[true] = 1
m[false] = 2
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m[1] = 1
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m["asdf"] = 1
end
@@ -639,7 +655,7 @@ module BasicTest
def test_map_msg_enum_valuetypes
m = Google::Protobuf::Map.new(:string, :message, TestMessage)
m["asdf"] = TestMessage.new
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m["jkl;"] = TestMessage2.new
end
@@ -706,17 +722,17 @@ module BasicTest
m.map_string_msg.delete("c")
assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.map_string_msg["e"] = TestMessage.new # wrong value type
end
# ensure nothing was added by the above
assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
m.map_string_int32 = {}
end
@@ -1015,7 +1031,7 @@ module BasicTest
def test_def_errors
s = Google::Protobuf::DescriptorPool.new
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
s.build do
# enum with no default (integer value 0)
add_enum "MyEnum" do
@@ -1023,7 +1039,7 @@ module BasicTest
end
end
end
- assert_raise TypeError do
+ assert_raise Google::Protobuf::TypeError do
s.build do
# message with required field (unsupported in proto3)
add_message "MyMessage" do
@@ -1259,6 +1275,10 @@ module BasicTest
Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2]))
end
+ def test_json_empty
+ assert TestMessage.encode_json(TestMessage.new) == '{}'
+ end
+
def test_json_emit_defaults
# TODO: Fix JSON in JRuby version.
return if RUBY_PLATFORM == "java"
diff --git a/ruby/tests/repeated_field_test.rb b/ruby/tests/repeated_field_test.rb
index 61ac4afd..a4f3aab8 100644
--- a/ruby/tests/repeated_field_test.rb
+++ b/ruby/tests/repeated_field_test.rb
@@ -18,7 +18,7 @@ class RepeatedFieldTest < Test::Unit::TestCase
# jRuby additions to the Array class that we can ignore
arr_methods -= [ :indices, :iter_for_each, :iter_for_each_index,
:iter_for_each_with_index, :dimensions, :copy_data, :copy_data_simple,
- :nitems, :iter_for_reverse_each, :indexes]
+ :nitems, :iter_for_reverse_each, :indexes, :append, :prepend]
arr_methods.each do |method_name|
assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
end
diff --git a/ruby/tests/well_known_types_test.rb b/ruby/tests/well_known_types_test.rb
index bd24c328..f35f7b13 100644
--- a/ruby/tests/well_known_types_test.rb
+++ b/ruby/tests/well_known_types_test.rb
@@ -60,6 +60,9 @@ class TestWellKnownTypes < Test::Unit::TestCase
assert_equal(Google::Protobuf::ListValue.from_a(sublist),
struct["sublist"])
+ assert_equal true, struct.has_key?("null")
+ assert_equal false, struct.has_key?("missing_key")
+
should_equal = {
"number" => 12345,
"boolean-true" => true,
@@ -82,6 +85,9 @@ class TestWellKnownTypes < Test::Unit::TestCase
# to_h returns a fully-flattened Ruby structure (Hash and Array).
assert_equal(should_equal, struct.to_h)
+ # Test that we can safely access a missing key
+ assert_equal(nil, struct["missing_key"])
+
# Test that we can assign Struct and ListValue directly.
struct["substruct"] = Google::Protobuf::Struct.from_hash(substruct)
struct["sublist"] = Google::Protobuf::ListValue.from_a(sublist)
@@ -120,11 +126,17 @@ class TestWellKnownTypes < Test::Unit::TestCase
end
def test_any
- any = Google::Protobuf::Any.new
ts = Google::Protobuf::Timestamp.new(seconds: 12345, nanos: 6789)
+
+ any = Google::Protobuf::Any.new
any.pack(ts)
assert any.is(Google::Protobuf::Timestamp)
assert_equal ts, any.unpack(Google::Protobuf::Timestamp)
+
+ any = Google::Protobuf::Any.pack(ts)
+
+ assert any.is(Google::Protobuf::Timestamp)
+ assert_equal ts, any.unpack(Google::Protobuf::Timestamp)
end
end