require 'test/unit' require 'pp' require_relative 'envutil' $m0 = Module.nesting class TestModule < Test::Unit::TestCase def _wrap_assertion yield end def assert_method_defined?(klass, mid, message="") message = build_message(message, "#{klass}\##{mid} expected to be defined.") _wrap_assertion do klass.method_defined?(mid) or raise Test::Unit::AssertionFailedError, message, caller(3) end end def assert_method_not_defined?(klass, mid, message="") message = build_message(message, "#{klass}\##{mid} expected to not be defined.") _wrap_assertion do klass.method_defined?(mid) and raise Test::Unit::AssertionFailedError, message, caller(3) end end def setup @verbose = $VERBOSE $VERBOSE = nil end def teardown $VERBOSE = @verbose end def test_LT_0 assert_equal true, String < Object assert_equal false, Object < String assert_nil String < Array assert_equal true, Array < Enumerable assert_equal false, Enumerable < Array assert_nil Proc < Comparable assert_nil Comparable < Proc end def test_GT_0 assert_equal false, String > Object assert_equal true, Object > String assert_nil String > Array assert_equal false, Array > Enumerable assert_equal true, Enumerable > Array assert_nil Comparable > Proc assert_nil Proc > Comparable end def test_CMP_0 assert_equal(-1, (String <=> Object)) assert_equal 1, (Object <=> String) assert_nil(Array <=> String) end ExpectedException = NoMethodError # Support stuff module Mixin MIXIN = 1 def mixin end end module User USER = 2 include Mixin def user end end module Other def other end end class AClass def AClass.cm1 "cm1" end def AClass.cm2 cm1 + "cm2" + cm3 end def AClass.cm3 "cm3" end private_class_method :cm1, "cm3" def aClass :aClass end def aClass1 :aClass1 end def aClass2 :aClass2 end private :aClass1 protected :aClass2 end class BClass < AClass def bClass1 :bClass1 end private def bClass2 :bClass2 end protected def bClass3 :bClass3 end end class CClass < BClass def self.cClass end end MyClass = AClass.clone class MyClass public_class_method :cm1 end # ----------------------------------------------------------- def test_CMP # '<=>' assert_equal( 0, Mixin <=> Mixin) assert_equal(-1, User <=> Mixin) assert_equal( 1, Mixin <=> User) assert_equal( 0, Object <=> Object) assert_equal(-1, String <=> Object) assert_equal( 1, Object <=> String) end def test_GE # '>=' assert_operator(Mixin, :>=, User) assert_operator(Mixin, :>=, Mixin) assert_not_operator(User, :>=, Mixin) assert_operator(Object, :>=, String) assert_operator(String, :>=, String) assert_not_operator(String, :>=, Object) end def test_GT # '>' assert_operator(Mixin, :>, User) assert_not_operator(Mixin, :>, Mixin) assert_not_operator(User, :>, Mixin) assert_operator(Object, :>, String) assert_not_operator(String, :>, String) assert_not_operator(String, :>, Object) end def test_LE # '<=' assert_operator(User, :<=, Mixin) assert_operator(Mixin, :<=, Mixin) assert_not_operator(Mixin, :<=, User) assert_operator(String, :<=, Object) assert_operator(String, :<=, String) assert_not_operator(Object, :<=, String) end def test_LT # '<' assert_operator(User, :<, Mixin) assert_not_operator(Mixin, :<, Mixin) assert_not_operator(Mixin, :<, User) assert_operator(String, :<, Object) assert_not_operator(String, :<, String) assert_not_operator(Object, :<, String) end def test_VERY_EQUAL # '===' assert_operator(Object, :===, self) assert_operator(Test::Unit::TestCase, :===, self) assert_operator(TestModule, :===, self) assert_not_operator(String, :===, self) end def test_ancestors assert_equal([User, Mixin], User.ancestors) assert_equal([Mixin], Mixin.ancestors) ancestors = Object.ancestors mixins = ancestors - [Object, Kernel, BasicObject] mixins << JSON::Ext::Generator::GeneratorMethods::String if defined?(JSON::Ext::Generator::GeneratorMethods::String) assert_equal([Object, Kernel, BasicObject], ancestors - mixins) assert_equal([String, Comparable, Object, Kernel, BasicObject], String.ancestors - mixins) end CLASS_EVAL = 2 @@class_eval = 'b' def test_class_eval Other.class_eval("CLASS_EVAL = 1") assert_equal(1, Other::CLASS_EVAL) assert_include(Other.constants, :CLASS_EVAL) assert_equal(2, Other.class_eval { CLASS_EVAL }) Other.class_eval("@@class_eval = 'a'") assert_equal('a', Other.class_variable_get(:@@class_eval)) assert_equal('b', Other.class_eval { @@class_eval }) Other.class_eval do module_function def class_eval_test "foo" end end assert_equal("foo", Other.class_eval_test) assert_equal([Other], Other.class_eval { |*args| args }) end def test_const_defined? assert_operator(Math, :const_defined?, :PI) assert_operator(Math, :const_defined?, "PI") assert_not_operator(Math, :const_defined?, :IP) assert_not_operator(Math, :const_defined?, "IP") end def each_bad_constants(m, &b) [ "#", ":Object", "", ":", ["String::", "[Bug #7573]"], "\u3042", "Name?", ].each do |name, msg| expected = "wrong constant name %s" % quote(name) msg = "#{msg}#{': ' if msg}wrong constant name #{name.dump}" assert_raise_with_message(NameError, expected, "#{msg} to #{m}") do yield name end end end def test_bad_constants_get each_bad_constants("get") {|name| Object.const_get name } end def test_bad_constants_defined each_bad_constants("defined?") {|name| Object.const_defined? name } end def test_leading_colons assert_equal Object, AClass.const_get('::Object') end def test_const_get assert_equal(Math::PI, Math.const_get("PI")) assert_equal(Math::PI, Math.const_get(:PI)) n = Object.new def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "PI"; end def n.count; @count; end assert_equal(Math::PI, Math.const_get(n)) assert_equal(1, n.count) end def test_nested_get assert_equal Other, Object.const_get([self.class, Other].join('::')) assert_equal User::USER, self.class.const_get([User, 'USER'].join('::')) end def test_nested_get_symbol const = [self.class, Other].join('::').to_sym assert_raise(NameError) {Object.const_get(const)} const = [User, 'USER'].join('::').to_sym assert_raise(NameError) {self.class.const_get(const)} end def test_nested_get_const_missing classes = [] klass = Class.new { define_singleton_method(:const_missing) { |name| classes << name klass } } klass.const_get("Foo::Bar::Baz") assert_equal [:Foo, :Bar, :Baz], classes end def test_nested_get_bad_class assert_raise(TypeError) do self.class.const_get([User, 'USER', 'Foo'].join('::')) end end def test_nested_defined 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']) end def test_nested_defined_symbol const = [self.class, Other].join('::').to_sym assert_raise(NameError) {Object.const_defined?(const)} const = [User, 'USER'].join('::').to_sym assert_raise(NameError) {self.class.const_defined?(const)} end def test_nested_defined_bad_class assert_raise(TypeError) do self.class.const_defined?('User::USER::Foo') end end def test_const_set assert_not_operator(Other, :const_defined?, :KOALA) Other.const_set(:KOALA, 99) assert_operator(Other, :const_defined?, :KOALA) assert_equal(99, Other::KOALA) Other.const_set("WOMBAT", "Hi") assert_equal("Hi", Other::WOMBAT) n = Object.new def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "HOGE"; end def n.count; @count; end def n.count=(v); @count=v; end assert_not_operator(Other, :const_defined?, :HOGE) Other.const_set(n, 999) assert_equal(1, n.count) n.count = 0 assert_equal(999, Other.const_get(n)) assert_equal(1, n.count) n.count = 0 assert_equal(true, Other.const_defined?(n)) assert_equal(1, n.count) end def test_constants assert_equal([:MIXIN], Mixin.constants) 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 const_set(:X, 1) @x = 2 end 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) end assert_empty(m.instance_methods, bug9813) assert_empty(m.instance_variables, bug9813) assert_empty(m.constants, bug9813) end def test_dup bug6454 = '[ruby-core:45132]' a = Module.new Other.const_set :BUG6454, a b = a.dup Other.const_set :BUG6454_dup, b assert_equal "TestModule::Other::BUG6454_dup", b.inspect, bug6454 end def test_dup_anonymous bug6454 = '[ruby-core:45132]' a = Module.new original = a.inspect b = a.dup assert_not_equal original, b.inspect, bug6454 end def test_public_include assert_nothing_raised('#8846') do Module.new.include(Module.new { def foo; end }).instance_methods == [:foo] end end def test_include_toplevel assert_separately([], <<-EOS) Mod = Module.new {def foo; :include_foo end} TOPLEVEL_BINDING.eval('include Mod') assert_equal(:include_foo, TOPLEVEL_BINDING.eval('foo')) assert_equal([Object, Mod], Object.ancestors.slice(0, 2)) EOS end def test_included_modules assert_equal([], Mixin.included_modules) assert_equal([Mixin], User.included_modules) mixins = Object.included_modules - [Kernel] mixins << JSON::Ext::Generator::GeneratorMethods::String if defined?(JSON::Ext::Generator::GeneratorMethods::String) assert_equal([Kernel], Object.included_modules - mixins) assert_equal([Comparable, Kernel], String.included_modules - mixins) end def test_instance_methods assert_equal([:user], User.instance_methods(false)) assert_equal([:user, :mixin].sort, User.instance_methods(true).sort) assert_equal([:mixin], Mixin.instance_methods) assert_equal([:mixin], Mixin.instance_methods(true)) assert_equal([:cClass], (class << CClass; self; end).instance_methods(false)) assert_equal([], (class << BClass; self; end).instance_methods(false)) assert_equal([:cm2], (class << AClass; self; end).instance_methods(false)) # Ruby 1.8 feature change: # #instance_methods includes protected methods. #assert_equal([:aClass], AClass.instance_methods(false)) assert_equal([:aClass, :aClass2], AClass.instance_methods(false).sort) assert_equal([:aClass, :aClass2], (AClass.instance_methods(true) - Object.instance_methods(true)).sort) end def test_method_defined? assert_method_not_defined?(User, :wombat) assert_method_defined?(User, :user) assert_method_defined?(User, :mixin) assert_method_not_defined?(User, :wombat) assert_method_defined?(User, :user) assert_method_defined?(User, :mixin) end def module_exec_aux Proc.new do def dynamically_added_method_3; end end end def module_exec_aux_2(&block) User.module_exec(&block) end def test_module_exec User.module_exec do def dynamically_added_method_1; end end assert_method_defined?(User, :dynamically_added_method_1) block = Proc.new do def dynamically_added_method_2; end end User.module_exec(&block) assert_method_defined?(User, :dynamically_added_method_2) User.module_exec(&module_exec_aux) assert_method_defined?(User, :dynamically_added_method_3) module_exec_aux_2 do def dynamically_added_method_4; end end assert_method_defined?(User, :dynamically_added_method_4) end def test_module_eval User.module_eval("MODULE_EVAL = 1") assert_equal(1, User::MODULE_EVAL) assert_include(User.constants, :MODULE_EVAL) User.instance_eval("remove_const(:MODULE_EVAL)") assert_not_include(User.constants, :MODULE_EVAL) end def test_name assert_equal("Fixnum", Fixnum.name) assert_equal("TestModule::Mixin", Mixin.name) assert_equal("TestModule::User", User.name) end def test_classpath m = Module.new n = Module.new m.const_set(:N, n) assert_nil(m.name) assert_nil(n.name) assert_equal([:N], m.constants) m.module_eval("module O end") assert_equal([:N, :O], m.constants) m.module_eval("class C; end") assert_equal([:N, :O, :C], m.constants) assert_nil(m::N.name) assert_match(/\A#::O\z/, m::O.name) assert_match(/\A#::C\z/, m::C.name) self.class.const_set(:M, m) prefix = self.class.name + "::M::" assert_equal(prefix+"N", m.const_get(:N).name) assert_equal(prefix+"O", m.const_get(:O).name) assert_equal(prefix+"C", m.const_get(:C).name) end def test_private_class_method assert_raise(ExpectedException) { AClass.cm1 } assert_raise(ExpectedException) { AClass.cm3 } assert_equal("cm1cm2cm3", AClass.cm2) end def test_private_instance_methods assert_equal([:aClass1], AClass.private_instance_methods(false)) assert_equal([:bClass2], BClass.private_instance_methods(false)) assert_equal([:aClass1, :bClass2], (BClass.private_instance_methods(true) - Object.private_instance_methods(true)).sort) end def test_protected_instance_methods assert_equal([:aClass2], AClass.protected_instance_methods) assert_equal([:bClass3], BClass.protected_instance_methods(false)) assert_equal([:bClass3, :aClass2].sort, (BClass.protected_instance_methods(true) - Object.protected_instance_methods(true)).sort) end def test_public_class_method assert_equal("cm1", MyClass.cm1) assert_equal("cm1cm2cm3", MyClass.cm2) assert_raise(ExpectedException) { eval "MyClass.cm3" } end def test_public_instance_methods assert_equal([:aClass], AClass.public_instance_methods(false)) assert_equal([:bClass1], BClass.public_instance_methods(false)) end def test_s_constants c1 = Module.constants Object.module_eval "WALTER = 99" c2 = Module.constants assert_equal([:WALTER], c2 - c1) assert_equal([], Module.constants(true)) assert_equal([], Module.constants(false)) src = <<-INPUT ary = Module.constants module M WALTER = 99 end class Module include M end p Module.constants - ary, Module.constants(true), Module.constants(false) INPUT assert_in_out_err([], src, %w([:M] [:WALTER] []), []) klass = Class.new do const_set(:X, 123) end assert_equal(false, klass.class_eval { Module.constants }.include?(:X)) end module M1 $m1 = Module.nesting module M2 $m2 = Module.nesting end end def test_s_nesting assert_equal([], $m0) assert_equal([TestModule::M1, TestModule], $m1) assert_equal([TestModule::M1::M2, TestModule::M1, TestModule], $m2) end def test_s_new m = Module.new assert_instance_of(Module, m) end def test_freeze m = Module.new m.freeze assert_raise(RuntimeError) do m.module_eval do def foo; end end end end def test_attr_obsoleted_flag c = Class.new c.class_eval do def initialize @foo = :foo @bar = :bar end attr :foo, true attr :bar, false end o = c.new assert_equal(true, o.respond_to?(:foo)) assert_equal(true, o.respond_to?(:foo=)) assert_equal(true, o.respond_to?(:bar)) assert_equal(false, o.respond_to?(:bar=)) end def test_const_get_evaled c1 = Class.new c2 = Class.new(c1) eval("c1::Foo = :foo") assert_equal(:foo, c1::Foo) assert_equal(:foo, c2::Foo) assert_equal(:foo, c2.const_get(:Foo)) assert_raise(NameError) { c2.const_get(:Foo, false) } eval("c1::Foo = :foo") assert_raise(NameError) { c1::Bar } assert_raise(NameError) { c2::Bar } assert_raise(NameError) { c2.const_get(:Bar) } assert_raise(NameError) { c2.const_get(:Bar, false) } assert_raise(NameError) { c2.const_get("Bar", false) } assert_raise(NameError) { c2.const_get("BaR11", false) } assert_raise(NameError) { Object.const_get("BaR11", false) } c1.instance_eval do def const_missing(x) x end end assert_equal(:Bar, c1::Bar) assert_equal(:Bar, c2::Bar) assert_equal(:Bar, c2.const_get(:Bar)) assert_equal(:Bar, c2.const_get(:Bar, false)) assert_equal(:Bar, c2.const_get("Bar")) assert_equal(:Bar, c2.const_get("Bar", false)) v = c2.const_get("Bar11", false) assert_equal("Bar11".to_sym, v) assert_raise(NameError) { c1.const_get(:foo) } end def test_const_set_invalid_name c1 = Class.new assert_raise(NameError) { c1.const_set(:foo, :foo) } assert_raise(NameError) { c1.const_set("bar", :foo) } assert_raise(TypeError) { c1.const_set(1, :foo) } assert_nothing_raised(NameError) { c1.const_set("X\u{3042}", :foo) } assert_raise(NameError) { c1.const_set("X\u{3042}".encode("utf-16be"), :foo) } 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) } end def test_const_get_invalid_name c1 = Class.new assert_raise(NameError) { c1.const_get(:foo) } bug5084 = '[ruby-dev:44200]' assert_raise(TypeError, bug5084) { c1.const_get(1) } bug7574 = '[ruby-dev:46749]' assert_raise_with_message(NameError, "wrong constant name \"String\\u0000\"", bug7574) { Object.const_get("String\0") } end def test_const_defined_invalid_name c1 = Class.new assert_raise(NameError) { c1.const_defined?(:foo) } bug5084 = '[ruby-dev:44200]' assert_raise(TypeError, bug5084) { c1.const_defined?(1) } bug7574 = '[ruby-dev:46749]' assert_raise_with_message(NameError, "wrong constant name \"String\\u0000\"", bug7574) { Object.const_defined?("String\0") } end def test_const_get_no_inherited bug3422 = '[ruby-core:30719]' assert_in_out_err([], <<-INPUT, %w[1 NameError A], [], bug3422) BasicObject::A = 1 puts [true, false].map {|inh| begin Object.const_get(:A, inh) rescue NameError => e [e.class, e.name] end } INPUT end def test_const_get_inherited bug3423 = '[ruby-core:30720]' assert_in_out_err([], <<-INPUT, %w[NameError A NameError A], [], bug3423) module Foo; A = 1; end class Object; include Foo; end class Bar; include Foo; end puts [Object, Bar].map {|klass| begin klass.const_get(:A, false) rescue NameError => e [e.class, e.name] end } INPUT end def test_const_in_module bug3423 = '[ruby-core:37698]' assert_in_out_err([], <<-INPUT, %w[ok], [], bug3423) module LangModuleSpecInObject module LangModuleTop end end include LangModuleSpecInObject module LangModuleTop end puts "ok" if LangModuleSpecInObject::LangModuleTop == LangModuleTop INPUT bug5264 = '[ruby-core:39227]' assert_in_out_err([], <<-'INPUT', [], [], bug5264) class A class X; end end class B < A module X; end end INPUT end def test_class_variable_get c = Class.new c.class_eval('@@foo = :foo') assert_equal(:foo, c.class_variable_get(:@@foo)) assert_raise(NameError) { c.class_variable_get(:@@bar) } # c.f. instance_variable_get assert_raise(NameError) { c.class_variable_get(:'@@') } assert_raise(NameError) { c.class_variable_get('@@') } assert_raise(NameError) { c.class_variable_get(:foo) } assert_raise(NameError) { c.class_variable_get("bar") } assert_raise(TypeError) { c.class_variable_get(1) } n = Object.new def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end def n.count; @count; end assert_equal(:foo, c.class_variable_get(n)) assert_equal(1, n.count) end def test_class_variable_set c = Class.new c.class_variable_set(:@@foo, :foo) assert_equal(:foo, c.class_eval('@@foo')) assert_raise(NameError) { c.class_variable_set(:'@@', 1) } assert_raise(NameError) { c.class_variable_set('@@', 1) } assert_raise(NameError) { c.class_variable_set(:foo, 1) } assert_raise(NameError) { c.class_variable_set("bar", 1) } assert_raise(TypeError) { c.class_variable_set(1, 1) } n = Object.new def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end def n.count; @count; end c.class_variable_set(n, :bar) assert_equal(:bar, c.class_eval('@@foo')) assert_equal(1, n.count) end def test_class_variable_defined c = Class.new c.class_eval('@@foo = :foo') assert_equal(true, c.class_variable_defined?(:@@foo)) assert_equal(false, c.class_variable_defined?(:@@bar)) assert_raise(NameError) { c.class_variable_defined?(:'@@') } assert_raise(NameError) { c.class_variable_defined?('@@') } assert_raise(NameError) { c.class_variable_defined?(:foo) } assert_raise(NameError) { c.class_variable_defined?("bar") } assert_raise(TypeError) { c.class_variable_defined?(1) } n = Object.new def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@@foo"; end def n.count; @count; end assert_equal(true, c.class_variable_defined?(n)) assert_equal(1, n.count) end def test_remove_class_variable c = Class.new c.class_eval('@@foo = :foo') c.class_eval { remove_class_variable(:@@foo) } assert_equal(false, c.class_variable_defined?(:@@foo)) end def test_export_method m = Module.new assert_raise(NameError) do m.instance_eval { public(:foo) } end end def test_attr assert_in_out_err([], <<-INPUT, %w(:ok nil), /warning: private attribute\?$/) $VERBOSE = true c = Class.new c.instance_eval do private attr_reader :foo end o = c.new o.foo rescue p(:ok) p(o.instance_eval { foo }) INPUT c = Class.new assert_raise(NameError) do c.instance_eval { attr_reader :"." } end end def test_undef c = Class.new assert_raise(NameError) do c.instance_eval { undef_method(:foo) } end m = Module.new assert_raise(NameError) do m.instance_eval { undef_method(:foo) } end o = Object.new assert_raise(NameError) do 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$") $VERBOSE = false Class.new.instance_eval { undef_method(:#{n}) } INPUT end end def test_alias m = Module.new assert_raise(NameError) do m.class_eval { alias foo bar } end assert_in_out_err([], <<-INPUT, %w(2), /discarding old foo$/) $VERBOSE = true c = Class.new c.class_eval do def foo; 1; end def bar; 2; end end c.class_eval { alias foo bar } p c.new.foo INPUT end def test_mod_constants m = Module.new m.const_set(:Foo, :foo) assert_equal([:Foo], m.constants(true)) assert_equal([:Foo], m.constants(false)) m.instance_eval { remove_const(:Foo) } end class Bug9413 class << self Foo = :foo end end def test_singleton_constants bug9413 = '[ruby-core:59763] [Bug #9413]' c = Bug9413.singleton_class assert_include(c.constants(true), :Foo, bug9413) assert_include(c.constants(false), :Foo, bug9413) end def test_frozen_module m = Module.new m.freeze assert_raise(RuntimeError) do m.instance_eval { undef_method(:foo) } end end def test_frozen_class c = Class.new c.freeze assert_raise(RuntimeError) do c.instance_eval { undef_method(:foo) } end end def test_frozen_singleton_class klass = Class.new o = klass.new c = class << o; self; end c.freeze assert_raise_with_message(RuntimeError, /frozen/) do c.instance_eval { undef_method(:foo) } end klass.class_eval do def self.foo end end end def test_method_defined c = Class.new c.class_eval do def foo; end def bar; end def baz; end public :foo protected :bar private :baz end assert_equal(true, c.public_method_defined?(:foo)) assert_equal(false, c.public_method_defined?(:bar)) assert_equal(false, c.public_method_defined?(:baz)) assert_equal(false, c.protected_method_defined?(:foo)) assert_equal(true, c.protected_method_defined?(:bar)) assert_equal(false, c.protected_method_defined?(:baz)) assert_equal(false, c.private_method_defined?(:foo)) assert_equal(false, c.private_method_defined?(:bar)) assert_equal(true, c.private_method_defined?(:baz)) end def test_top_public_private assert_in_out_err([], <<-INPUT, %w([:foo] [:bar]), []) private def foo; :foo; end public def bar; :bar; end p self.private_methods.grep(/^foo$|^bar$/) p self.methods.grep(/^foo$|^bar$/) INPUT end def test_append_features t = nil m = Module.new m.module_eval do def foo; :foo; end end class << m; self; end.class_eval do define_method(:append_features) do |mod| t = mod super(mod) end end m2 = Module.new m2.module_eval { include(m) } assert_equal(m2, t) o = Object.new o.extend(m2) assert_equal(true, o.respond_to?(:foo)) end def test_append_features_raise m = Module.new m.module_eval do def foo; :foo; end end class << m; self; end.class_eval do define_method(:append_features) {|mod| raise } end m2 = Module.new assert_raise(RuntimeError) do m2.module_eval { include(m) } end o = Object.new o.extend(m2) assert_equal(false, o.respond_to?(:foo)) end def test_append_features_type_error assert_raise(TypeError) do Module.new.instance_eval { append_features(1) } end end def test_included m = Module.new m.module_eval do def foo; :foo; end end class << m; self; end.class_eval do define_method(:included) {|mod| raise } end m2 = Module.new assert_raise(RuntimeError) do m2.module_eval { include(m) } end o = Object.new o.extend(m2) assert_equal(true, o.respond_to?(:foo)) end def test_cyclic_include m1 = Module.new m2 = Module.new m1.instance_eval { include(m2) } assert_raise(ArgumentError) do m2.instance_eval { include(m1) } end end def test_include_p m = Module.new c1 = Class.new c1.instance_eval { include(m) } c2 = Class.new(c1) assert_equal(true, c1.include?(m)) assert_equal(true, c2.include?(m)) assert_equal(false, m.include?(m)) end def test_send a = AClass.new assert_equal(:aClass, a.__send__(:aClass)) assert_equal(:aClass1, a.__send__(:aClass1)) assert_equal(:aClass2, a.__send__(:aClass2)) b = BClass.new assert_equal(:aClass, b.__send__(:aClass)) assert_equal(:aClass1, b.__send__(:aClass1)) assert_equal(:aClass2, b.__send__(:aClass2)) assert_equal(:bClass1, b.__send__(:bClass1)) assert_equal(:bClass2, b.__send__(:bClass2)) assert_equal(:bClass3, b.__send__(:bClass3)) end def test_nonascii_name c = eval("class ::C\u{df}; self; end") assert_equal("C\u{df}", c.name, '[ruby-core:24600]') c = eval("class C\u{df}; self; end") assert_equal("TestModule::C\u{df}", c.name, '[ruby-core:24600]') end def test_method_added memo = [] mod = Module.new do mod = self (class << self ; self ; end).class_eval do define_method :method_added do |sym| memo << sym memo << mod.instance_methods(false) memo << (mod.instance_method(sym) rescue nil) end end def f end alias g f attr_reader :a attr_writer :a end assert_equal :f, memo.shift assert_equal [:f], memo.shift, '[ruby-core:25536]' assert_equal mod.instance_method(:f), memo.shift assert_equal :g, memo.shift assert_equal [:f, :g], memo.shift assert_equal mod.instance_method(:f), memo.shift assert_equal :a, memo.shift assert_equal [:f, :g, :a], memo.shift assert_equal mod.instance_method(:a), memo.shift assert_equal :a=, memo.shift assert_equal [:f, :g, :a, :a=], memo.shift assert_equal mod.instance_method(:a=), memo.shift end def test_method_undefined added = [] undefed = [] removed = [] mod = Module.new do mod = self def f end (class << self ; self ; end).class_eval do define_method :method_added do |sym| added << sym end define_method :method_undefined do |sym| undefed << sym end define_method :method_removed do |sym| removed << sym end end end assert_method_defined?(mod, :f) mod.module_eval do undef :f end assert_equal [], added assert_equal [:f], undefed assert_equal [], removed end def test_method_removed added = [] undefed = [] removed = [] mod = Module.new do mod = self def f end (class << self ; self ; end).class_eval do define_method :method_added do |sym| added << sym end define_method :method_undefined do |sym| undefed << sym end define_method :method_removed do |sym| removed << sym end end end assert_method_defined?(mod, :f) mod.module_eval do remove_method :f end assert_equal [], added assert_equal [], undefed assert_equal [:f], removed end def test_method_redefinition feature2155 = '[ruby-dev:39400]' line = __LINE__+4 stderr = EnvUtil.verbose_warning do Module.new do def foo; end def foo; end end end assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr) assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155) assert_warning '' do Module.new do def foo; end alias bar foo def foo; end end end assert_warning '' do Module.new do def foo; end alias bar foo alias bar foo end end line = __LINE__+4 stderr = EnvUtil.verbose_warning do Module.new do define_method(:foo) do end def foo; end end end assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr) assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155) assert_warning '' do Module.new do define_method(:foo) do end alias bar foo alias bar foo end end assert_warning('', '[ruby-dev:39397]') do Module.new do module_function def foo; end module_function :foo end end assert_warning '' do Module.new do def foo; end undef foo end end end def test_protected_singleton_method klass = Class.new x = klass.new class << x protected def foo end end assert_raise(NoMethodError) do x.foo end klass.send(:define_method, :bar) do x.foo end assert_nothing_raised do x.bar end y = klass.new assert_raise(NoMethodError) do y.bar end end def test_uninitialized_toplevel_constant bug3123 = '[ruby-dev:40951]' e = assert_raise(NameError) {eval("Bug3123", TOPLEVEL_BINDING)} assert_not_match(/Object::/, e.message, bug3123) end def test_attr_inherited_visibility bug3406 = '[ruby-core:30638]' c = Class.new do class << self private def attr_accessor(*); super; end end attr_accessor :x end.new assert_nothing_raised(bug3406) {c.x = 1} assert_equal(1, c.x, bug3406) end def test_attr_writer_with_no_arguments bug8540 = "[ruby-core:55543]" c = Class.new do attr_writer :foo end assert_raise(ArgumentError, bug8540) { c.new.send :foo= } end def test_private_constant c = Class.new c.const_set(:FOO, "foo") assert_equal("foo", c::FOO) c.private_constant(:FOO) assert_raise(NameError) { c::FOO } assert_equal("foo", c.class_eval("FOO")) assert_equal("foo", c.const_get("FOO")) $VERBOSE, verbose = nil, $VERBOSE c.const_set(:FOO, "foo") $VERBOSE = verbose assert_raise(NameError) { c::FOO } end def test_private_constant2 c = Class.new c.const_set(:FOO, "foo") c.const_set(:BAR, "bar") assert_equal("foo", c::FOO) assert_equal("bar", c::BAR) c.private_constant(:FOO, :BAR) assert_raise(NameError) { c::FOO } assert_raise(NameError) { c::BAR } assert_equal("foo", c.class_eval("FOO")) assert_equal("bar", c.class_eval("BAR")) end def test_private_constant_with_no_args assert_in_out_err([], <<-RUBY, [], ["-:3: warning: private_constant with no argument is just ignored"]) $-w = true class X private_constant end RUBY end class PrivateClass end private_constant :PrivateClass def test_define_module_under_private_constant assert_raise(NameError) do eval %q{class TestModule::PrivateClass; end} end assert_raise(NameError) do eval %q{module TestModule::PrivateClass::TestModule; end} end eval %q{class PrivateClass; end} eval %q{module PrivateClass::TestModule; end} assert_instance_of(Module, PrivateClass::TestModule) PrivateClass.class_eval { remove_const(:TestModule) } end def test_public_constant c = Class.new c.const_set(:FOO, "foo") assert_equal("foo", c::FOO) c.private_constant(:FOO) assert_raise(NameError) { c::FOO } assert_equal("foo", c.class_eval("FOO")) c.public_constant(:FOO) assert_equal("foo", c::FOO) end def test_constants_with_private_constant assert_not_include(::TestModule.constants, :PrivateClass) end def test_toplevel_private_constant src = <<-INPUT class Object private_constant :Object end p Object begin p ::Object rescue p :ok end INPUT assert_in_out_err([], src, %w(Object :ok), []) end def test_private_constants_clear_inlinecache bug5702 = '[ruby-dev:44929]' src = <<-INPUT class A C = :Const def self.get_C A::C end # fill cache A.get_C private_constant :C, :D rescue nil begin A.get_C rescue NameError puts "A.get_C" end end INPUT assert_in_out_err([], src, %w(A.get_C), [], bug5702) end def test_constant_lookup_in_method_defined_by_class_eval src = <<-INPUT class A B = 42 end A.class_eval do def self.f B end def f B end end begin A.f rescue NameError puts "A.f" end begin A.new.f rescue NameError puts "A.new.f" end INPUT assert_in_out_err([], src, %w(A.f A.new.f), []) end def test_constant_lookup_in_toplevel_class_eval src = <<-INPUT module X A = 123 end begin X.class_eval { A } rescue NameError => e puts e end INPUT assert_in_out_err([], src, ["uninitialized constant A"], []) end def test_constant_lookup_in_module_in_class_eval src = <<-INPUT class A B = 42 end A.class_eval do module C begin B rescue NameError puts "NameError" end end end INPUT assert_in_out_err([], src, ["NameError"], []) end module M0 def m1; [:M0] end end module M1 def m1; [:M1, *super] end end module M2 def m1; [:M2, *super] end end M3 = Module.new do def m1; [:M3, *super] end end module M4 def m1; [:M4, *super] end end class C def m1; end end class C0 < C include M0 prepend M1 def m1; [:C0, *super] end end class C1 < C0 prepend M2, M3 include M4 def m1; [:C1, *super] end end def test_prepend obj = C0.new expected = [:M1,:C0,:M0] assert_equal(expected, obj.m1) obj = C1.new expected = [:M2,:M3,:C1,:M4,:M1,:C0,:M0] assert_equal(expected, obj.m1) end def test_public_prepend assert_nothing_raised('#8846') do Class.new.prepend(Module.new) end end def test_prepend_inheritance bug6654 = '[ruby-core:45914]' a = labeled_module("a") b = labeled_module("b") {include a} c = labeled_class("c") {prepend b} assert_operator(c, :<, b, bug6654) assert_operator(c, :<, a, bug6654) bug8357 = '[ruby-core:54736] [Bug #8357]' b = labeled_module("b") {prepend a} c = labeled_class("c") {include b} assert_operator(c, :<, b, bug8357) assert_operator(c, :<, a, bug8357) bug8357 = '[ruby-core:54742] [Bug #8357]' assert_kind_of(b, c.new, bug8357) end def test_prepend_instance_methods bug6655 = '[ruby-core:45915]' assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655) end def test_prepend_singleton_methods o = Object.new o.singleton_class.class_eval {prepend Module.new} assert_equal([], o.singleton_methods) end def test_prepend_remove_method c = Class.new do prepend Module.new {def foo; end} end assert_raise(NameError) do c.class_eval do remove_method(:foo) end end c.class_eval do def foo; end end removed = nil c.singleton_class.class_eval do define_method(:method_removed) {|id| removed = id} end assert_nothing_raised(NoMethodError, NameError, '[Bug #7843]') do c.class_eval do remove_method(:foo) end end assert_equal(:foo, removed) end def test_prepend_class_ancestors bug6658 = '[ruby-core:45919]' m = labeled_module("m") c = labeled_class("c") {prepend m} assert_equal([m, c], c.ancestors[0, 2], bug6658) bug6662 = '[ruby-dev:45868]' c2 = labeled_class("c2", c) anc = c2.ancestors assert_equal([c2, m, c, Object], anc[0..anc.index(Object)], bug6662) end def test_prepend_module_ancestors bug6659 = '[ruby-dev:45861]' m0 = labeled_module("m0") {def x; [:m0, *super] end} m1 = labeled_module("m1") {def x; [:m1, *super] end; prepend m0} m2 = labeled_module("m2") {def x; [:m2, *super] end; prepend m1} c0 = labeled_class("c0") {def x; [:c0] end} c1 = labeled_class("c1") {def x; [:c1] end; prepend m2} c2 = labeled_class("c2", c0) {def x; [:c2, *super] end; include m2} assert_equal([m0, m1], m1.ancestors, bug6659) bug6662 = '[ruby-dev:45868]' assert_equal([m0, m1, m2], m2.ancestors, bug6662) assert_equal([m0, m1, m2, c1], c1.ancestors[0, 4], bug6662) assert_equal([:m0, :m1, :m2, :c1], c1.new.x) assert_equal([c2, m0, m1, m2, c0], c2.ancestors[0, 5], bug6662) 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) m3 = labeled_module("m3") {prepend m1; include m1} assert_equal([m0, m1, m3], m3.ancestors) m3 = labeled_module("m3") {prepend m1; prepend m1} assert_equal([m0, m1, m3], m3.ancestors) m3 = labeled_module("m3") {include m1; include m1} assert_equal([m3, m0, m1], m3.ancestors) end def labeled_module(name, &block) EnvUtil.labeled_module(name, &block) end def labeled_class(name, superclass = Object, &block) EnvUtil.labeled_class(name, superclass, &block) end def test_prepend_instance_methods_false bug6660 = '[ruby-dev:45863]' assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660) assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660) end def test_cyclic_prepend bug7841 = '[ruby-core:52205] [Bug #7841]' m1 = Module.new m2 = Module.new m1.instance_eval { prepend(m2) } assert_raise(ArgumentError, bug7841) do m2.instance_eval { prepend(m1) } end end def test_prepend_optmethod bug7983 = '[ruby-dev:47124] [Bug #7983]' assert_separately [], %{ module M def /(other) to_f / other end end Fixnum.send(:prepend, M) assert_equal(0.5, 1 / 2, "#{bug7983}") } assert_equal(0, 1 / 2) end def test_prepend_visibility bug8005 = '[ruby-core:53106] [Bug #8005]' c = Class.new do prepend Module.new {} def foo() end protected :foo end a = c.new assert_respond_to a, [:foo, true], bug8005 assert_nothing_raised(NoMethodError, bug8005) {a.send :foo} end def test_prepend_visibility_inherited bug8238 = '[ruby-core:54105] [Bug #8238]' assert_separately [], <<-"end;", timeout: 20 class A def foo() A; end private :foo end class B < A public :foo prepend Module.new end assert_equal(A, B.new.foo, "#{bug8238}") end; end def test_prepend_included_modules bug8025 = '[ruby-core:53158] [Bug #8025]' mixin = labeled_module("mixin") c = labeled_module("c") {prepend mixin} im = c.included_modules assert_not_include(im, c, bug8025) assert_include(im, mixin, bug8025) c1 = labeled_class("c1") {prepend mixin} c2 = labeled_class("c2", c1) im = c2.included_modules assert_not_include(im, c1, bug8025) assert_not_include(im, c2, bug8025) assert_include(im, mixin, bug8025) end def test_prepend_super_in_alias bug7842 = '[Bug #7842]' p = labeled_module("P") do def m; "P"+super; end end a = labeled_class("A") do def m; "A"; end end b = labeled_class("B", a) do def m; "B"+super; end alias m2 m prepend p alias m3 m end assert_equal("BA", b.new.m2, bug7842) assert_equal("PBA", b.new.m3, bug7842) end def test_include_super_in_alias bug9236 = '[Bug #9236]' fun = labeled_module("Fun") do def hello orig_hello end end m1 = labeled_module("M1") do def hello 'hello!' end end m2 = labeled_module("M2") do def hello super end end foo = labeled_class("Foo") do include m1 include m2 alias orig_hello hello include fun end assert_equal('hello!', foo.new.hello, bug9236) end def test_class_variables m = Module.new m.class_variable_set(:@@foo, 1) m2 = Module.new m2.send(:include, m) m2.class_variable_set(:@@bar, 2) assert_equal([:@@foo], m.class_variables) assert_equal([:@@bar, :@@foo], m2.class_variables) assert_equal([:@@bar, :@@foo], m2.class_variables(true)) assert_equal([:@@bar], m2.class_variables(false)) end Bug6891 = '[ruby-core:47241]' def test_extend_module_with_protected_method list = [] x = Class.new { @list = list extend Module.new { protected def inherited(klass) @list << "protected" super(klass) end } extend Module.new { def inherited(klass) @list << "public" super(klass) end } } assert_nothing_raised(NoMethodError, Bug6891) {Class.new(x)} assert_equal(['public', 'protected'], list) end def test_extend_module_with_protected_bmethod list = [] x = Class.new { extend Module.new { protected define_method(:inherited) do |klass| list << "protected" super(klass) end } extend Module.new { define_method(:inherited) do |klass| list << "public" super(klass) end } } assert_nothing_raised(NoMethodError, Bug6891) {Class.new(x)} assert_equal(['public', 'protected'], list) end def test_invalid_attr %W[ foo? @foo @@foo $foo \u3042$ ].each do |name| assert_raise_with_message(NameError, /#{Regexp.quote(quote(name))}/) do Module.new { attr_accessor name.to_sym } end end end private def quote(name) encoding = Encoding.default_internal || Encoding.default_external (name.encoding == encoding || name.ascii_only?) ? name : name.inspect end class AttrTest class << self attr_accessor :cattr end attr_accessor :iattr def ivar @ivar end end def test_uninitialized_instance_variable a = AttrTest.new assert_warning(/instance variable @ivar not initialized/) do assert_nil(a.ivar) end a.instance_variable_set(:@ivar, 42) assert_warning '' do assert_equal(42, a.ivar) end end def test_uninitialized_attr a = AttrTest.new assert_warning '' do assert_nil(a.iattr) end a.iattr = 42 assert_warning '' do assert_equal(42, a.iattr) end end def test_uninitialized_attr_class assert_warning '' do assert_nil(AttrTest.cattr) end AttrTest.cattr = 42 assert_warning '' do assert_equal(42, AttrTest.cattr) end end def test_uninitialized_attr_non_object a = Class.new(Array) do attr_accessor :iattr end.new assert_warning '' do assert_nil(a.iattr) end a.iattr = 42 assert_warning '' do assert_equal(42, a.iattr) end end def test_remove_const m = Module.new assert_raise(NameError){ m.instance_eval { remove_const(:__FOO__) } } end def test_private_top_methods assert_top_method_is_private(:include) assert_top_method_is_private(:public) assert_top_method_is_private(:private) assert_top_method_is_private(:define_method) end module PrivateConstantReopen PRIVATE_CONSTANT = true private_constant :PRIVATE_CONSTANT end def test_private_constant_reopen assert_raise(NameError) do eval <<-EOS, TOPLEVEL_BINDING module TestModule::PrivateConstantReopen::PRIVATE_CONSTANT end EOS end assert_raise(NameError) do eval <<-EOS, TOPLEVEL_BINDING class TestModule::PrivateConstantReopen::PRIVATE_CONSTANT end EOS end end def test_singleton_class_ancestors feature8035 = '[ruby-core:53171]' obj = Object.new assert_equal [obj.singleton_class, Object], obj.singleton_class.ancestors.first(2), feature8035 mod = Module.new obj.extend mod assert_equal [obj.singleton_class, mod, Object], obj.singleton_class.ancestors.first(3) obj = Object.new obj.singleton_class.send :prepend, mod assert_equal [mod, obj.singleton_class, Object], obj.singleton_class.ancestors.first(3) end def test_visibility_by_public_class_method bug8284 = '[ruby-core:54404] [Bug #8284]' assert_raise(NoMethodError) {Object.define_method} Module.new.public_class_method(:define_method) assert_raise(NoMethodError, bug8284) {Object.define_method} end def test_include_module_with_constants_invalidates_method_cache assert_in_out_err([], <<-RUBY, %w(123 456), []) A = 123 class Foo def self.a A end end module M A = 456 end puts Foo.a Foo.send(:include, M) puts Foo.a RUBY end def test_return_value_of_define_method retvals = [] Class.new.class_eval do retvals << define_method(:foo){} retvals << define_method(:bar, instance_method(:foo)) end assert_equal :foo, retvals[0] assert_equal :bar, retvals[1] end def test_return_value_of_define_singleton_method retvals = [] Class.new do retvals << define_singleton_method(:foo){} retvals << define_singleton_method(:bar, method(:foo)) end assert_equal :foo, retvals[0] assert_equal :bar, retvals[1] end def test_prepend_gc assert_separately [], %{ module Foo end class Object prepend Foo end GC.start # make created T_ICLASS old (or remembered shady) class Object # add methods into T_ICLASS (need WB if it is old) def foo; end attr_reader :bar end 1_000_000.times{''} # cause GC } end def test_inspect_segfault bug_10282 = '[ruby-core:65214] [Bug #10282]' assert_separately [], <<-RUBY module ShallowInspect def shallow_inspect "foo" end end module InspectIsShallow include ShallowInspect alias_method :inspect, :shallow_inspect end class A end A.prepend InspectIsShallow expect = "#" assert_equal expect, A.new.method(:inspect).inspect, "#{bug_10282}" RUBY end private def assert_top_method_is_private(method) assert_separately [], %{ 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} } } end end