summaryrefslogtreecommitdiff
path: root/test/ruby/test_module.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_module.rb')
-rw-r--r--test/ruby/test_module.rb891
1 files changed, 787 insertions, 104 deletions
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index d2da384cbd..9ed6c1e321 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -9,25 +9,24 @@ class TestModule < Test::Unit::TestCase
yield
end
- def assert_method_defined?(klass, mid, message="")
+ def assert_method_defined?(klass, (mid, *args), message="")
message = build_message(message, "#{klass}\##{mid} expected to be defined.")
_wrap_assertion do
- klass.method_defined?(mid) or
+ klass.method_defined?(mid, *args) or
raise Test::Unit::AssertionFailedError, message, caller(3)
end
end
- def assert_method_not_defined?(klass, mid, message="")
+ def assert_method_not_defined?(klass, (mid, *args), message="")
message = build_message(message, "#{klass}\##{mid} expected to not be defined.")
_wrap_assertion do
- klass.method_defined?(mid) and
+ klass.method_defined?(mid, *args) and
raise Test::Unit::AssertionFailedError, message, caller(3)
end
end
def setup
@verbose = $VERBOSE
- $VERBOSE = nil
@deprecated = Warning[:deprecated]
Warning[:deprecated] = true
end
@@ -254,6 +253,14 @@ class TestModule < Test::Unit::TestCase
assert_operator(Math, :const_defined?, "PI")
assert_not_operator(Math, :const_defined?, :IP)
assert_not_operator(Math, :const_defined?, "IP")
+
+ # Test invalid symbol name
+ # [Bug #20245]
+ EnvUtil.under_gc_stress do
+ assert_raise(EncodingError) do
+ Math.const_defined?("\xC3")
+ end
+ end
end
def each_bad_constants(m, &b)
@@ -268,7 +275,7 @@ class TestModule < Test::Unit::TestCase
].each do |name, msg|
expected = "wrong constant name %s" % name
msg = "#{msg}#{': ' if msg}wrong constant name #{name.dump}"
- assert_raise_with_message(NameError, expected, "#{msg} to #{m}") do
+ assert_raise_with_message(NameError, Regexp.compile(Regexp.quote(expected)), "#{msg} to #{m}") do
yield name
end
end
@@ -405,19 +412,7 @@ class TestModule < Test::Unit::TestCase
assert_equal([:MIXIN, :USER], User.constants.sort)
end
- def test_self_initialize_copy
- bug9535 = '[ruby-dev:47989] [Bug #9535]'
- m = Module.new do
- def foo
- :ok
- end
- initialize_copy(self)
- end
- assert_equal(:ok, Object.new.extend(m).foo, bug9535)
- end
-
def test_initialize_copy_empty
- bug9813 = '[ruby-dev:48182] [Bug #9813]'
m = Module.new do
def x
end
@@ -427,12 +422,56 @@ class TestModule < Test::Unit::TestCase
assert_equal([:x], m.instance_methods)
assert_equal([:@x], m.instance_variables)
assert_equal([:X], m.constants)
- m.module_eval do
- initialize_copy(Module.new)
+
+ m = Class.new(Module) do
+ def initialize_copy(other)
+ # leave uninitialized
+ end
+ end.new.dup
+ c = Class.new
+ assert_operator(c.include(m), :<, m)
+ cp = Module.instance_method(:initialize_copy)
+ assert_raise(TypeError) do
+ cp.bind_call(m, Module.new)
+ end
+ end
+
+ class Bug18185 < Module
+ module InstanceMethods
+ end
+ attr_reader :ancestor_list
+ def initialize
+ @ancestor_list = ancestors
+ include InstanceMethods
end
- assert_empty(m.instance_methods, bug9813)
- assert_empty(m.instance_variables, bug9813)
- assert_empty(m.constants, bug9813)
+ class Foo
+ attr_reader :key
+ def initialize(key:)
+ @key = key
+ end
+ end
+ end
+
+ def test_module_subclass_initialize
+ mod = Bug18185.new
+ c = Class.new(Bug18185::Foo) do
+ include mod
+ end
+ anc = c.ancestors
+ assert_include(anc, mod)
+ assert_equal(1, anc.count(BasicObject), ->{anc.inspect})
+ b = c.new(key: 1)
+ assert_equal(1, b.key)
+ assert_not_include(mod.ancestor_list, BasicObject)
+ end
+
+ def test_module_collected_extended_object
+ m1 = labeled_module("m1")
+ m2 = labeled_module("m2")
+ Object.new.extend(m1)
+ GC.start
+ m1.include(m2)
+ assert_equal([m1, m2], m1.ancestors)
end
def test_dup
@@ -479,6 +518,36 @@ class TestModule < Test::Unit::TestCase
assert_raise(ArgumentError) { Module.new { include } }
end
+ def test_include_before_initialize
+ m = Class.new(Module) do
+ def initialize(...)
+ include Enumerable
+ super
+ end
+ end.new
+ assert_operator(m, :<, Enumerable)
+ end
+
+ def test_prepend_self
+ m = Module.new
+ assert_equal([m], m.ancestors)
+ m.prepend(m) rescue nil
+ assert_equal([m], m.ancestors)
+ end
+
+ def test_bug17590
+ m = Module.new
+ c = Class.new
+ c.prepend(m)
+ c.include(m)
+ m.prepend(m) rescue nil
+ m2 = Module.new
+ m2.prepend(m)
+ c.include(m2)
+
+ assert_equal([m, c, m2] + Object.ancestors, c.ancestors)
+ end
+
def test_prepend_works_with_duped_classes
m = Module.new
a = Class.new do
@@ -487,13 +556,34 @@ class TestModule < Test::Unit::TestCase
end
a2 = a.dup.new
a.class_eval do
+ alias _b b
def b; 1 end
end
assert_equal(2, a2.b)
end
+ def test_ancestry_of_duped_classes
+ m = Module.new
+ sc = Class.new
+ a = Class.new(sc) do
+ def b; 2 end
+ prepend m
+ end
+
+ a2 = a.dup.new
+
+ assert_kind_of Object, a2
+ assert_kind_of sc, a2
+ refute_kind_of a, a2
+ assert_kind_of m, a2
+
+ assert_kind_of Class, a2.class
+ assert_kind_of sc.singleton_class, a2.class
+ assert_same sc, a2.class.superclass
+ end
+
def test_gc_prepend_chain
- assert_separately([], <<-EOS)
+ assert_ruby_status([], <<-EOS)
10000.times { |i|
m1 = Module.new do
def foo; end
@@ -631,6 +721,82 @@ class TestModule < Test::Unit::TestCase
assert_equal([m1, m2], m3.included_modules)
end
+ def test_include_with_prepend
+ c = Class.new{def m; [:c] end}
+ p = Module.new{def m; [:p] + super end}
+ q = Module.new{def m; [:q] + super end; include p}
+ r = Module.new{def m; [:r] + super end; prepend q}
+ s = Module.new{def m; [:s] + super end; include r}
+ a = Class.new(c){def m; [:a] + super end; prepend p; include s}
+ assert_equal([:p, :a, :s, :q, :r, :c], a.new.m)
+ end
+
+ def test_prepend_after_include
+ c = Class.new{def m; [:c] end}
+ sc = Class.new(c){def m; [:sc] + super end}
+ m = Module.new{def m; [:m] + super end}
+ sc.include m
+ sc.prepend m
+ sc.prepend m
+ assert_equal([:m, :sc, :m, :c], sc.new.m)
+
+ c = Class.new{def m; [:c] end}
+ sc = Class.new(c){def m; [:sc] + super end}
+ m0 = Module.new{def m; [:m0] + super end}
+ m1 = Module.new{def m; [:m1] + super end}
+ m1.prepend m0
+ sc.include m1
+ sc.prepend m1
+ assert_equal([:m0, :m1, :sc, :m0, :m1, :c], sc.new.m)
+ sc.prepend m
+ assert_equal([:m, :m0, :m1, :sc, :m0, :m1, :c], sc.new.m)
+ sc.prepend m1
+ assert_equal([:m, :m0, :m1, :sc, :m0, :m1, :c], sc.new.m)
+
+
+ c = Class.new{def m; [:c] end}
+ sc = Class.new(c){def m; [:sc] + super end}
+ m0 = Module.new{def m; [:m0] + super end}
+ m1 = Module.new{def m; [:m1] + super end}
+ m1.include m0
+ sc.include m1
+ sc.prepend m
+ sc.prepend m1
+ sc.prepend m1
+ assert_equal([:m1, :m0, :m, :sc, :m1, :m0, :c], sc.new.m)
+ end
+
+ def test_include_into_module_after_prepend_bug_20871
+ bar = Module.new{def bar; 'bar'; end}
+ foo = Module.new{def foo; 'foo'; end}
+ m = Module.new
+ c = Class.new{include m}
+ m.prepend bar
+ Class.new{include m}
+ m.include foo
+ assert_include c.ancestors, foo
+ assert_equal "foo", c.new.foo
+ end
+
+ def test_protected_include_into_included_module
+ m1 = Module.new do
+ def other_foo(other)
+ other.foo
+ end
+
+ protected
+ def foo
+ :ok
+ end
+ end
+ m2 = Module.new
+ c1 = Class.new { include m2 }
+ c2 = Class.new { include m2 }
+ m2.include(m1)
+
+ assert_equal :ok, c1.new.other_foo(c2.new)
+ end
+
def test_instance_methods
assert_equal([:user, :user2], User.instance_methods(false).sort)
assert_equal([:user, :user2, :mixin].sort, User.instance_methods(true).sort)
@@ -647,40 +813,40 @@ class TestModule < Test::Unit::TestCase
def test_method_defined?
[User, Class.new{include User}, Class.new{prepend User}].each do |klass|
[[], [true]].each do |args|
- assert !klass.method_defined?(:wombat, *args)
- assert klass.method_defined?(:mixin, *args)
- assert klass.method_defined?(:user, *args)
- assert klass.method_defined?(:user2, *args)
- assert !klass.method_defined?(:user3, *args)
+ assert_method_not_defined?(klass, [:wombat, *args])
+ assert_method_defined?(klass, [:mixin, *args])
+ assert_method_defined?(klass, [:user, *args])
+ assert_method_defined?(klass, [:user2, *args])
+ assert_method_not_defined?(klass, [:user3, *args])
- assert !klass.method_defined?("wombat", *args)
- assert klass.method_defined?("mixin", *args)
- assert klass.method_defined?("user", *args)
- assert klass.method_defined?("user2", *args)
- assert !klass.method_defined?("user3", *args)
+ assert_method_not_defined?(klass, ["wombat", *args])
+ assert_method_defined?(klass, ["mixin", *args])
+ assert_method_defined?(klass, ["user", *args])
+ assert_method_defined?(klass, ["user2", *args])
+ assert_method_not_defined?(klass, ["user3", *args])
end
end
end
def test_method_defined_without_include_super
- assert User.method_defined?(:user, false)
- assert !User.method_defined?(:mixin, false)
- assert Mixin.method_defined?(:mixin, false)
+ assert_method_defined?(User, [:user, false])
+ assert_method_not_defined?(User, [:mixin, false])
+ assert_method_defined?(Mixin, [:mixin, false])
User.const_set(:FOO, c = Class.new)
c.prepend(User)
- assert !c.method_defined?(:user, false)
+ assert_method_not_defined?(c, [:user, false])
c.define_method(:user){}
- assert c.method_defined?(:user, false)
+ assert_method_defined?(c, [:user, false])
- assert !c.method_defined?(:mixin, false)
+ assert_method_not_defined?(c, [:mixin, false])
c.define_method(:mixin){}
- assert c.method_defined?(:mixin, false)
+ assert_method_defined?(c, [:mixin, false])
- assert !c.method_defined?(:userx, false)
+ assert_method_not_defined?(c, [:userx, false])
c.define_method(:userx){}
- assert c.method_defined?(:userx, false)
+ assert_method_defined?(c, [:userx, false])
# cleanup
User.class_eval do
@@ -767,13 +933,13 @@ class TestModule < Test::Unit::TestCase
n = Module.new
m.const_set(:N, n)
assert_nil(m.name)
- assert_nil(n.name)
+ assert_match(/::N$/, n.name)
assert_equal([:N], m.constants)
m.module_eval("module O end")
assert_equal([:N, :O], m.constants.sort)
m.module_eval("class C; end")
assert_equal([:C, :N, :O], m.constants.sort)
- assert_nil(m::N.name)
+ assert_match(/::N$/, m::N.name)
assert_match(/\A#<Module:.*>::O\z/, m::O.name)
assert_match(/\A#<Module:.*>::C\z/, m::C.name)
self.class.const_set(:M, m)
@@ -783,12 +949,19 @@ class TestModule < Test::Unit::TestCase
assert_equal(prefix+"C", m.const_get(:C).name)
c = m.class_eval("Bug15891 = Class.new.freeze")
assert_equal(prefix+"Bug15891", c.name)
+ ensure
+ self.class.class_eval {remove_const(:M)}
end
def test_private_class_method
assert_raise(ExpectedException) { AClass.cm1 }
assert_raise(ExpectedException) { AClass.cm3 }
assert_equal("cm1cm2cm3", AClass.cm2)
+
+ c = Class.new(AClass)
+ c.class_eval {private_class_method [:cm1, :cm2]}
+ assert_raise(NoMethodError, /private method/) {c.cm1}
+ assert_raise(NoMethodError, /private method/) {c.cm2}
end
def test_private_instance_methods
@@ -811,6 +984,11 @@ class TestModule < Test::Unit::TestCase
assert_equal("cm1", MyClass.cm1)
assert_equal("cm1cm2cm3", MyClass.cm2)
assert_raise(ExpectedException) { eval "MyClass.cm3" }
+
+ c = Class.new(AClass)
+ c.class_eval {public_class_method [:cm1, :cm2]}
+ assert_equal("cm1", c.cm1)
+ assert_equal("cm1cm2cm3", c.cm2)
end
def test_public_instance_methods
@@ -818,6 +996,115 @@ class TestModule < Test::Unit::TestCase
assert_equal([:bClass1], BClass.public_instance_methods(false))
end
+ def test_undefined_instance_methods
+ assert_equal([], AClass.undefined_instance_methods)
+ assert_equal([], BClass.undefined_instance_methods)
+ c = Class.new(AClass) {undef aClass}
+ assert_equal([:aClass], c.undefined_instance_methods)
+ c = Class.new(c)
+ assert_equal([], c.undefined_instance_methods)
+ end
+
+ def test_s_public
+ o = (c = Class.new(AClass)).new
+ assert_raise(NoMethodError, /private method/) {o.aClass1}
+ assert_raise(NoMethodError, /protected method/) {o.aClass2}
+ c.class_eval {public :aClass1}
+ assert_equal(:aClass1, o.aClass1)
+
+ o = (c = Class.new(AClass)).new
+ c.class_eval {public :aClass1, :aClass2}
+ assert_equal(:aClass1, o.aClass1)
+ assert_equal(:aClass2, o.aClass2)
+
+ o = (c = Class.new(AClass)).new
+ c.class_eval {public [:aClass1, :aClass2]}
+ assert_equal(:aClass1, o.aClass1)
+ assert_equal(:aClass2, o.aClass2)
+
+ o = AClass.new
+ assert_equal(:aClass, o.aClass)
+ assert_raise(NoMethodError, /private method/) {o.aClass1}
+ assert_raise(NoMethodError, /protected method/) {o.aClass2}
+ end
+
+ def test_s_private
+ o = (c = Class.new(AClass)).new
+ assert_equal(:aClass, o.aClass)
+ c.class_eval {private :aClass}
+ assert_raise(NoMethodError, /private method/) {o.aClass}
+
+ o = (c = Class.new(AClass)).new
+ c.class_eval {private :aClass, :aClass2}
+ assert_raise(NoMethodError, /private method/) {o.aClass}
+ assert_raise(NoMethodError, /private method/) {o.aClass2}
+
+ o = (c = Class.new(AClass)).new
+ c.class_eval {private [:aClass, :aClass2]}
+ assert_raise(NoMethodError, /private method/) {o.aClass}
+ assert_raise(NoMethodError, /private method/) {o.aClass2}
+
+ o = AClass.new
+ assert_equal(:aClass, o.aClass)
+ assert_raise(NoMethodError, /private method/) {o.aClass1}
+ assert_raise(NoMethodError, /protected method/) {o.aClass2}
+ end
+
+ def test_s_protected
+ aclass = Class.new(AClass) do
+ def _aClass(o) o.aClass; end
+ def _aClass1(o) o.aClass1; end
+ def _aClass2(o) o.aClass2; end
+ end
+
+ o = (c = Class.new(aclass)).new
+ assert_equal(:aClass, o.aClass)
+ c.class_eval {protected :aClass}
+ assert_raise(NoMethodError, /protected method/) {o.aClass}
+ assert_equal(:aClass, c.new._aClass(o))
+
+ o = (c = Class.new(aclass)).new
+ c.class_eval {protected :aClass, :aClass1}
+ assert_raise(NoMethodError, /protected method/) {o.aClass}
+ assert_raise(NoMethodError, /protected method/) {o.aClass1}
+ assert_equal(:aClass, c.new._aClass(o))
+ assert_equal(:aClass1, c.new._aClass1(o))
+
+ o = (c = Class.new(aclass)).new
+ c.class_eval {protected [:aClass, :aClass1]}
+ assert_raise(NoMethodError, /protected method/) {o.aClass}
+ assert_raise(NoMethodError, /protected method/) {o.aClass1}
+ assert_equal(:aClass, c.new._aClass(o))
+ assert_equal(:aClass1, c.new._aClass1(o))
+
+ o = AClass.new
+ assert_equal(:aClass, o.aClass)
+ assert_raise(NoMethodError, /private method/) {o.aClass1}
+ assert_raise(NoMethodError, /protected method/) {o.aClass2}
+ end
+
+ def test_visibility_method_return_value
+ no_arg_results = nil
+ c = Module.new do
+ singleton_class.send(:public, :public, :private, :protected, :module_function)
+ def foo; end
+ def bar; end
+ no_arg_results = [public, private, protected, module_function]
+ end
+
+ assert_equal([nil]*4, no_arg_results)
+
+ assert_equal(:foo, c.private(:foo))
+ assert_equal(:foo, c.public(:foo))
+ assert_equal(:foo, c.protected(:foo))
+ assert_equal(:foo, c.module_function(:foo))
+
+ assert_equal([:foo, :bar], c.private(:foo, :bar))
+ assert_equal([:foo, :bar], c.public(:foo, :bar))
+ assert_equal([:foo, :bar], c.protected(:foo, :bar))
+ assert_equal([:foo, :bar], c.module_function(:foo, :bar))
+ end
+
def test_s_constants
c1 = Module.constants
Object.module_eval "WALTER = 99"
@@ -890,14 +1177,19 @@ class TestModule < Test::Unit::TestCase
end
def test_attr_obsoleted_flag
- c = Class.new
- c.class_eval do
+ c = Class.new do
+ extend Test::Unit::Assertions
+ extend Test::Unit::CoreAssertions
def initialize
@foo = :foo
@bar = :bar
end
- attr :foo, true
- attr :bar, false
+ assert_deprecated_warning(/optional boolean argument/) do
+ attr :foo, true
+ end
+ assert_deprecated_warning(/optional boolean argument/) do
+ attr :bar, false
+ end
end
o = c.new
assert_equal(true, o.respond_to?(:foo))
@@ -942,6 +1234,7 @@ class TestModule < Test::Unit::TestCase
assert_equal(:foo, c2.const_get(:Foo))
assert_raise(NameError) { c2.const_get(:Foo, false) }
+ c1.__send__(:remove_const, :Foo)
eval("c1::Foo = :foo")
assert_raise(NameError) { c1::Bar }
assert_raise(NameError) { c2::Bar }
@@ -980,8 +1273,11 @@ class TestModule < Test::Unit::TestCase
assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-16le"), :foo) }
assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-32be"), :foo) }
assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-32le"), :foo) }
+
cx = EnvUtil.labeled_class("X\u{3042}")
- assert_raise_with_message(TypeError, /X\u{3042}/) { c1.const_set(cx, :foo) }
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /X\u{3042}/) { c1.const_set(cx, :foo) }
+ end
end
def test_const_get_invalid_name
@@ -1037,8 +1333,6 @@ class TestModule < Test::Unit::TestCase
end
end
include LangModuleSpecInObject
- module LangModuleTop
- end
puts "ok" if LangModuleSpecInObject::LangModuleTop == LangModuleTop
INPUT
@@ -1139,6 +1433,39 @@ class TestModule < Test::Unit::TestCase
assert_raise(NameError) do
c.instance_eval { attr_reader :"." }
end
+
+ c = Class.new
+ assert_equal([:a], c.class_eval { attr :a })
+ assert_equal([:b, :c], c.class_eval { attr :b, :c })
+ assert_equal([:d], c.class_eval { attr_reader :d })
+ assert_equal([:e, :f], c.class_eval { attr_reader :e, :f })
+ assert_equal([:g=], c.class_eval { attr_writer :g })
+ assert_equal([:h=, :i=], c.class_eval { attr_writer :h, :i })
+ assert_equal([:j, :j=], c.class_eval { attr_accessor :j })
+ assert_equal([:k, :k=, :l, :l=], c.class_eval { attr_accessor :k, :l })
+
+ c = Class.new
+ assert_equal([:a], c.class_eval { attr "a" })
+ assert_equal([:b, :c], c.class_eval { attr "b", "c" })
+ assert_equal([:d], c.class_eval { attr_reader "d" })
+ assert_equal([:e, :f], c.class_eval { attr_reader "e", "f" })
+ assert_equal([:g=], c.class_eval { attr_writer "g" })
+ assert_equal([:h=, :i=], c.class_eval { attr_writer "h", "i" })
+ assert_equal([:j, :j=], c.class_eval { attr_accessor "j" })
+ assert_equal([:k, :k=, :l, :l=], c.class_eval { attr_accessor "k", "l" })
+ end
+
+ def test_alias_method
+ c = Class.new do
+ def foo; :foo end
+ end
+ o = c.new
+ assert_respond_to(o, :foo)
+ assert_not_respond_to(o, :bar)
+ r = c.class_eval {alias_method :bar, :foo}
+ assert_respond_to(o, :bar)
+ assert_equal(:foo, o.bar)
+ assert_equal(:bar, r)
end
def test_undef
@@ -1157,8 +1484,8 @@ class TestModule < Test::Unit::TestCase
class << o; self; end.instance_eval { undef_method(:foo) }
end
- %w(object_id __send__ initialize).each do |n|
- assert_in_out_err([], <<-INPUT, [], %r"warning: undefining `#{n}' may cause serious problems$")
+ %w(object_id __id__ __send__ initialize).each do |n|
+ assert_in_out_err([], <<-INPUT, [], %r"warning: undefining '#{n}' may cause serious problems$")
$VERBOSE = false
Class.new.instance_eval { undef_method(:#{n}) }
INPUT
@@ -1288,13 +1615,25 @@ class TestModule < Test::Unit::TestCase
end
def test_top_public_private
- assert_in_out_err([], <<-INPUT, %w([:foo] [:bar]), [])
+ assert_in_out_err([], <<-INPUT, %w([:foo] [:bar] [:bar,\ :foo] [] [:bar,\ :foo] []), [])
private
def foo; :foo; end
public
def bar; :bar; end
p self.private_methods.grep(/^foo$|^bar$/)
p self.methods.grep(/^foo$|^bar$/)
+
+ private :foo, :bar
+ p self.private_methods.grep(/^foo$|^bar$/).sort
+
+ public :foo, :bar
+ p self.private_methods.grep(/^foo$|^bar$/).sort
+
+ private [:foo, :bar]
+ p self.private_methods.grep(/^foo$|^bar$/).sort
+
+ public [:foo, :bar]
+ p self.private_methods.grep(/^foo$|^bar$/).sort
INPUT
end
@@ -1405,6 +1744,47 @@ class TestModule < Test::Unit::TestCase
assert_equal("TestModule::C\u{df}", c.name, '[ruby-core:24600]')
c = Module.new.module_eval("class X\u{df} < Module; self; end")
assert_match(/::X\u{df}:/, c.new.to_s)
+ ensure
+ Object.send(:remove_const, "C\u{df}")
+ end
+
+
+ def test_const_added
+ eval(<<~RUBY)
+ module TestConstAdded
+ @memo = []
+ class << self
+ attr_accessor :memo
+
+ def const_added(sym)
+ memo << sym
+ end
+ end
+ CONST = 1
+ module SubModule
+ end
+
+ class SubClass
+ end
+ end
+ TestConstAdded::OUTSIDE_CONST = 2
+ module TestConstAdded::OutsideSubModule; end
+ class TestConstAdded::OutsideSubClass; end
+ RUBY
+ TestConstAdded.const_set(:CONST_SET, 3)
+ assert_equal [
+ :CONST,
+ :SubModule,
+ :SubClass,
+ :OUTSIDE_CONST,
+ :OutsideSubModule,
+ :OutsideSubClass,
+ :CONST_SET,
+ ], TestConstAdded.memo
+ ensure
+ if self.class.const_defined? :TestConstAdded
+ self.class.send(:remove_const, :TestConstAdded)
+ end
end
def test_method_added
@@ -1755,23 +2135,30 @@ class TestModule < Test::Unit::TestCase
c = Class.new
c.const_set(:FOO, "foo")
c.deprecate_constant(:FOO)
- assert_warn(/deprecated/) {c::FOO}
- assert_warn(/#{c}::FOO is deprecated/) {Class.new(c)::FOO}
+ assert_warn(/deprecated/) do
+ Warning[:deprecated] = true
+ c::FOO
+ end
+ assert_warn(/#{c}::FOO is deprecated/) do
+ Warning[:deprecated] = true
+ Class.new(c)::FOO
+ end
bug12382 = '[ruby-core:75505] [Bug #12382]'
- assert_warn(/deprecated/, bug12382) {c.class_eval "FOO"}
- Warning[:deprecated] = false
- assert_warn('') {c::FOO}
- end
-
- NIL = nil
- FALSE = false
- deprecate_constant(:NIL, :FALSE)
-
- def test_deprecate_nil_constant
- w = EnvUtil.verbose_warning {2.times {FALSE}}
- assert_equal(1, w.scan("::FALSE").size, w)
- w = EnvUtil.verbose_warning {2.times {NIL}}
- assert_equal(1, w.scan("::NIL").size, w)
+ assert_warn(/deprecated/, bug12382) do
+ Warning[:deprecated] = true
+ c.class_eval "FOO"
+ end
+ assert_warn('') do
+ Warning[:deprecated] = false
+ c::FOO
+ end
+ assert_warn('') do
+ Warning[:deprecated] = false
+ Class.new(c)::FOO
+ end
+ assert_warn(/deprecated/) do
+ c.class_eval {remove_const "FOO"}
+ end
end
def test_constants_with_private_constant
@@ -1980,6 +2367,18 @@ class TestModule < Test::Unit::TestCase
assert_equal(:foo, removed)
end
+ def test_frozen_prepend_remove_method
+ [Module, Class].each do |klass|
+ mod = klass.new do
+ prepend(Module.new)
+ def foo; end
+ end
+ mod.freeze
+ assert_raise(FrozenError, '[Bug #19166]') { mod.send(:remove_method, :foo) }
+ assert_equal([:foo], mod.instance_methods(false))
+ end
+ end
+
def test_prepend_class_ancestors
bug6658 = '[ruby-core:45919]'
m = labeled_module("m")
@@ -2011,7 +2410,7 @@ class TestModule < Test::Unit::TestCase
assert_equal([:c2, :m0, :m1, :m2, :c0], c2.new.x)
m3 = labeled_module("m3") {include m1; prepend m1}
- assert_equal([m3, m0, m1], m3.ancestors)
+ assert_equal([m0, m1, m3, m0, m1], m3.ancestors)
m3 = labeled_module("m3") {prepend m1; include m1}
assert_equal([m0, m1, m3], m3.ancestors)
m3 = labeled_module("m3") {prepend m1; prepend m1}
@@ -2092,6 +2491,137 @@ class TestModule < Test::Unit::TestCase
assert_equal(0, 1 / 2)
end
+ def test_visibility_after_refine_and_visibility_change_with_origin_class
+ m = Module.new
+ c = Class.new do
+ def x; :x end
+ end
+ c.prepend(m)
+ Module.new do
+ refine c do
+ def x; :y end
+ end
+ end
+
+ o1 = c.new
+ o2 = c.new
+ assert_equal(:x, o1.public_send(:x))
+ assert_equal(:x, o2.public_send(:x))
+ o1.singleton_class.send(:private, :x)
+ o2.singleton_class.send(:public, :x)
+
+ assert_raise(NoMethodError) { o1.public_send(:x) }
+ assert_equal(:x, o2.public_send(:x))
+ end
+
+ def test_visibility_after_multiple_refine_and_visibility_change_with_origin_class
+ m = Module.new
+ c = Class.new do
+ def x; :x end
+ end
+ c.prepend(m)
+ Module.new do
+ refine c do
+ def x; :y end
+ end
+ end
+ Module.new do
+ refine c do
+ def x; :z end
+ end
+ end
+
+ o1 = c.new
+ o2 = c.new
+ assert_equal(:x, o1.public_send(:x))
+ assert_equal(:x, o2.public_send(:x))
+ o1.singleton_class.send(:private, :x)
+ o2.singleton_class.send(:public, :x)
+
+ assert_raise(NoMethodError) { o1.public_send(:x) }
+ assert_equal(:x, o2.public_send(:x))
+ end
+
+ def test_visibility_after_refine_and_visibility_change_without_origin_class
+ c = Class.new do
+ def x; :x end
+ end
+ Module.new do
+ refine c do
+ def x; :y end
+ end
+ end
+ o1 = c.new
+ o2 = c.new
+ o1.singleton_class.send(:private, :x)
+ o2.singleton_class.send(:public, :x)
+ assert_raise(NoMethodError) { o1.public_send(:x) }
+ assert_equal(:x, o2.public_send(:x))
+ end
+
+ def test_visibility_after_multiple_refine_and_visibility_change_without_origin_class
+ c = Class.new do
+ def x; :x end
+ end
+ Module.new do
+ refine c do
+ def x; :y end
+ end
+ end
+ Module.new do
+ refine c do
+ def x; :z end
+ end
+ end
+ o1 = c.new
+ o2 = c.new
+ o1.singleton_class.send(:private, :x)
+ o2.singleton_class.send(:public, :x)
+ assert_raise(NoMethodError) { o1.public_send(:x) }
+ assert_equal(:x, o2.public_send(:x))
+ end
+
+ def test_visibility_after_refine_and_visibility_change_with_superclass
+ c = Class.new do
+ def x; :x end
+ end
+ sc = Class.new(c)
+ Module.new do
+ refine sc do
+ def x; :y end
+ end
+ end
+ o1 = sc.new
+ o2 = sc.new
+ o1.singleton_class.send(:private, :x)
+ o2.singleton_class.send(:public, :x)
+ assert_raise(NoMethodError) { o1.public_send(:x) }
+ assert_equal(:x, o2.public_send(:x))
+ end
+
+ def test_visibility_after_multiple_refine_and_visibility_change_with_superclass
+ c = Class.new do
+ def x; :x end
+ end
+ sc = Class.new(c)
+ Module.new do
+ refine sc do
+ def x; :y end
+ end
+ end
+ Module.new do
+ refine sc do
+ def x; :z end
+ end
+ end
+ o1 = sc.new
+ o2 = sc.new
+ o1.singleton_class.send(:private, :x)
+ o2.singleton_class.send(:public, :x)
+ assert_raise(NoMethodError) { o1.public_send(:x) }
+ assert_equal(:x, o2.public_send(:x))
+ end
+
def test_prepend_visibility
bug8005 = '[ruby-core:53106] [Bug #8005]'
c = Class.new do
@@ -2355,6 +2885,7 @@ class TestModule < Test::Unit::TestCase
def test_invalid_attr
%W[
+ foo=
foo?
@foo
@@foo
@@ -2383,7 +2914,7 @@ class TestModule < Test::Unit::TestCase
def test_uninitialized_instance_variable
a = AttrTest.new
- assert_warning(/instance variable @ivar not initialized/) do
+ assert_warning('') do
assert_nil(a.ivar)
end
a.instance_variable_set(:@ivar, 42)
@@ -2392,7 +2923,7 @@ class TestModule < Test::Unit::TestCase
end
name = "@\u{5909 6570}"
- assert_warning(/instance variable #{name} not initialized/) do
+ assert_warning('') do
assert_nil(a.instance_eval(name))
end
end
@@ -2485,17 +3016,17 @@ class TestModule < Test::Unit::TestCase
bug11532 = '[ruby-core:70828] [Bug #11532]'
c = Class.new {const_set(:A, 1)}.freeze
- assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
+ assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {private_constant :A}
}
c = Class.new {const_set(:A, 1); private_constant :A}.freeze
- assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
+ assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {public_constant :A}
}
c = Class.new {const_set(:A, 1)}.freeze
- assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
+ assert_raise_with_message(FrozenError, /frozen Class/, bug11532) {
c.class_eval {deprecate_constant :A}
}
end
@@ -2521,31 +3052,6 @@ class TestModule < Test::Unit::TestCase
assert_raise(NoMethodError, bug8284) {Object.remove_const}
end
- def test_include_module_with_constants_does_not_invalidate_method_cache
- assert_in_out_err([], <<-RUBY, %w(123 456 true), [])
- A = 123
-
- class Foo
- def self.a
- A
- end
- end
-
- module M
- A = 456
- end
-
- puts Foo.a
- starting = RubyVM.stat[:global_method_state]
-
- Foo.send(:include, M)
-
- ending = RubyVM.stat[:global_method_state]
- puts Foo.a
- puts starting == ending
- RUBY
- end
-
def test_return_value_of_define_method
retvals = []
Class.new.class_eval do
@@ -2567,7 +3073,7 @@ class TestModule < Test::Unit::TestCase
end
def test_prepend_gc
- assert_separately [], %{
+ assert_ruby_status [], %{
module Foo
end
class Object
@@ -2582,6 +3088,61 @@ class TestModule < Test::Unit::TestCase
}
end
+ def test_prepend_constant_lookup
+ m = Module.new do
+ const_set(:C, :m)
+ end
+ c = Class.new do
+ const_set(:C, :c)
+ prepend m
+ end
+ sc = Class.new(c)
+ # Situation from [Bug #17887]
+ assert_equal(sc.ancestors.take(3), [sc, m, c])
+ assert_equal(:m, sc.const_get(:C))
+ assert_equal(:m, sc::C)
+
+ assert_equal(:c, c::C)
+
+ m.send(:remove_const, :C)
+ assert_equal(:c, sc.const_get(:C))
+ assert_equal(:c, sc::C)
+
+ # Same ancestors, built with include instead of prepend
+ m = Module.new do
+ const_set(:C, :m)
+ end
+ c = Class.new do
+ const_set(:C, :c)
+ end
+ sc = Class.new(c) do
+ include m
+ end
+
+ assert_equal(sc.ancestors.take(3), [sc, m, c])
+ assert_equal(:m, sc.const_get(:C))
+ assert_equal(:m, sc::C)
+
+ m.send(:remove_const, :C)
+ assert_equal(:c, sc.const_get(:C))
+ assert_equal(:c, sc::C)
+
+ # Situation from [Bug #17887], but with modules
+ m = Module.new do
+ const_set(:C, :m)
+ end
+ m2 = Module.new do
+ const_set(:C, :m2)
+ prepend m
+ end
+ c = Class.new do
+ include m2
+ end
+ assert_equal(c.ancestors.take(3), [c, m, m2])
+ assert_equal(:m, c.const_get(:C))
+ assert_equal(:m, c::C)
+ end
+
def test_inspect_segfault
bug_10282 = '[ruby-core:65214] [Bug #10282]'
assert_separately [], "#{<<~"begin;"}\n#{<<~'end;'}"
@@ -2609,6 +3170,19 @@ class TestModule < Test::Unit::TestCase
end;
end
+ def test_define_method_changes_visibility_with_existing_method_bug_19749
+ c = Class.new do
+ def a; end
+ private def b; end
+
+ define_method(:b, instance_method(:b))
+ private
+ define_method(:a, instance_method(:a))
+ end
+ assert_equal([:b], c.public_instance_methods(false))
+ assert_equal([:a], c.private_instance_methods(false))
+ end
+
def test_define_method_with_unbound_method
# Passing an UnboundMethod to define_method succeeds if it is from an ancestor
assert_nothing_raised do
@@ -2724,6 +3298,115 @@ class TestModule < Test::Unit::TestCase
assert_not_predicate m.clone(freeze: false), :frozen?
end
+ def test_module_name_in_singleton_method
+ s = Object.new.singleton_class
+ mod = s.const_set(:Foo, Module.new)
+ assert_match(/::Foo$/, mod.name, '[Bug #14895]')
+ end
+
+ def test_iclass_memory_leak
+ # [Bug #19550]
+ assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true)
+ code = proc do
+ mod = Module.new
+ Class.new do
+ include mod
+ end
+ end
+ 1_000.times(&code)
+ PREP
+ 3_000_000.times(&code)
+ CODE
+ end
+
+ def test_complemented_method_entry_memory_leak
+ # [Bug #19894] [Bug #19896]
+ assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true)
+ code = proc do
+ $c = Class.new do
+ def foo; end
+ end
+
+ $m = Module.new do
+ refine $c do
+ def foo; end
+ end
+ end
+
+ Class.new do
+ using $m
+
+ def initialize
+ o = $c.new
+ o.method(:foo).unbind
+ end
+ end.new
+ end
+ 1_000.times(&code)
+ PREP
+ 300_000.times(&code)
+ CODE
+ end
+
+ def test_module_clone_memory_leak
+ # [Bug #19901]
+ assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true)
+ code = proc do
+ Module.new.clone
+ end
+ 1_000.times(&code)
+ PREP
+ 1_000_000.times(&code)
+ CODE
+ end
+
+ def test_set_temporary_name
+ m = Module.new
+ assert_nil m.name
+
+ m.const_set(:N, Module.new)
+
+ assert_match(/\A#<Module:0x\h+>::N\z/, m::N.name)
+ assert_same m::N, m::N.set_temporary_name(name = "fake_name_under_M")
+ name.upcase!
+ assert_equal("fake_name_under_M", m::N.name)
+ assert_raise(FrozenError) {m::N.name.upcase!}
+ assert_same m::N, m::N.set_temporary_name(nil)
+ assert_nil(m::N.name)
+
+ m::N.const_set(:O, Module.new)
+ m.const_set(:Recursive, m)
+ m::N.const_set(:Recursive, m)
+ m.const_set(:A, 42)
+
+ assert_same m, m.set_temporary_name(name = "fake_name")
+ name.upcase!
+ assert_equal("fake_name", m.name)
+ assert_raise(FrozenError) {m.name.upcase!}
+ assert_equal("fake_name::N", m::N.name)
+ assert_equal("fake_name::N::O", m::N::O.name)
+
+ assert_same m, m.set_temporary_name(nil)
+ assert_nil m.name
+ assert_nil m::N.name
+ assert_nil m::N::O.name
+
+ assert_raise_with_message(ArgumentError, "empty class/module name") do
+ m.set_temporary_name("")
+ end
+ %w[A A::B ::A ::A::B].each do |name|
+ assert_raise_with_message(ArgumentError, /must not be a constant path/) do
+ m.set_temporary_name(name)
+ end
+ end
+
+ [Object, User, AClass].each do |mod|
+ assert_raise_with_message(RuntimeError, /permanent name/) do
+ mod.set_temporary_name("fake_name")
+ end
+ end
+ end
+
private
def assert_top_method_is_private(method)
@@ -2731,7 +3414,7 @@ class TestModule < Test::Unit::TestCase
methods = singleton_class.private_instance_methods(false)
assert_include(methods, :#{method}, ":#{method} should be private")
- assert_raise_with_message(NoMethodError, "private method `#{method}' called for main:Object") {
+ assert_raise_with_message(NoMethodError, /^private method '#{method}' called for /) {
recv = self
recv.#{method}
}