diff options
Diffstat (limited to 'spec/ruby/core/class')
-rw-r--r-- | spec/ruby/core/class/allocate_spec.rb | 41 | ||||
-rw-r--r-- | spec/ruby/core/class/dup_spec.rb | 64 | ||||
-rw-r--r-- | spec/ruby/core/class/fixtures/classes.rb | 47 | ||||
-rw-r--r-- | spec/ruby/core/class/inherited_spec.rb | 102 | ||||
-rw-r--r-- | spec/ruby/core/class/initialize_spec.rb | 34 | ||||
-rw-r--r-- | spec/ruby/core/class/new_spec.rb | 154 | ||||
-rw-r--r-- | spec/ruby/core/class/superclass_spec.rb | 27 | ||||
-rw-r--r-- | spec/ruby/core/class/to_s_spec.rb | 23 |
8 files changed, 492 insertions, 0 deletions
diff --git a/spec/ruby/core/class/allocate_spec.rb b/spec/ruby/core/class/allocate_spec.rb new file mode 100644 index 0000000000..015db292eb --- /dev/null +++ b/spec/ruby/core/class/allocate_spec.rb @@ -0,0 +1,41 @@ +require File.expand_path('../../../spec_helper', __FILE__) + +describe "Class#allocate" do + it "returns an instance of self" do + klass = Class.new + klass.allocate.should be_an_instance_of(klass) + end + + it "returns a fully-formed instance of Module" do + klass = Class.allocate + klass.constants.should_not == nil + klass.methods.should_not == nil + end + + it "throws an exception when calling a method on a new instance" do + klass = Class.allocate + lambda do + klass.new + end.should raise_error(Exception) + end + + it "does not call initialize on the new instance" do + klass = Class.new do + def initialize(*args) + @initialized = true + end + + def initialized? + @initialized || false + end + end + + klass.allocate.initialized?.should == false + end + + it "raises TypeError for #superclass" do + lambda do + Class.allocate.superclass + end.should raise_error(TypeError) + end +end diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb new file mode 100644 index 0000000000..0548536bd6 --- /dev/null +++ b/spec/ruby/core/class/dup_spec.rb @@ -0,0 +1,64 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +# NOTE: This is actually implemented by Module#initialize_copy +describe "Class#dup" do + it "duplicates both the class and the singleton class" do + klass = Class.new do + def hello + "hello" + end + + def self.message + "text" + end + end + + klass_dup = klass.dup + + klass_dup.new.hello.should == "hello" + klass_dup.message.should == "text" + end + + it "retains an included module in the ancestor chain for the singleton class" do + klass = Class.new + mod = Module.new do + def hello + "hello" + end + end + + klass.extend(mod) + klass_dup = klass.dup + klass_dup.hello.should == "hello" + end + + it "retains the correct ancestor chain for the singleton class" do + super_klass = Class.new do + def hello + "hello" + end + + def self.message + "text" + end + end + + klass = Class.new(super_klass) + klass_dup = klass.dup + + klass_dup.new.hello.should == "hello" + klass_dup.message.should == "text" + end + + it "sets the name from the class to nil if not assigned to a constant" do + copy = CoreClassSpecs::Record.dup + copy.name.should be_nil + end + + it "stores the new name if assigned to a constant" do + CoreClassSpecs::RecordCopy = CoreClassSpecs::Record.dup + CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy" + end + +end diff --git a/spec/ruby/core/class/fixtures/classes.rb b/spec/ruby/core/class/fixtures/classes.rb new file mode 100644 index 0000000000..f96db90795 --- /dev/null +++ b/spec/ruby/core/class/fixtures/classes.rb @@ -0,0 +1,47 @@ +module CoreClassSpecs + class Record + end + + module M + def inherited(klass) + ScratchPad.record klass + super + end + end + + class F; end + class << F + include M + end + + class A + def self.inherited(klass) + ScratchPad.record klass + end + end + + class H < A + def self.inherited(klass) + super + end + end + + module Inherited + class A + SUBCLASSES = [] + def self.inherited(subclass) + SUBCLASSES << [self, subclass] + end + end + + class B < A; end + class B < A; end # reopen + class C < B; end + + class D + def self.inherited(subclass) + ScratchPad << self + end + end + end +end diff --git a/spec/ruby/core/class/inherited_spec.rb b/spec/ruby/core/class/inherited_spec.rb new file mode 100644 index 0000000000..356e46be7c --- /dev/null +++ b/spec/ruby/core/class/inherited_spec.rb @@ -0,0 +1,102 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Class.inherited" do + + before :each do + ScratchPad.record nil + end + + it "is invoked with the child Class when self is subclassed" do + begin + top = Class.new do + def self.inherited(cls) + $child_class = cls + end + end + + child = Class.new(top) + $child_class.should == child + + other_child = Class.new(top) + $child_class.should == other_child + ensure + $child_class = nil + end + end + + it "is invoked only once per subclass" do + expected = [ + [CoreClassSpecs::Inherited::A, CoreClassSpecs::Inherited::B], + [CoreClassSpecs::Inherited::B, CoreClassSpecs::Inherited::C], + ] + + CoreClassSpecs::Inherited::A::SUBCLASSES.should == expected + end + + it "is called when marked as a private class method" do + a = Class.new do + def self.inherited(klass) + ScratchPad.record klass + end + end + a.private_class_method :inherited + ScratchPad.recorded.should == nil + b = Class.new(a) + ScratchPad.recorded.should == b + end + + it "is called when marked as a protected class method" do + a = Class.new + class << a + def inherited(klass) + ScratchPad.record klass + end + protected :inherited + end + ScratchPad.recorded.should == nil + b = Class.new(a) + ScratchPad.recorded.should == b + end + + it "is called when marked as a public class method" do + a = Class.new do + def self.inherited(klass) + ScratchPad.record klass + end + end + a.public_class_method :inherited + ScratchPad.recorded.should == nil + b = Class.new(a) + ScratchPad.recorded.should == b + end + + it "is called by super from a method provided by an included module" do + ScratchPad.recorded.should == nil + e = Class.new(CoreClassSpecs::F) + ScratchPad.recorded.should == e + end + + it "is called by super even when marked as a private class method" do + ScratchPad.recorded.should == nil + CoreClassSpecs::H.private_class_method :inherited + i = Class.new(CoreClassSpecs::H) + ScratchPad.recorded.should == i + end + + it "will be invoked by child class regardless of visibility" do + top = Class.new do + class << self + def inherited(cls); end + end + end + + class << top; private :inherited; end + lambda { Class.new(top) }.should_not raise_error + + class << top; protected :inherited; end + lambda { Class.new(top) }.should_not raise_error + end + +end + diff --git a/spec/ruby/core/class/initialize_spec.rb b/spec/ruby/core/class/initialize_spec.rb new file mode 100644 index 0000000000..d268596dfe --- /dev/null +++ b/spec/ruby/core/class/initialize_spec.rb @@ -0,0 +1,34 @@ +require File.expand_path('../../../spec_helper', __FILE__) + +describe "Class#initialize" do + it "is private" do + Class.should have_private_method(:initialize) + end + + it "raises a TypeError when called on already initialized classes" do + lambda{ + Fixnum.send :initialize + }.should raise_error(TypeError) + + lambda{ + Object.send :initialize + }.should raise_error(TypeError) + end + + # See [redmine:2601] + it "raises a TypeError when called on BasicObject" do + lambda{ + BasicObject.send :initialize + }.should raise_error(TypeError) + end + + describe "when given the Class" do + before :each do + @uninitialized = Class.allocate + end + + it "raises a TypeError" do + lambda{@uninitialized.send(:initialize, Class)}.should raise_error(TypeError) + end + end +end diff --git a/spec/ruby/core/class/new_spec.rb b/spec/ruby/core/class/new_spec.rb new file mode 100644 index 0000000000..86323b1575 --- /dev/null +++ b/spec/ruby/core/class/new_spec.rb @@ -0,0 +1,154 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Class.new with a block given" do + it "yields the new class as self in the block" do + self_in_block = nil + klass = Class.new do + self_in_block = self + end + self_in_block.should equal klass + end + + it "uses the given block as the class' body" do + klass = Class.new do + def self.message + "text" + end + + def hello + "hello again" + end + end + + klass.message.should == "text" + klass.new.hello.should == "hello again" + end + + it "creates a subclass of the given superclass" do + sc = Class.new do + def self.body + @body + end + @body = self + def message; "text"; end + end + klass = Class.new(sc) do + def self.body + @body + end + @body = self + def message2; "hello"; end + end + + klass.body.should == klass + sc.body.should == sc + klass.superclass.should == sc + klass.new.message.should == "text" + klass.new.message2.should == "hello" + end + + it "runs the inherited hook after yielding the block" do + ScratchPad.record [] + klass = Class.new(CoreClassSpecs::Inherited::D) do + ScratchPad << self + end + + ScratchPad.recorded.should == [CoreClassSpecs::Inherited::D, klass] + end +end + +describe "Class.new" do + it "creates a new anonymous class" do + klass = Class.new + klass.is_a?(Class).should == true + + klass_instance = klass.new + klass_instance.is_a?(klass).should == true + end + + it "raises a TypeError if passed a metaclass" do + obj = mock("Class.new metaclass") + meta = obj.singleton_class + lambda { Class.new meta }.should raise_error(TypeError) + end + + it "creates a class without a name" do + Class.new.name.should be_nil + end + + it "creates a class that can be given a name by assigning it to a constant" do + ::MyClass = Class.new + ::MyClass.name.should == "MyClass" + a = Class.new + MyClass::NestedClass = a + MyClass::NestedClass.name.should == "MyClass::NestedClass" + end + + it "sets the new class' superclass to the given class" do + top = Class.new + Class.new(top).superclass.should == top + end + + it "sets the new class' superclass to Object when no class given" do + Class.new.superclass.should == Object + end + + it "raises a TypeError when given a non-Class" do + error_msg = /superclass must be a Class/ + lambda { Class.new("") }.should raise_error(TypeError, error_msg) + lambda { Class.new(1) }.should raise_error(TypeError, error_msg) + lambda { Class.new(:symbol) }.should raise_error(TypeError, error_msg) + lambda { Class.new(mock('o')) }.should raise_error(TypeError, error_msg) + lambda { Class.new(Module.new) }.should raise_error(TypeError, error_msg) + end +end + +describe "Class#new" do + it "returns a new instance of self" do + klass = Class.new + klass.new.is_a?(klass).should == true + end + + it "invokes #initialize on the new instance with the given args" do + klass = Class.new do + def initialize(*args) + @initialized = true + @args = args + end + + def args + @args + end + + def initialized? + @initialized || false + end + end + + klass.new.initialized?.should == true + klass.new(1, 2, 3).args.should == [1, 2, 3] + end + + it "uses the internal allocator and does not call #allocate" do + klass = Class.new do + def self.allocate + raise "allocate should not be called" + end + end + + instance = klass.new + instance.should be_kind_of klass + instance.class.should equal klass + end + + it "passes the block to #initialize" do + klass = Class.new do + def initialize + yield + end + end + + klass.new { break 42 }.should == 42 + end +end diff --git a/spec/ruby/core/class/superclass_spec.rb b/spec/ruby/core/class/superclass_spec.rb new file mode 100644 index 0000000000..18b7ce5bde --- /dev/null +++ b/spec/ruby/core/class/superclass_spec.rb @@ -0,0 +1,27 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Class#superclass" do + it "returns the superclass of self" do + BasicObject.superclass.should be_nil + Object.superclass.should == BasicObject + Class.superclass.should == Module + Class.new.superclass.should == Object + Class.new(String).superclass.should == String + Class.new(Fixnum).superclass.should == Fixnum + end + + # redmine:567 + describe "for a singleton class" do + it "of an object returns the class of the object" do + a = CoreClassSpecs::A.new + sc = class << a; self; end + sc.superclass.should == CoreClassSpecs::A + end + + it "of a class returns the singleton class of its superclass" do # sorry, can't find a simpler way to express this... + sc = class << CoreClassSpecs::H; self; end + sc.superclass.should == class << CoreClassSpecs::A; self; end + end + end +end diff --git a/spec/ruby/core/class/to_s_spec.rb b/spec/ruby/core/class/to_s_spec.rb new file mode 100644 index 0000000000..693517f0da --- /dev/null +++ b/spec/ruby/core/class/to_s_spec.rb @@ -0,0 +1,23 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../fixtures/classes', __FILE__) + +describe "Class#to_s" do + it 'regular class returns same name as Module#to_s' do + String.to_s.should == 'String' + end + + describe 'singleton class' do + it 'for modules includes module name' do + CoreClassSpecs.singleton_class.to_s.should == '#<Class:CoreClassSpecs>' + end + + it 'for classes includes class name' do + CoreClassSpecs::Record.singleton_class.to_s.should == '#<Class:CoreClassSpecs::Record>' + end + + it 'for objects includes class name and object ID' do + obj = CoreClassSpecs::Record.new + obj.singleton_class.to_s.should =~ /#<Class:#<CoreClassSpecs::Record:0x[0-9a-f]+>>/ + end + end +end |