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