diff options
Diffstat (limited to 'spec/ruby/core/data')
| -rw-r--r-- | spec/ruby/core/data/constants_spec.rb | 20 | ||||
| -rw-r--r-- | spec/ruby/core/data/deconstruct_keys_spec.rb | 227 | ||||
| -rw-r--r-- | spec/ruby/core/data/deconstruct_spec.rb | 8 | ||||
| -rw-r--r-- | spec/ruby/core/data/define_spec.rb | 48 | ||||
| -rw-r--r-- | spec/ruby/core/data/eql_spec.rb | 92 | ||||
| -rw-r--r-- | spec/ruby/core/data/equal_value_spec.rb | 92 | ||||
| -rw-r--r-- | spec/ruby/core/data/fixtures/classes.rb | 23 | ||||
| -rw-r--r-- | spec/ruby/core/data/hash_spec.rb | 36 | ||||
| -rw-r--r-- | spec/ruby/core/data/initialize_spec.rb | 145 | ||||
| -rw-r--r-- | spec/ruby/core/data/inspect_spec.rb | 6 | ||||
| -rw-r--r-- | spec/ruby/core/data/members_spec.rb | 26 | ||||
| -rw-r--r-- | spec/ruby/core/data/shared/inspect.rb | 8 | ||||
| -rw-r--r-- | spec/ruby/core/data/to_h_spec.rb | 94 | ||||
| -rw-r--r-- | spec/ruby/core/data/to_s_spec.rb | 6 | ||||
| -rw-r--r-- | spec/ruby/core/data/with_spec.rb | 66 |
15 files changed, 501 insertions, 396 deletions
diff --git a/spec/ruby/core/data/constants_spec.rb b/spec/ruby/core/data/constants_spec.rb index 2eb43d501e..ad0b1ddea7 100644 --- a/spec/ruby/core/data/constants_spec.rb +++ b/spec/ruby/core/data/constants_spec.rb @@ -1,21 +1,11 @@ require_relative '../../spec_helper' -ruby_version_is ''...'3.2' do - describe "Data" do - it "does not exist anymore" do - Object.should_not have_constant(:Data) - end +describe "Data" do + it "is a new constant" do + Data.superclass.should == Object end -end - -ruby_version_is '3.2' do - describe "Data" do - it "is a new constant" do - Data.superclass.should == Object - end - it "is not deprecated" do - -> { Data }.should_not complain - end + it "is not deprecated" do + -> { Data }.should_not complain end end diff --git a/spec/ruby/core/data/deconstruct_keys_spec.rb b/spec/ruby/core/data/deconstruct_keys_spec.rb index 07af87771d..df378f8b98 100644 --- a/spec/ruby/core/data/deconstruct_keys_spec.rb +++ b/spec/ruby/core/data/deconstruct_keys_spec.rb @@ -1,107 +1,130 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#deconstruct" do - it "returns a hash of attributes" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2} - end - - it "requires one argument" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - -> { - d.deconstruct_keys - }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/) - end - - it "returns only specified keys" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2} - d.deconstruct_keys([:x] ).should == {x: 1} - d.deconstruct_keys([] ).should == {} - end - - it "accepts string attribute names" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2} - end - - it "accepts argument position number as well but returns them as keys" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - d.deconstruct_keys([0, 1]).should == {0 => 1, 1 => 2} - d.deconstruct_keys([0] ).should == {0 => 1} - d.deconstruct_keys([-1] ).should == {-1 => 2} - end - - it "ignores incorrect position numbers" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - d.deconstruct_keys([0, 3]).should == {0 => 1} - end - - it "support mixing attribute names and argument position numbers" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - d.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1} - end - - it "returns an empty hash when there are more keys than attributes" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - d.deconstruct_keys([:x, :y, :x]).should == {} - end - - it "returns at first not existing attribute name" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - d.deconstruct_keys([:a, :x]).should == {} - d.deconstruct_keys([:x, :a]).should == {x: 1} - end - - it "returns at first not existing argument position number" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - d.deconstruct_keys([3, 0]).should == {} - d.deconstruct_keys([0, 3]).should == {0 => 1} - end - - it "accepts nil argument and return all the attributes" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - d.deconstruct_keys(nil).should == {x: 1, y: 2} - end - - it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - -> { - d.deconstruct_keys([0, []]) - }.should raise_error(TypeError, "no implicit conversion of Array into Integer") - end - - it "raise TypeError if passed anything except nil or array" do - klass = Data.define(:x, :y) - d = klass.new(1, 2) - - -> { d.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/) - -> { d.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/) - -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/) - -> { d.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/) - end +describe "Data#deconstruct_keys" do + it "returns a hash of attributes" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2} + end + + it "requires one argument" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + -> { + d.deconstruct_keys + }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/) + end + + it "returns only specified keys" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2} + d.deconstruct_keys([:x] ).should == {x: 1} + d.deconstruct_keys([] ).should == {} + end + + it "accepts string attribute names" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2} + end + + it "accepts argument position number as well but returns them as keys" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys([0, 1]).should == {0 => 1, 1 => 2} + d.deconstruct_keys([0] ).should == {0 => 1} + d.deconstruct_keys([-1] ).should == {-1 => 2} + end + + it "ignores incorrect position numbers" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys([0, 3]).should == {0 => 1} + end + + it "support mixing attribute names and argument position numbers" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1} + end + + it "returns an empty hash when there are more keys than attributes" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys([:x, :y, :x]).should == {} + end + + it "returns at first not existing attribute name" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys([:a, :x]).should == {} + d.deconstruct_keys([:x, :a]).should == {x: 1} + end + + it "returns at first not existing argument position number" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys([3, 0]).should == {} + d.deconstruct_keys([0, 3]).should == {0 => 1} + end + + it "accepts nil argument and return all the attributes" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + d.deconstruct_keys(nil).should == {x: 1, y: 2} + end + + it "tries to convert a key with #to_int if index is not a String nor a Symbol, but responds to #to_int" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + key = mock("to_int") + key.should_receive(:to_int).and_return(1) + + d.deconstruct_keys([key]).should == { key => 2 } + end + + it "raises a TypeError if the conversion with #to_int does not return an Integer" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + key = mock("to_int") + key.should_receive(:to_int).and_return("not an Integer") + + -> { + d.deconstruct_keys([key]) + }.should raise_error(TypeError, /can't convert MockObject to Integer/) + end + + it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + -> { + d.deconstruct_keys([0, []]) + }.should raise_error(TypeError, "no implicit conversion of Array into Integer") + end + + it "raise TypeError if passed anything except nil or array" do + klass = Data.define(:x, :y) + d = klass.new(1, 2) + + -> { d.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/) + -> { d.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/) + -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/) + -> { d.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/) end end diff --git a/spec/ruby/core/data/deconstruct_spec.rb b/spec/ruby/core/data/deconstruct_spec.rb index f0995e8fed..4ca0b87039 100644 --- a/spec/ruby/core/data/deconstruct_spec.rb +++ b/spec/ruby/core/data/deconstruct_spec.rb @@ -1,10 +1,8 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#deconstruct" do - it "returns an array of attribute values" do - DataSpecs::Measure.new(42, "km").deconstruct.should == [42, "km"] - end +describe "Data#deconstruct" do + it "returns an array of attribute values" do + DataSpecs::Measure.new(42, "km").deconstruct.should == [42, "km"] end end diff --git a/spec/ruby/core/data/define_spec.rb b/spec/ruby/core/data/define_spec.rb index 2aa2c50d4c..c0b4671e39 100644 --- a/spec/ruby/core/data/define_spec.rb +++ b/spec/ruby/core/data/define_spec.rb @@ -1,36 +1,34 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data.define" do - it "accepts no arguments" do - empty_data = Data.define - empty_data.members.should == [] - end +describe "Data.define" do + it "accepts no arguments" do + empty_data = Data.define + empty_data.members.should == [] + end - it "accepts symbols" do - movie = Data.define(:title, :year) - movie.members.should == [:title, :year] - end + it "accepts symbols" do + movie = Data.define(:title, :year) + movie.members.should == [:title, :year] + end - it "accepts strings" do - movie = Data.define("title", "year") - movie.members.should == [:title, :year] - end + it "accepts strings" do + movie = Data.define("title", "year") + movie.members.should == [:title, :year] + end - it "accepts a mix of strings and symbols" do - movie = Data.define("title", :year, "genre") - movie.members.should == [:title, :year, :genre] - end + it "accepts a mix of strings and symbols" do + movie = Data.define("title", :year, "genre") + movie.members.should == [:title, :year, :genre] + end - it "accepts a block" do - movie = Data.define(:title, :year) do - def title_with_year - "#{title} (#{year})" - end + it "accepts a block" do + movie = Data.define(:title, :year) do + def title_with_year + "#{title} (#{year})" end - movie.members.should == [:title, :year] - movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)" end + movie.members.should == [:title, :year] + movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)" end end diff --git a/spec/ruby/core/data/eql_spec.rb b/spec/ruby/core/data/eql_spec.rb index 906e46316c..6958d5de4a 100644 --- a/spec/ruby/core/data/eql_spec.rb +++ b/spec/ruby/core/data/eql_spec.rb @@ -1,65 +1,63 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#eql?" do - it "returns true if the other is the same object" do - a = DataSpecs::Measure.new(42, "km") - a.should.eql?(a) - end +describe "Data#eql?" do + it "returns true if the other is the same object" do + a = DataSpecs::Measure.new(42, "km") + a.should.eql?(a) + end - it "returns true if the other has all the same fields" do - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(42, "km") - a.should.eql?(b) - end + it "returns true if the other has all the same fields" do + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(42, "km") + a.should.eql?(b) + end - it "returns false if the other is a different object or has different fields" do - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(42, "mi") - a.should_not.eql?(b) - end + it "returns false if the other is a different object or has different fields" do + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(42, "mi") + a.should_not.eql?(b) + end - it "returns false if other is of a different class" do - a = DataSpecs::Measure.new(42, "km") - klass = Data.define(*DataSpecs::Measure.members) - b = klass.new(42, "km") - a.should_not.eql?(b) - end + it "returns false if other is of a different class" do + a = DataSpecs::Measure.new(42, "km") + klass = Data.define(*DataSpecs::Measure.members) + b = klass.new(42, "km") + a.should_not.eql?(b) + end - it "returns false if any corresponding elements are not equal with #eql?" do - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(42.0, "mi") - a.should_not.eql?(b) - end + it "returns false if any corresponding elements are not equal with #eql?" do + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(42.0, "mi") + a.should_not.eql?(b) + end - context "recursive structure" do - it "returns true the other is the same object" do - a = DataSpecs::Measure.allocate - a.send(:initialize, amount: 42, unit: a) + context "recursive structure" do + it "returns true the other is the same object" do + a = DataSpecs::Measure.allocate + a.send(:initialize, amount: 42, unit: a) - a.should.eql?(a) - end + a.should.eql?(a) + end - it "returns true if the other has all the same fields" do - a = DataSpecs::Measure.allocate - a.send(:initialize, amount: 42, unit: a) + it "returns true if the other has all the same fields" do + a = DataSpecs::Measure.allocate + a.send(:initialize, amount: 42, unit: a) - b = DataSpecs::Measure.allocate - b.send(:initialize, amount: 42, unit: b) + b = DataSpecs::Measure.allocate + b.send(:initialize, amount: 42, unit: b) - a.should.eql?(b) - end + a.should.eql?(b) + end - it "returns false if any corresponding elements are not equal with #eql?" do - a = DataSpecs::Measure.allocate - a.send(:initialize, amount: a, unit: "km") + it "returns false if any corresponding elements are not equal with #eql?" do + a = DataSpecs::Measure.allocate + a.send(:initialize, amount: a, unit: "km") - b = DataSpecs::Measure.allocate - b.send(:initialize, amount: b, unit: "mi") + b = DataSpecs::Measure.allocate + b.send(:initialize, amount: b, unit: "mi") - a.should_not.eql?(b) - end + a.should_not.eql?(b) end end end diff --git a/spec/ruby/core/data/equal_value_spec.rb b/spec/ruby/core/data/equal_value_spec.rb index f90a7d7a62..d9a0dcff3e 100644 --- a/spec/ruby/core/data/equal_value_spec.rb +++ b/spec/ruby/core/data/equal_value_spec.rb @@ -1,65 +1,63 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#==" do - it "returns true if the other is the same object" do - a = DataSpecs::Measure.new(42, "km") - a.should == a - end +describe "Data#==" do + it "returns true if the other is the same object" do + a = DataSpecs::Measure.new(42, "km") + a.should == a + end - it "returns true if the other has all the same fields" do - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(42, "km") - a.should == b - end + it "returns true if the other has all the same fields" do + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(42, "km") + a.should == b + end - it "returns false if the other is a different object or has different fields" do - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(42, "mi") - a.should_not == b - end + it "returns false if the other is a different object or has different fields" do + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(42, "mi") + a.should_not == b + end - it "returns false if other is of a different class" do - a = DataSpecs::Measure.new(42, "km") - klass = Data.define(*DataSpecs::Measure.members) - b = klass.new(42, "km") - a.should_not == b - end + it "returns false if other is of a different class" do + a = DataSpecs::Measure.new(42, "km") + klass = Data.define(*DataSpecs::Measure.members) + b = klass.new(42, "km") + a.should_not == b + end - it "returns false if any corresponding elements are not equal with #==" do - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(42.0, "mi") - a.should_not == b - end + it "returns false if any corresponding elements are not equal with #==" do + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(42.0, "mi") + a.should_not == b + end - context "recursive structure" do - it "returns true the other is the same object" do - a = DataSpecs::Measure.allocate - a.send(:initialize, amount: 42, unit: a) + context "recursive structure" do + it "returns true the other is the same object" do + a = DataSpecs::Measure.allocate + a.send(:initialize, amount: 42, unit: a) - a.should == a - end + a.should == a + end - it "returns true if the other has all the same fields" do - a = DataSpecs::Measure.allocate - a.send(:initialize, amount: 42, unit: a) + it "returns true if the other has all the same fields" do + a = DataSpecs::Measure.allocate + a.send(:initialize, amount: 42, unit: a) - b = DataSpecs::Measure.allocate - b.send(:initialize, amount: 42, unit: b) + b = DataSpecs::Measure.allocate + b.send(:initialize, amount: 42, unit: b) - a.should == b - end + a.should == b + end - it "returns false if any corresponding elements are not equal with #==" do - a = DataSpecs::Measure.allocate - a.send(:initialize, amount: a, unit: "km") + it "returns false if any corresponding elements are not equal with #==" do + a = DataSpecs::Measure.allocate + a.send(:initialize, amount: a, unit: "km") - b = DataSpecs::Measure.allocate - b.send(:initialize, amount: b, unit: "mi") + b = DataSpecs::Measure.allocate + b.send(:initialize, amount: b, unit: "mi") - a.should_not == b - end + a.should_not == b end end end diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb index f0a526517d..650c0b2a62 100644 --- a/spec/ruby/core/data/fixtures/classes.rb +++ b/spec/ruby/core/data/fixtures/classes.rb @@ -1,5 +1,5 @@ module DataSpecs - guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do + if Data.respond_to?(:define) Measure = Data.define(:amount, :unit) class MeasureWithOverriddenName < Measure @@ -9,5 +9,26 @@ module DataSpecs end class DataSubclass < Data; end + + MeasureSubclass = Class.new(Measure) do + def initialize(amount:, unit:) + super + end + end + + Empty = Data.define() + + DataWithOverriddenInitialize = Data.define(:amount, :unit) do + def initialize(*rest, **kw) + super + ScratchPad.record [:initialize, rest, kw] + end + end + + Area = Data.define(:width, :height, :area) do + def initialize(width:, height:) + super(width: width, height: height, area: width * height) + end + end end end diff --git a/spec/ruby/core/data/hash_spec.rb b/spec/ruby/core/data/hash_spec.rb index 324a2abca4..c23f08a71d 100644 --- a/spec/ruby/core/data/hash_spec.rb +++ b/spec/ruby/core/data/hash_spec.rb @@ -1,27 +1,25 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#hash" do - it "returns the same integer for objects with the same content" do - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(42, "km") - a.hash.should == b.hash - a.hash.should be_an_instance_of(Integer) - end +describe "Data#hash" do + it "returns the same integer for objects with the same content" do + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(42, "km") + a.hash.should == b.hash + a.hash.should be_an_instance_of(Integer) + end - it "returns different hashes for objects with different values" do - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(42, "ml") - a.hash.should_not == b.hash + it "returns different hashes for objects with different values" do + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(42, "ml") + a.hash.should_not == b.hash - a = DataSpecs::Measure.new(42, "km") - b = DataSpecs::Measure.new(13, "km") - a.hash.should_not == b.hash - end + a = DataSpecs::Measure.new(42, "km") + b = DataSpecs::Measure.new(13, "km") + a.hash.should_not == b.hash + end - it "returns different hashes for different classes" do - Data.define(:x).new(1).hash.should != Data.define(:x).new(1).hash - end + it "returns different hashes for different classes" do + Data.define(:x).new(1).hash.should != Data.define(:x).new(1).hash end end diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb index 2c36bd3ac4..010c73b91b 100644 --- a/spec/ruby/core/data/initialize_spec.rb +++ b/spec/ruby/core/data/initialize_spec.rb @@ -1,65 +1,124 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#initialize" do - it "accepts positional arguments" do - data = DataSpecs::Measure.new(42, "km") +describe "Data#initialize" do + it "accepts positional arguments" do + data = DataSpecs::Measure.new(42, "km") - data.amount.should == 42 - data.unit.should == "km" - end + data.amount.should == 42 + data.unit.should == "km" + end - it "accepts alternative positional arguments" do - data = DataSpecs::Measure[42, "km"] + it "accepts alternative positional arguments" do + data = DataSpecs::Measure[42, "km"] - data.amount.should == 42 - data.unit.should == "km" - end + data.amount.should == 42 + data.unit.should == "km" + end - it "accepts keyword arguments" do - data = DataSpecs::Measure.new(amount: 42, unit: "km") + it "accepts keyword arguments" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") - data.amount.should == 42 - data.unit.should == "km" - end + data.amount.should == 42 + data.unit.should == "km" + end + + it "accepts alternative keyword arguments" do + data = DataSpecs::Measure[amount: 42, unit: "km"] - it "accepts alternative keyword arguments" do - data = DataSpecs::Measure[amount: 42, unit: "km"] + data.amount.should == 42 + data.unit.should == "km" + end + + it "accepts String keyword arguments" do + data = DataSpecs::Measure.new("amount" => 42, "unit" => "km") + + data.amount.should == 42 + data.unit.should == "km" + end - data.amount.should == 42 - data.unit.should == "km" + it "raises ArgumentError if no arguments are given" do + -> { + DataSpecs::Measure.new + }.should raise_error(ArgumentError) { |e| + e.message.should.include?("missing keywords: :amount, :unit") + } + end + + it "raises ArgumentError if at least one argument is missing" do + -> { + DataSpecs::Measure.new(unit: "km") + }.should raise_error(ArgumentError) { |e| + e.message.should.include?("missing keyword: :amount") + } + end + + it "raises ArgumentError if unknown keyword is given" do + -> { + DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric") + }.should raise_error(ArgumentError) { |e| + e.message.should.include?("unknown keyword: :system") + } + end + + it "supports super from a subclass" do + ms = DataSpecs::MeasureSubclass.new(amount: 1, unit: "km") + + ms.amount.should == 1 + ms.unit.should == "km" + end + + it "supports Data with no fields" do + -> { DataSpecs::Empty.new }.should_not raise_error + end + + it "can be overridden" do + ScratchPad.record [] + + measure_class = Data.define(:amount, :unit) do + def initialize(*, **) + super + ScratchPad << :initialize + end end - it "accepts String keyword arguments" do - data = DataSpecs::Measure.new("amount" => 42, "unit" => "km") + measure_class.new(42, "m") + ScratchPad.recorded.should == [:initialize] + end + + context "when it is overridden" do + it "is called with keyword arguments when given positional arguments" do + ScratchPad.clear + DataSpecs::DataWithOverriddenInitialize.new(42, "m") + ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}] + end - data.amount.should == 42 - data.unit.should == "km" + it "is called with keyword arguments when given keyword arguments" do + ScratchPad.clear + DataSpecs::DataWithOverriddenInitialize.new(amount: 42, unit: "m") + ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}] end - it "raises ArgumentError if no arguments are given" do - -> { - DataSpecs::Measure.new - }.should raise_error(ArgumentError) { |e| - e.message.should.include?("missing keywords: :amount, :unit") - } + it "is called with keyword arguments when given alternative positional arguments" do + ScratchPad.clear + DataSpecs::DataWithOverriddenInitialize[42, "m"] + ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}] end - it "raises ArgumentError if at least one argument is missing" do - -> { - DataSpecs::Measure.new(unit: "km") - }.should raise_error(ArgumentError) { |e| - e.message.should.include?("missing keyword: :amount") - } + it "is called with keyword arguments when given alternative keyword arguments" do + ScratchPad.clear + DataSpecs::DataWithOverriddenInitialize[amount: 42, unit: "m"] + ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}] end - it "raises ArgumentError if unknown keyword is given" do - -> { - DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric") - }.should raise_error(ArgumentError) { |e| - e.message.should.include?("unknown keyword: :system") - } + # See https://github.com/ruby/psych/pull/765 + it "can be deserialized by calling Data.instance_method(:initialize)" do + d1 = DataSpecs::Area.new(width: 2, height: 3) + d1.area.should == 6 + + d2 = DataSpecs::Area.allocate + Data.instance_method(:initialize).bind_call(d2, **d1.to_h) + d2.should == d1 end end end diff --git a/spec/ruby/core/data/inspect_spec.rb b/spec/ruby/core/data/inspect_spec.rb index 3d337fac68..38642910a0 100644 --- a/spec/ruby/core/data/inspect_spec.rb +++ b/spec/ruby/core/data/inspect_spec.rb @@ -1,8 +1,6 @@ require_relative '../../spec_helper' require_relative 'shared/inspect' -ruby_version_is "3.2" do - describe "Data#inspect" do - it_behaves_like :data_inspect, :inspect - end +describe "Data#inspect" do + it_behaves_like :data_inspect, :inspect end diff --git a/spec/ruby/core/data/members_spec.rb b/spec/ruby/core/data/members_spec.rb index 1776b0b9c1..457a90a0d6 100644 --- a/spec/ruby/core/data/members_spec.rb +++ b/spec/ruby/core/data/members_spec.rb @@ -1,23 +1,21 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#members" do - it "returns an array of attribute names" do - measure = DataSpecs::Measure.new(amount: 42, unit: 'km') - measure.members.should == [:amount, :unit] - end +describe "Data#members" do + it "returns an array of attribute names" do + measure = DataSpecs::Measure.new(amount: 42, unit: 'km') + measure.members.should == [:amount, :unit] end +end - describe "DataClass#members" do - it "returns an array of attribute names" do - DataSpecs::Measure.members.should == [:amount, :unit] - end +describe "DataClass#members" do + it "returns an array of attribute names" do + DataSpecs::Measure.members.should == [:amount, :unit] + end - context "class inheriting Data" do - it "isn't available in a subclass" do - DataSpecs::DataSubclass.should_not.respond_to?(:members) - end + context "class inheriting Data" do + it "isn't available in a subclass" do + DataSpecs::DataSubclass.should_not.respond_to?(:members) end end end diff --git a/spec/ruby/core/data/shared/inspect.rb b/spec/ruby/core/data/shared/inspect.rb index 7f54a46de3..6cd5664da7 100644 --- a/spec/ruby/core/data/shared/inspect.rb +++ b/spec/ruby/core/data/shared/inspect.rb @@ -50,5 +50,13 @@ describe :data_inspect, shared: true do a.send(@method).should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>" end + + it "returns string representation with recursive attribute replaced with ... when an anonymous class" do + klass = Class.new(DataSpecs::Measure) + a = klass.allocate + a.send(:initialize, amount: 42, unit: a) + + a.send(@method).should =~ /#<data amount=42, unit=#<data #<Class:0x.+?>:\.\.\.>>/ + end end end diff --git a/spec/ruby/core/data/to_h_spec.rb b/spec/ruby/core/data/to_h_spec.rb index 41d6960c97..64816b7251 100644 --- a/spec/ruby/core/data/to_h_spec.rb +++ b/spec/ruby/core/data/to_h_spec.rb @@ -1,65 +1,63 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#to_h" do - it "transforms the data object into a hash" do +describe "Data#to_h" do + it "transforms the data object into a hash" do + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + data.to_h.should == { amount: 42, unit: 'km' } + end + + context "with block" do + it "transforms [key, value] pairs returned by the block into a hash" do data = DataSpecs::Measure.new(amount: 42, unit: 'km') - data.to_h.should == { amount: 42, unit: 'km' } + data.to_h { |key, value| [value, key] }.should == { 42 => :amount, 'km' => :unit } end - context "with block" do - it "transforms [key, value] pairs returned by the block into a hash" do - data = DataSpecs::Measure.new(amount: 42, unit: 'km') - data.to_h { |key, value| [value, key] }.should == { 42 => :amount, 'km' => :unit } - end - - it "passes to a block each pair's key and value as separate arguments" do - ScratchPad.record [] - data = DataSpecs::Measure.new(amount: 42, unit: 'km') - data.to_h { |k, v| ScratchPad << [k, v]; [k, v] } - ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']] + it "passes to a block each pair's key and value as separate arguments" do + ScratchPad.record [] + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + data.to_h { |k, v| ScratchPad << [k, v]; [k, v] } + ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']] - ScratchPad.record [] - data.to_h { |*args| ScratchPad << args; [args[0], args[1]] } - ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']] - end + ScratchPad.record [] + data.to_h { |*args| ScratchPad << args; [args[0], args[1]] } + ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']] + end - it "raises ArgumentError if block returns longer or shorter array" do - data = DataSpecs::Measure.new(amount: 42, unit: 'km') - -> do - data.to_h { |k, v| [k.to_s, v*v, 1] } - end.should raise_error(ArgumentError, /element has wrong array length/) + it "raises ArgumentError if block returns longer or shorter array" do + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + -> do + data.to_h { |k, v| [k.to_s, v*v, 1] } + end.should raise_error(ArgumentError, /element has wrong array length/) - -> do - data.to_h { |k, v| [k] } - end.should raise_error(ArgumentError, /element has wrong array length/) - end + -> do + data.to_h { |k, v| [k] } + end.should raise_error(ArgumentError, /element has wrong array length/) + end - it "raises TypeError if block returns something other than Array" do - data = DataSpecs::Measure.new(amount: 42, unit: 'km') - -> do - data.to_h { |k, v| "not-array" } - end.should raise_error(TypeError, /wrong element type String/) - end + it "raises TypeError if block returns something other than Array" do + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + -> do + data.to_h { |k, v| "not-array" } + end.should raise_error(TypeError, /wrong element type String/) + end - it "coerces returned pair to Array with #to_ary" do - x = mock('x') - x.stub!(:to_ary).and_return([:b, 'b']) - data = DataSpecs::Measure.new(amount: 42, unit: 'km') + it "coerces returned pair to Array with #to_ary" do + x = mock('x') + x.stub!(:to_ary).and_return([:b, 'b']) + data = DataSpecs::Measure.new(amount: 42, unit: 'km') - data.to_h { |k| x }.should == { :b => 'b' } - end + data.to_h { |k| x }.should == { :b => 'b' } + end - it "does not coerce returned pair to Array with #to_a" do - x = mock('x') - x.stub!(:to_a).and_return([:b, 'b']) - data = DataSpecs::Measure.new(amount: 42, unit: 'km') + it "does not coerce returned pair to Array with #to_a" do + x = mock('x') + x.stub!(:to_a).and_return([:b, 'b']) + data = DataSpecs::Measure.new(amount: 42, unit: 'km') - -> do - data.to_h { |k| x } - end.should raise_error(TypeError, /wrong element type MockObject/) - end + -> do + data.to_h { |k| x } + end.should raise_error(TypeError, /wrong element type MockObject/) end end end diff --git a/spec/ruby/core/data/to_s_spec.rb b/spec/ruby/core/data/to_s_spec.rb index 0b9099f035..2b4a670e8e 100644 --- a/spec/ruby/core/data/to_s_spec.rb +++ b/spec/ruby/core/data/to_s_spec.rb @@ -1,8 +1,6 @@ require_relative '../../spec_helper' require_relative 'shared/inspect' -ruby_version_is "3.2" do - describe "Data#to_s" do - it_behaves_like :data_inspect, :to_s - end +describe "Data#to_s" do + it_behaves_like :data_inspect, :to_s end diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb index 97e34c951f..fd0a99d1fa 100644 --- a/spec/ruby/core/data/with_spec.rb +++ b/spec/ruby/core/data/with_spec.rb @@ -1,35 +1,57 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "3.2" do - describe "Data#with" do - it "returns self if given no arguments" do - data = DataSpecs::Measure.new(amount: 42, unit: "km") - data = data.with.should.equal?(data) - end +describe "Data#with" do + it "returns self if given no arguments" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") + data = data.with.should.equal?(data) + end - it "accepts keyword arguments" do - data = DataSpecs::Measure.new(amount: 42, unit: "km") - data = data.with(amount: 4, unit: "m") + it "accepts keyword arguments" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") + data = data.with(amount: 4, unit: "m") - data.amount.should == 4 - data.unit.should == "m" - end + data.amount.should == 4 + data.unit.should == "m" + end + + it "accepts String keyword arguments" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") + data = data.with("amount" => 4, "unit" => "m") + + data.amount.should == 4 + data.unit.should == "m" + end - it "accepts String keyword arguments" do - data = DataSpecs::Measure.new(amount: 42, unit: "km") - data = data.with("amount" => 4, "unit" => "m") + it "raises ArgumentError if no keyword arguments are given" do + data = DataSpecs::Measure.new(amount: 42, unit: "km") - data.amount.should == 4 - data.unit.should == "m" + -> { + data.with(4, "m") + }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)") + end + + it "does not depend on the Data.new method" do + subclass = Class.new(DataSpecs::Measure) + data = subclass.new(amount: 42, unit: "km") + + def subclass.new(*) + raise "Data.new is called" end - it "raises ArgumentError if no keyword arguments are given" do - data = DataSpecs::Measure.new(amount: 42, unit: "km") + data_copy = data.with(unit: "m") + data_copy.amount.should == 42 + data_copy.unit.should == "m" + end + + ruby_version_is "3.3" do + it "calls #initialize" do + data = DataSpecs::DataWithOverriddenInitialize.new(42, "m") + ScratchPad.clear + + data.with(amount: 0) - -> { - data.with(4, "m") - }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)") + ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}] end end end |
