diff --git a/lib/net/imap/sequence_set.rb b/lib/net/imap/sequence_set.rb index cbdc2a74..568e2a4c 100644 --- a/lib/net/imap/sequence_set.rb +++ b/lib/net/imap/sequence_set.rb @@ -676,7 +676,7 @@ def &(other) # # (seqset ^ other) is equivalent to ((seqset | other) - # (seqset & other)). - def ^(other) remain_frozen (self | other).subtract(self & other) end + def ^(other) remain_frozen (dup | other).subtract(self & other) end alias xor :^ # :call-seq: @@ -1245,14 +1245,18 @@ def slice_length(start, length) def slice_range(range) first = range.begin || 0 last = range.end || -1 - last -= 1 if range.exclude_end? && range.end && last != STAR_INT + if range.exclude_end? + return remain_frozen_empty if last.zero? + last -= 1 if range.end && last != STAR_INT + end if (first * last).positive? && last < first - SequenceSet.empty + remain_frozen_empty elsif (min = at(first)) max = at(last) + max = :* if max.nil? if max == :* then self & (min..) elsif min <= max then self & (min..max) - else SequenceSet.empty + else remain_frozen_empty end end end @@ -1380,6 +1384,7 @@ def send_data(imap, tag) # :nodoc: private def remain_frozen(set) frozen? ? set.freeze : set end + def remain_frozen_empty; frozen? ? SequenceSet.empty : SequenceSet.new end # frozen clones are shallow copied def initialize_clone(other) diff --git a/test/net/imap/test_sequence_set.rb b/test/net/imap/test_sequence_set.rb index f9f43145..bbc22f26 100644 --- a/test/net/imap/test_sequence_set.rb +++ b/test/net/imap/test_sequence_set.rb @@ -83,6 +83,34 @@ def compare_to_reference_set(nums, set, seqset) end end + data "#slice(length)", {transform: ->{ _1.slice(0, 10) }, } + data "#slice(range)", {transform: ->{ _1.slice(0...10) }, } + data "#slice => empty", {transform: ->{ _1.slice(0...0) }, } + data "#slice => empty", {transform: ->{ _1.slice(10..9) }, } + data "#union", {transform: ->{ _1 | (1..100) }, } + data "#intersection", {transform: ->{ _1 & (1..100) }, } + data "#difference", {transform: ->{ _1 - (1..100) }, } + data "#xor", {transform: ->{ _1 ^ (1..100) }, } + data "#complement", {transform: ->{ ~_1 }, } + data "#normalize", {transform: ->{ _1.normalize }, } + data "#limit", {transform: ->{ _1.limit(max: 22) }, freeze: :always } + data "#limit => empty", {transform: ->{ _1.limit(max: 1) }, freeze: :always } + test "transforms keep frozen status" do |data| + transform = data.fetch(:transform) + set = SequenceSet.new("2:4,7:11,99,999") + dup = set.dup + result = transform.to_proc.(set) + assert_equal dup, set, "transform should not modified" + if data[:freeze] == :always + assert result.frozen?, "this transform always returns frozen" + else + refute result.frozen?, "transform of non-frozen returned frozen" + end + set.freeze + result = transform.to_proc.(set) + assert result.frozen?, "transform of frozen returned non-frozen" + end + %i[clone dup].each do |method| test "##{method}" do orig = SequenceSet.new "2:4,7:11,99,999" @@ -265,6 +293,9 @@ def obj.to_sequence_set; 192_168.001_255 end SequenceSet[((1..10_000) % 10).to_a][-5, 4] assert_nil SequenceSet[111..222, 888..999][2000, 4] assert_nil SequenceSet[111..222, 888..999][-2000, 4] + # with length longer than the remaining members + assert_equal SequenceSet[101...200], + SequenceSet[1...200][100, 10000] end test "#[range]" do @@ -286,9 +317,13 @@ def obj.to_sequence_set; 192_168.001_255 end assert_equal SequenceSet.empty, SequenceSet[1..100][-50..-60] assert_equal SequenceSet.empty, SequenceSet[1..100][-10..10] assert_equal SequenceSet.empty, SequenceSet[1..100][60..-60] + assert_equal SequenceSet.empty, SequenceSet[1..100][10...0] + assert_equal SequenceSet.empty, SequenceSet[1..100][0...0] assert_nil SequenceSet.empty[2..4] assert_nil SequenceSet[101..200][1000..1060] assert_nil SequenceSet[101..200][-1000..-60] + # with length longer than the remaining members + assert_equal SequenceSet[101..1111], SequenceSet[1..1111][100..999_999] end test "#find_index" do