diff --git a/lib/ClusterShell/RangeSet.py b/lib/ClusterShell/RangeSet.py index c44adf4d..7296db2d 100644 --- a/lib/ClusterShell/RangeSet.py +++ b/lib/ClusterShell/RangeSet.py @@ -1133,7 +1133,7 @@ def rgveckeyfunc(rgvec): # (3) lower first index first # (4) lower last index first return (-reduce(mul, [len(rg) for rg in rgvec]), \ - tuple((-len(rg), int(rg[0]), int(rg[-1])) for rg in rgvec)) + tuple((-len(rg), rg[0], rg[-1]) for rg in rgvec)) self._veclist.sort(key=rgveckeyfunc) @precond_fold() @@ -1181,72 +1181,23 @@ def _fold_multivariate(self): """Multivariate nD folding""" # PHASE 1: expand with respect to uniqueness self._fold_multivariate_expand() - self._sort() # PHASE 2: merge self._fold_multivariate_merge() - self._sort() self._dirty = False def _fold_multivariate_expand(self): """Multivariate nD folding: expand [phase 1]""" - max_length = sum([reduce(mul, [len(rg) for rg in rgvec]) \ - for rgvec in self._veclist]) - # Simple heuristic to make us faster - if len(self._veclist) * (len(self._veclist) - 1) / 2 > max_length * 10: - # *** nD full expand is preferred *** - self._veclist = [[RangeSet.fromone(i, autostep=self.autostep) - for i in tvec] - for tvec in set(self._iter())] - return - - # *** nD compare algorithm is preferred *** - index1, index2 = 0, 1 - while (index1 + 1) < len(self._veclist): - # use 2 references on iterator to compare items by couples - item1 = self._veclist[index1] - index2 = index1 + 1 - index1 += 1 - while index2 < len(self._veclist): - item2 = self._veclist[index2] - index2 += 1 - new_item = None - disjoint = False - suppl = [] - for pos, (rg1, rg2) in enumerate(zip(item1, item2)): - if not rg1 & rg2: - disjoint = True - break - - if new_item is None: - new_item = [None] * len(item1) - - if rg1 == rg2: - new_item[pos] = rg1 - else: - assert rg1 & rg2 - # intersection - new_item[pos] = rg1 & rg2 - # create part 1 - if rg1 - rg2: - item1_p = item1[0:pos] + [rg1 - rg2] + item1[pos+1:] - suppl.append(item1_p) - # create part 2 - if rg2 - rg1: - item2_p = item2[0:pos] + [rg2 - rg1] + item2[pos+1:] - suppl.append(item2_p) - if not disjoint: - assert new_item is not None - assert suppl is not None - item1 = self._veclist[index1 - 1] = new_item - index2 -= 1 - self._veclist.pop(index2) - self._veclist += suppl + self._veclist = [[RangeSet.fromone(i, autostep=self.autostep) + for i in tvec] + for tvec in set(self._iter())] def _fold_multivariate_merge(self): """Multivariate nD folding: merge [phase 2]""" - chg = True + full = False # try easy O(n) passes first + chg = True # new pass (eg. after change on veclist) while chg: chg = False + self._sort() # sort veclist before new pass index1, index2 = 0, 1 while (index1 + 1) < len(self._veclist): # use 2 references on iterator to compare items by couples @@ -1288,6 +1239,16 @@ def _fold_multivariate_merge(self): item1 = self._veclist[index1 - 1] = new_item index2 -= 1 self._veclist.pop(index2) + elif not full: + # easy pass so break to avoid scanning all + # index2; advance with next index1 for now + break + if not chg and not full: + # if no change was done during the last normal pass, we do a + # full O(n^2) pass. This pass is done only at the end in the + # hope that most vectors have already been merged by easy + # O(n) passes. + chg = full = True def __or__(self, other): """Return the union of two RangeSetNDs as a new RangeSetND. diff --git a/tests/NodeSetTest.py b/tests/NodeSetTest.py index 85651a1c..9e6ded4a 100644 --- a/tests/NodeSetTest.py +++ b/tests/NodeSetTest.py @@ -576,10 +576,13 @@ def test_nd_fold_axis_errors(self): self.assertRaises(NodeSetParseError, str, n1) n1.fold_axis = range(2) # ok self.assertEqual(str(n1), "a[1,3]b2c0,a[1,3]b2c1,a2b[3-5]c1") + self.assertEqual(n1, NodeSet("a[1,3]b2c0,a[1,3]b2c1,a2b[3-5]c1")) n1.fold_axis = RangeSet("0-1") # ok self.assertEqual(str(n1), "a[1,3]b2c0,a[1,3]b2c1,a2b[3-5]c1") + self.assertEqual(n1, NodeSet("a[1,3]b2c0,a[1,3]b2c1,a2b[3-5]c1")) n1.fold_axis = (0, 1) # ok self.assertEqual(str(n1), "a[1,3]b2c0,a[1,3]b2c1,a2b[3-5]c1") + self.assertEqual(n1, NodeSet("a[1,3]b2c0,a[1,3]b2c1,a2b[3-5]c1")) def testSimpleNodeSetUpdates(self): """test NodeSet simple nodeset-based update()""" @@ -2093,14 +2096,19 @@ def test_nd_contiguous(self): def test_nd_fold(self): ns = NodeSet("da[2-3]c[1-2],da[3-4]c[3-4]") - self.assertEqual(str(ns), "da[2-3]c[1-2],da[3-4]c[3-4]") + self.assertEqual(ns, NodeSet("da[2-3]c[1-2],da[3-4]c[3-4]")) + self.assertEqual(str(ns), "da3c[1-4],da2c[1-2],da4c[3-4]") ns = NodeSet("da[2-3]c[1-2],da[3-4]c[2-3]") + self.assertEqual(ns, NodeSet("da[2-3]c[1-2],da[3-4]c[2-3]")) self.assertEqual(str(ns), "da3c[1-3],da2c[1-2],da4c[2-3]") ns = NodeSet("da[2-3]c[1-2],da[3-4]c[1-2]") + self.assertEqual(ns, NodeSet("da[2-3]c[1-2],da[3-4]c[1-2]")) self.assertEqual(str(ns), "da[2-4]c[1-2]") ns = NodeSet("da[2-3]c[1-2]p3,da[3-4]c[1-3]p3") - self.assertEqual(str(ns), "da[2-4]c[1-2]p3,da[3-4]c3p3") + self.assertEqual(ns, NodeSet("da[2-3]c[1-2]p3,da[3-4]c[1-3]p3")) + self.assertEqual(str(ns), "da[3-4]c[1-3]p3,da2c[1-2]p3") ns = NodeSet("da[2-3]c[1-2],da[2,5]c[2-3]") + self.assertEqual(ns, NodeSet("da[2-3]c[1-2],da[2,5]c[2-3]")) self.assertEqual(str(ns), "da2c[1-3],da3c[1-2],da5c[2-3]") def test_nd_issuperset(self): @@ -2193,19 +2201,28 @@ def test_nd_intersection(self): def test_nd_nonoverlap(self): ns1 = NodeSet("a[0-2]b[1-3]c[4]") ns1.add("a[0-1]b[2-3]c[4-5]") - self.assertEqual(str(ns1), "a[0-1]b[2-3]c[4-5],a[0-2]b1c4,a2b[2-3]c4") + self.assertEqual(ns1, NodeSet("a[0-1]b[2-3]c[4-5],a[0-2]b1c4,a2b[2-3]c4")) + self.assertEqual(ns1, NodeSet("a2b[1-3]c4,a0b[1-2]c4,a0b3c[4-5],a1b[1-2]c4,a1b3c[4-5],a0b2c5,a1b2c5")) + self.assertEqual(str(ns1), "a[0-1]b[1-2]c4,a[0-1]b3c[4-5],a2b[1-3]c4,a[0-1]b2c5") self.assertEqual(len(ns1), 13) ns1 = NodeSet("a[0-1]b[2-3]c[4-5]") ns1.add("a[0-2]b[1-3]c[4]") - self.assertEqual(str(ns1), "a[0-1]b[2-3]c[4-5],a[0-2]b1c4,a2b[2-3]c4") + self.assertEqual(ns1, NodeSet("a[0-1]b[2-3]c[4-5],a[0-2]b1c4,a2b[2-3]c4")) + self.assertEqual(ns1, NodeSet("a2b[1-3]c4,a0b[1-2]c4,a0b3c[4-5],a1b[1-2]c4,a1b3c[4-5],a0b2c5,a1b2c5")) + self.assertEqual(str(ns1), "a[0-1]b[1-2]c4,a[0-1]b3c[4-5],a2b[1-3]c4,a[0-1]b2c5") self.assertEqual(len(ns1), 13) ns1 = NodeSet("a[0-2]b[1-3]c[4],a[0-1]b[2-3]c[4-5]") - self.assertEqual(str(ns1), "a[0-1]b[2-3]c[4-5],a[0-2]b1c4,a2b[2-3]c4") + self.assertEqual(ns1, NodeSet("a[0-2]b[1-3]c[4],a[0-1]b[2-3]c[4-5]")) + self.assertEqual(ns1, NodeSet("a2b[1-3]c4,a0b[1-2]c4,a0b3c[4-5],a1b[1-2]c4,a1b3c[4-5],a0b2c5,a1b2c5")) + self.assertEqual(ns1, NodeSet("a[0-2]b[1-3]c4,a[0-1]b[2-3]c5")) + self.assertEqual(str(ns1), "a[0-1]b[1-2]c4,a[0-1]b3c[4-5],a2b[1-3]c4,a[0-1]b2c5") self.assertEqual(len(ns1), 13) ns1 = NodeSet("a[0-2]b[1-3]c[4-6],a[0-1]b[2-3]c[4-5]") + self.assertEqual(ns1, NodeSet("a[0-2]b[1-3]c[4-6],a[0-1]b[2-3]c[4-5]")) + self.assertEqual(ns1, NodeSet("a[0-2]b[1-3]c[4-6]")) self.assertEqual(str(ns1), "a[0-2]b[1-3]c[4-6]") self.assertEqual(len(ns1), 3*3*3) @@ -2223,13 +2240,14 @@ def test_nd_nonoverlap(self): self.assertEqual(len(ns1), (3*2*3)+(2*1*2)) ns1 = NodeSet("a[0-2]b[2-3]c[4-6],a[0-1]b[1-3]c[4-5],a2b1c[4-6]") - self.assertEqual(str(ns1), "a[0-2]b[2-3]c[4-6],a[0-1]b1c[4-5],a2b1c[4-6]") + self.assertEqual(str(ns1), "a[0-1]b[2-3]c[4-6],a2b[1-3]c[4-6],a[0-1]b1c[4-5]") self.assertEqual(ns1, NodeSet("a[0-1]b[1-3]c[4-5],a[0-2]b[2-3]c6,a2b[2-3]c[4-5],a2b1c[4-6]")) self.assertEqual(ns1, NodeSet("a[0-2]b[2-3]c[4-6],a[0-1]b1c[4-5],a2b1c[4-6]")) self.assertEqual(len(ns1), (3*3*2)+1+(3*2*1)) ns1.add("a1b1c6") - self.assertEqual(str(ns1), "a[0-2]b[2-3]c[4-6],a[0-1]b1c[4-5],a2b1c[4-6],a1b1c6") + self.assertEqual(str(ns1), "a[1-2]b[1-3]c[4-6],a0b[2-3]c[4-6],a0b1c[4-5]") self.assertEqual(ns1, NodeSet("a[0-2]b[2-3]c[4-6],a[0-1]b1c[4-5],a2b1c[4-6],a1b1c6")) + self.assertEqual(ns1, NodeSet("a[1-2]b[1-3]c[4-6],a0b[2-3]c[4-6],a0b1c[4-5]")) ns1.add("a0b1c6") self.assertEqual(str(ns1), "a[0-2]b[1-3]c[4-6]") self.assertEqual(ns1, NodeSet("a[0-2]b[1-3]c[4-6]")) @@ -2254,7 +2272,10 @@ def test_nd_difference(self): self.assertEqual(len(ns1.difference(ns2)), 6) ns1 = NodeSet("a[0-2]b[1-3]c[4],a[0-1]b[2-3]c[4-5]") - self.assertEqual(str(ns1), "a[0-1]b[2-3]c[4-5],a[0-2]b1c4,a2b[2-3]c4") + self.assertEqual(str(ns1), "a[0-1]b[1-2]c4,a[0-1]b3c[4-5],a2b[1-3]c4,a[0-1]b2c5") + self.assertEqual(ns1, NodeSet("a[0-2]b[1-3]c[4],a[0-1]b[2-3]c[4-5]")) + self.assertEqual(ns1, NodeSet("a[0-1]b[2-3]c[4-5],a[0-2]b1c4,a2b[2-3]c4")) + self.assertEqual(ns1, NodeSet("a2b[1-3]c4,a0b[1-2]c4,a0b3c[4-5],a1b[1-2]c4,a1b3c[4-5],a0b2c5,a1b2c5")) self.assertEqual(len(ns1), 3*3 + 2*2) ns2 = NodeSet("a[0-3]b[1]c[4-5]") @@ -2267,7 +2288,7 @@ def test_nd_difference(self): ns1 = NodeSet("a[0-3]b[1-5]c5") ns2 = NodeSet("a[0-2]b[2-4]c5") - self.assertEqual(str(ns1.difference(ns2)), "a[0-3]b[1,5]c5,a3b[2-4]c5") + self.assertEqual(str(ns1.difference(ns2)), "a[0-2]b[1,5]c5,a3b[1-5]c5") ns1 = NodeSet("a[0-3]b2c5") ns2 = NodeSet("a[0-2]b1c5") @@ -2275,7 +2296,7 @@ def test_nd_difference(self): ns1 = NodeSet("a[0-3]b[1-4]c[5]") ns2 = NodeSet("a[0-2]b1c5") - self.assertEqual(str(ns1.difference(ns2)), "a[0-3]b[2-4]c5,a3b1c5") + self.assertEqual(str(ns1.difference(ns2)), "a[0-2]b[2-4]c5,a3b[1-4]c5") ns1 = NodeSet("a[0-2]b[1-4]c5") ns2 = NodeSet("a[0-3]b[2-3]c5") @@ -2308,7 +2329,7 @@ def test_nd_difference_test(self): ns1 = NodeSet("a[1-10]b[1-10]") ns2 = NodeSet("a[5-20]b[5-20]") nsdiff = ns1.difference(ns2) - self.assertEqual(str(nsdiff), "a[1-10]b[1-4],a[1-4]b[5-10]") + self.assertEqual(str(nsdiff), "a[1-4]b[1-10],a[5-10]b[1-4]") self.assertEqual(nsdiff, NodeSet("a[1-4]b[1-10],a[1-10]b[1-4]")) # manually checked with overlap # node[1-100]x[1-10] -x node4x4 @@ -2340,7 +2361,7 @@ def test_nd_difference_m(self): ns1 = NodeSet("a[2-3]b[0,3-4],a[6-10]b[0-2]") ns2 = NodeSet("a[3-6]b[2-3]") nsdiff = ns1.difference(ns2) - self.assertEqual(str(nsdiff), "a[7-10]b[0-2],a[2-3]b[0,4],a6b[0-1],a2b3") + self.assertEqual(str(nsdiff), "a[7-10]b[0-2],a2b[0,3-4],a3b[0,4],a6b[0-1]") self.assertEqual(nsdiff, NodeSet("a[7-10]b[0-2],a[2-3]b[0,4],a6b[0-1],a2b3")) self.assertEqual(nsdiff, NodeSet("a[2-3,6-10]b0,a[6-10]b1,a[7-10]b2,a2b3,a[2-3]b4")) # manually checked @@ -2387,25 +2408,33 @@ def test_nd_xor(self): first = NodeSet("a[2-3,5]b[1,4],a6b5") second = NodeSet("a[4-6]b[3-6]") first.symmetric_difference_update(second) - self.assertEqual(str(first), "a[4-6]b[3,6],a[2-3]b[1,4],a4b[4-5],a5b[1,5],a6b4") + self.assertEqual(str(first), "a[2-3]b[1,4],a4b[3-6],a5b[1,3,5-6],a6b[3-4,6]") + self.assertEqual(first, NodeSet("a[2-3]b[1,4],a4b[3-6],a5b[1,3,5-6],a6b[3-4,6]")) self.assertEqual(first, NodeSet("a[4-6]b[3,6],a[2-3]b[1,4],a4b[4-5],a5b[1,5],a6b4")) first = NodeSet("a[1-50]b[1-20]") second = NodeSet("a[40-60]b[10-30]") first.symmetric_difference_update(second) - self.assertEqual(str(first), "a[1-39]b[1-20],a[40-60]b[21-30],a[51-60]b[10-20],a[40-50]b[1-9]") - self.assertEqual(first, NodeSet("a[1-39]b[1-20],a[51-60]b[10-30],a[40-50]b[1-9,21-30]")) + self.assertEqual(str(first), "a[1-39]b[1-20],a[51-60]b[10-30],a[40-50]b[1-9,21-30]") + self.assertEqual(first, NodeSet("a[1-39]b[1-20],a[40-60]b[21-30],a[51-60]b[10-20],a[40-50]b[1-9]")) + + first = NodeSet("a[1-2]p[1-2]") + second = NodeSet("a[2-3]p[2-3]") + first.symmetric_difference_update(second) + self.assertEqual(str(first), "a1p[1-2],a2p[1,3],a3p[2-3]") + self.assertEqual(first, NodeSet("a1p1,a1p2,a2p1,a2p3,a3p2,a3p3")) - first = NodeSet("artcore[3-999]p[1-99,500-598]") - second = NodeSet("artcore[1-2000]p[40-560]") + first = NodeSet("a[3-29]p[1-9,50-58]") + second = NodeSet("a[1-110]p[4-56]") first.symmetric_difference_update(second) - self.assertEqual(str(first), "artcore[1-2000]p[100-499],artcore[1-2,1000-2000]p[40-99,500-560],artcore[3-999]p[1-39,561-598]") - self.assertEqual(first, NodeSet("artcore[1-2000]p[100-499],artcore[1-2,1000-2000]p[40-99,500-560],artcore[3-999]p[1-39,561-598]")) + self.assertEqual(str(first), "a[1-2,30-110]p[4-56],a[3-29]p[1-3,10-49,57-58]") + self.assertEqual(first, NodeSet("a[1-2,30-110]p[4-56],a[3-29]p[1-3,10-49,57-58]")) ns1 = NodeSet("a[1-6]b4") ns2 = NodeSet("a5b[2-5]") ns1.symmetric_difference_update(ns2) self.assertEqual(str(ns1), "a[1-4,6]b4,a5b[2-3,5]") + self.assertEqual(ns1, NodeSet("a[1-4]b4,a5b[2-3,5],a6b4")) self.assertEqual(ns1, NodeSet("a[1-4,6]b4,a5b[2-3,5]")) def test_autostep(self): diff --git a/tests/RangeSetNDTest.py b/tests/RangeSetNDTest.py index 66c1cfa1..95ec86ac 100644 --- a/tests/RangeSetNDTest.py +++ b/tests/RangeSetNDTest.py @@ -37,8 +37,9 @@ def test_simple(self): def test_vectors(self): rn = RangeSetND([["0-10", "1-2"], ["5-60", "2"]]) # vectors() should perform automatic folding - self.assertEqual([[RangeSet("0-60"), RangeSet("2")], [RangeSet("0-10"), RangeSet("1")]], list(rn.vectors())) - self.assertEqual(str(rn), "0-60; 2\n0-10; 1\n") + + self.assertEqual([[RangeSet("11-60"), RangeSet("2")], [RangeSet("0-10"), RangeSet("1-2")],], list(rn.vectors())) + self.assertEqual(str(rn), "11-60; 2\n0-10; 1-2\n") self.assertEqual(len(rn), 72) def test_nonzero(self): @@ -141,9 +142,9 @@ def test_sorting(self): self._testRS([["10-30", "3", "5"], ["10-30", "2", "6"]], "10-30; 2; 6\n10-30; 3; 5\n", 42) self._testRS([["10-30", "2", "6"], ["10-30", "3", "5"]], "10-30; 2; 6\n10-30; 3; 5\n", 42) # sorting condition (4) - self._testRS([["10-30", "2,6", "6"], ["10-30", "2-3", "5"]], "10-30; 2-3; 5\n10-30; 2,6; 6\n", 84) + self._testRS([["10-30", "2,6", "6"], ["10-30", "2-3", "5"]], "10-30; 2; 5-6\n10-30; 3; 5\n10-30; 6; 6\n", 84) # the following test triggers folding loop protection - self._testRS([["40-60", "5"], ["30-50", "6"]], "30-50; 6\n40-60; 5\n", 42) + self._testRS([["40-60", "5"], ["30-50", "6"]], "40-50; 5-6\n30-39; 6\n51-60; 5\n", 42) # 1D self._testRS([["40-60"], ["10-12"]], "10-12,40-60\n", 24) @@ -157,11 +158,11 @@ def test_folding(self): self._testRS([["0-2", "1-2"], ["3", "1-3"]], "0-2; 1-2\n3; 1-3\n", 9) self._testRS([["0-2", "1-2"], ["1-3", "1-3"]], - "1-2; 1-3\n0,3; 1-2\n3; 3\n", 11) + "1-3; 1-3\n0; 1-2\n", 11) self._testRS([["0-2", "1-2", "0-4"], ["3", "1-2", "0-5"]], "0-2; 1-2; 0-4\n3; 1-2; 0-5\n", 42) self._testRS([["0-2", "1-2", "0-4"], ["1-3", "1-3", "0-4"]], - "1-2; 1-3; 0-4\n0,3; 1-2; 0-4\n3; 3; 0-4\n", 55) + "1-3; 1-3; 0-4\n0; 1-2; 0-4\n", 55) # triggers full expand heuristic veclist = [item for x in range(0, 22, 2) for item in [(x,0), (x,1)]] @@ -169,25 +170,25 @@ def test_folding(self): # the following test triggers folding loop protection self._testRS([["0-100", "50-200"], ["2-101", "49"]], - "0-100; 50-200\n2-101; 49\n", 15351) + "2-100; 49-200\n0-1; 50-200\n101; 49\n", 15351) # the following test triggers full expand veclist = [] for v1, v2, v3 in zip(range(30), range(5, 35), range(10, 40)): veclist.append((v1, v2, v3)) - self._testRS(veclist, "0; 5; 10\n1; 6; 11\n2; 7; 12\n3; 8; 13\n4; 9; 14\n5; 10; 15\n6; 11; 16\n7; 12; 17\n8; 13; 18\n9; 14; 19\n10; 15; 20\n11; 16; 21\n12; 17; 22\n13; 18; 23\n14; 19; 24\n15; 20; 25\n16; 21; 26\n17; 22; 27\n18; 23; 28\n19; 24; 29\n20; 25; 30\n21; 26; 31\n22; 27; 32\n23; 28; 33\n24; 29; 34\n25; 30; 35\n26; 31; 36\n27; 32; 37\n28; 33; 38\n29; 34; 39\n", 30) + self._testRS(veclist, "0; 5; 10\n1; 6; 11\n10; 15; 20\n11; 16; 21\n12; 17; 22\n13; 18; 23\n14; 19; 24\n15; 20; 25\n16; 21; 26\n17; 22; 27\n18; 23; 28\n19; 24; 29\n2; 7; 12\n20; 25; 30\n21; 26; 31\n22; 27; 32\n23; 28; 33\n24; 29; 34\n25; 30; 35\n26; 31; 36\n27; 32; 37\n28; 33; 38\n29; 34; 39\n3; 8; 13\n4; 9; 14\n5; 10; 15\n6; 11; 16\n7; 12; 17\n8; 13; 18\n9; 14; 19\n", 30) def test_union(self): rn1 = RangeSetND([["10-100", "1-3"], ["1100-1300", "2-3"]]) self.assertEqual(str(rn1), "1100-1300; 2-3\n10-100; 1-3\n") self.assertEqual(len(rn1), 675) rn2 = RangeSetND([["1100-1200", "1"], ["10-49", "1,3"]]) - self.assertEqual(str(rn2), "1100-1200; 1\n10-49; 1,3\n") + self.assertEqual(str(rn2), "12-13,1100-1200; 1\n10-11,14-49; 1,3\n12-13; 3\n") self.assertEqual(len(rn2), 181) rnu = rn1.union(rn2) - self.assertEqual(str(rnu), "1100-1300; 2-3\n10-100; 1-3\n1100-1200; 1\n") + self.assertEqual(str(rnu), "10-100,1100-1200; 1-3\n1201-1300; 2-3\n") self.assertEqual(len(rnu), 776) rnu2 = rn1 | rn2 - self.assertEqual(str(rnu2), "1100-1300; 2-3\n10-100; 1-3\n1100-1200; 1\n") + self.assertEqual(str(rnu2), "10-100,1100-1200; 1-3\n1201-1300; 2-3\n") self.assertEqual(len(rnu2), 776) self.assertEqual(rnu, rnu2) # btw test __eq__ self.assertNotEqual(rnu, rn1) # btw test __eq__ @@ -202,7 +203,7 @@ def test_union(self): rn1 = RangeSetND([["10", "10-13"], ["10", "9-12"]]) rn2 = RangeSetND([["1100-1200", "1"], ["10-49", "1,3"]]) rn1 |= rn2 - self.assertEqual(str(rn2), "1100-1200; 1\n10-49; 1,3\n") + self.assertEqual(str(rn2), "12-13,1100-1200; 1\n10-11,14-49; 1,3\n12-13; 3\n") self.assertEqual(len(rn2), 181) rn2 = set([3, 5]) self.assertRaises(TypeError, rn1.__ior__, rn2) @@ -256,7 +257,7 @@ def test_difference_update(self): rn2 = RangeSetND([["10", "10"], ["9", "12-15"]]) rn1.difference_update(rn2) self.assertEqual(len(rn1), 8) - self.assertEqual(str(rn1), "8; 12-15\n10; 9,11-13\n") + self.assertEqual(str(rn1), "10; 9,11-13\n8; 12-15\n") rn1 = RangeSetND([["10", "10-13"], ["10", "9-12"], ["8-9", "12-15"]]) rn2 = RangeSetND([["10", "10"], ["9", "12-15"], ["10-12", "11-15"], ["11", "14"]]) @@ -268,10 +269,7 @@ def test_difference_update(self): rn2 = RangeSetND([["10", "10"], ["9", "12-15"], ["10-12", "11-15"], ["11", "14"]]) rn1.difference_update(rn2) self.assertEqual(len(rn1), 7) - # no pre-fold (self._veclist) - self.assertEqual(str(rn1), "8; 12-15\n9-10; 16\n10; 9\n") - # pre-fold (self.veclist) - #self.assertEqual(str(rn1), "8; 12-15\n10; 9,16\n9; 16\n") + self.assertEqual(str(rn1), "8; 12-15\n10; 9,16\n9; 16\n") # strict mode rn1 = RangeSetND([["10", "10-13"], ["10", "9-12"], ["8-9", "12-15"]]) @@ -341,7 +339,7 @@ def test_intersection_update(self): rn2 = RangeSetND([["10", "10"], ["9", "12-15"], ["10-12", "11-15"], ["11", "14"]]) rn1.intersection_update(rn2) self.assertEqual(len(rn1), 8) - self.assertEqual(str(rn1), "9; 12-15\n10; 10-13\n") + self.assertEqual(str(rn1), "10; 10-13\n9; 12-15\n") rn1 = RangeSetND([["10", "10-13"], ["10", "9-12"], ["8-9", "12-15"], ["10", "10-13"], ["10", "12-16"], ["9", "13-16"]]) rn2 = RangeSetND([["10", "10"], ["9", "12-15"], ["10-12", "11-15"], ["11", "14"]]) @@ -451,12 +449,13 @@ def test_contiguous(self): def test_iter(self): rn0 = RangeSetND([['1-2', '3'], ['1-2', '4'], ['2-6', '6-9,11']]) self.assertEqual(len([r for r in rn0]), len(rn0)) - self.assertEqual([('2', '6'), ('2', '7'), ('2', '8'), ('2', '9'), ('2', '11'), ('3', '6'), - ('3', '7'), ('3', '8'), ('3', '9'), ('3', '11'), ('4', '6'), ('4', '7'), - ('4', '8'), ('4', '9'), ('4', '11'), ('5', '6'), ('5', '7'), ('5', '8'), - ('5', '9'), ('5', '11'), ('6', '6'), ('6', '7'), ('6', '8'), ('6', '9'), - ('6', '11'), ('1', '3'), ('1', '4'), ('2', '3'), ('2', '4')], - [r for r in rn0]) + # at this time, iter nD is not sorted + self.assertEqual([('3', '6'), ('3', '7'), ('3', '8'), ('3', '9'), ('3', '11'), ('4', '6'), + ('4', '7'), ('4', '8'), ('4', '9'), ('4', '11'), ('5', '6'), ('5', '7'), + ('5', '8'), ('5', '9'), ('5', '11'), ('6', '6'), ('6', '7'), ('6', '8'), + ('6', '9'), ('6', '11'), ('2', '3'), ('2', '4'), ('2', '6'), ('2', '7'), + ('2', '8'), ('2', '9'), ('2', '11'), ('1', '3'), ('1', '4')], + [r for r in rn0]) def test_pads(self): rn0 = RangeSetND() @@ -464,18 +463,18 @@ def test_pads(self): self.assertEqual(len(rn0), 0) self.assertEqual(rn0.pads(), ()) rn1 = RangeSetND([['01-02', '003'], ['01-02', '004'], ['02-06', '006-009,411']]) - self.assertEqual(str(rn1), "02-06; 006-009,411\n01-02; 003-004\n") + self.assertEqual(str(rn1), "03-06; 006-009,411\n02; 003-004,006-009,411\n01; 003-004\n") self.assertEqual(len(rn1), 29) self.assertEqual(rn1.pads(), (2, 3)) # Note: mixed lenghts zero-padding supported in ClusterShell v1.9 rn1 = RangeSetND([['01-02', '003'], ['01-02', '0101'], ['02-06', '006-009,411']]) # before v1.9: 0101 padding was changed to 101 - self.assertEqual(str(rn1), '02-06; 006-009,411\n01-02; 003,0101\n') + self.assertEqual(str(rn1), '03-06; 006-009,411\n02; 003,006-009,411,0101\n01; 003,0101\n') self.assertEqual(len(rn1), 29) self.assertEqual(rn1.pads(), (2, 4)) rn1 = RangeSetND([['01-02', '0003'], ['01-02', '004'], ['02-06', '006-009,411']]) # before v1.9: 004 padding was wrongly changed to 0004 - self.assertEqual(str(rn1), '02-06; 006-009,411\n01-02; 004,0003\n') + self.assertEqual(str(rn1), '03-06; 006-009,411\n02; 004,006-009,411,0003\n01; 004,0003\n') self.assertEqual(len(rn1), 29) self.assertEqual(rn1.pads(), (2, 4)) # pads() returns max padding length by axis