diff options
Diffstat (limited to 'spec/ruby/core/struct/new_spec.rb')
| -rw-r--r-- | spec/ruby/core/struct/new_spec.rb | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb new file mode 100644 index 0000000000..b3ece2efed --- /dev/null +++ b/spec/ruby/core/struct/new_spec.rb @@ -0,0 +1,255 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "Struct.new" do + it "creates a constant in Struct namespace with string as first argument" do + struct = Struct.new('Animal', :name, :legs, :eyeballs) + struct.should == Struct::Animal + struct.name.should == "Struct::Animal" + ensure + Struct.send(:remove_const, :Animal) + end + + it "overwrites previously defined constants with string as first argument" do + first = Struct.new('Person', :height, :weight) + first.should == Struct::Person + + second = nil + -> { + second = Struct.new('Person', :hair, :sex) + }.should complain(/constant/) + second.should == Struct::Person + + first.members.should_not == second.members + ensure + Struct.send(:remove_const, :Person) + end + + it "calls to_str on its first argument (constant name)" do + obj = mock('Foo') + def obj.to_str() "Foo" end + struct = Struct.new(obj) + struct.should == Struct::Foo + struct.name.should == "Struct::Foo" + ensure + Struct.send(:remove_const, :Foo) + end + + it "creates a new anonymous class with nil first argument" do + struct = Struct.new(nil, :foo) + struct.new("bar").foo.should == "bar" + struct.should.is_a?(Class) + struct.name.should == nil + end + + it "creates a new anonymous class with symbol arguments" do + struct = Struct.new(:make, :model) + struct.should.is_a?(Class) + struct.name.should == nil + end + + it "does not create a constant with symbol as first argument" do + Struct.new(:Animal2, :name, :legs, :eyeballs) + Struct.const_defined?("Animal2").should == false + end + + it "allows non-ASCII member name" do + name = "r\xe9sum\xe9".dup.force_encoding(Encoding::ISO_8859_1).to_sym + struct = Struct.new(name) + struct.new("foo").send(name).should == "foo" + end + + it "fails with invalid constant name as first argument" do + -> { Struct.new('animal', :name, :legs, :eyeballs) }.should.raise(NameError) + end + + it "raises a TypeError if object doesn't respond to to_sym" do + -> { Struct.new(:animal, mock('giraffe')) }.should.raise(TypeError) + -> { Struct.new(:animal, 1.0) }.should.raise(TypeError) + -> { Struct.new(:animal, Time.now) }.should.raise(TypeError) + -> { Struct.new(:animal, Class) }.should.raise(TypeError) + -> { Struct.new(:animal, nil) }.should.raise(TypeError) + -> { Struct.new(:animal, true) }.should.raise(TypeError) + -> { Struct.new(:animal, ['chris', 'evan']) }.should.raise(TypeError) + end + + it "raises a TypeError if passed a Hash with an unknown key" do + -> { Struct.new(:animal, { name: 'chris' }) }.should.raise(TypeError) + end + + it "works when not provided any arguments" do + c = Struct.new + c.should.is_a?(Class) + c.superclass.should == Struct + end + + it "raises ArgumentError when there is a duplicate member" do + -> { Struct.new(:foo, :foo) }.should.raise(ArgumentError, "duplicate member: foo") + end + + it "raises a TypeError if object is not a Symbol" do + obj = mock(':ruby') + def obj.to_sym() :ruby end + -> { Struct.new(:animal, obj) }.should.raise(TypeError) + end + + it "processes passed block with instance_eval" do + klass = Struct.new(:something) { @something_else = 'something else entirely!' } + klass.instance_variables.should.include?(:@something_else) + end + + context "with a block" do + it "allows class to be modified via the block" do + klass = Struct.new(:version) do + def platform + :ruby + end + end + instance = klass.new('2.2') + + instance.version.should == '2.2' + instance.platform.should == :ruby + end + + it "passes same struct class to the block" do + given = nil + klass = Struct.new(:attr) do |block_parameter| + given = block_parameter + end + klass.should.equal?(given) + end + end + + context "on subclasses" do + it "creates a constant in subclass' namespace" do + struct = StructClasses::Apple.new('Computer', :size) + struct.should == StructClasses::Apple::Computer + ensure + StructClasses::Apple.send(:remove_const, :Computer) + end + + it "creates an instance" do + StructClasses::Ruby.new.kind_of?(StructClasses::Ruby).should == true + end + + it "creates reader methods" do + StructClasses::Ruby.new.should.respond_to?(:version) + StructClasses::Ruby.new.should.respond_to?(:platform) + end + + it "creates writer methods" do + StructClasses::Ruby.new.should.respond_to?(:version=) + StructClasses::Ruby.new.should.respond_to?(:platform=) + end + + it "fails with too many arguments" do + -> { StructClasses::Ruby.new('2.0', 'i686', true) }.should.raise(ArgumentError) + end + + it "accepts keyword arguments to initialize" do + type = Struct.new(:args) + + obj = type.new(args: 42) + obj2 = type.new(42) + + obj.should == obj2 + obj.args.should == 42 + obj2.args.should == 42 + end + + context "given positional and keyword arguments" do + it "treats keyword arguments as a positional parameter" do + type = Struct.new(:a, :b) + s = type.new("a", b: "b") + s.a.should == "a" + s.b.should == {b: "b"} + + type = Struct.new(:a, :b, :c) + s = type.new("a", b: "b", c: "c") + s.a.should == "a" + s.b.should == {b: "b", c: "c"} + s.c.should == nil + end + + it "ignores empty keyword arguments" do + type = Struct.new(:a, :b) + h = {} + s = type.new("a", **h) + + s.a.should == "a" + s.b.should == nil + end + + it "raises ArgumentError when all struct attribute values are specified" do + type = Struct.new(:a, :b) + -> { type.new("a", "b", c: "c") }.should.raise(ArgumentError, "struct size differs") + end + end + end + + context "keyword_init: true option" do + before :all do + @struct_with_kwa = Struct.new(:name, :legs, keyword_init: true) + end + + it "creates a class that accepts keyword arguments to initialize" do + obj = @struct_with_kwa.new(name: "elefant", legs: 4) + obj.name.should == "elefant" + obj.legs.should == 4 + end + + it "raises when there is a duplicate member" do + -> { Struct.new(:foo, :foo, keyword_init: true) }.should.raise(ArgumentError, "duplicate member: foo") + end + + describe "new class instantiation" do + it "accepts arguments as hash as well" do + obj = @struct_with_kwa.new({name: "elefant", legs: 4}) + obj.name.should == "elefant" + obj.legs.should == 4 + end + + it "allows missing arguments" do + obj = @struct_with_kwa.new(name: "elefant") + obj.name.should == "elefant" + obj.legs.should == nil + end + + it "allows no arguments" do + obj = @struct_with_kwa.new + obj.name.should == nil + obj.legs.should == nil + end + + it "raises ArgumentError when passed not declared keyword argument" do + -> { + @struct_with_kwa.new(name: "elefant", legs: 4, foo: "bar") + }.should.raise(ArgumentError, /unknown keywords: foo/) + end + + it "raises ArgumentError when passed a list of arguments" do + -> { + @struct_with_kwa.new("elefant", 4) + }.should.raise(ArgumentError, /wrong number of arguments/) + end + + it "raises ArgumentError when passed a single non-hash argument" do + -> { + @struct_with_kwa.new("elefant") + }.should.raise(ArgumentError, /wrong number of arguments/) + end + end + end + + context "keyword_init: false option" do + before :all do + @struct_without_kwa = Struct.new(:name, :legs, keyword_init: false) + end + + it "behaves like it does without :keyword_init option" do + obj = @struct_without_kwa.new("elefant", 4) + obj.name.should == "elefant" + obj.legs.should == 4 + end + end +end |
