2015-12-16 00:07:31 -05:00
|
|
|
# frozen_string_literal: false
|
2006-12-31 10:02:22 -05:00
|
|
|
require 'test/unit'
|
|
|
|
|
|
|
|
class TestClass < Test::Unit::TestCase
|
|
|
|
# ------------------
|
|
|
|
# Various test classes
|
|
|
|
# ------------------
|
|
|
|
|
|
|
|
class ClassOne
|
|
|
|
attr :num_args
|
|
|
|
@@subs = []
|
|
|
|
def initialize(*args)
|
|
|
|
@num_args = args.size
|
|
|
|
@args = args
|
|
|
|
end
|
|
|
|
def [](n)
|
|
|
|
@args[n]
|
|
|
|
end
|
|
|
|
def ClassOne.inherited(klass)
|
|
|
|
@@subs.push klass
|
|
|
|
end
|
|
|
|
def subs
|
|
|
|
@@subs
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class ClassTwo < ClassOne
|
|
|
|
end
|
|
|
|
|
|
|
|
class ClassThree < ClassOne
|
|
|
|
end
|
|
|
|
|
|
|
|
class ClassFour < ClassThree
|
|
|
|
end
|
|
|
|
|
|
|
|
# ------------------
|
|
|
|
# Start of tests
|
|
|
|
# ------------------
|
|
|
|
|
|
|
|
def test_s_inherited
|
|
|
|
assert_equal([ClassTwo, ClassThree, ClassFour], ClassOne.new.subs)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_s_new
|
|
|
|
c = Class.new
|
|
|
|
assert_same(Class, c.class)
|
|
|
|
assert_same(Object, c.superclass)
|
|
|
|
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
c = Class.new(Integer)
|
2006-12-31 10:02:22 -05:00
|
|
|
assert_same(Class, c.class)
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
assert_same(Integer, c.superclass)
|
2006-12-31 10:02:22 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_00_new_basic
|
|
|
|
a = ClassOne.new
|
|
|
|
assert_equal(ClassOne, a.class)
|
|
|
|
assert_equal(0, a.num_args)
|
|
|
|
|
|
|
|
a = ClassOne.new(1, 2, 3)
|
|
|
|
assert_equal(3, a.num_args)
|
|
|
|
assert_equal(1, a[0])
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_01_new_inherited
|
|
|
|
a = ClassTwo.new
|
|
|
|
assert_equal(ClassTwo, a.class)
|
|
|
|
assert_equal(0, a.num_args)
|
|
|
|
|
|
|
|
a = ClassTwo.new(1, 2, 3)
|
|
|
|
assert_equal(3, a.num_args)
|
|
|
|
assert_equal(1, a[0])
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_superclass
|
|
|
|
assert_equal(ClassOne, ClassTwo.superclass)
|
|
|
|
assert_equal(Object, ClassTwo.superclass.superclass)
|
|
|
|
assert_equal(BasicObject, ClassTwo.superclass.superclass.superclass)
|
|
|
|
end
|
|
|
|
|
2008-05-14 08:52:17 -04:00
|
|
|
def test_class_cmp
|
|
|
|
assert_raise(TypeError) { Class.new <= 1 }
|
|
|
|
assert_raise(TypeError) { Class.new >= 1 }
|
|
|
|
assert_nil(Class.new <=> 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_class_initialize
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
Class.new.instance_eval { initialize }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-22 07:27:06 -04:00
|
|
|
def test_instantiate_singleton_class
|
2008-05-14 08:52:17 -04:00
|
|
|
c = class << Object.new; self; end
|
|
|
|
assert_raise(TypeError) { c.new }
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_superclass_of_basicobject
|
|
|
|
assert_equal(nil, BasicObject.superclass)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_module_function
|
|
|
|
c = Class.new
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
Module.instance_method(:module_function).bind(c).call(:foo)
|
|
|
|
end
|
2009-09-29 02:26:46 -04:00
|
|
|
end
|
2009-09-28 23:53:44 -04:00
|
|
|
|
2013-08-13 08:52:25 -04:00
|
|
|
def test_extend_object
|
|
|
|
c = Class.new
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
Module.instance_method(:extend_object).bind(c).call(Object.new)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_append_features
|
|
|
|
c = Class.new
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
Module.instance_method(:append_features).bind(c).call(Module.new)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_prepend_features
|
|
|
|
c = Class.new
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
Module.instance_method(:prepend_features).bind(c).call(Module.new)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_module_specific_methods
|
|
|
|
assert_empty(Class.private_instance_methods(true) &
|
|
|
|
[:module_function, :extend_object, :append_features, :prepend_features])
|
|
|
|
end
|
|
|
|
|
2019-08-24 20:11:06 -04:00
|
|
|
def test_visibility_inside_method
|
|
|
|
assert_warn(/calling private without arguments inside a method may not have the intended effect/, '[ruby-core:79751]') do
|
|
|
|
Class.new do
|
|
|
|
def self.foo
|
|
|
|
private
|
|
|
|
end
|
|
|
|
foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_warn(/calling protected without arguments inside a method may not have the intended effect/, '[ruby-core:79751]') do
|
|
|
|
Class.new do
|
|
|
|
def self.foo
|
|
|
|
protected
|
|
|
|
end
|
|
|
|
foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_warn(/calling public without arguments inside a method may not have the intended effect/, '[ruby-core:79751]') do
|
|
|
|
Class.new do
|
|
|
|
def self.foo
|
|
|
|
public
|
|
|
|
end
|
|
|
|
foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_warn(/calling private without arguments inside a method may not have the intended effect/, '[ruby-core:79751]') do
|
|
|
|
Class.new do
|
|
|
|
class << self
|
|
|
|
alias priv private
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.foo
|
|
|
|
priv
|
|
|
|
end
|
|
|
|
foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-09-29 02:26:46 -04:00
|
|
|
def test_method_redefinition
|
2009-09-30 00:15:46 -04:00
|
|
|
feature2155 = '[ruby-dev:39400]'
|
|
|
|
|
2009-09-29 02:59:42 -04:00
|
|
|
line = __LINE__+4
|
2009-09-29 02:26:46 -04:00
|
|
|
stderr = EnvUtil.verbose_warning do
|
|
|
|
Class.new do
|
2009-09-28 23:53:44 -04:00
|
|
|
def foo; end
|
|
|
|
def foo; end
|
|
|
|
end
|
|
|
|
end
|
2009-09-29 02:59:42 -04:00
|
|
|
assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr)
|
2009-09-30 00:15:46 -04:00
|
|
|
assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155)
|
2009-09-29 02:26:46 -04:00
|
|
|
|
2013-03-30 00:33:28 -04:00
|
|
|
assert_warning '' do
|
2009-09-29 02:26:46 -04:00
|
|
|
Class.new do
|
|
|
|
def foo; end
|
|
|
|
alias bar foo
|
|
|
|
def foo; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-03-30 00:33:28 -04:00
|
|
|
assert_warning '' do
|
2009-09-29 02:26:46 -04:00
|
|
|
Class.new do
|
2009-09-28 23:53:44 -04:00
|
|
|
def foo; end
|
|
|
|
alias bar foo
|
|
|
|
alias bar foo
|
|
|
|
end
|
|
|
|
end
|
2009-09-29 02:26:46 -04:00
|
|
|
|
2009-09-29 02:59:42 -04:00
|
|
|
line = __LINE__+4
|
2009-09-29 02:26:46 -04:00
|
|
|
stderr = EnvUtil.verbose_warning do
|
|
|
|
Class.new do
|
|
|
|
define_method(:foo) do end
|
2009-09-29 00:37:52 -04:00
|
|
|
def foo; end
|
|
|
|
end
|
|
|
|
end
|
2009-09-29 03:03:11 -04:00
|
|
|
assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr)
|
2009-09-30 00:15:46 -04:00
|
|
|
assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155)
|
2009-09-29 02:26:46 -04:00
|
|
|
|
2013-03-30 00:33:28 -04:00
|
|
|
assert_warning '' do
|
2009-09-29 02:26:46 -04:00
|
|
|
Class.new do
|
|
|
|
define_method(:foo) do end
|
|
|
|
alias bar foo
|
2009-10-03 08:19:19 -04:00
|
|
|
alias bar foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-03-30 00:33:28 -04:00
|
|
|
assert_warning '' do
|
2009-10-03 08:19:19 -04:00
|
|
|
Class.new do
|
|
|
|
def foo; end
|
|
|
|
undef foo
|
2009-09-29 02:26:46 -04:00
|
|
|
end
|
|
|
|
end
|
2008-05-14 08:52:17 -04:00
|
|
|
end
|
|
|
|
|
2008-05-21 11:31:15 -04:00
|
|
|
def test_check_inheritable
|
|
|
|
assert_raise(TypeError) { Class.new(Object.new) }
|
|
|
|
|
|
|
|
o = Object.new
|
|
|
|
c = class << o; self; end
|
|
|
|
assert_raise(TypeError) { Class.new(c) }
|
2009-10-23 19:37:14 -04:00
|
|
|
assert_raise(TypeError) { Class.new(Class) }
|
2008-05-21 11:31:15 -04:00
|
|
|
assert_raise(TypeError) { eval("class Foo < Class; end") }
|
2015-06-27 23:28:50 -04:00
|
|
|
m = "M\u{1f5ff}"
|
|
|
|
o = Class.new {break eval("class #{m}; self; end.new")}
|
|
|
|
assert_raise_with_message(TypeError, /#{m}/) {Class.new(o)}
|
2008-05-21 11:31:15 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_initialize_copy
|
|
|
|
c = Class.new
|
|
|
|
assert_raise(TypeError) { c.instance_eval { initialize_copy(1) } }
|
|
|
|
|
|
|
|
o = Object.new
|
|
|
|
c = class << o; self; end
|
|
|
|
assert_raise(TypeError) { c.dup }
|
2010-02-06 10:26:34 -05:00
|
|
|
|
|
|
|
assert_raise(TypeError) { BasicObject.dup }
|
2008-05-21 11:31:15 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_singleton_class
|
|
|
|
assert_raise(TypeError) { 1.extend(Module.new) }
|
2012-10-26 22:10:53 -04:00
|
|
|
assert_raise(TypeError) { 1.0.extend(Module.new) }
|
|
|
|
assert_raise(TypeError) { (2.0**1000).extend(Module.new) }
|
2008-05-21 11:31:15 -04:00
|
|
|
assert_raise(TypeError) { :foo.extend(Module.new) }
|
|
|
|
|
2008-07-15 11:26:04 -04:00
|
|
|
assert_in_out_err([], <<-INPUT, %w(:foo :foo true true), [])
|
|
|
|
module Foo; def foo; :foo; end; end
|
|
|
|
false.extend(Foo)
|
|
|
|
true.extend(Foo)
|
|
|
|
p false.foo
|
|
|
|
p true.foo
|
|
|
|
p FalseClass.include?(Foo)
|
|
|
|
p TrueClass.include?(Foo)
|
|
|
|
INPUT
|
2008-05-21 11:31:15 -04:00
|
|
|
end
|
2008-06-02 08:57:18 -04:00
|
|
|
|
|
|
|
def test_uninitialized
|
|
|
|
assert_raise(TypeError) { Class.allocate.new }
|
|
|
|
assert_raise(TypeError) { Class.allocate.superclass }
|
2012-08-16 06:15:28 -04:00
|
|
|
bug6863 = '[ruby-core:47148]'
|
|
|
|
assert_raise(TypeError, bug6863) { Class.new(Class.allocate) }
|
2019-11-05 21:17:09 -05:00
|
|
|
|
|
|
|
allocator = Class.instance_method(:allocate)
|
|
|
|
assert_raise_with_message(TypeError, /prohibited/) {
|
|
|
|
allocator.bind(Rational).call
|
|
|
|
}
|
|
|
|
assert_raise_with_message(TypeError, /prohibited/) {
|
|
|
|
allocator.bind_call(Rational)
|
|
|
|
}
|
2008-06-02 08:57:18 -04:00
|
|
|
end
|
2009-07-30 03:45:42 -04:00
|
|
|
|
|
|
|
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("TestClass::C\u{df}", c.name, '[ruby-core:24600]')
|
|
|
|
end
|
2010-01-21 11:08:40 -05:00
|
|
|
|
2017-11-16 00:36:42 -05:00
|
|
|
def test_invalid_next_from_class_definition
|
2019-02-07 21:54:21 -05:00
|
|
|
assert_syntax_error("class C; next; end", /Invalid next/)
|
2017-11-16 00:36:42 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_invalid_break_from_class_definition
|
2019-02-07 21:54:21 -05:00
|
|
|
assert_syntax_error("class C; break; end", /Invalid break/)
|
2017-11-16 00:36:42 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_invalid_redo_from_class_definition
|
2019-02-07 21:54:21 -05:00
|
|
|
assert_syntax_error("class C; redo; end", /Invalid redo/)
|
2017-11-16 00:36:42 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_invalid_retry_from_class_definition
|
2019-02-07 21:54:21 -05:00
|
|
|
assert_syntax_error("class C; retry; end", /Invalid retry/)
|
2017-11-02 08:45:37 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_invalid_return_from_class_definition
|
2019-02-07 21:54:21 -05:00
|
|
|
assert_syntax_error("class C; return; end", /Invalid return/)
|
2017-11-02 08:45:37 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_invalid_yield_from_class_definition
|
2020-02-11 14:56:34 -05:00
|
|
|
assert_raise(SyntaxError) {
|
2019-02-07 21:54:20 -05:00
|
|
|
EnvUtil.suppress_warning {eval("class C; yield; end")}
|
|
|
|
}
|
2010-01-21 11:08:40 -05:00
|
|
|
end
|
2010-03-10 11:07:06 -05:00
|
|
|
|
|
|
|
def test_clone
|
|
|
|
original = Class.new {
|
|
|
|
def foo
|
|
|
|
return super()
|
|
|
|
end
|
|
|
|
}
|
|
|
|
mod = Module.new {
|
|
|
|
def foo
|
|
|
|
return "mod#foo"
|
|
|
|
end
|
|
|
|
}
|
|
|
|
copy = original.clone
|
|
|
|
copy.send(:include, mod)
|
|
|
|
assert_equal("mod#foo", copy.new.foo)
|
|
|
|
end
|
2010-10-16 21:40:22 -04:00
|
|
|
|
|
|
|
def test_nested_class_removal
|
|
|
|
assert_normal_exit('File.__send__(:remove_const, :Stat); at_exit{File.stat(".")}; GC.start')
|
|
|
|
end
|
2011-01-28 12:57:34 -05:00
|
|
|
|
|
|
|
class PrivateClass
|
|
|
|
end
|
|
|
|
private_constant :PrivateClass
|
|
|
|
|
|
|
|
def test_redefine_private_class
|
|
|
|
assert_raise(NameError) do
|
|
|
|
eval("class ::TestClass::PrivateClass; end")
|
|
|
|
end
|
|
|
|
eval <<-END
|
|
|
|
class ::TestClass
|
|
|
|
class PrivateClass
|
|
|
|
def foo; 42; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
END
|
|
|
|
assert_equal(42, PrivateClass.new.foo)
|
|
|
|
end
|
2011-09-18 18:54:25 -04:00
|
|
|
|
|
|
|
StrClone = String.clone
|
|
|
|
Class.new(StrClone)
|
|
|
|
|
|
|
|
def test_cloned_class
|
|
|
|
bug5274 = StrClone.new("[ruby-dev:44460]")
|
|
|
|
assert_equal(bug5274, Marshal.load(Marshal.dump(bug5274)))
|
|
|
|
end
|
2012-12-13 09:11:01 -05:00
|
|
|
|
|
|
|
def test_cannot_reinitialize_class_with_initialize_copy # [ruby-core:50869]
|
2017-08-29 03:11:52 -04:00
|
|
|
assert_in_out_err([], "#{<<~"begin;"}\n#{<<~'end;'}", ["Object"], [])
|
|
|
|
begin;
|
2012-12-13 09:11:01 -05:00
|
|
|
class Class
|
|
|
|
def initialize_copy(*); super; end
|
|
|
|
end
|
|
|
|
|
|
|
|
class A; end
|
|
|
|
class B; end
|
|
|
|
|
|
|
|
A.send(:initialize_copy, Class.new(B)) rescue nil
|
|
|
|
|
|
|
|
p A.superclass
|
2012-12-28 20:13:53 -05:00
|
|
|
end;
|
2012-12-13 09:11:01 -05:00
|
|
|
end
|
2012-12-17 04:49:00 -05:00
|
|
|
|
2019-08-08 22:00:34 -04:00
|
|
|
class CloneTest
|
|
|
|
def foo; TEST; end
|
|
|
|
end
|
2012-12-17 04:49:00 -05:00
|
|
|
|
2019-08-08 22:00:34 -04:00
|
|
|
CloneTest1 = CloneTest.clone
|
|
|
|
CloneTest2 = CloneTest.clone
|
|
|
|
class CloneTest1
|
|
|
|
TEST = :C1
|
|
|
|
end
|
|
|
|
class CloneTest2
|
|
|
|
TEST = :C2
|
2012-12-17 04:49:00 -05:00
|
|
|
end
|
|
|
|
|
2019-08-08 22:00:34 -04:00
|
|
|
def test_constant_access_from_method_in_cloned_class
|
|
|
|
assert_equal :C1, CloneTest1.new.foo, '[Bug #15877]'
|
|
|
|
assert_equal :C2, CloneTest2.new.foo, '[Bug #15877]'
|
2012-12-17 04:49:00 -05:00
|
|
|
end
|
2012-12-20 03:13:53 -05:00
|
|
|
|
|
|
|
def test_invalid_superclass
|
|
|
|
assert_raise(TypeError) do
|
2012-12-28 20:13:53 -05:00
|
|
|
eval <<-'end;'
|
2012-12-20 03:13:53 -05:00
|
|
|
class C < nil
|
|
|
|
end
|
2012-12-28 20:13:53 -05:00
|
|
|
end;
|
2012-12-20 03:13:53 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise(TypeError) do
|
2012-12-28 20:13:53 -05:00
|
|
|
eval <<-'end;'
|
2012-12-20 03:13:53 -05:00
|
|
|
class C < false
|
|
|
|
end
|
2012-12-28 20:13:53 -05:00
|
|
|
end;
|
2012-12-20 03:13:53 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise(TypeError) do
|
2012-12-28 20:13:53 -05:00
|
|
|
eval <<-'end;'
|
2012-12-20 03:13:53 -05:00
|
|
|
class C < true
|
|
|
|
end
|
2012-12-28 20:13:53 -05:00
|
|
|
end;
|
2012-12-20 03:13:53 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise(TypeError) do
|
2012-12-28 20:13:53 -05:00
|
|
|
eval <<-'end;'
|
2012-12-20 03:13:53 -05:00
|
|
|
class C < 0
|
|
|
|
end
|
2012-12-28 20:13:53 -05:00
|
|
|
end;
|
2012-12-20 03:13:53 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise(TypeError) do
|
2012-12-28 20:13:53 -05:00
|
|
|
eval <<-'end;'
|
2012-12-20 03:13:53 -05:00
|
|
|
class C < ""
|
|
|
|
end
|
2012-12-28 20:13:53 -05:00
|
|
|
end;
|
2012-12-20 03:13:53 -05:00
|
|
|
end
|
2015-06-28 13:10:00 -04:00
|
|
|
|
|
|
|
m = Module.new
|
|
|
|
n = "M\u{1f5ff}"
|
|
|
|
c = m.module_eval "class #{n}; new; end"
|
|
|
|
assert_raise_with_message(TypeError, /#{n}/) {
|
|
|
|
eval <<-"end;"
|
|
|
|
class C < c
|
|
|
|
end
|
|
|
|
end;
|
2015-06-28 13:10:26 -04:00
|
|
|
}
|
2016-02-19 02:48:02 -05:00
|
|
|
assert_raise_with_message(TypeError, /#{n}/) {
|
|
|
|
Class.new(c)
|
|
|
|
}
|
2015-06-28 13:10:26 -04:00
|
|
|
assert_raise_with_message(TypeError, /#{n}/) {
|
|
|
|
m.module_eval "class #{n} < Class.new; end"
|
2015-06-28 13:10:00 -04:00
|
|
|
}
|
2012-12-20 03:13:53 -05:00
|
|
|
end
|
2012-12-28 21:37:47 -05:00
|
|
|
|
2016-05-10 08:46:43 -04:00
|
|
|
define_method :test_invalid_reset_superclass do
|
|
|
|
class A; end
|
|
|
|
class SuperclassCannotBeReset < A
|
|
|
|
end
|
|
|
|
assert_equal A, SuperclassCannotBeReset.superclass
|
|
|
|
|
|
|
|
assert_raise_with_message(TypeError, /superclass mismatch/) {
|
|
|
|
class SuperclassCannotBeReset < String
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_raise_with_message(TypeError, /superclass mismatch/, "[ruby-core:75446]") {
|
|
|
|
class SuperclassCannotBeReset < Object
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_equal A, SuperclassCannotBeReset.superclass
|
|
|
|
end
|
|
|
|
|
2012-12-28 21:37:47 -05:00
|
|
|
def test_cloned_singleton_method_added
|
|
|
|
bug5283 = '[ruby-dev:44477]'
|
|
|
|
added = []
|
|
|
|
c = Class.new
|
|
|
|
c.singleton_class.class_eval do
|
|
|
|
define_method(:singleton_method_added) {|mid| added << [self, mid]}
|
|
|
|
def foo; :foo; end
|
|
|
|
end
|
|
|
|
added.clear
|
|
|
|
d = c.clone
|
|
|
|
assert_empty(added.grep(->(k) {c == k[0]}), bug5283)
|
|
|
|
assert_equal(:foo, d.foo)
|
|
|
|
end
|
2013-08-08 10:01:23 -04:00
|
|
|
|
2020-11-11 16:38:03 -05:00
|
|
|
def test_clone_singleton_class_exists
|
|
|
|
klass = Class.new do
|
|
|
|
def self.bar; :bar; end
|
|
|
|
end
|
|
|
|
|
|
|
|
o = klass.new
|
|
|
|
o.singleton_class
|
|
|
|
clone = o.clone
|
|
|
|
|
|
|
|
assert_empty(o.singleton_class.instance_methods(false))
|
|
|
|
assert_empty(clone.singleton_class.instance_methods(false))
|
|
|
|
assert_empty(o.singleton_class.singleton_class.instance_methods(false))
|
|
|
|
assert_empty(clone.singleton_class.singleton_class.instance_methods(false))
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_clone_when_singleton_class_of_singleton_class_exists
|
|
|
|
klass = Class.new do
|
|
|
|
def self.bar; :bar; end
|
|
|
|
end
|
|
|
|
|
|
|
|
o = klass.new
|
|
|
|
o.singleton_class.singleton_class
|
|
|
|
clone = o.clone
|
|
|
|
|
|
|
|
assert_empty(o.singleton_class.instance_methods(false))
|
|
|
|
assert_empty(clone.singleton_class.instance_methods(false))
|
|
|
|
assert_empty(o.singleton_class.singleton_class.instance_methods(false))
|
|
|
|
assert_empty(clone.singleton_class.singleton_class.instance_methods(false))
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_clone_when_method_exists_on_singleton_class_of_singleton_class
|
|
|
|
klass = Class.new do
|
|
|
|
def self.bar; :bar; end
|
|
|
|
end
|
|
|
|
|
|
|
|
o = klass.new
|
|
|
|
o.singleton_class.singleton_class.define_method(:s2_method) { :s2 }
|
|
|
|
clone = o.clone
|
|
|
|
|
|
|
|
assert_empty(o.singleton_class.instance_methods(false))
|
|
|
|
assert_empty(clone.singleton_class.instance_methods(false))
|
|
|
|
assert_equal(:s2, o.singleton_class.s2_method)
|
|
|
|
assert_equal(:s2, clone.singleton_class.s2_method)
|
|
|
|
assert_equal([:s2_method], o.singleton_class.singleton_class.instance_methods(false))
|
|
|
|
assert_equal([:s2_method], clone.singleton_class.singleton_class.instance_methods(false))
|
|
|
|
end
|
|
|
|
|
2013-08-08 10:01:23 -04:00
|
|
|
def test_singleton_class_p
|
|
|
|
feature7609 = '[ruby-core:51087] [Feature #7609]'
|
|
|
|
assert_predicate(self.singleton_class, :singleton_class?, feature7609)
|
|
|
|
assert_not_predicate(self.class, :singleton_class?, feature7609)
|
|
|
|
end
|
2014-06-06 22:41:01 -04:00
|
|
|
|
|
|
|
def test_freeze_to_s
|
|
|
|
assert_nothing_raised("[ruby-core:41858] [Bug #5828]") {
|
|
|
|
Class.new.freeze.clone.to_s
|
|
|
|
}
|
|
|
|
end
|
2014-09-12 04:13:28 -04:00
|
|
|
|
|
|
|
def test_singleton_class_of_frozen_object
|
|
|
|
obj = Object.new
|
|
|
|
c = obj.singleton_class
|
|
|
|
obj.freeze
|
2017-12-11 19:46:34 -05:00
|
|
|
assert_raise_with_message(FrozenError, /frozen object/) {
|
2014-09-12 04:13:28 -04:00
|
|
|
c.class_eval {def f; end}
|
|
|
|
}
|
2014-09-13 09:03:46 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_singleton_class_message
|
2014-09-12 21:22:01 -04:00
|
|
|
c = Class.new.freeze
|
2017-12-11 19:46:34 -05:00
|
|
|
assert_raise_with_message(FrozenError, /frozen Class/) {
|
2014-09-12 21:22:01 -04:00
|
|
|
def c.f; end
|
|
|
|
}
|
2014-09-12 04:13:28 -04:00
|
|
|
end
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 07:24:58 -05:00
|
|
|
|
|
|
|
def test_singleton_class_should_has_own_namespace
|
|
|
|
# CONST in singleton class
|
|
|
|
objs = []
|
|
|
|
$i = 0
|
|
|
|
|
|
|
|
2.times{
|
|
|
|
objs << obj = Object.new
|
|
|
|
class << obj
|
|
|
|
CONST = ($i += 1)
|
|
|
|
def foo
|
|
|
|
CONST
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
assert_equal(1, objs[0].foo, '[Bug #10943]')
|
|
|
|
assert_equal(2, objs[1].foo, '[Bug #10943]')
|
|
|
|
|
|
|
|
# CONST in block in singleton class
|
|
|
|
objs = []
|
|
|
|
$i = 0
|
|
|
|
|
|
|
|
2.times{
|
|
|
|
objs << obj = Object.new
|
|
|
|
class << obj
|
|
|
|
1.times{
|
|
|
|
CONST = ($i += 1)
|
|
|
|
}
|
|
|
|
def foo
|
|
|
|
[nil].map{
|
|
|
|
CONST
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
assert_equal([1], objs[0].foo, '[Bug #10943]')
|
|
|
|
assert_equal([2], objs[1].foo, '[Bug #10943]')
|
|
|
|
|
|
|
|
# class def in singleton class
|
|
|
|
objs = []
|
|
|
|
$xs = []
|
|
|
|
$i = 0
|
|
|
|
|
|
|
|
2.times{
|
|
|
|
objs << obj = Object.new
|
|
|
|
class << obj
|
|
|
|
CONST = ($i += 1)
|
|
|
|
class X
|
|
|
|
$xs << self
|
|
|
|
CONST = ($i += 1)
|
|
|
|
def foo
|
|
|
|
CONST
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def x
|
|
|
|
X
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
assert_not_equal($xs[0], $xs[1], '[Bug #10943]')
|
|
|
|
assert_not_equal(objs[0].x, objs[1].x, '[Bug #10943]')
|
|
|
|
assert_equal(2, $xs[0]::CONST, '[Bug #10943]')
|
|
|
|
assert_equal(2, $xs[0].new.foo, '[Bug #10943]')
|
|
|
|
assert_equal(4, $xs[1]::CONST, '[Bug #10943]')
|
|
|
|
assert_equal(4, $xs[1].new.foo, '[Bug #10943]')
|
|
|
|
|
|
|
|
# class def in block in singleton class
|
|
|
|
objs = []
|
|
|
|
$xs = []
|
|
|
|
$i = 0
|
|
|
|
|
|
|
|
2.times{
|
|
|
|
objs << obj = Object.new
|
|
|
|
class << obj
|
|
|
|
1.times{
|
|
|
|
CONST = ($i += 1)
|
|
|
|
}
|
|
|
|
1.times{
|
|
|
|
class X
|
|
|
|
$xs << self
|
|
|
|
CONST = ($i += 1)
|
|
|
|
def foo
|
|
|
|
CONST
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def x
|
|
|
|
X
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
|
|
|
}
|
|
|
|
assert_not_equal($xs[0], $xs[1], '[Bug #10943]')
|
|
|
|
assert_not_equal(objs[0].x, objs[1].x, '[Bug #10943]')
|
|
|
|
assert_equal(2, $xs[0]::CONST, '[Bug #10943]')
|
|
|
|
assert_equal(2, $xs[0].new.foo, '[Bug #10943]')
|
|
|
|
assert_equal(4, $xs[1]::CONST, '[Bug #10943]')
|
|
|
|
assert_equal(4, $xs[1].new.foo, '[Bug #10943]')
|
|
|
|
|
|
|
|
# method def in singleton class
|
|
|
|
ms = []
|
|
|
|
ps = $test_singleton_class_shared_cref_ps = []
|
|
|
|
2.times{
|
|
|
|
ms << Module.new do
|
|
|
|
class << self
|
|
|
|
$test_singleton_class_shared_cref_ps << Proc.new{
|
|
|
|
def xyzzy
|
|
|
|
self
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
ps.each{|p| p.call} # define xyzzy methods for each singleton classes
|
|
|
|
ms.each{|m|
|
|
|
|
assert_equal(m, m.xyzzy, "Bug #10871")
|
|
|
|
}
|
|
|
|
end
|
2015-06-28 12:35:58 -04:00
|
|
|
|
2016-01-24 09:59:16 -05:00
|
|
|
def test_namescope_error_message
|
|
|
|
m = Module.new
|
|
|
|
o = m.module_eval "class A\u{3042}; self; end.new"
|
|
|
|
assert_raise_with_message(TypeError, /A\u{3042}/) {
|
2016-04-08 21:25:11 -04:00
|
|
|
o::Foo
|
2016-01-24 09:59:16 -05:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2015-06-28 12:35:58 -04:00
|
|
|
def test_redefinition_mismatch
|
|
|
|
m = Module.new
|
2019-07-04 03:54:34 -04:00
|
|
|
m.module_eval "A = 1", __FILE__, line = __LINE__
|
|
|
|
e = assert_raise_with_message(TypeError, /is not a class/) {
|
2015-06-28 12:35:58 -04:00
|
|
|
m.module_eval "class A; end"
|
|
|
|
}
|
2019-07-04 03:54:34 -04:00
|
|
|
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
|
2015-06-28 13:06:59 -04:00
|
|
|
n = "M\u{1f5ff}"
|
2019-07-04 03:54:34 -04:00
|
|
|
m.module_eval "#{n} = 42", __FILE__, line = __LINE__
|
|
|
|
e = assert_raise_with_message(TypeError, /#{n} is not a class/) {
|
2015-06-28 13:06:59 -04:00
|
|
|
m.module_eval "class #{n}; end"
|
|
|
|
}
|
2019-07-04 03:54:34 -04:00
|
|
|
assert_include(e.message, "#{__FILE__}:#{line}: previous definition")
|
2015-09-27 10:32:50 -04:00
|
|
|
|
2017-08-29 03:11:52 -04:00
|
|
|
assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}")
|
|
|
|
begin;
|
2015-09-27 10:32:50 -04:00
|
|
|
Date = (class C\u{1f5ff}; self; end).new
|
|
|
|
assert_raise_with_message(TypeError, /C\u{1f5ff}/) {
|
|
|
|
require 'date'
|
|
|
|
}
|
|
|
|
end;
|
2015-06-28 12:35:58 -04:00
|
|
|
end
|
2015-12-22 08:15:58 -05:00
|
|
|
|
|
|
|
def test_should_not_expose_singleton_class_without_metaclass
|
2017-08-29 03:11:52 -04:00
|
|
|
assert_normal_exit "#{<<~"begin;"}\n#{<<~'end;'}", '[Bug #11740]'
|
|
|
|
begin;
|
2015-12-22 08:15:58 -05:00
|
|
|
klass = Class.new(Array)
|
|
|
|
# The metaclass of +klass+ should handle #bla since it should inherit methods from meta:meta:Array
|
|
|
|
def (Array.singleton_class).bla; :bla; end
|
|
|
|
hidden = ObjectSpace.each_object(Class).find { |c| klass.is_a? c and c.inspect.include? klass.inspect }
|
|
|
|
raise unless hidden.nil?
|
2017-08-29 03:11:52 -04:00
|
|
|
end;
|
2015-12-22 08:15:58 -05:00
|
|
|
|
2017-08-29 03:11:52 -04:00
|
|
|
assert_normal_exit "#{<<~"begin;"}\n#{<<~'end;'}", '[Bug #11740]'
|
|
|
|
begin;
|
2015-12-22 08:15:58 -05:00
|
|
|
klass = Class.new(Array)
|
|
|
|
klass.singleton_class
|
|
|
|
# The metaclass of +klass+ should handle #bla since it should inherit methods from meta:meta:Array
|
|
|
|
def (Array.singleton_class).bla; :bla; end
|
|
|
|
hidden = ObjectSpace.each_object(Class).find { |c| klass.is_a? c and c.inspect.include? klass.inspect }
|
|
|
|
raise if hidden.nil?
|
2017-08-29 03:11:52 -04:00
|
|
|
end;
|
2015-12-22 08:15:58 -05:00
|
|
|
|
|
|
|
end
|
2021-01-20 01:05:30 -05:00
|
|
|
|
|
|
|
def test_assign_frozen_class_to_const
|
|
|
|
c = Class.new.freeze
|
|
|
|
assert_same(c, Module.new.module_eval("self::Foo = c"))
|
|
|
|
c = Class.new.freeze
|
|
|
|
assert_same(c, Module.new.const_set(:Foo, c))
|
|
|
|
end
|
2006-12-31 10:02:22 -05:00
|
|
|
end
|