Add frozen checks in Ruby (#5726)

* add frozen checks

* Use rb_check_frozen

* Correct assertion on frozen error message

The second argument for the method assert_raise is the message
to show when the assertion fails. It does not check the error
object's message.
Add an additional assertion that does check the error's message.

* do frozen check first
This commit is contained in:
Joe Bolinger 2019-03-02 10:37:37 -08:00 committed by Paul Yang
parent a6e3ac0db1
commit 76685c6fae
4 changed files with 57 additions and 0 deletions

View File

@ -386,6 +386,8 @@ VALUE Map_index(VALUE _self, VALUE key) {
* was just inserted.
*/
VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
rb_check_frozen(_self);
Map* self = ruby_to_Map(_self);
char keybuf[TABLE_KEY_BUF_LENGTH];
@ -438,6 +440,8 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
* nil if none was present. Throws an exception if the key is of the wrong type.
*/
VALUE Map_delete(VALUE _self, VALUE key) {
rb_check_frozen(_self);
Map* self = ruby_to_Map(_self);
char keybuf[TABLE_KEY_BUF_LENGTH];
@ -461,6 +465,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
* Removes all entries from the map.
*/
VALUE Map_clear(VALUE _self) {
rb_check_frozen(_self);
Map* self = ruby_to_Map(_self);
// Uninit and reinit the table -- this is faster than iterating and doing a

View File

@ -242,6 +242,7 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
if (argc != 2) {
rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
}
rb_check_frozen(_self);
} else if (argc != 1) {
rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
}

View File

@ -357,5 +357,22 @@ module BasicTest
assert_equal nil, file_descriptor.name
assert_equal :proto3, file_descriptor.syntax
end
def test_map_freeze
m = proto_module::MapMessage.new
m.map_string_int32['a'] = 5
m.map_string_msg['b'] = proto_module::TestMessage2.new
m.map_string_int32.freeze
m.map_string_msg.freeze
assert m.map_string_int32.frozen?
assert m.map_string_msg.frozen?
assert_raise(FrozenError) { m.map_string_int32['foo'] = 1 }
assert_raise(FrozenError) { m.map_string_msg['bar'] = proto_module::TestMessage2.new }
assert_raise(FrozenError) { m.map_string_int32.delete('a') }
assert_raise(FrozenError) { m.map_string_int32.clear }
end
end
end

View File

@ -1269,6 +1269,39 @@ module CommonTests
assert proto_module::TestMessage.new != nil
end
def test_freeze
m = proto_module::TestMessage.new
m.optional_int32 = 10
m.freeze
frozen_error = assert_raise(FrozenError) { m.optional_int32 = 20 }
assert_equal "can't modify frozen #{proto_module}::TestMessage", frozen_error.message
assert_equal 10, m.optional_int32
assert_equal true, m.frozen?
assert_raise(FrozenError) { m.optional_int64 = 2 }
assert_raise(FrozenError) { m.optional_uint32 = 3 }
assert_raise(FrozenError) { m.optional_uint64 = 4 }
assert_raise(FrozenError) { m.optional_bool = true }
assert_raise(FrozenError) { m.optional_float = 6.0 }
assert_raise(FrozenError) { m.optional_double = 7.0 }
assert_raise(FrozenError) { m.optional_string = '8' }
assert_raise(FrozenError) { m.optional_bytes = nil }
assert_raise(FrozenError) { m.optional_msg = proto_module::TestMessage2.new }
assert_raise(FrozenError) { m.optional_enum = :A }
assert_raise(FrozenError) { m.repeated_int32 = 1 }
assert_raise(FrozenError) { m.repeated_int64 = 2 }
assert_raise(FrozenError) { m.repeated_uint32 = 3 }
assert_raise(FrozenError) { m.repeated_uint64 = 4 }
assert_raise(FrozenError) { m.repeated_bool = true }
assert_raise(FrozenError) { m.repeated_float = 6.0 }
assert_raise(FrozenError) { m.repeated_double = 7.0 }
assert_raise(FrozenError) { m.repeated_string = '8' }
assert_raise(FrozenError) { m.repeated_bytes = nil }
assert_raise(FrozenError) { m.repeated_msg = proto_module::TestMessage2.new }
assert_raise(FrozenError) { m.repeated_enum = :A }
end
def test_eq
m1 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
m2 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])