Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Indexable::Mutable#fill's overloads #11368

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
195 changes: 28 additions & 167 deletions spec/std/array_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -698,173 +698,34 @@ describe "Array" do
end

describe "#fill" do
it "replaces all values" do
a = ['a', 'b', 'c']
expected = ['x', 'x', 'x']
a.fill('x').should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [0, 0, 0]
a.fill(0).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [0.0, 0.0, 0.0]
a.fill(0.0).should be(a)
a.should eq(expected)
end

it "replaces only values between index and size" do
a = ['a', 'b', 'c']
expected = ['x', 'x', 'c']
a.fill('x', 0, 2).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [0, 0, 3]
a.fill(0, 0, 2).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [0, 0, 3]
a.fill(0, 0, 2).should be(a)
a.should eq(expected)
end

it "replaces only values between index and size (2)" do
a = ['a', 'b', 'c']
expected = ['a', 'x', 'x']
a.fill('x', 1, 2).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [1, 0, 0]
a.fill(0, 1, 2).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [1, 0, 0]
a.fill(0, 1, 2).should be(a)
a.should eq(expected)
end

it "replaces all values from index onwards" do
a = ['a', 'b', 'c']
expected = ['a', 'x', 'x']
a.fill('x', -2).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [1, 0, 0]
a.fill(0, -2).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [1, 0, 0]
a.fill(0, -2).should be(a)
a.should eq(expected)
end

it "raises when given big negative number (#4539)" do
expect_raises(IndexError) do
['a', 'b', 'c'].fill('x', -4)
end
expect_raises(IndexError) do
[1, 2, 3].fill(0, -4)
end
expect_raises(IndexError) do
[1.0, 2.0, 3.0].fill(0, -4)
end
end

it "replaces only values between negative index and size" do
a = ['a', 'b', 'c']
expected = ['a', 'b', 'x']
a.fill('x', -1, 1).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [1, 2, 0]
a.fill(0, -1, 1).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [1, 2, 0]
a.fill(0, -1, 1).should be(a)
a.should eq(expected)
end

it "raises when given big negative number in from/count (#4539)" do
expect_raises(IndexError) do
['a', 'b', 'c'].fill('x', -4, 1)
end
expect_raises(IndexError) do
[1, 2, 3].fill(0, -4, 1)
end
expect_raises(IndexError) do
[1.0, 2.0, 3.0].fill(0, -4, 1)
end
end

it "replaces only values in range" do
a = ['a', 'b', 'c']
expected = ['x', 'x', 'c']
a.fill('x', -3..1).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [0, 0, 3]
a.fill(0, -3..1).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [0, 0, 3]
a.fill(0, -3..1).should be(a)
a.should eq(expected)
end

it "replaces only values in range without end" do
a = ['a', 'b', 'c']
expected = ['a', 'x', 'x']
a.fill('x', 1..nil).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [1, 0, 0]
a.fill(0, 1..nil).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [1, 0, 0]
a.fill(0, 1..nil).should be(a)
a.should eq(expected)
end

it "replaces only values in range begin" do
a = ['a', 'b', 'c']
expected = ['x', 'x', 'c']
a.fill('x', nil..1).should be(a)
a.should eq(expected)

a = [1, 2, 3]
expected = [0, 0, 3]
a.fill(0, nil..1).should be(a)
a.should eq(expected)

a = [1.0, 2.0, 3.0]
expected = [0, 0, 3]
a.fill(0, nil..1).should be(a)
a.should eq(expected)
end

it "works with a block" do
a = [3, 6, 9]
a.clone.fill { 0 }.should eq([0, 0, 0])
a.clone.fill { |i| i }.should eq([0, 1, 2])
a.clone.fill(1) { |i| i ** i }.should eq([3, 1, 4])
a.clone.fill(1, 1) { |i| i ** i }.should eq([3, 1, 9])
a.clone.fill(1..1) { |i| i ** i }.should eq([3, 1, 9])
it "replaces values in a subrange" do
a = [0, 1, 2, 3, 4]
a.fill(7).should be(a)
a.should eq([7, 7, 7, 7, 7])

a = [0, 1, 2, 3, 4]
a.fill(7, 1, 2).should be(a)
a.should eq([0, 7, 7, 3, 4])

a = [0, 1, 2, 3, 4]
a.fill(7, 2..3).should be(a)
a.should eq([0, 1, 7, 7, 4])

a = [0, 0, 0, 0, 0]
a.fill { |i| i + 7 }.should be(a)
a.should eq([7, 8, 9, 10, 11])

a = [0, 0, 0, 0, 0]
a.fill(offset: 2) { |i| i * i }.should be(a)
a.should eq([4, 9, 16, 25, 36])

a = [0, 0, 0, 0, 0]
a.fill(1, 2) { |i| i + 7 }.should be(a)
a.should eq([0, 8, 9, 0, 0])

a = [0, 0, 0, 0, 0]
a.fill(2..3) { |i| i + 7 }.should be(a)
a.should eq([0, 0, 9, 10, 0])
end
end

Expand Down
156 changes: 148 additions & 8 deletions spec/std/indexable/mutable_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -161,41 +161,181 @@ describe Indexable::Mutable do
context "without block" do
it "sets all elements to the same value" do
coll = SafeIndexableMutable.new(5)
coll.fill(4)
coll.fill(4).should be(coll)
coll.to_a.should eq([4, 4, 4, 4, 4])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(foo)
coll.fill(foo).should be(coll)
coll.to_a.should eq([foo, foo, foo, foo, foo])
end
end

context "without block, with start + count" do
it "sets a subrange of elements to the same value" do
coll = SafeIndexableMutable.new(5)
coll.fill(7, 2, 2).should be(coll)
coll.to_a.should eq([0, 1, 7, 7, 4])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
foo = Foo.new
coll.fill(foo, -4, 2).should be(coll)
coll.to_a.should eq([foos[0], foo, foo, foos[3], foos[4]])
end

it "sets zero elements" do
coll = SafeIndexableMutable.new(5)
coll.fill(7, 1, 0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, 5, 0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, -3, 0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, -5, 0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, 4, -1).to_a.should eq([0, 1, 2, 3, 4])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(foo, 1, 0).includes?(foo).should be_false
coll.fill(foo, 5, 0).includes?(foo).should be_false
coll.fill(foo, -3, 0).includes?(foo).should be_false
coll.fill(foo, -5, 0).includes?(foo).should be_false
coll.fill(foo, 4, -1).includes?(foo).should be_false
end

it "raises on out of bound start index" do
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(7, 6, 1) }
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(7, -6, 1) }
end
end

context "without block, with range" do
it "sets a subrange of elements to the same value" do
coll = SafeIndexableMutable.new(5)
coll.fill(7, 2..3).should be(coll)
coll.to_a.should eq([0, 1, 7, 7, 4])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
foo = Foo.new
coll.fill(foo, -4...-2).should be(coll)
coll.to_a.should eq([foos[0], foo, foo, foos[3], foos[4]])
end

it "sets zero elements" do
coll = SafeIndexableMutable.new(5)
coll.fill(7, 1..0).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, 5...5).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, -3...1).to_a.should eq([0, 1, 2, 3, 4])
coll.fill(7, -5..-6).to_a.should eq([0, 1, 2, 3, 4])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(foo, 1..0).includes?(foo).should be_false
coll.fill(foo, 5...5).includes?(foo).should be_false
coll.fill(foo, -3...1).includes?(foo).should be_false
coll.fill(foo, -5..-6).includes?(foo).should be_false
end

it "raises on out of bound start index" do
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(7, 6..7) }
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(7, -6..-1) }
end
end

context "with block" do
it "yields index to the block and sets all elements" do
coll = SafeIndexableMutable.new(5)
coll.fill { |i| i * i }
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill { |i| i * i }.should be(coll)
coll.to_a.should eq([0, 1, 4, 9, 16])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill { foo }
coll.fill { foo }.should be(coll)
coll.to_a.should eq([foo, foo, foo, foo, foo])
end
end

context "with block + offset" do
it "yields index plus offset to the block and sets all elements" do
coll = SafeIndexableMutable.new(5)
coll.fill(offset: 7) { |i| i * i }
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(offset: 7) { |i| i * i }.should be(coll)
coll.to_a.should eq([49, 64, 81, 100, 121])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
coll.fill(offset: -2) { |i| foos[i] }
coll.fill(offset: -2) { |i| foos[i] }.should be(coll)
coll.to_a.should eq([foos[-2], foos[-1], foos[0], foos[1], foos[2]])
end
end

context "with block + start + count" do
it "yields index to the block and sets elements in a subrange" do
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(2, 2) { |i| i + 7 }.should be(coll)
coll.to_a.should eq([10, 11, 9, 10, 14])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
foo = Foo.new
coll.fill(-4, 2) { foo }.should be(coll)
coll.to_a.should eq([foos[0], foo, foo, foos[3], foos[4]])
end

it "sets zero elements" do
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(1, 0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(5, 0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(-3, 0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(-5, 0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(4, -1) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(1, 0) { foo }.includes?(foo).should be_false
coll.fill(5, 0) { foo }.includes?(foo).should be_false
coll.fill(-3, 0) { foo }.includes?(foo).should be_false
coll.fill(-5, 0) { foo }.includes?(foo).should be_false
coll.fill(4, -1) { foo }.includes?(foo).should be_false
end

it "raises on out of bound start index" do
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(6, 1, &.itself) }
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(-6, 1, &.itself) }
end
end

context "with block + range" do
it "yields index to the block and sets elements in a subrange" do
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(2..3) { |i| i + 7 }.should be(coll)
coll.to_a.should eq([10, 11, 9, 10, 14])

coll = SafeIndexableMutableFoo.new(5)
foos = coll.to_a
foo = Foo.new
coll.fill(-4...-2) { foo }.should be(coll)
coll.to_a.should eq([foos[0], foo, foo, foos[3], foos[4]])
end

it "sets zero elements" do
coll = SafeIndexableMutable.new(5, offset: 10)
coll.fill(1..0) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(5...5) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(-3...1) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])
coll.fill(-5..-6) { |i| i + 7 }.to_a.should eq([10, 11, 12, 13, 14])

coll = SafeIndexableMutableFoo.new(5)
foo = Foo.new
coll.fill(1..0) { foo }.includes?(foo).should be_false
coll.fill(5...5) { foo }.includes?(foo).should be_false
coll.fill(-3...1) { foo }.includes?(foo).should be_false
coll.fill(-5..-6) { foo }.includes?(foo).should be_false
end

it "raises on out of bound start index" do
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(6..7, &.itself) }
expect_raises(IndexError) { SafeIndexableMutable.new(5).fill(-6..-1, &.itself) }
end
end
end

describe "#map!" do
Expand Down