add unit tests for rangelib

Change-Id: I3b77e849007259e697da56bd493ae5b553b901d1
This commit is contained in:
Doug Zongker
2014-09-09 10:55:36 -07:00
parent 623381880a
commit 846cb3a9e6

View File

@@ -24,7 +24,9 @@ class RangeSet(object):
lots of runs.""" lots of runs."""
def __init__(self, data=None): def __init__(self, data=None):
if data: if isinstance(data, str):
self._parse_internal(data)
elif data:
self.data = tuple(self._remove_pairs(data)) self.data = tuple(self._remove_pairs(data))
else: else:
self.data = () self.data = ()
@@ -46,6 +48,9 @@ class RangeSet(object):
else: else:
return self.to_string() return self.to_string()
def __repr__(self):
return '<RangeSet("' + self.to_string() + '")>'
@classmethod @classmethod
def parse(cls, text): def parse(cls, text):
"""Parse a text string consisting of a space-separated list of """Parse a text string consisting of a space-separated list of
@@ -59,7 +64,9 @@ class RangeSet(object):
"15-20 30 10-14" is not, even though they represent the same set "15-20 30 10-14" is not, even though they represent the same set
of blocks (and the two RangeSets will compare equal with ==). of blocks (and the two RangeSets will compare equal with ==).
""" """
return cls(text)
def _parse_internal(self, text):
data = [] data = []
last = -1 last = -1
monotonic = True monotonic = True
@@ -81,9 +88,8 @@ class RangeSet(object):
else: else:
monotonic = True monotonic = True
data.sort() data.sort()
r = RangeSet(cls._remove_pairs(data)) self.data = tuple(self._remove_pairs(data))
r.monotonic = monotonic self.monotonic = monotonic
return r
@staticmethod @staticmethod
def _remove_pairs(source): def _remove_pairs(source):
@@ -113,7 +119,13 @@ class RangeSet(object):
def union(self, other): def union(self, other):
"""Return a new RangeSet representing the union of this RangeSet """Return a new RangeSet representing the union of this RangeSet
with the argument.""" with the argument.
>>> RangeSet("10-19 30-34").union(RangeSet("18-29"))
<RangeSet("10-34")>
>>> RangeSet("10-19 30-34").union(RangeSet("22 32"))
<RangeSet("10-19 22 30-34")>
"""
out = [] out = []
z = 0 z = 0
for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
@@ -125,7 +137,13 @@ class RangeSet(object):
def intersect(self, other): def intersect(self, other):
"""Return a new RangeSet representing the intersection of this """Return a new RangeSet representing the intersection of this
RangeSet with the argument.""" RangeSet with the argument.
>>> RangeSet("10-19 30-34").intersect(RangeSet("18-32"))
<RangeSet("18-19 30-32")>
>>> RangeSet("10-19 30-34").intersect(RangeSet("22-28"))
<RangeSet("")>
"""
out = [] out = []
z = 0 z = 0
for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
@@ -137,7 +155,13 @@ class RangeSet(object):
def subtract(self, other): def subtract(self, other):
"""Return a new RangeSet representing subtracting the argument """Return a new RangeSet representing subtracting the argument
from this RangeSet.""" from this RangeSet.
>>> RangeSet("10-19 30-34").subtract(RangeSet("18-32"))
<RangeSet("10-17 33-34")>
>>> RangeSet("10-19 30-34").subtract(RangeSet("22-28"))
<RangeSet("10-19 30-34")>
"""
out = [] out = []
z = 0 z = 0
@@ -150,7 +174,13 @@ class RangeSet(object):
def overlaps(self, other): def overlaps(self, other):
"""Returns true if the argument has a nonempty overlap with this """Returns true if the argument has a nonempty overlap with this
RangeSet.""" RangeSet.
>>> RangeSet("10-19 30-34").overlaps(RangeSet("18-32"))
True
>>> RangeSet("10-19 30-34").overlaps(RangeSet("22-28"))
False
"""
# This is like intersect, but we can stop as soon as we discover the # This is like intersect, but we can stop as soon as we discover the
# output is going to be nonempty. # output is going to be nonempty.
@@ -164,7 +194,11 @@ class RangeSet(object):
def size(self): def size(self):
"""Returns the total size of the RangeSet (ie, how many integers """Returns the total size of the RangeSet (ie, how many integers
are in the set).""" are in the set).
>>> RangeSet("10-19 30-34").size()
15
"""
total = 0 total = 0
for i, p in enumerate(self.data): for i, p in enumerate(self.data):
@@ -179,16 +213,14 @@ class RangeSet(object):
representing what 'other' would get translated to if the integers representing what 'other' would get translated to if the integers
of 'self' were translated down to be contiguous starting at zero. of 'self' were translated down to be contiguous starting at zero.
>>> RangeSet.parse("0-9").map_within(RangeSet.parse("3-4")).to_string() >>> RangeSet("0-9").map_within(RangeSet("3-4"))
'3-4' <RangeSet("3-4")>
>>> RangeSet.parse("10-19").map_within(RangeSet.parse("13-14")).to_string() >>> RangeSet("10-19").map_within(RangeSet("13-14"))
'3-4' <RangeSet("3-4")>
>>> RangeSet.parse("10-19 30-39").map_within( >>> RangeSet("10-19 30-39").map_within(RangeSet("17-19 30-32"))
... RangeSet.parse("17-19 30-32")).to_string() <RangeSet("7-12")>
'7-12' >>> RangeSet("10-19 30-39").map_within(RangeSet("12-13 17-19 30-32"))
>>> RangeSet.parse("10-19 30-39").map_within( <RangeSet("2-3 7-12")>
... RangeSet.parse("12-13 17-19 30-32")).to_string()
'2-3 7-12'
""" """
out = [] out = []