1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/ruby/test_module.rb
nobu 335dfa1255 vm_method.c: fix visibility on anonymous module
* vm_method.c (rb_mod_public_method): fix visibility on anonymous
  module. set visibility of singleton method, not method in base
  class.  [ruby-core:54404] [Bug #8284]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40346 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-04-18 07:59:06 +00:00

1742 lines
42 KiB
Ruby

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(Mixin >= User)
assert(Mixin >= Mixin)
assert(!(User >= Mixin))
assert(Object >= String)
assert(String >= String)
assert(!(String >= Object))
end
def test_GT # '>'
assert(Mixin > User)
assert(!(Mixin > Mixin))
assert(!(User > Mixin))
assert(Object > String)
assert(!(String > String))
assert(!(String > Object))
end
def test_LE # '<='
assert(User <= Mixin)
assert(Mixin <= Mixin)
assert(!(Mixin <= User))
assert(String <= Object)
assert(String <= String)
assert(!(Object <= String))
end
def test_LT # '<'
assert(User < Mixin)
assert(!(Mixin < Mixin))
assert(!(Mixin < User))
assert(String < Object)
assert(!(String < String))
assert(!(Object < String))
end
def test_VERY_EQUAL # '==='
assert(Object === self)
assert(Test::Unit::TestCase === self)
assert(TestModule === self)
assert(!(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(Other.constants.include?(: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(Math.const_defined?(:PI))
assert(Math.const_defined?("PI"))
assert(!Math.const_defined?(:IP))
assert(!Math.const_defined?("IP"))
end
def test_bad_constants
[
"#<Class:0x7b8b718b>",
":Object",
"",
":",
["String::", "[Bug #7573]"],
].each do |name, msg|
e = assert_raises(NameError, "#{msg}#{': ' if msg}wrong constant name #{name.dump}") {
Object.const_get name
}
assert_equal("wrong constant name %s" % name, e.message)
end
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_bad_class
assert_raises(TypeError) do
self.class.const_get([User, 'USER', 'Foo'].join('::'))
end
end
def test_const_set
assert(!Other.const_defined?(:KOALA))
Other.const_set(:KOALA, 99)
assert(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(!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_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
refute_equal original, b.inspect, bug6454
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(User.constants.include?(:MODULE_EVAL))
User.instance_eval("remove_const(:MODULE_EVAL)")
assert(!User.constants.include?(: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#<Module:.*>::O\z/, m::O.name)
assert_match(/\A#<Module:.*>::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) }
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]'
e = assert_raise(NameError) { Object.const_get("String\0") }
assert_equal("wrong constant name \"String\\0\"", e.message, bug7574)
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]'
e = assert_raise(NameError) { Object.const_defined?("String\0") }
assert_equal("wrong constant name \"String\\0\"", e.message, bug7574)
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(: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(: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?(: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
assert_raise(SecurityError) do
Thread.new do
$SAFE = 4
Class.instance_eval { undef_method(:foo) }
end.join
end
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
def test_frozen_class
m = Module.new
m.freeze
assert_raise(RuntimeError) do
m.instance_eval { undef_method(:foo) }
end
c = Class.new
c.freeze
assert_raise(RuntimeError) do
c.instance_eval { undef_method(:foo) }
end
o = Object.new
c = class << o; self; end
c.freeze
assert_raise(RuntimeError) do
c.instance_eval { undef_method(:foo) }
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_change_visibility_under_safe4
c = Class.new
c.class_eval do
def foo; end
end
assert_raise(SecurityError) do
Thread.new do
$SAFE = 4
c.class_eval { private :foo }
end.join
end
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_include_under_safe4
m = Module.new
c1 = Class.new
assert_raise(SecurityError) do
lambda {
$SAFE = 4
c1.instance_eval { include(m) }
}.call
end
assert_nothing_raised do
lambda {
$SAFE = 4
c2 = Class.new
c2.instance_eval { include(m) }
}.call
end
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_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
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(!(::TestModule).constants.include?(: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_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)
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)
Module.new do
singleton_class.class_eval {define_method(:to_s) {name}}
class_eval(&block) if block
end
end
def labeled_class(name, superclass = Object, &block)
Class.new(superclass) do
singleton_class.class_eval {define_method(:to_s) {name}}
class_eval(&block) if block
end
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_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
].each do |name|
assert_raises(NameError) do
Module.new { attr_accessor name.to_sym }
end
end
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_anonymous_module_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
private
def assert_top_method_is_private(method)
top = eval("self", TOPLEVEL_BINDING)
methods = top.singleton_class.private_instance_methods(false)
assert(methods.include?(method), "#{method} should be private")
assert_in_out_err([], <<-INPUT, [], /private method `#{method}' called for main:Object \(NoMethodError\)/)
self.#{method}
INPUT
end
end