1require 'test/unit'
2require_relative 'envutil'
3
4class TestClass < Test::Unit::TestCase
5  # ------------------
6  # Various test classes
7  # ------------------
8
9  class ClassOne
10    attr :num_args
11    @@subs = []
12    def initialize(*args)
13      @num_args = args.size
14      @args = args
15    end
16    def [](n)
17      @args[n]
18    end
19    def ClassOne.inherited(klass)
20      @@subs.push klass
21    end
22    def subs
23      @@subs
24    end
25  end
26
27  class ClassTwo < ClassOne
28  end
29
30  class ClassThree < ClassOne
31  end
32
33  class ClassFour < ClassThree
34  end
35
36  # ------------------
37  # Start of tests
38  # ------------------
39
40  def test_s_inherited
41    assert_equal([ClassTwo, ClassThree, ClassFour], ClassOne.new.subs)
42  end
43
44  def test_s_new
45    c = Class.new
46    assert_same(Class, c.class)
47    assert_same(Object, c.superclass)
48
49    c = Class.new(Fixnum)
50    assert_same(Class, c.class)
51    assert_same(Fixnum, c.superclass)
52  end
53
54  def test_00_new_basic
55    a = ClassOne.new
56    assert_equal(ClassOne, a.class)
57    assert_equal(0, a.num_args)
58
59    a = ClassOne.new(1, 2, 3)
60    assert_equal(3, a.num_args)
61    assert_equal(1, a[0])
62  end
63
64  def test_01_new_inherited
65    a = ClassTwo.new
66    assert_equal(ClassTwo, a.class)
67    assert_equal(0, a.num_args)
68
69    a = ClassTwo.new(1, 2, 3)
70    assert_equal(3, a.num_args)
71    assert_equal(1, a[0])
72  end
73
74  def test_superclass
75    assert_equal(ClassOne, ClassTwo.superclass)
76    assert_equal(Object,   ClassTwo.superclass.superclass)
77    assert_equal(BasicObject, ClassTwo.superclass.superclass.superclass)
78  end
79
80  def test_class_cmp
81    assert_raise(TypeError) { Class.new <= 1 }
82    assert_raise(TypeError) { Class.new >= 1 }
83    assert_nil(Class.new <=> 1)
84  end
85
86  def test_class_initialize
87    assert_raise(TypeError) do
88      Class.new.instance_eval { initialize }
89    end
90  end
91
92  def test_instanciate_singleton_class
93    c = class << Object.new; self; end
94    assert_raise(TypeError) { c.new }
95  end
96
97  def test_superclass_of_basicobject
98    assert_equal(nil, BasicObject.superclass)
99  end
100
101  def test_module_function
102    c = Class.new
103    assert_raise(TypeError) do
104      Module.instance_method(:module_function).bind(c).call(:foo)
105    end
106  end
107
108  def test_extend_object
109    c = Class.new
110    assert_raise(TypeError) do
111      Module.instance_method(:extend_object).bind(c).call(Object.new)
112    end
113  end
114
115  def test_append_features
116    c = Class.new
117    assert_raise(TypeError) do
118      Module.instance_method(:append_features).bind(c).call(Module.new)
119    end
120  end
121
122  def test_prepend_features
123    c = Class.new
124    assert_raise(TypeError) do
125      Module.instance_method(:prepend_features).bind(c).call(Module.new)
126    end
127  end
128
129  def test_module_specific_methods
130    assert_empty(Class.private_instance_methods(true) &
131      [:module_function, :extend_object, :append_features, :prepend_features])
132  end
133
134  def test_method_redefinition
135    feature2155 = '[ruby-dev:39400]'
136
137    line = __LINE__+4
138    stderr = EnvUtil.verbose_warning do
139      Class.new do
140        def foo; end
141        def foo; end
142      end
143    end
144    assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr)
145    assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155)
146
147    stderr = EnvUtil.verbose_warning do
148      Class.new do
149        def foo; end
150        alias bar foo
151        def foo; end
152      end
153    end
154    assert_equal("", stderr)
155
156    stderr = EnvUtil.verbose_warning do
157      Class.new do
158        def foo; end
159        alias bar foo
160        alias bar foo
161      end
162    end
163    assert_equal("", stderr)
164
165    line = __LINE__+4
166    stderr = EnvUtil.verbose_warning do
167      Class.new do
168        define_method(:foo) do end
169        def foo; end
170      end
171    end
172    assert_match(/:#{line}: warning: method redefined; discarding old foo/, stderr)
173    assert_match(/:#{line-1}: warning: previous definition of foo/, stderr, feature2155)
174
175    stderr = EnvUtil.verbose_warning do
176      Class.new do
177        define_method(:foo) do end
178        alias bar foo
179        alias bar foo
180      end
181    end
182    assert_equal("", stderr)
183
184    stderr = EnvUtil.verbose_warning do
185      Class.new do
186        def foo; end
187        undef foo
188      end
189    end
190    assert_equal("", stderr)
191  end
192
193  def test_check_inheritable
194    assert_raise(TypeError) { Class.new(Object.new) }
195
196    o = Object.new
197    c = class << o; self; end
198    assert_raise(TypeError) { Class.new(c) }
199    assert_raise(TypeError) { Class.new(Class) }
200    assert_raise(TypeError) { eval("class Foo < Class; end") }
201  end
202
203  def test_initialize_copy
204    c = Class.new
205    assert_raise(TypeError) { c.instance_eval { initialize_copy(1) } }
206
207    o = Object.new
208    c = class << o; self; end
209    assert_raise(TypeError) { c.dup }
210
211    assert_raise(TypeError) { BasicObject.dup }
212  end
213
214  def test_singleton_class
215    assert_raise(TypeError) { 1.extend(Module.new) }
216    assert_raise(TypeError) { 1.0.extend(Module.new) }
217    assert_raise(TypeError) { (2.0**1000).extend(Module.new) }
218    assert_raise(TypeError) { :foo.extend(Module.new) }
219
220    assert_in_out_err([], <<-INPUT, %w(:foo :foo true true), [])
221      module Foo; def foo; :foo; end; end
222      false.extend(Foo)
223      true.extend(Foo)
224      p false.foo
225      p true.foo
226      p FalseClass.include?(Foo)
227      p TrueClass.include?(Foo)
228    INPUT
229  end
230
231  def test_uninitialized
232    assert_raise(TypeError) { Class.allocate.new }
233    assert_raise(TypeError) { Class.allocate.superclass }
234    bug6863 = '[ruby-core:47148]'
235    assert_raise(TypeError, bug6863) { Class.new(Class.allocate) }
236  end
237
238  def test_nonascii_name
239    c = eval("class ::C\u{df}; self; end")
240    assert_equal("C\u{df}", c.name, '[ruby-core:24600]')
241    c = eval("class C\u{df}; self; end")
242    assert_equal("TestClass::C\u{df}", c.name, '[ruby-core:24600]')
243  end
244
245  def test_invalid_jump_from_class_definition
246    assert_raise(SyntaxError) { eval("class C; next; end") }
247    assert_raise(SyntaxError) { eval("class C; break; end") }
248    assert_raise(SyntaxError) { eval("class C; redo; end") }
249    assert_raise(SyntaxError) { eval("class C; retry; end") }
250    assert_raise(SyntaxError) { eval("class C; return; end") }
251    assert_raise(SyntaxError) { eval("class C; yield; end") }
252  end
253
254  def test_clone
255    original = Class.new {
256      def foo
257        return super()
258      end
259    }
260    mod = Module.new {
261      def foo
262        return "mod#foo"
263      end
264    }
265    copy = original.clone
266    copy.send(:include, mod)
267    assert_equal("mod#foo", copy.new.foo)
268  end
269
270  def test_nested_class_removal
271    assert_normal_exit('File.__send__(:remove_const, :Stat); at_exit{File.stat(".")}; GC.start')
272  end
273
274  class PrivateClass
275  end
276  private_constant :PrivateClass
277
278  def test_redefine_private_class
279    assert_raise(NameError) do
280      eval("class ::TestClass::PrivateClass; end")
281    end
282    eval <<-END
283      class ::TestClass
284        class PrivateClass
285          def foo; 42; end
286        end
287      end
288    END
289    assert_equal(42, PrivateClass.new.foo)
290  end
291
292  StrClone = String.clone
293  Class.new(StrClone)
294
295  def test_cloned_class
296    bug5274 = StrClone.new("[ruby-dev:44460]")
297    assert_equal(bug5274, Marshal.load(Marshal.dump(bug5274)))
298  end
299
300  def test_cannot_reinitialize_class_with_initialize_copy # [ruby-core:50869]
301    assert_in_out_err([], <<-'end;', ["Object"], [])
302      class Class
303        def initialize_copy(*); super; end
304      end
305
306      class A; end
307      class B; end
308
309      A.send(:initialize_copy, Class.new(B)) rescue nil
310
311      p A.superclass
312    end;
313  end
314
315  module M
316    C = 1
317
318    def self.m
319      C
320    end
321  end
322
323  def test_constant_access_from_method_in_cloned_module # [ruby-core:47834]
324    m = M.dup
325    assert_equal 1, m::C
326    assert_equal 1, m.m
327  end
328
329  def test_invalid_superclass
330    assert_raise(TypeError) do
331      eval <<-'end;'
332        class C < nil
333        end
334      end;
335    end
336
337    assert_raise(TypeError) do
338      eval <<-'end;'
339        class C < false
340        end
341      end;
342    end
343
344    assert_raise(TypeError) do
345      eval <<-'end;'
346        class C < true
347        end
348      end;
349    end
350
351    assert_raise(TypeError) do
352      eval <<-'end;'
353        class C < 0
354        end
355      end;
356    end
357
358    assert_raise(TypeError) do
359      eval <<-'end;'
360        class C < ""
361        end
362      end;
363    end
364  end
365
366  def test_cloned_singleton_method_added
367    bug5283 = '[ruby-dev:44477]'
368    added = []
369    c = Class.new
370    c.singleton_class.class_eval do
371      define_method(:singleton_method_added) {|mid| added << [self, mid]}
372      def foo; :foo; end
373    end
374    added.clear
375    d = c.clone
376    assert_empty(added.grep(->(k) {c == k[0]}), bug5283)
377    assert_equal(:foo, d.foo)
378  end
379end
380