summaryrefslogtreecommitdiff
path: root/test/ruby/test_refinement.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_refinement.rb')
-rw-r--r--test/ruby/test_refinement.rb708
1 files changed, 586 insertions, 122 deletions
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index afb4784d00..209e55294b 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -225,6 +225,8 @@ class TestRefinement < Test::Unit::TestCase
end
end
def test_method_should_use_refinements
+ omit if Test::Unit::Runner.current_repeat_count > 0
+
foo = Foo.new
assert_raise(NameError) { foo.method(:z) }
assert_equal("FooExt#z", FooExtClient.method_z(foo).call)
@@ -235,7 +237,7 @@ class TestRefinement < Test::Unit::TestCase
meth.call(3)
EOS
assert_equal(:refine_pow, eval_using(MethodIntegerPowEx, "2.pow(3)"))
- assert_equal(:refine_pow, eval_using(MethodIntegerPowEx, "2.:pow.(3)"))
+ assert_equal(:refine_pow, eval_using(MethodIntegerPowEx, "2.method(:pow).(3)"))
end
module InstanceMethodIntegerPowEx
@@ -246,6 +248,8 @@ class TestRefinement < Test::Unit::TestCase
end
end
def test_instance_method_should_use_refinements
+ omit if Test::Unit::Runner.current_repeat_count > 0
+
foo = Foo.new
assert_raise(NameError) { Foo.instance_method(:z) }
assert_equal("FooExt#z", FooExtClient.instance_method_z(foo).bind(foo).call)
@@ -538,7 +542,7 @@ class TestRefinement < Test::Unit::TestCase
def test_main_using_is_private
assert_raise(NoMethodError) do
- eval("self.using Module.new", Sandbox::BINDING)
+ eval("recv = self; recv.using Module.new", Sandbox::BINDING)
end
end
@@ -743,130 +747,37 @@ class TestRefinement < Test::Unit::TestCase
end
end
- module IncludeIntoRefinement
- class C
- def bar
- return "C#bar"
- end
-
- def baz
- return "C#baz"
- end
- end
-
- module Mixin
- def foo
- return "Mixin#foo"
- end
-
- def bar
- return super << " Mixin#bar"
- end
-
- def baz
- return super << " Mixin#baz"
- end
- end
-
- module M
- refine C do
- include Mixin
-
- def baz
- return super << " M#baz"
- end
- end
- end
+ def self.suppress_verbose
+ verbose, $VERBOSE = $VERBOSE, nil
+ yield
+ ensure
+ $VERBOSE = verbose
end
- eval <<-EOF, Sandbox::BINDING
- using TestRefinement::IncludeIntoRefinement::M
-
- module TestRefinement::IncludeIntoRefinement::User
- def self.invoke_foo_on(x)
- x.foo
- end
-
- def self.invoke_bar_on(x)
- x.bar
- end
-
- def self.invoke_baz_on(x)
- x.baz
- end
- end
- EOF
-
def test_include_into_refinement
- x = IncludeIntoRefinement::C.new
- assert_equal("Mixin#foo", IncludeIntoRefinement::User.invoke_foo_on(x))
- assert_equal("C#bar Mixin#bar",
- IncludeIntoRefinement::User.invoke_bar_on(x))
- assert_equal("C#baz Mixin#baz M#baz",
- IncludeIntoRefinement::User.invoke_baz_on(x))
- end
-
- module PrependIntoRefinement
- class C
- def bar
- return "C#bar"
- end
-
- def baz
- return "C#baz"
- end
- end
-
- module Mixin
- def foo
- return "Mixin#foo"
- end
-
- def bar
- return super << " Mixin#bar"
- end
-
- def baz
- return super << " Mixin#baz"
- end
- end
-
- module M
- refine C do
- prepend Mixin
+ assert_raise(TypeError) do
+ c = Class.new
+ mixin = Module.new
- def baz
- return super << " M#baz"
+ Module.new do
+ refine c do
+ include mixin
end
end
end
end
- eval <<-EOF, Sandbox::BINDING
- using TestRefinement::PrependIntoRefinement::M
-
- module TestRefinement::PrependIntoRefinement::User
- def self.invoke_foo_on(x)
- x.foo
- end
-
- def self.invoke_bar_on(x)
- x.bar
- end
+ def test_prepend_into_refinement
+ assert_raise(TypeError) do
+ c = Class.new
+ mixin = Module.new
- def self.invoke_baz_on(x)
- x.baz
+ Module.new do
+ refine c do
+ prepend mixin
+ end
end
end
- EOF
-
- def test_prepend_into_refinement
- x = PrependIntoRefinement::C.new
- assert_equal("Mixin#foo", PrependIntoRefinement::User.invoke_foo_on(x))
- assert_equal("C#bar Mixin#bar",
- PrependIntoRefinement::User.invoke_bar_on(x))
- assert_equal("C#baz M#baz Mixin#baz",
- PrependIntoRefinement::User.invoke_baz_on(x))
end
PrependAfterRefine_CODE = <<-EOC
@@ -908,15 +819,15 @@ class TestRefinement < Test::Unit::TestCase
def test_prepend_after_refine_wb_miss
if /\A(arm|mips)/ =~ RUBY_PLATFORM
- skip "too slow cpu"
+ omit "too slow cpu"
end
assert_normal_exit %Q{
GC.stress = true
10.times{
#{PrependAfterRefine_CODE}
- undef PrependAfterRefine
+ Object.send(:remove_const, :PrependAfterRefine)
}
- }, timeout: 30
+ }, timeout: 60
end
def test_prepend_after_refine
@@ -1133,7 +1044,7 @@ class TestRefinement < Test::Unit::TestCase
end
using Test
def t
- 'Refinements are broken!'.chop!
+ 'Refinements are broken!'.dup.chop!
end
t
module Test
@@ -1295,6 +1206,41 @@ class TestRefinement < Test::Unit::TestCase
INPUT
end
+ def test_refined_protected_methods
+ assert_separately([], <<-"end;")
+ bug18806 = '[ruby-core:108705] [Bug #18806]'
+ class C; end
+
+ module R
+ refine C do
+ def refined_call_foo = foo
+ def refined_call_foo_on(other) = other.foo
+
+ protected
+
+ def foo = :foo
+ end
+ end
+
+ class C
+ using R
+
+ def call_foo = foo
+ def call_foo_on(other) = other.foo
+ end
+
+ c = C.new
+ assert_equal :foo, c.call_foo, bug18806
+ assert_equal :foo, c.call_foo_on(c), bug18806
+ assert_equal :foo, c.call_foo_on(C.new), bug18806
+
+ using R
+ assert_equal :foo, c.refined_call_foo, bug18806
+ assert_equal :foo, c.refined_call_foo_on(c), bug18806
+ assert_equal :foo, c.refined_call_foo_on(C.new), bug18806
+ end;
+ end
+
def test_refine_basic_object
assert_separately([], <<-"end;")
bug10106 = '[ruby-core:64166] [Bug #10106]'
@@ -1648,7 +1594,6 @@ class TestRefinement < Test::Unit::TestCase
def test_reopen_refinement_module
assert_separately([], <<-"end;")
- $VERBOSE = nil
class C
end
@@ -1661,17 +1606,35 @@ class TestRefinement < Test::Unit::TestCase
end
using R
+ def m
+ C.new.m
+ end
+
assert_equal(:foo, C.new.m)
+ assert_equal(:foo, m)
module R
refine C do
+
+ assert_equal(:foo, C.new.m)
+ assert_equal(:foo, m)
+
+ alias m m
+
+ assert_equal(:foo, C.new.m)
+ assert_equal(:foo, m)
+
def m
:bar
end
+
+ assert_equal(:bar, C.new.m, "[ruby-core:71423] [Bug #11672]")
+ assert_equal(:bar, m, "[Bug #20285]")
end
end
assert_equal(:bar, C.new.m, "[ruby-core:71423] [Bug #11672]")
+ assert_equal(:bar, m, "[Bug #20285]")
end;
end
@@ -1776,6 +1739,8 @@ class TestRefinement < Test::Unit::TestCase
refine Object do
def in_ref_a
end
+
+ RefA.const_set(:REF, self)
end
end
@@ -1783,6 +1748,8 @@ class TestRefinement < Test::Unit::TestCase
refine Object do
def in_ref_b
end
+
+ RefB.const_set(:REF, self)
end
end
@@ -1792,23 +1759,28 @@ class TestRefinement < Test::Unit::TestCase
refine Object do
def in_ref_c
end
+
+ RefC.const_set(:REF, self)
end
end
module Foo
using RefB
USED_MODS = Module.used_modules
+ USED_REFS = Module.used_refinements
end
module Bar
using RefC
USED_MODS = Module.used_modules
+ USED_REFS = Module.used_refinements
end
module Combined
using RefA
using RefB
USED_MODS = Module.used_modules
+ USED_REFS = Module.used_refinements
end
end
@@ -1820,6 +1792,41 @@ class TestRefinement < Test::Unit::TestCase
assert_equal [ref::RefB, ref::RefA], ref::Combined::USED_MODS
end
+ def test_used_refinements
+ ref = VisibleRefinements
+ assert_equal [], Module.used_refinements
+ assert_equal [ref::RefB::REF], ref::Foo::USED_REFS
+ assert_equal [ref::RefC::REF], ref::Bar::USED_REFS
+ assert_equal [ref::RefB::REF, ref::RefA::REF], ref::Combined::USED_REFS
+ end
+
+ def test_refinements
+ int_refinement = nil
+ str_refinement = nil
+ m = Module.new {
+ refine Integer do
+ int_refinement = self
+ end
+
+ refine String do
+ str_refinement = self
+ end
+ }
+ assert_equal([int_refinement, str_refinement], m.refinements)
+ end
+
+ def test_target
+ refinements = Module.new {
+ refine Integer do
+ end
+
+ refine String do
+ end
+ }.refinements
+ assert_equal(Integer, refinements[0].target)
+ assert_equal(String, refinements[1].target)
+ end
+
def test_warn_setconst_in_refinmenet
bug10103 = '[ruby-core:64143] [Bug #10103]'
warnings = [
@@ -1926,6 +1933,29 @@ class TestRefinement < Test::Unit::TestCase
end;
end
+ def test_public_in_refine_for_method_in_superclass
+ assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ bug21446 = '[ruby-core:122558] [Bug #21446]'
+
+ class CowSuper
+ private
+ def moo() "Moo"; end
+ end
+ class Cow < CowSuper
+ end
+
+ module PublicCows
+ refine(Cow) {
+ public :moo
+ }
+ end
+
+ using PublicCows
+ assert_equal("Moo", Cow.new.moo, bug21446)
+ end;
+ end
+
module SuperToModule
class Parent
end
@@ -1964,10 +1994,10 @@ class TestRefinement < Test::Unit::TestCase
m = Module.new do
r = refine(String) {def test;:ok end}
end
- assert_raise_with_message(ArgumentError, /refinement/, bug) do
+ assert_raise_with_message(TypeError, /refinement/, bug) do
m.module_eval {include r}
end
- assert_raise_with_message(ArgumentError, /refinement/, bug) do
+ assert_raise_with_message(TypeError, /refinement/, bug) do
m.module_eval {prepend r}
end
end
@@ -2064,7 +2094,6 @@ class TestRefinement < Test::Unit::TestCase
def test_tostring
assert_equal("ok", ToString.new.string)
- assert_predicate(ToString.new.taint.string, :tainted?)
end
class ToSymbol
@@ -2295,6 +2324,441 @@ class TestRefinement < Test::Unit::TestCase
d
end
+ class RefineInUsing
+ module M1
+ refine RefineInUsing do
+ def foo
+ :ok
+ end
+ end
+ end
+
+ module M2
+ using M1
+ refine RefineInUsing do
+ def call_foo
+ RefineInUsing.new.foo
+ end
+ end
+ end
+
+ using M2
+ def self.test
+ new.call_foo
+ end
+ end
+
+ def test_refine_in_using
+ assert_equal(:ok, RefineInUsing.test)
+ end
+
+ class Bug16242
+ module OtherM
+ end
+
+ module M
+ prepend OtherM
+
+ refine M do
+ def refine_method
+ "refine_method"
+ end
+ end
+ using M
+
+ def hoge
+ refine_method
+ end
+ end
+
+ class X
+ include M
+ end
+ end
+
+ def test_refine_prepended_module
+ assert_equal("refine_method", Bug16242::X.new.hoge)
+ end
+
+ module Bug13446
+ module Enumerable
+ def sum(*args)
+ i = 0
+ args.each { |arg| i += a }
+ i
+ end
+ end
+
+ using Module.new {
+ refine Enumerable do
+ alias :orig_sum :sum
+ end
+ }
+
+ module Enumerable
+ def sum(*args)
+ orig_sum(*args)
+ end
+ end
+
+ class GenericEnumerable
+ include Enumerable
+ end
+
+ Enumerable.prepend(Module.new)
+ end
+
+ def test_prepend_refined_module
+ assert_equal(0, Bug13446::GenericEnumerable.new.sum)
+ end
+
+ def test_unbound_refine_method
+ a = EnvUtil.labeled_class("A") do
+ def foo
+ self.class
+ end
+ end
+ b = EnvUtil.labeled_class("B")
+ bar = EnvUtil.labeled_module("R") do
+ break refine a do
+ def foo
+ super
+ end
+ end
+ end
+ assert_raise(TypeError) do
+ bar.instance_method(:foo).bind(b.new)
+ end
+ end
+
+ def test_refine_frozen_class
+ verbose_bak, $VERBOSE = $VERBOSE, nil
+ singleton_class.instance_variable_set(:@x, self)
+ class << self
+ c = Class.new do
+ def foo
+ :cfoo
+ end
+ end
+ foo = Module.new do
+ refine c do
+ def foo
+ :rfoo
+ end
+ end
+ end
+ using foo
+ @x.assert_equal(:rfoo, c.new.foo)
+ c.freeze
+ foo.module_eval do
+ refine c do
+ def foo
+ :rfoo2
+ end
+ def bar
+ :rbar
+ end
+ end
+ end
+ @x.assert_equal(:rfoo2, c.new.foo)
+ @x.assert_equal(:rbar, c.new.bar, '[ruby-core:71391] [Bug #11669]')
+ end
+ ensure
+ $VERBOSE = verbose_bak
+ end
+
+ # [Bug #17386]
+ def test_prepended_with_method_cache
+ foo = Class.new do
+ def foo
+ :Foo
+ end
+ end
+
+ code = Module.new do
+ def foo
+ :Code
+ end
+ end
+
+ _ext = Module.new do
+ refine foo do
+ def foo; end
+ end
+ end
+
+ obj = foo.new
+
+ assert_equal :Foo, obj.foo
+ foo.prepend code
+ assert_equal :Code, obj.foo
+ end
+
+ # [Bug #17417]
+ def test_prepended_with_method_cache_17417
+ assert_normal_exit %q{
+ module M
+ def hoge; end
+ end
+
+ module R
+ refine Hash do
+ def except *args; end
+ end
+ end
+
+ h = {}
+ h.method(:except) # put it on pCMC
+ Hash.prepend(M)
+ h.method(:except)
+ }
+ end
+
+ def test_defining_after_cached
+ klass = Class.new
+ _refinement = Module.new { refine(klass) { def foo; end } }
+ klass.new.foo rescue nil # cache the refinement method entry
+ klass.define_method(:foo) { 42 }
+ assert_equal(42, klass.new.foo)
+ end
+
+ # [Bug #17806]
+ def test_two_refinements_for_prepended_class
+ assert_normal_exit %q{
+ module R1
+ refine Hash do
+ def foo; :r1; end
+ end
+ end
+
+ class Hash
+ prepend(Module.new)
+ end
+
+ class Hash
+ def foo; end
+ end
+
+ {}.method(:foo) # put it on pCMC
+
+ module R2
+ refine Hash do
+ def foo; :r2; end
+ end
+ end
+
+ {}.foo
+ }
+ end
+
+ # [Bug #17806]
+ def test_redefining_refined_for_prepended_class
+ klass = Class.new { def foo; end }
+ _refinement = Module.new do
+ refine(klass) { def foo; :refined; end }
+ end
+ klass.prepend(Module.new)
+ klass.new.foo # cache foo
+ klass.define_method(:foo) { :second }
+ assert_equal(:second, klass.new.foo)
+ end
+
+ class Bug18180
+ module M
+ refine Array do
+ def min; :min; end
+ def max; :max; end
+ end
+ end
+
+ using M
+
+ def t
+ [[1+0, 2, 4].min, [1, 2, 4].min, [1+0, 2, 4].max, [1, 2, 4].max]
+ end
+ end
+
+ def test_refine_array_min_max
+ assert_equal([:min, :min, :max, :max], Bug18180.new.t)
+ end
+
+ class Bug17822
+ module Ext
+ refine(Bug17822) do
+ def foo = :refined
+ end
+ end
+
+ private(def foo = :not_refined)
+
+ module Client
+ using Ext
+ def self.call_foo
+ Bug17822.new.foo
+ end
+ end
+ end
+
+ # [Bug #17822]
+ def test_privatizing_refined_method
+ assert_equal(:refined, Bug17822::Client.call_foo)
+ end
+
+ def test_ancestors
+ refinement = nil
+ as = nil
+ Module.new do
+ refine Array do
+ refinement = self
+ as = ancestors
+ end
+ end
+ assert_equal([refinement], as, "[ruby-core:86949] [Bug #14744]")
+ end
+
+ module TestImport
+ class A
+ def foo
+ "original"
+ end
+ end
+
+ module B
+ BAR = "bar"
+
+ def bar
+ "#{foo}:#{BAR}"
+ end
+ end
+
+ module C
+ refine A do
+ import_methods B
+
+ def foo
+ "refined"
+ end
+ end
+ end
+
+ module UsingC
+ using C
+
+ def self.call_bar
+ A.new.bar
+ end
+ end
+ end
+
+ def test_import_methods
+ assert_equal("refined:bar", TestImport::UsingC.call_bar)
+
+ assert_raise(ArgumentError) do
+ Module.new do
+ refine Integer do
+ import_methods Enumerable
+ end
+ end
+ end
+ end
+
+ def test_inherit_singleton_methods_of_module
+ assert_equal([], Refinement.used_modules)
+ end
+
+ def test_inlinecache
+ assert_separately([], <<-"end;")
+ module R
+ refine String do
+ def to_s = :R
+ end
+ end
+
+ 2.times{|i|
+ s = ''.to_s
+ assert_equal '', s if i == 0
+ assert_equal :R, s if i == 1
+ using R if i == 0
+ assert_equal :R, ''.to_s
+ }
+ end;
+ end
+
+ def test_inline_cache_invalidation
+ klass = Class.new do
+ def cached_foo_callsite = foo
+
+ def foo = :v1
+
+ host = self
+ @refinement = Module.new do
+ refine(host) do
+ def foo = :unused
+ end
+ end
+ end
+
+ obj = klass.new
+ obj.cached_foo_callsite # prime cache
+ klass.class_eval do
+ def foo = :v2 # invalidate
+ end
+ assert_equal(:v2, obj.cached_foo_callsite)
+ end
+
+ # [Bug #20302]
+ def test_multiple_refinements_for_same_module
+ assert_in_out_err([], <<-INPUT, %w(:f2 :f1), [])
+ module M1
+ refine(Kernel) do
+ def f1 = :f1
+ end
+ end
+
+ module M2
+ refine(Kernel) do
+ def f2 = :f2
+ end
+ end
+
+ class Foo
+ using M1
+ using M2
+
+ def test
+ p f2
+ p f1
+ end
+ end
+
+ Foo.new.test
+ INPUT
+ end
+
+ def test_refined_module_method
+ m = Module.new {
+ x = Module.new {def qux;end}
+ refine(x) {def qux;end}
+ break x
+ }
+ extend m
+ meth = method(:qux)
+ assert_equal m, meth.owner
+ assert_equal :qux, meth.name
+ end
+
+ def test_symbol_proc_from_using_scope
+ # assert_separately to contain the side effects of refining Kernel
+ assert_separately([], <<~RUBY)
+ class RefinedScope
+ using(Module.new { refine(Kernel) { def itself = 0 } })
+ ITSELF = :itself.to_proc
+ end
+
+ assert_equal(1, RefinedScope::ITSELF[1], "[Bug #21265]")
+ RUBY
+ end
+
private
def eval_using(mod, s)