summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2020-11-11 16:38:03 -0500
committerAlan Wu <XrXr@users.noreply.github.com>2020-11-16 17:41:17 -0500
commitebb96fa8808317ad53a4977bff26cf755d68077e (patch)
treeb7e3dd43bbc16ce71235b773df598f8138cb1065 /test
parent084e7e31b257f6ac859769553b4c1c6ca2930152 (diff)
Fix singleton class cloning
Before this commit, `clone` gave different results depending on whether the original object had an attached singleton class or not. Consider the following setup: ``` class Foo; end Foo.singleton_class.define_method(:foo) {} obj = Foo.new obj.singleton_class if $call_singleton clone = obj.clone ``` When `$call_singleton = false`, neither `obj.singleton_class.singleton_class` nor `clone.singleton_class.singleton_class` own any methods. However, when `$call_singleton = true`, `clone.singleton_class.singleton_class` would own a copy of `foo` from `Foo.singleton_class`, even though `obj.singleton_class.singleton_class` does not. The latter case is unexpected and results in a visibly different clone, depending on if the original object had an attached class or not. Co-authored-by: Ufuk Kayserilioglu <ufuk.kayserilioglu@shopify.com>
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3761
Diffstat (limited to 'test')
-rw-r--r--test/ruby/test_class.rb47
1 files changed, 47 insertions, 0 deletions
diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb
index 82a2e55634..6a8234a9d3 100644
--- a/test/ruby/test_class.rb
+++ b/test/ruby/test_class.rb
@@ -483,6 +483,53 @@ class TestClass < Test::Unit::TestCase
assert_equal(:foo, d.foo)
end
+ def test_clone_singleton_class_exists
+ klass = Class.new do
+ def self.bar; :bar; end
+ end
+
+ o = klass.new
+ o.singleton_class
+ clone = o.clone
+
+ assert_empty(o.singleton_class.instance_methods(false))
+ assert_empty(clone.singleton_class.instance_methods(false))
+ assert_empty(o.singleton_class.singleton_class.instance_methods(false))
+ assert_empty(clone.singleton_class.singleton_class.instance_methods(false))
+ end
+
+ def test_clone_when_singleton_class_of_singleton_class_exists
+ klass = Class.new do
+ def self.bar; :bar; end
+ end
+
+ o = klass.new
+ o.singleton_class.singleton_class
+ clone = o.clone
+
+ assert_empty(o.singleton_class.instance_methods(false))
+ assert_empty(clone.singleton_class.instance_methods(false))
+ assert_empty(o.singleton_class.singleton_class.instance_methods(false))
+ assert_empty(clone.singleton_class.singleton_class.instance_methods(false))
+ end
+
+ def test_clone_when_method_exists_on_singleton_class_of_singleton_class
+ klass = Class.new do
+ def self.bar; :bar; end
+ end
+
+ o = klass.new
+ o.singleton_class.singleton_class.define_method(:s2_method) { :s2 }
+ clone = o.clone
+
+ assert_empty(o.singleton_class.instance_methods(false))
+ assert_empty(clone.singleton_class.instance_methods(false))
+ assert_equal(:s2, o.singleton_class.s2_method)
+ assert_equal(:s2, clone.singleton_class.s2_method)
+ assert_equal([:s2_method], o.singleton_class.singleton_class.instance_methods(false))
+ assert_equal([:s2_method], clone.singleton_class.singleton_class.instance_methods(false))
+ end
+
def test_singleton_class_p
feature7609 = '[ruby-core:51087] [Feature #7609]'
assert_predicate(self.singleton_class, :singleton_class?, feature7609)