Skip to content

Commit f32117b

Browse files
committed
[GR-20446] Add missing specs for Data
PullRequest: truffleruby/4491
2 parents fa1a18a + a07ec4d commit f32117b

File tree

14 files changed

+389
-9
lines changed

14 files changed

+389
-9
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
require_relative '../../spec_helper'
2+
require_relative 'fixtures/classes'
3+
4+
ruby_version_is "3.2" do
5+
describe "Data#deconstruct" do
6+
it "returns a hash of attributes" do
7+
klass = Data.define(:x, :y)
8+
d = klass.new(1, 2)
9+
d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
10+
end
11+
12+
it "requires one argument" do
13+
klass = Data.define(:x, :y)
14+
d = klass.new(1, 2)
15+
16+
-> {
17+
d.deconstruct_keys
18+
}.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
19+
end
20+
21+
it "returns only specified keys" do
22+
klass = Data.define(:x, :y)
23+
d = klass.new(1, 2)
24+
25+
d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
26+
d.deconstruct_keys([:x] ).should == {x: 1}
27+
d.deconstruct_keys([] ).should == {}
28+
end
29+
30+
it "accepts string attribute names" do
31+
klass = Data.define(:x, :y)
32+
d = klass.new(1, 2)
33+
d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
34+
end
35+
36+
it "accepts argument position number as well but returns them as keys" do
37+
klass = Data.define(:x, :y)
38+
d = klass.new(1, 2)
39+
40+
d.deconstruct_keys([0, 1]).should == {0 => 1, 1 => 2}
41+
d.deconstruct_keys([0] ).should == {0 => 1}
42+
d.deconstruct_keys([-1] ).should == {-1 => 2}
43+
end
44+
45+
it "ignores incorrect position numbers" do
46+
klass = Data.define(:x, :y)
47+
d = klass.new(1, 2)
48+
49+
d.deconstruct_keys([0, 3]).should == {0 => 1}
50+
end
51+
52+
it "support mixing attribute names and argument position numbers" do
53+
klass = Data.define(:x, :y)
54+
d = klass.new(1, 2)
55+
56+
d.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1}
57+
end
58+
59+
it "returns an empty hash when there are more keys than attributes" do
60+
klass = Data.define(:x, :y)
61+
d = klass.new(1, 2)
62+
d.deconstruct_keys([:x, :y, :x]).should == {}
63+
end
64+
65+
it "returns at first not existing attribute name" do
66+
klass = Data.define(:x, :y)
67+
d = klass.new(1, 2)
68+
69+
d.deconstruct_keys([:a, :x]).should == {}
70+
d.deconstruct_keys([:x, :a]).should == {x: 1}
71+
end
72+
73+
it "returns at first not existing argument position number" do
74+
klass = Data.define(:x, :y)
75+
d = klass.new(1, 2)
76+
77+
d.deconstruct_keys([3, 0]).should == {}
78+
d.deconstruct_keys([0, 3]).should == {0 => 1}
79+
end
80+
81+
it "accepts nil argument and return all the attributes" do
82+
klass = Data.define(:x, :y)
83+
d = klass.new(1, 2)
84+
85+
d.deconstruct_keys(nil).should == {x: 1, y: 2}
86+
end
87+
88+
it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do
89+
klass = Data.define(:x, :y)
90+
d = klass.new(1, 2)
91+
92+
-> {
93+
d.deconstruct_keys([0, []])
94+
}.should raise_error(TypeError, "no implicit conversion of Array into Integer")
95+
end
96+
97+
it "raise TypeError if passed anything except nil or array" do
98+
klass = Data.define(:x, :y)
99+
d = klass.new(1, 2)
100+
101+
-> { d.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
102+
-> { d.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
103+
-> { d.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
104+
-> { d.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
105+
end
106+
end
107+
end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
require_relative '../../spec_helper'
2+
require_relative 'fixtures/classes'
3+
4+
ruby_version_is "3.2" do
5+
describe "Data#deconstruct" do
6+
it "returns an array of attribute values" do
7+
DataSpecs::Measure.new(42, "km").deconstruct.should == [42, "km"]
8+
end
9+
end
10+
end

spec/ruby/core/data/eql_spec.rb

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require_relative '../../spec_helper'
2+
require_relative 'fixtures/classes'
3+
4+
ruby_version_is "3.2" do
5+
describe "Data#eql?" do
6+
it "returns true if the other is the same object" do
7+
a = DataSpecs::Measure.new(42, "km")
8+
a.should.eql?(a)
9+
end
10+
11+
it "returns true if the other has all the same fields" do
12+
a = DataSpecs::Measure.new(42, "km")
13+
b = DataSpecs::Measure.new(42, "km")
14+
a.should.eql?(b)
15+
end
16+
17+
it "returns false if the other is a different object or has different fields" do
18+
a = DataSpecs::Measure.new(42, "km")
19+
b = DataSpecs::Measure.new(42, "mi")
20+
a.should_not.eql?(b)
21+
end
22+
23+
it "returns false if other is of a different class" do
24+
a = DataSpecs::Measure.new(42, "km")
25+
klass = Data.define(*DataSpecs::Measure.members)
26+
b = klass.new(42, "km")
27+
a.should_not.eql?(b)
28+
end
29+
30+
it "returns false if any corresponding elements are not equal with #eql?" do
31+
a = DataSpecs::Measure.new(42, "km")
32+
b = DataSpecs::Measure.new(42.0, "mi")
33+
a.should_not.eql?(b)
34+
end
35+
36+
context "recursive structure" do
37+
it "returns true the other is the same object" do
38+
a = DataSpecs::Measure.allocate
39+
a.send(:initialize, amount: 42, unit: a)
40+
41+
a.should.eql?(a)
42+
end
43+
44+
it "returns true if the other has all the same fields" do
45+
a = DataSpecs::Measure.allocate
46+
a.send(:initialize, amount: 42, unit: a)
47+
48+
b = DataSpecs::Measure.allocate
49+
b.send(:initialize, amount: 42, unit: b)
50+
51+
a.should.eql?(b)
52+
end
53+
54+
it "returns false if any corresponding elements are not equal with #eql?" do
55+
a = DataSpecs::Measure.allocate
56+
a.send(:initialize, amount: a, unit: "km")
57+
58+
b = DataSpecs::Measure.allocate
59+
b.send(:initialize, amount: b, unit: "mi")
60+
61+
a.should_not.eql?(b)
62+
end
63+
end
64+
end
65+
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require_relative '../../spec_helper'
2+
require_relative 'fixtures/classes'
3+
4+
ruby_version_is "3.2" do
5+
describe "Data#==" do
6+
it "returns true if the other is the same object" do
7+
a = DataSpecs::Measure.new(42, "km")
8+
a.should == a
9+
end
10+
11+
it "returns true if the other has all the same fields" do
12+
a = DataSpecs::Measure.new(42, "km")
13+
b = DataSpecs::Measure.new(42, "km")
14+
a.should == b
15+
end
16+
17+
it "returns false if the other is a different object or has different fields" do
18+
a = DataSpecs::Measure.new(42, "km")
19+
b = DataSpecs::Measure.new(42, "mi")
20+
a.should_not == b
21+
end
22+
23+
it "returns false if other is of a different class" do
24+
a = DataSpecs::Measure.new(42, "km")
25+
klass = Data.define(*DataSpecs::Measure.members)
26+
b = klass.new(42, "km")
27+
a.should_not == b
28+
end
29+
30+
it "returns false if any corresponding elements are not equal with #==" do
31+
a = DataSpecs::Measure.new(42, "km")
32+
b = DataSpecs::Measure.new(42.0, "mi")
33+
a.should_not == b
34+
end
35+
36+
context "recursive structure" do
37+
it "returns true the other is the same object" do
38+
a = DataSpecs::Measure.allocate
39+
a.send(:initialize, amount: 42, unit: a)
40+
41+
a.should == a
42+
end
43+
44+
it "returns true if the other has all the same fields" do
45+
a = DataSpecs::Measure.allocate
46+
a.send(:initialize, amount: 42, unit: a)
47+
48+
b = DataSpecs::Measure.allocate
49+
b.send(:initialize, amount: 42, unit: b)
50+
51+
a.should == b
52+
end
53+
54+
it "returns false if any corresponding elements are not equal with #==" do
55+
a = DataSpecs::Measure.allocate
56+
a.send(:initialize, amount: a, unit: "km")
57+
58+
b = DataSpecs::Measure.allocate
59+
b.send(:initialize, amount: b, unit: "mi")
60+
61+
a.should_not == b
62+
end
63+
end
64+
end
65+
end

spec/ruby/core/data/fixtures/classes.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ module DataSpecs
22
guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
33
Measure = Data.define(:amount, :unit)
44

5+
class MeasureWithOverriddenName < Measure
6+
def self.name
7+
"A"
8+
end
9+
end
10+
511
class DataSubclass < Data; end
612
end
713
end

spec/ruby/core/data/hash_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
require_relative '../../spec_helper'
2+
require_relative 'fixtures/classes'
3+
4+
ruby_version_is "3.2" do
5+
describe "Data#hash" do
6+
it "returns the same integer for objects with the same content" do
7+
a = DataSpecs::Measure.new(42, "km")
8+
b = DataSpecs::Measure.new(42, "km")
9+
a.hash.should == b.hash
10+
a.hash.should be_an_instance_of(Integer)
11+
end
12+
13+
it "returns different hashes for objects with different values" do
14+
a = DataSpecs::Measure.new(42, "km")
15+
b = DataSpecs::Measure.new(42, "ml")
16+
a.hash.should_not == b.hash
17+
18+
a = DataSpecs::Measure.new(42, "km")
19+
b = DataSpecs::Measure.new(13, "km")
20+
a.hash.should_not == b.hash
21+
end
22+
23+
it "returns different hashes for different classes" do
24+
Data.define(:x).new(1).hash.should != Data.define(:x).new(1).hash
25+
end
26+
end
27+
end

spec/ruby/core/data/inspect_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
require_relative '../../spec_helper'
2+
require_relative 'shared/inspect'
3+
4+
ruby_version_is "3.2" do
5+
describe "Data#inspect" do
6+
it_behaves_like :data_inspect, :inspect
7+
end
8+
end

spec/ruby/core/data/shared/inspect.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
require_relative '../fixtures/classes'
2+
3+
describe :data_inspect, shared: true do
4+
it "returns a string representation showing members and values" do
5+
a = DataSpecs::Measure.new(42, "km")
6+
a.send(@method).should == '#<data DataSpecs::Measure amount=42, unit="km">'
7+
end
8+
9+
it "returns a string representation without the class name for anonymous structs" do
10+
Data.define(:a).new("").send(@method).should == '#<data a="">'
11+
end
12+
13+
it "returns a string representation without the class name for structs nested in anonymous classes" do
14+
c = Class.new
15+
c.class_eval <<~DOC
16+
Foo = Data.define(:a)
17+
DOC
18+
19+
c::Foo.new("").send(@method).should == '#<data a="">'
20+
end
21+
22+
it "returns a string representation without the class name for structs nested in anonymous modules" do
23+
m = Module.new
24+
m.class_eval <<~DOC
25+
Foo = Data.define(:a)
26+
DOC
27+
28+
m::Foo.new("").send(@method).should == '#<data a="">'
29+
end
30+
31+
it "does not call #name method" do
32+
struct = DataSpecs::MeasureWithOverriddenName.new(42, "km")
33+
struct.send(@method).should == '#<data DataSpecs::MeasureWithOverriddenName amount=42, unit="km">'
34+
end
35+
36+
it "does not call #name method when struct is anonymous" do
37+
klass = Class.new(DataSpecs::Measure) do
38+
def self.name
39+
"A"
40+
end
41+
end
42+
struct = klass.new(42, "km")
43+
struct.send(@method).should == '#<data amount=42, unit="km">'
44+
end
45+
46+
context "recursive structure" do
47+
it "returns string representation with recursive attribute replaced with ..." do
48+
a = DataSpecs::Measure.allocate
49+
a.send(:initialize, amount: 42, unit: a)
50+
51+
a.send(@method).should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>"
52+
end
53+
end
54+
end

spec/ruby/core/data/to_s_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
require_relative '../../spec_helper'
2+
require_relative 'shared/inspect'
3+
4+
ruby_version_is "3.2" do
5+
describe "Data#to_s" do
6+
it_behaves_like :data_inspect, :to_s
7+
end
8+
end

0 commit comments

Comments
 (0)