summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2019-08-25 21:11:46 -0700
committerJeremy Evans <code@jeremyevans.net>2020-01-03 20:13:09 -0800
commit04eb7c7e462d1fcbab9efc7022c1b43636ab878a (patch)
tree025cb1f1e10736e9c37eb991a8c4cdb1931d4ff2 /test
parent0eeed5bcc5530edb0af2af2ccff09d067c59e8f9 (diff)
Call initialize_clone with freeze: false if clone called with freeze: false
This makes it possible to initialize_clone to correctly not freeze internal state if the freeze: false keyword is passed to clone. If clone is called with freeze: true or no keyword, do not pass a second argument to initialize_clone to keep backwards compatibility. This makes it so that external libraries that override initialize_clone but do not support the freeze keyword will fail with ArgumentError if passing freeze: false to clone. I think that is better than the current behavior, which succeeds but results in an unfrozen object with frozen internals. Fix related issues in set and delegate in stdlib. Fixes [Bug #14266]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2816
Diffstat (limited to 'test')
-rw-r--r--test/ruby/test_module.rb6
-rw-r--r--test/ruby/test_object.rb22
-rw-r--r--test/test_delegate.rb15
-rw-r--r--test/test_set.rb11
4 files changed, 54 insertions, 0 deletions
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index 2e7e5804d0..9373c48a9a 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -2491,6 +2491,12 @@ class TestModule < Test::Unit::TestCase
assert_equal :M2, CloneTestC2.new.foo, '[Bug #15877]'
end
+ def test_clone_freeze
+ m = Module.new.freeze
+ assert_predicate m.clone, :frozen?
+ assert_not_predicate m.clone(freeze: false), :frozen?
+ end
+
private
def assert_top_method_is_private(method)
diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb
index add5b9fb15..bfc7d7de1d 100644
--- a/test/ruby/test_object.rb
+++ b/test/ruby/test_object.rb
@@ -75,6 +75,28 @@ class TestObject < Test::Unit::TestCase
assert_raise_with_message(ArgumentError, /\u{1f4a9}/) do
Object.new.clone(freeze: x)
end
+
+ c = Class.new do
+ attr_reader :f
+ end
+ o = c.new
+ f = true
+ def o.initialize_clone(_, freeze: true)
+ @f = freeze
+ super
+ end
+ clone = o.clone
+ assert_kind_of c, clone
+ assert_equal true, clone.f
+ clone = o.clone(freeze: false)
+ assert_kind_of c, clone
+ assert_equal false, clone.f
+
+ def o.initialize_clone(_)
+ super
+ end
+ assert_kind_of c, o.clone
+ assert_raise(ArgumentError) { o.clone(freeze: false) }
end
def test_init_dupclone
diff --git a/test/test_delegate.rb b/test/test_delegate.rb
index 303cd16897..80bf41638a 100644
--- a/test/test_delegate.rb
+++ b/test/test_delegate.rb
@@ -50,6 +50,21 @@ class TestDelegateClass < Test::Unit::TestCase
assert_equal(SimpleDelegator,simple.clone.class)
end
+ def test_simpledelegator_clone
+ simple=SimpleDelegator.new([])
+ simple.freeze
+
+ clone = simple.clone
+ assert_predicate clone, :frozen?
+ assert_predicate clone.__getobj__, :frozen?
+ assert_equal true, Kernel.instance_method(:frozen?).bind(clone).call
+
+ clone = simple.clone(freeze: false)
+ assert_not_predicate clone, :frozen?
+ assert_not_predicate clone.__getobj__, :frozen?
+ assert_equal false, Kernel.instance_method(:frozen?).bind(clone).call
+ end
+
class Object
def m
:o
diff --git a/test/test_set.rb b/test/test_set.rb
index b0f669ce86..68ee7ce8a3 100644
--- a/test/test_set.rb
+++ b/test/test_set.rb
@@ -730,6 +730,17 @@ class TC_Set < Test::Unit::TestCase
}
end
+ def test_freeze_clone_false
+ set1 = Set[1,2,3]
+ set1.freeze
+ set2 = set1.clone(freeze: false)
+
+ assert_not_predicate set2, :frozen?
+ set2.add 5
+ assert_equal Set[1,2,3,5], set2
+ assert_equal Set[1,2,3], set1
+ end
+
def test_inspect
set1 = Set[1, 2]
assert_equal('#<Set: {1, 2}>', set1.inspect)