Some Hash destructive methods ensure the receiver modifiable [Bug #17736]

refs:

* https://bugs.ruby-lang.org/issues/17736
* https://github.com/ruby/ruby/pull/4296

This commit aims to cover following methods

* Hash#select!
* Hash#filter!
* Hash#keep_if
* Hash#reject!
* Hash#delete_if

I think these are not all.

---

* Ensure the receiver is modifiable or not
* Assert the receiver is not modified
This commit is contained in:
Kenichi Kamiya 2021-03-20 19:35:36 +09:00 коммит произвёл Nobuyoshi Nakada
Родитель 278522f053
Коммит 7954bb056b
2 изменённых файлов: 44 добавлений и 0 удалений

2
hash.c
Просмотреть файл

@ -2476,6 +2476,7 @@ static int
delete_if_i(VALUE key, VALUE value, VALUE hash)
{
if (RTEST(rb_yield_values(2, key, value))) {
rb_hash_modify(hash);
return ST_DELETE;
}
return ST_CONTINUE;
@ -2705,6 +2706,7 @@ static int
keep_if_i(VALUE key, VALUE value, VALUE hash)
{
if (!RTEST(rb_yield_values(2, key, value))) {
rb_hash_modify(hash);
return ST_DELETE;
}
return ST_CONTINUE;

Просмотреть файл

@ -439,6 +439,15 @@ class TestHash < Test::Unit::TestCase
true
}
assert_equal(base.size, n)
h = base.dup
assert_raise(FrozenError) do
h.delete_if do
h.freeze
true
end
end
assert_equal(base.dup, h)
end
def test_keep_if
@ -446,6 +455,14 @@ class TestHash < Test::Unit::TestCase
assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 })
h = @cls[1=>2,3=>4,5=>6]
assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true})
h = @cls[1=>2,3=>4,5=>6]
assert_raise(FrozenError) do
h.keep_if do
h.freeze
false
end
end
assert_equal(@cls[1=>2,3=>4,5=>6], h)
end
def test_compact
@ -743,6 +760,15 @@ class TestHash < Test::Unit::TestCase
h = base.dup
assert_equal(h3, h.reject! {|k,v| v })
assert_equal(h3, h)
h = base.dup
assert_raise(FrozenError) do
h.reject! do
h.freeze
true
end
end
assert_equal(base.dup, h)
end
def test_replace
@ -1046,6 +1072,14 @@ class TestHash < Test::Unit::TestCase
assert_equal({3=>4,5=>6}, h)
h = @cls[1=>2,3=>4,5=>6]
assert_equal(nil, h.select!{true})
h = @cls[1=>2,3=>4,5=>6]
assert_raise(FrozenError) do
h.select! do
h.freeze
false
end
end
assert_equal(@cls[1=>2,3=>4,5=>6], h)
end
def test_slice
@ -1098,6 +1132,14 @@ class TestHash < Test::Unit::TestCase
assert_equal({3=>4,5=>6}, h)
h = @cls[1=>2,3=>4,5=>6]
assert_equal(nil, h.filter!{true})
h = @cls[1=>2,3=>4,5=>6]
assert_raise(FrozenError) do
h.filter! do
h.freeze
false
end
end
assert_equal(@cls[1=>2,3=>4,5=>6], h)
end
def test_clear2