# encoding: UTF-8 # Copyright 2012 Twitter, Inc # http://www.apache.org/licenses/LICENSE-2.0 require 'spec_helper' include TwitterCldr::Utils describe RangeSet do describe "rangify" do it "should identify runs in an array of integers and return an array of ranges" do expect(RangeSet.rangify([1, 2, 3, 6, 7, 8, 11, 14, 17, 18, 19])). to eq([1..3, 6..8, 11..11, 14..14, 17..19]) end it "should not rangify zero-length values when told to compress" do expect(RangeSet.rangify([1, 2, 3, 5, 8, 11, 12], true)). to eq([1..3, 5, 8, 11..12]) end end describe "#to_a" do it "should return a copy of the ranges in the set" do set = RangeSet.new([1..10]) expect(set.to_a.object_id).not_to eq(set.ranges.object_id) end it "should return compressed ranges when asked" do expect(RangeSet.new([1..10, 12..12]).to_a(true)).to eq([1..10, 12]) end end describe "#to_full_a" do it "expands all ranges" do expect(RangeSet.new([1..5]).to_full_a).to eq([1, 2, 3, 4, 5]) end end describe "#new" do it "should flatten leading overlapping ranges" do expect(RangeSet.new([3..10, 1..8]).to_a).to eq([1..10]) end it "should flatten trailing overlapping ranges" do expect(RangeSet.new([1..10, 8..12]).to_a).to eq([1..12]) end it "should flatten completely overlapping ranges" do expect(RangeSet.new([2..3, 1..10]).to_a).to eq([1..10]) end it "should join ranges that are within 1 of each other" do expect(RangeSet.new([1..10, 11..15]).to_a).to eq([1..15]) end end describe "#union" do it "should aggregate the ranges and flatten when necessary" do set = RangeSet.new([3..10]).union( RangeSet.new([9..11, 1..2, 2..3, 14..18]) ) expect(set.to_a).to eq([1..11, 14..18]) end it "should aggregate the ranges correctly even if they're given in reverse order" do set = RangeSet.new([3..10]).union(RangeSet.new([1..4])) expect(set.to_a).to eq([1..10]) set = RangeSet.new([1..4]).union(RangeSet.new([3..10])) expect(set.to_a).to eq([1..10]) end end describe "#intersection" do it "computes the intersection for leading overlapping ranges" do set = RangeSet.new([3..10]).intersection(RangeSet.new([1..7])) expect(set.to_a).to eq([3..7]) end it "computes the intersection for trailing overlapping ranges" do set = RangeSet.new([1..10]).intersection(RangeSet.new([5..15])) expect(set.to_a).to eq([5..10]) end it "computes the intersection for two completely overlapping ranges" do set = RangeSet.new([1..10]).intersection(RangeSet.new([3..6])) expect(set.to_a).to eq([3..6]) end it "returns an empty intersection if no elements exist in both ranges" do set = RangeSet.new([1..10]).intersection(RangeSet.new([15..20])) expect(set.to_a).to eq([]) end it "returns partial intersections when the range set contains multiple matching ranges" do set = RangeSet.new([1..5, 7..10]).intersection(RangeSet.new([3..8])) expect(set.to_a).to eq([3..5, 7..8]) end it "doesn't matter what order the ranges are compared in" do set = RangeSet.new([2..3]).intersection(RangeSet.new([1..4])) expect(set.to_a).to eq([2..3]) set = RangeSet.new([1..4]).intersection(RangeSet.new([2..3])) expect(set.to_a).to eq([2..3]) end end describe "#subtract" do it "subtracts the intersection for leading overlapping ranges" do set = RangeSet.new([3..10]).subtract(RangeSet.new([1..5])) expect(set.to_a).to eq([6..10]) end it "subtracts the intersection for trailing overlapping ranges" do set = RangeSet.new([1..7]).subtract(RangeSet.new([3..9])) expect(set.to_a).to eq([1..2]) end it "subtracts the intersection for completely overlapping ranges (generates two ranges)" do set = RangeSet.new([1..10]).subtract(RangeSet.new([4..6])) expect(set.to_a).to eq([1..3, 7..10]) end it "results in an empty set if the deducted range entirely overlaps the existing ranges" do set = RangeSet.new([3..10]).subtract(RangeSet.new([1..15])) expect(set.to_a).to eq([]) end it "subtracts the intersection when the range set contians multiple matching ranges" do set = RangeSet.new([1..5, 7..10]).subtract(RangeSet.new([3..8])) expect(set.to_a).to eq([1..2, 9..10]) end it "does not change object when subtracting an empty set" do set = RangeSet.new([1..5]).subtract(RangeSet.new([])) expect(set.to_a).to eq([1..5]) end end describe "#difference" do it "returns the symmetric difference (union - intersection) between completely overlapping ranges" do set = RangeSet.new([1..10]).difference(RangeSet.new([3..8])) expect(set.to_a).to eq([1..2, 9..10]) end it "returns the symmetric difference between leading overlapping ranges" do set = RangeSet.new([3..10]).difference(RangeSet.new([1..5])) expect(set.to_a).to eq([1..2, 6..10]) end it "returns the symmetric difference between trailing overlapping ranges" do set = RangeSet.new([1..5]).difference(RangeSet.new([3..8])) expect(set.to_a).to eq([1..2, 6..8]) end end describe "#include?" do let(:set) { RangeSet.new([1..5, 9..16]) } it "returns true if the set completely includes the range, false otherwise" do expect(set.include?(10..15)).to eq(true) expect(set.include?(3..8)).to eq(false) expect(set.include?(8..14)).to eq(false) end it "returns true if the set contains the value, false otherwise" do expect(set.include?(3)).to eq(true) expect(set.include?(10)).to eq(true) expect(set.include?(6)).to eq(false) expect(set.include?(8)).to eq(false) end end describe '#<<' do let(:set) { RangeSet.new([5..10]) } it "adds a new range to the set when nothing overlaps" do set << (1..3) expect(set.to_a).to eq([1..3, 5..10]) end it "adds a new range to the set and handles overlapping" do set << (3..6) expect(set.to_a).to eq([3..10]) end it "adds a new range to the set and handles full overlapping" do set << (1..15) expect(set.to_a).to eq([1..15]) end end describe "#each_range" do let(:set) { RangeSet.new([5..10, 15..20]) } it "yields each individual range to the block" do expect(set.each_range.to_a).to eq([5..10, 15..20]) end end describe "#each" do let(:set) { RangeSet.new([5..10]) } it "yields each number the set contains (as opposed to each range)" do expect(set.each.to_a).to eq([5, 6, 7, 8, 9, 10]) end end describe "#size" do it "returns the number of items in the set" do set = RangeSet.from_array([1, 3, 5]) expect(set.size).to eq(3) end it "includes all elements in ranges" do set = RangeSet.from_array([1, 2, 3, 5, 6, 7]) expect(set.size).to eq(6) end end end