summaryrefslogtreecommitdiff
path: root/spec/ruby/core/struct/new_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/struct/new_spec.rb')
-rw-r--r--spec/ruby/core/struct/new_spec.rb255
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