diff options
Diffstat (limited to 'test/ruby/test_module.rb')
| -rw-r--r-- | test/ruby/test_module.rb | 1240 |
1 files changed, 1128 insertions, 112 deletions
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 37045ad0d9..9ed6c1e321 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -9,29 +9,31 @@ 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 def teardown $VERBOSE = @verbose + Warning[:deprecated] = @deprecated end def test_LT_0 @@ -85,8 +87,11 @@ class TestModule < Test::Unit::TestCase private :user3 end - module Other - def other + OtherSetup = -> do + remove_const :Other if defined? ::TestModule::Other + module Other + def other + end end end @@ -220,6 +225,8 @@ class TestModule < Test::Unit::TestCase @@class_eval = 'b' def test_class_eval + OtherSetup.call + Other.class_eval("CLASS_EVAL = 1") assert_equal(1, Other::CLASS_EVAL) assert_include(Other.constants, :CLASS_EVAL) @@ -246,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) @@ -260,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 @@ -294,6 +309,8 @@ class TestModule < Test::Unit::TestCase end def test_nested_get + OtherSetup.call + assert_equal Other, Object.const_get([self.class, 'Other'].join('::')) assert_equal User::USER, self.class.const_get([User, 'USER'].join('::')) assert_raise(NameError) { @@ -302,6 +319,8 @@ class TestModule < Test::Unit::TestCase end def test_nested_get_symbol + OtherSetup.call + const = [self.class, Other].join('::').to_sym assert_raise(NameError) {Object.const_get(const)} @@ -328,6 +347,8 @@ class TestModule < Test::Unit::TestCase end def test_nested_defined + OtherSetup.call + assert_send([Object, :const_defined?, [self.class.name, 'Other'].join('::')]) assert_send([self.class, :const_defined?, 'User::USER']) assert_not_send([self.class, :const_defined?, 'User::Foo']) @@ -335,6 +356,8 @@ class TestModule < Test::Unit::TestCase end def test_nested_defined_symbol + OtherSetup.call + const = [self.class, Other].join('::').to_sym assert_raise(NameError) {Object.const_defined?(const)} @@ -360,6 +383,8 @@ class TestModule < Test::Unit::TestCase end def test_const_set + OtherSetup.call + assert_not_operator(Other, :const_defined?, :KOALA) Other.const_set(:KOALA, 99) assert_operator(Other, :const_defined?, :KOALA) @@ -387,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 @@ -409,15 +422,61 @@ 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 - assert_empty(m.instance_methods, bug9813) - assert_empty(m.instance_variables, bug9813) - assert_empty(m.constants, bug9813) + end + + class Bug18185 < Module + module InstanceMethods + end + attr_reader :ancestor_list + def initialize + @ancestor_list = ancestors + include InstanceMethods + end + 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 + OtherSetup.call + bug6454 = '[ruby-core:45132]' a = Module.new @@ -459,6 +518,189 @@ 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 + def b; 2 end + prepend m + 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_ruby_status([], <<-EOS) + 10000.times { |i| + m1 = Module.new do + def foo; end + end + m2 = Module.new do + prepend m1 + def bar; end + end + m3 = Module.new do + def baz; end + prepend m2 + end + Class.new do + prepend m3 + end + } + GC.start + EOS + end + + def test_refine_module_then_include + assert_separately([], "#{<<~"end;"}\n") + module M + end + class C + include M + end + module RefinementBug + refine M do + def refined_method + :rm + end + end + end + using RefinementBug + + class A + include M + end + + assert_equal(:rm, C.new.refined_method) + end; + end + + def test_include_into_module_already_included + c = Class.new{def foo; [:c] end} + modules = lambda do || + sub = Class.new(c){def foo; [:sc] + super end} + [ + Module.new{def foo; [:m1] + super end}, + Module.new{def foo; [:m2] + super end}, + Module.new{def foo; [:m3] + super end}, + sub, + sub.new + ] + end + + m1, m2, m3, sc, o = modules.call + assert_equal([:sc, :c], o.foo) + sc.include m1 + assert_equal([:sc, :m1, :c], o.foo) + m1.include m2 + assert_equal([:sc, :m1, :m2, :c], o.foo) + m2.include m3 + assert_equal([:sc, :m1, :m2, :m3, :c], o.foo) + + m1, m2, m3, sc, o = modules.call + sc.prepend m1 + assert_equal([:m1, :sc, :c], o.foo) + m1.include m2 + assert_equal([:m1, :m2, :sc, :c], o.foo) + m2.include m3 + assert_equal([:m1, :m2, :m3, :sc, :c], o.foo) + + m1, m2, m3, sc, o = modules.call + sc.include m2 + assert_equal([:sc, :m2, :c], o.foo) + sc.prepend m1 + assert_equal([:m1, :sc, :m2, :c], o.foo) + m1.include m2 + assert_equal([:m1, :sc, :m2, :c], o.foo) + m1.include m3 + assert_equal([:m1, :m3, :sc, :m2, :c], o.foo) + + m1, m2, m3, sc, o = modules.call + sc.include m3 + sc.include m2 + assert_equal([:sc, :m2, :m3, :c], o.foo) + sc.prepend m1 + assert_equal([:m1, :sc, :m2, :m3, :c], o.foo) + m1.include m2 + m1.include m3 + assert_equal([:m1, :sc, :m2, :m3, :c], o.foo) + + m1, m2, m3, sc, o = modules.call + assert_equal([:sc, :c], o.foo) + sc.prepend m1 + assert_equal([:m1, :sc, :c], o.foo) + m1.prepend m2 + assert_equal([:m2, :m1, :sc, :c], o.foo) + m2.prepend m3 + assert_equal([:m3, :m2, :m1, :sc, :c], o.foo) + m1, m2, m3, sc, o = modules.call + sc.include m1 + assert_equal([:sc, :m1, :c], o.foo) + sc.prepend m2 + assert_equal([:m2, :sc, :m1, :c], o.foo) + sc.prepend m3 + assert_equal([:m3, :m2, :sc, :m1, :c], o.foo) + m1, m2, m3, sc, o = modules.call + sc.include m1 + assert_equal([:sc, :m1, :c], o.foo) + m2.prepend m3 + m1.include m2 + assert_equal([:sc, :m1, :m3, :m2, :c], o.foo) + end + def test_included_modules assert_equal([], Mixin.included_modules) assert_equal([Mixin], User.included_modules) @@ -469,6 +711,92 @@ class TestModule < Test::Unit::TestCase assert_equal([Comparable, Kernel], String.included_modules - mixins) end + def test_included_modules_with_prepend + m1 = Module.new + m2 = Module.new + m3 = Module.new + + m2.prepend m1 + m3.include m2 + 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) @@ -485,40 +813,45 @@ 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 + remove_const :FOO + end end def module_exec_aux @@ -549,6 +882,14 @@ class TestModule < Test::Unit::TestCase def dynamically_added_method_4; end end assert_method_defined?(User, :dynamically_added_method_4) + + # cleanup + User.class_eval do + remove_method :dynamically_added_method_1 + remove_method :dynamically_added_method_2 + remove_method :dynamically_added_method_3 + remove_method :dynamically_added_method_4 + end end def test_module_eval @@ -563,6 +904,28 @@ class TestModule < Test::Unit::TestCase assert_equal("Integer", Integer.name) assert_equal("TestModule::Mixin", Mixin.name) assert_equal("TestModule::User", User.name) + + assert_predicate Integer.name, :frozen? + assert_predicate Mixin.name, :frozen? + assert_predicate User.name, :frozen? + end + + def test_accidental_singleton_naming_with_module + o = Object.new + assert_nil(o.singleton_class.name) + class << o + module Hi; end + end + assert_nil(o.singleton_class.name) + end + + def test_accidental_singleton_naming_with_class + o = Object.new + assert_nil(o.singleton_class.name) + class << o + class Hi; end + end + assert_nil(o.singleton_class.name) end def test_classpath @@ -570,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) @@ -586,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 @@ -614,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 @@ -621,12 +996,125 @@ 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" c2 = Module.constants assert_equal([:WALTER], c2 - c1) + Object.class_eval do + remove_const :WALTER + end + assert_equal([], Module.constants(true)) assert_equal([], Module.constants(false)) @@ -689,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)) @@ -705,6 +1198,32 @@ class TestModule < Test::Unit::TestCase assert_equal(false, o.respond_to?(:bar=)) end + def test_attr_public_at_toplevel + s = Object.new + TOPLEVEL_BINDING.eval(<<-END).call(s.singleton_class) + proc do |c| + c.send(:attr_accessor, :x) + c.send(:attr, :y) + c.send(:attr_reader, :z) + c.send(:attr_writer, :w) + end + END + assert_nil s.x + s.x = 1 + assert_equal 1, s.x + + assert_nil s.y + s.instance_variable_set(:@y, 2) + assert_equal 2, s.y + + assert_nil s.z + s.instance_variable_set(:@z, 3) + assert_equal 3, s.z + + s.w = 4 + assert_equal 4, s.instance_variable_get(:@w) + end + def test_const_get_evaled c1 = Class.new c2 = Class.new(c1) @@ -715,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 } @@ -753,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 @@ -810,8 +1333,6 @@ class TestModule < Test::Unit::TestCase end end include LangModuleSpecInObject - module LangModuleTop - end puts "ok" if LangModuleSpecInObject::LangModuleTop == LangModuleTop INPUT @@ -912,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 @@ -930,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 @@ -1061,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 @@ -1178,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 @@ -1346,6 +1953,17 @@ class TestModule < Test::Unit::TestCase assert_match(/: warning: previous definition of foo/, stderr) end + def test_module_function_inside_method + assert_warn(/calling module_function without arguments inside a method may not have the intended effect/, '[ruby-core:79751]') do + Module.new do + def self.foo + module_function + end + foo + end + end + end + def test_protected_singleton_method klass = Class.new x = klass.new @@ -1517,21 +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"} - 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 @@ -1740,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") @@ -1771,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} @@ -1852,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 @@ -1894,6 +2664,33 @@ class TestModule < Test::Unit::TestCase assert_include(im, mixin, bug8025) end + def test_prepended_module_with_super_and_alias + bug16736 = '[Bug #16736]' + + a = labeled_class("A") do + def m; "A"; end + end + m = labeled_module("M") do + prepend Module.new + + def self.included(base) + base.alias_method :base_m, :m + end + + def m + super + "M" + end + + def m2 + base_m + end + end + b = labeled_class("B", a) do + include m + end + assert_equal("AM", b.new.m2, bug16736) + end + def test_prepend_super_in_alias bug7842 = '[Bug #7842]' @@ -2012,6 +2809,22 @@ class TestModule < Test::Unit::TestCase assert_equal([:@@bar], m2.class_variables(false)) end + def test_class_variable_in_dup_class + a = Class.new do + @@a = 'A' + def a=(x) + @@a = x + end + def a + @@a + end + end + + b = a.dup + b.new.a = 'B' + assert_equal 'A', a.new.a, '[ruby-core:17019]' + end + Bug6891 = '[ruby-core:47241]' def test_extend_module_with_protected_method @@ -2072,6 +2885,7 @@ class TestModule < Test::Unit::TestCase def test_invalid_attr %W[ + foo= foo? @foo @@foo @@ -2088,6 +2902,9 @@ class TestModule < Test::Unit::TestCase class AttrTest class << self attr_accessor :cattr + def reset + self.cattr = nil + end end attr_accessor :iattr def ivar @@ -2097,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) @@ -2106,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 @@ -2130,6 +2947,8 @@ class TestModule < Test::Unit::TestCase assert_warning '' do assert_equal(42, AttrTest.cattr) end + + AttrTest.reset end def test_uninitialized_attr_non_object @@ -2197,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 @@ -2233,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 @@ -2279,7 +3073,7 @@ class TestModule < Test::Unit::TestCase end def test_prepend_gc - assert_separately [], %{ + assert_ruby_status [], %{ module Foo end class Object @@ -2294,9 +3088,67 @@ 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 [], <<-RUBY + assert_separately [], "#{<<~"begin;"}\n#{<<~'end;'}" + bug_10282 = "#{bug_10282}" + begin; + line = __LINE__ + 2 module ShallowInspect def shallow_inspect "foo" @@ -2313,9 +3165,22 @@ class TestModule < Test::Unit::TestCase A.prepend InspectIsShallow - expect = "#<Method: A(ShallowInspect)#inspect(shallow_inspect) -:7>" - assert_equal expect, A.new.method(:inspect).inspect, "#{bug_10282}" - RUBY + expect = "#<Method: A(ShallowInspect)#inspect(shallow_inspect)() -:#{line}>" + assert_equal expect, A.new.method(:inspect).inspect, bug_10282 + 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 @@ -2339,15 +3204,17 @@ class TestModule < Test::Unit::TestCase def test_redefinition_mismatch m = Module.new - m.module_eval "A = 1" - assert_raise_with_message(TypeError, /is not a module/) { + m.module_eval "A = 1", __FILE__, line = __LINE__ + e = assert_raise_with_message(TypeError, /is not a module/) { m.module_eval "module A; end" } + assert_include(e.message, "#{__FILE__}:#{line}: previous definition") n = "M\u{1f5ff}" - m.module_eval "#{n} = 42" - assert_raise_with_message(TypeError, "#{n} is not a module") { + m.module_eval "#{n} = 42", __FILE__, line = __LINE__ + e = assert_raise_with_message(TypeError, /#{n} is not a module/) { m.module_eval "module #{n}; end" } + assert_include(e.message, "#{__FILE__}:#{line}: previous definition") assert_separately([], <<-"end;") Etc = (class C\u{1f5ff}; self; end).new @@ -2392,6 +3259,154 @@ class TestModule < Test::Unit::TestCase } end + module CloneTestM_simple + C = 1 + def self.m; C; end + end + + module CloneTestM0 + def foo; TEST; end + end + + CloneTestM1 = CloneTestM0.clone + CloneTestM2 = CloneTestM0.clone + module CloneTestM1 + TEST = :M1 + end + module CloneTestM2 + TEST = :M2 + end + class CloneTestC1 + include CloneTestM1 + end + class CloneTestC2 + include CloneTestM2 + end + + def test_constant_access_from_method_in_cloned_module + m = CloneTestM_simple.dup + assert_equal 1, m::C, '[ruby-core:47834]' + assert_equal 1, m.m, '[ruby-core:47834]' + + assert_equal :M1, CloneTestC1.new.foo, '[Bug #15877]' + 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 + + 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) @@ -2399,8 +3414,9 @@ 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") { - self.#{method} + assert_raise_with_message(NoMethodError, /^private method '#{method}' called for /) { + recv = self + recv.#{method} } } end |
