mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
01b7d5acc7
This speeds up all instance variable access, even when not in verbose mode. Uninitialized instance variable warnings were rarely helpful, and resulted in slower code if you wanted to avoid warnings when run in verbose mode. Implements [Feature #17055]
2739 lines
69 KiB
Ruby
2739 lines
69 KiB
Ruby
# frozen_string_literal: false
|
|
require 'test/unit'
|
|
require 'pp'
|
|
|
|
$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
|
|
@deprecated = Warning[:deprecated]
|
|
Warning[:deprecated] = true
|
|
end
|
|
|
|
def teardown
|
|
$VERBOSE = @verbose
|
|
Warning[:deprecated] = @deprecated
|
|
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
|
|
|
|
def user2
|
|
end
|
|
protected :user2
|
|
|
|
def user3
|
|
end
|
|
private :user3
|
|
end
|
|
|
|
OtherSetup = -> do
|
|
remove_const :Other if defined? ::TestModule::Other
|
|
module Other
|
|
def other
|
|
end
|
|
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
|
|
OtherSetup.call
|
|
|
|
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)
|
|
[
|
|
"#<Class:0x7b8b718b>",
|
|
":Object",
|
|
"",
|
|
":",
|
|
["String::", "[Bug #7573]"],
|
|
"\u3042",
|
|
"Name?",
|
|
].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
|
|
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
|
|
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) {
|
|
Object.const_get([self.class.name, 'String'].join('::'))
|
|
}
|
|
end
|
|
|
|
def test_nested_get_symbol
|
|
OtherSetup.call
|
|
|
|
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
|
|
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'])
|
|
assert_not_send([Object, :const_defined?, [self.class.name, 'String'].join('::')])
|
|
end
|
|
|
|
def test_nested_defined_symbol
|
|
OtherSetup.call
|
|
|
|
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_inheritance
|
|
assert_send([Object, :const_defined?, [self.class.name, 'User', 'MIXIN'].join('::')])
|
|
assert_send([self.class, :const_defined?, 'User::MIXIN'])
|
|
assert_send([Object, :const_defined?, 'File::SEEK_SET'])
|
|
|
|
# const_defined? with `false`
|
|
assert_not_send([Object, :const_defined?, [self.class.name, 'User', 'MIXIN'].join('::'), false])
|
|
assert_not_send([self.class, :const_defined?, 'User::MIXIN', false])
|
|
assert_not_send([Object, :const_defined?, 'File::SEEK_SET', false])
|
|
end
|
|
|
|
def test_nested_defined_bad_class
|
|
assert_raise(TypeError) do
|
|
self.class.const_defined?('User::USER::Foo')
|
|
end
|
|
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)
|
|
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
|
|
OtherSetup.call
|
|
|
|
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_include_with_no_args
|
|
assert_raise(ArgumentError) { Module.new { include } }
|
|
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
|
|
def b; 1 end
|
|
end
|
|
assert_equal(2, a2.b)
|
|
end
|
|
|
|
def test_gc_prepend_chain
|
|
assert_separately([], <<-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)
|
|
|
|
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_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_instance_methods
|
|
assert_equal([:user, :user2], User.instance_methods(false).sort)
|
|
assert_equal([:user, :user2, :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))
|
|
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?
|
|
[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 !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)
|
|
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)
|
|
|
|
User.const_set(:FOO, c = Class.new)
|
|
|
|
c.prepend(User)
|
|
assert !c.method_defined?(:user, false)
|
|
c.define_method(:user){}
|
|
assert c.method_defined?(:user, false)
|
|
|
|
assert !c.method_defined?(:mixin, false)
|
|
c.define_method(:mixin){}
|
|
assert c.method_defined?(:mixin, false)
|
|
|
|
assert !c.method_defined?(:userx, false)
|
|
c.define_method(:userx){}
|
|
assert c.method_defined?(:userx, false)
|
|
|
|
# cleanup
|
|
User.class_eval do
|
|
remove_const :FOO
|
|
end
|
|
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)
|
|
|
|
# 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
|
|
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("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
|
|
m = Module.new
|
|
n = Module.new
|
|
m.const_set(:N, n)
|
|
assert_nil(m.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_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)
|
|
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)
|
|
c = m.class_eval("Bug15891 = Class.new.freeze")
|
|
assert_equal(prefix+"Bug15891", 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)
|
|
|
|
Object.class_eval do
|
|
remove_const :WALTER
|
|
end
|
|
|
|
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))
|
|
|
|
assert_equal(false, Complex.constants(false).include?(:compatible))
|
|
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 do
|
|
def self.baz; end
|
|
def bar; end
|
|
end
|
|
m.freeze
|
|
assert_raise(FrozenError) do
|
|
m.module_eval do
|
|
def foo; end
|
|
end
|
|
end
|
|
assert_raise(FrozenError) do
|
|
m.__send__ :private, :bar
|
|
end
|
|
assert_raise(FrozenError) do
|
|
m.private_class_method :baz
|
|
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_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)
|
|
|
|
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_with_message(NameError, /foo/) { c1.const_set(:foo, :foo) }
|
|
assert_raise_with_message(NameError, /bar/) { c1.const_set("bar", :foo) }
|
|
assert_raise_with_message(TypeError, /1/) { 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) }
|
|
cx = EnvUtil.labeled_class("X\u{3042}")
|
|
assert_raise_with_message(TypeError, /X\u{3042}/) { c1.const_set(cx, :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) }
|
|
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) }
|
|
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))
|
|
assert_raise(NameError) do
|
|
c.class_eval { remove_class_variable(:@var) }
|
|
end
|
|
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(nil))
|
|
$VERBOSE = true
|
|
c = Class.new
|
|
c.instance_eval do
|
|
private
|
|
attr_reader :foo
|
|
end
|
|
o = c.new
|
|
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(FrozenError) do
|
|
m.instance_eval { undef_method(:foo) }
|
|
end
|
|
end
|
|
|
|
def test_frozen_class
|
|
c = Class.new
|
|
c.freeze
|
|
assert_raise(FrozenError) 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(FrozenError, /frozen/) do
|
|
c.instance_eval { undef_method(:foo) }
|
|
end
|
|
klass.class_eval do
|
|
def self.foo
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_method_defined
|
|
cl = Class.new
|
|
def_methods = proc do
|
|
def foo; end
|
|
def bar; end
|
|
def baz; end
|
|
public :foo
|
|
protected :bar
|
|
private :baz
|
|
end
|
|
cl.class_eval(&def_methods)
|
|
sc = Class.new(cl)
|
|
mod = Module.new(&def_methods)
|
|
only_prepend = Class.new{prepend(mod)}
|
|
empty_prepend = cl.clone
|
|
empty_prepend.prepend(Module.new)
|
|
overlap_prepend = cl.clone
|
|
overlap_prepend.prepend(mod)
|
|
|
|
[[], [true], [false]].each do |args|
|
|
[cl, sc, only_prepend, empty_prepend, overlap_prepend].each do |c|
|
|
always_false = [sc, only_prepend].include?(c) && args == [false]
|
|
|
|
assert_equal(always_false ? false : true, c.public_method_defined?(:foo, *args))
|
|
assert_equal(always_false ? false : false, c.public_method_defined?(:bar, *args))
|
|
assert_equal(always_false ? false : false, c.public_method_defined?(:baz, *args))
|
|
|
|
# Test if string arguments are converted to symbols
|
|
assert_equal(always_false ? false : true, c.public_method_defined?("foo", *args))
|
|
assert_equal(always_false ? false : false, c.public_method_defined?("bar", *args))
|
|
assert_equal(always_false ? false : false, c.public_method_defined?("baz", *args))
|
|
|
|
assert_equal(always_false ? false : false, c.protected_method_defined?(:foo, *args))
|
|
assert_equal(always_false ? false : true, c.protected_method_defined?(:bar, *args))
|
|
assert_equal(always_false ? false : false, c.protected_method_defined?(:baz, *args))
|
|
|
|
# Test if string arguments are converted to symbols
|
|
assert_equal(always_false ? false : false, c.protected_method_defined?("foo", *args))
|
|
assert_equal(always_false ? false : true, c.protected_method_defined?("bar", *args))
|
|
assert_equal(always_false ? false : false, c.protected_method_defined?("baz", *args))
|
|
|
|
assert_equal(always_false ? false : false, c.private_method_defined?(:foo, *args))
|
|
assert_equal(always_false ? false : false, c.private_method_defined?(:bar, *args))
|
|
assert_equal(always_false ? false : true, c.private_method_defined?(:baz, *args))
|
|
|
|
# Test if string arguments are converted to symbols
|
|
assert_equal(always_false ? false : false, c.private_method_defined?("foo", *args))
|
|
assert_equal(always_false ? false : false, c.private_method_defined?("bar", *args))
|
|
assert_equal(always_false ? false : true, c.private_method_defined?("baz", *args))
|
|
end
|
|
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_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]')
|
|
c = Module.new.module_eval("class X\u{df} < Module; self; end")
|
|
assert_match(/::X\u{df}:/, c.new.to_s)
|
|
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].sort, memo.shift.sort
|
|
assert_equal mod.instance_method(:f), memo.shift
|
|
assert_equal :a, memo.shift
|
|
assert_equal [:f, :g, :a].sort, memo.shift.sort
|
|
assert_equal mod.instance_method(:a), memo.shift
|
|
assert_equal :a=, memo.shift
|
|
assert_equal [:f, :g, :a, :a=].sort, memo.shift.sort
|
|
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
|
|
|
|
stderr = EnvUtil.verbose_warning do
|
|
Module.new do
|
|
def foo; end
|
|
mod = self
|
|
c = Class.new do
|
|
include mod
|
|
end
|
|
c.new.foo
|
|
def foo; end
|
|
end
|
|
end
|
|
assert_match(/: warning: method redefined; discarding old foo/, stderr)
|
|
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
|
|
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_in_class
|
|
c = Class.new
|
|
c.const_set(:FOO, "foo")
|
|
assert_equal("foo", c::FOO)
|
|
c.private_constant(:FOO)
|
|
e = assert_raise(NameError) {c::FOO}
|
|
assert_equal(c, e.receiver)
|
|
assert_equal(:FOO, e.name)
|
|
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
|
|
e = assert_raise(NameError) {c::FOO}
|
|
assert_equal(c, e.receiver)
|
|
assert_equal(:FOO, e.name)
|
|
e = assert_raise_with_message(NameError, /#{c}::FOO/) do
|
|
Class.new(c)::FOO
|
|
end
|
|
assert_equal(c, e.receiver)
|
|
assert_equal(:FOO, e.name)
|
|
end
|
|
|
|
def test_private_constant_in_module
|
|
m = Module.new
|
|
m.const_set(:FOO, "foo")
|
|
assert_equal("foo", m::FOO)
|
|
m.private_constant(:FOO)
|
|
e = assert_raise(NameError) {m::FOO}
|
|
assert_equal(m, e.receiver)
|
|
assert_equal(:FOO, e.name)
|
|
assert_equal("foo", m.class_eval("FOO"))
|
|
assert_equal("foo", m.const_get("FOO"))
|
|
$VERBOSE, verbose = nil, $VERBOSE
|
|
m.const_set(:FOO, "foo")
|
|
$VERBOSE = verbose
|
|
e = assert_raise(NameError) {m::FOO}
|
|
assert_equal(m, e.receiver)
|
|
assert_equal(:FOO, e.name)
|
|
e = assert_raise(NameError, /#{m}::FOO/) do
|
|
Module.new {include m}::FOO
|
|
end
|
|
assert_equal(m, e.receiver)
|
|
assert_equal(:FOO, e.name)
|
|
e = assert_raise(NameError, /#{m}::FOO/) do
|
|
Class.new {include m}::FOO
|
|
end
|
|
assert_equal(m, e.receiver)
|
|
assert_equal(:FOO, e.name)
|
|
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
|
|
|
|
def test_private_constant_const_missing
|
|
c = Class.new
|
|
c.const_set(:FOO, "foo")
|
|
c.private_constant(:FOO)
|
|
class << c
|
|
attr_reader :const_missing_arg
|
|
def const_missing(name)
|
|
@const_missing_arg = name
|
|
name == :FOO ? const_get(:FOO) : super
|
|
end
|
|
end
|
|
assert_equal("foo", c::FOO)
|
|
assert_equal(:FOO, c.const_missing_arg)
|
|
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_deprecate_constant
|
|
c = Class.new
|
|
c.const_set(:FOO, "foo")
|
|
c.deprecate_constant(: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) 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('') do
|
|
Warning[:deprecated] = false
|
|
c.class_eval "FOO"
|
|
end
|
|
end
|
|
|
|
def test_constants_with_private_constant
|
|
assert_not_include(::TestModule.constants, :PrivateClass)
|
|
assert_not_include(::TestModule.constants(true), :PrivateClass)
|
|
assert_not_include(::TestModule.constants(false), :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_CMP
|
|
bug11878 = '[ruby-core:72493] [Bug #11878]'
|
|
assert_equal(-1, C1 <=> M2)
|
|
assert_equal(+1, M2 <=> C1, bug11878)
|
|
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
|
|
Integer.send(:prepend, M)
|
|
assert_equal(0.5, 1 / 2, "#{bug7983}")
|
|
}
|
|
assert_equal(0, 1 / 2)
|
|
end
|
|
|
|
def test_redefine_optmethod_after_prepend
|
|
bug11826 = '[ruby-core:72188] [Bug #11826]'
|
|
assert_separately [], %{
|
|
module M
|
|
end
|
|
class Integer
|
|
prepend M
|
|
def /(other)
|
|
quo(other)
|
|
end
|
|
end
|
|
assert_equal(1 / 2r, 1 / 2, "#{bug11826}")
|
|
}, ignore_stderr: true
|
|
assert_equal(0, 1 / 2)
|
|
end
|
|
|
|
def test_override_optmethod_after_prepend
|
|
bug11836 = '[ruby-core:72226] [Bug #11836]'
|
|
assert_separately [], %{
|
|
module M
|
|
end
|
|
class Integer
|
|
prepend M
|
|
end
|
|
module M
|
|
def /(other)
|
|
quo(other)
|
|
end
|
|
end
|
|
assert_equal(1 / 2r, 1 / 2, "#{bug11836}")
|
|
}, ignore_stderr: true
|
|
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_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]'
|
|
|
|
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_prepend_each_classes
|
|
m = labeled_module("M")
|
|
c1 = labeled_class("C1") {prepend m}
|
|
c2 = labeled_class("C2", c1) {prepend m}
|
|
assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should be able to prepend each classes")
|
|
end
|
|
|
|
def test_prepend_no_duplication
|
|
m = labeled_module("M")
|
|
c = labeled_class("C") {prepend m; prepend m}
|
|
assert_equal([m, c], c.ancestors[0, 2], "should never duplicate")
|
|
end
|
|
|
|
def test_prepend_in_superclass
|
|
m = labeled_module("M")
|
|
c1 = labeled_class("C1")
|
|
c2 = labeled_class("C2", c1) {prepend m}
|
|
c1.class_eval {prepend m}
|
|
assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should accesisble prepended module in superclass")
|
|
end
|
|
|
|
def test_prepend_call_super
|
|
assert_separately([], <<-'end;') #do
|
|
bug10847 = '[ruby-core:68093] [Bug #10847]'
|
|
module M; end
|
|
Float.prepend M
|
|
assert_nothing_raised(SystemStackError, bug10847) do
|
|
0.3.numerator
|
|
end
|
|
end;
|
|
end
|
|
|
|
def test_prepend_module_with_no_args
|
|
assert_raise(ArgumentError) { Module.new { prepend } }
|
|
end
|
|
|
|
def test_prepend_private_super
|
|
wrapper = Module.new do
|
|
def wrapped
|
|
super + 1
|
|
end
|
|
end
|
|
|
|
klass = Class.new do
|
|
prepend wrapper
|
|
|
|
def wrapped
|
|
1
|
|
end
|
|
private :wrapped
|
|
end
|
|
|
|
assert_equal(2, klass.new.wrapped)
|
|
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.sort)
|
|
assert_equal([:@@bar, :@@foo], m2.class_variables(true).sort)
|
|
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
|
|
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_extend_module_with_no_args
|
|
assert_raise(ArgumentError) { Module.new { extend } }
|
|
end
|
|
|
|
def test_invalid_attr
|
|
%W[
|
|
foo?
|
|
@foo
|
|
@@foo
|
|
$foo
|
|
\u3042$
|
|
].each do |name|
|
|
e = assert_raise(NameError) do
|
|
Module.new { attr_accessor name.to_sym }
|
|
end
|
|
assert_equal(name, e.name.to_s)
|
|
end
|
|
end
|
|
|
|
class AttrTest
|
|
class << self
|
|
attr_accessor :cattr
|
|
def reset
|
|
self.cattr = nil
|
|
end
|
|
end
|
|
attr_accessor :iattr
|
|
def ivar
|
|
@ivar
|
|
end
|
|
end
|
|
|
|
def test_uninitialized_instance_variable
|
|
a = AttrTest.new
|
|
assert_warning('') do
|
|
assert_nil(a.ivar)
|
|
end
|
|
a.instance_variable_set(:@ivar, 42)
|
|
assert_warning '' do
|
|
assert_equal(42, a.ivar)
|
|
end
|
|
|
|
name = "@\u{5909 6570}"
|
|
assert_warning('') do
|
|
assert_nil(a.instance_eval(name))
|
|
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
|
|
|
|
AttrTest.reset
|
|
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_public_methods
|
|
public_methods = %i[
|
|
include
|
|
prepend
|
|
attr
|
|
attr_accessor
|
|
attr_reader
|
|
attr_writer
|
|
define_method
|
|
alias_method
|
|
undef_method
|
|
remove_method
|
|
]
|
|
assert_equal public_methods.sort, (Module.public_methods & public_methods).sort
|
|
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_frozen_visibility
|
|
bug11532 = '[ruby-core:70828] [Bug #11532]'
|
|
|
|
c = Class.new {const_set(:A, 1)}.freeze
|
|
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) {
|
|
c.class_eval {public_constant :A}
|
|
}
|
|
|
|
c = Class.new {const_set(:A, 1)}.freeze
|
|
assert_raise_with_message(FrozenError, /frozen class/, bug11532) {
|
|
c.class_eval {deprecate_constant :A}
|
|
}
|
|
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.remove_const}
|
|
Module.new.public_class_method(:remove_const)
|
|
assert_raise(NoMethodError, bug8284) {Object.remove_const}
|
|
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 [], "#{<<~"begin;"}\n#{<<~'end;'}"
|
|
bug_10282 = "#{bug_10282}"
|
|
begin;
|
|
line = __LINE__ + 2
|
|
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 = "#<Method: A(ShallowInspect)#inspect(shallow_inspect)() -:#{line}>"
|
|
assert_equal expect, A.new.method(:inspect).inspect, bug_10282
|
|
end;
|
|
end
|
|
|
|
def test_define_method_with_unbound_method
|
|
# Passing an UnboundMethod to define_method succeeds if it is from an ancestor
|
|
assert_nothing_raised do
|
|
cls = Class.new(String) do
|
|
define_method('foo', String.instance_method(:to_s))
|
|
end
|
|
|
|
obj = cls.new('bar')
|
|
assert_equal('bar', obj.foo)
|
|
end
|
|
|
|
# Passing an UnboundMethod to define_method fails if it is not from an ancestor
|
|
assert_raise(TypeError) do
|
|
Class.new do
|
|
define_method('foo', String.instance_method(:to_s))
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_redefinition_mismatch
|
|
m = Module.new
|
|
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", __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
|
|
assert_raise_with_message(TypeError, /C\u{1f5ff}/) {
|
|
require 'etc'
|
|
}
|
|
end;
|
|
end
|
|
|
|
def test_private_extended_module
|
|
assert_separately [], %q{
|
|
class Object
|
|
def bar; "Object#bar"; end
|
|
end
|
|
module M1
|
|
def bar; super; end
|
|
end
|
|
module M2
|
|
include M1
|
|
private(:bar)
|
|
def foo; bar; end
|
|
end
|
|
extend M2
|
|
assert_equal 'Object#bar', foo
|
|
}
|
|
end
|
|
|
|
ConstLocation = [__FILE__, __LINE__]
|
|
|
|
def test_const_source_location
|
|
assert_equal(ConstLocation, self.class.const_source_location(:ConstLocation))
|
|
assert_equal(ConstLocation, self.class.const_source_location("ConstLocation"))
|
|
assert_equal(ConstLocation, Object.const_source_location("#{self.class.name}::ConstLocation"))
|
|
assert_raise(TypeError) {
|
|
self.class.const_source_location(nil)
|
|
}
|
|
assert_raise_with_message(NameError, /wrong constant name/) {
|
|
self.class.const_source_location("xxx")
|
|
}
|
|
assert_raise_with_message(TypeError, %r'does not refer to class/module') {
|
|
self.class.const_source_location("ConstLocation::FILE")
|
|
}
|
|
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
|
|
|
|
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") {
|
|
recv = self
|
|
recv.#{method}
|
|
}
|
|
}
|
|
end
|
|
end
|