# Copyright (c) 2008-2009 Aryeh Leib Taurog, http://www.aryehleib.com # All rights reserved. # # Modified from original contribution by Aryeh Leib Taurog, which was # released under the New BSD license. import unittest from django.contrib.gis.geos.mutable_list import ListMixin class UserListA(ListMixin): _mytype = tuple def __init__(self, i_list, *args, **kwargs): self._list = self._mytype(i_list) super().__init__(*args, **kwargs) def __len__(self): return len(self._list) def __str__(self): return str(self._list) def __repr__(self): return repr(self._list) def _set_list(self, length, items): # this would work: # self._list = self._mytype(items) # but then we wouldn't be testing length parameter itemList = ['x'] * length for i, v in enumerate(items): itemList[i] = v self._list = self._mytype(itemList) def _get_single_external(self, index): return self._list[index] class UserListB(UserListA): _mytype = list def _set_single(self, index, value): self._list[index] = value def nextRange(length): nextRange.start += 100 return range(nextRange.start, nextRange.start + length) nextRange.start = 0 class ListMixinTest(unittest.TestCase): """ Tests base class ListMixin by comparing a list clone which is a ListMixin subclass with a real Python list. """ limit = 3 listType = UserListA def lists_of_len(self, length=None): if length is None: length = self.limit pl = list(range(length)) return pl, self.listType(pl) def limits_plus(self, b): return range(-self.limit - b, self.limit + b) def step_range(self): return [*range(-1 - self.limit, 0), *range(1, 1 + self.limit)] def test01_getslice(self): 'Slice retrieval' pl, ul = self.lists_of_len() for i in self.limits_plus(1): self.assertEqual(pl[i:], ul[i:], 'slice [%d:]' % (i)) self.assertEqual(pl[:i], ul[:i], 'slice [:%d]' % (i)) for j in self.limits_plus(1): self.assertEqual(pl[i:j], ul[i:j], 'slice [%d:%d]' % (i, j)) for k in self.step_range(): self.assertEqual(pl[i:j:k], ul[i:j:k], 'slice [%d:%d:%d]' % (i, j, k)) for k in self.step_range(): self.assertEqual(pl[i::k], ul[i::k], 'slice [%d::%d]' % (i, k)) self.assertEqual(pl[:i:k], ul[:i:k], 'slice [:%d:%d]' % (i, k)) for k in self.step_range(): self.assertEqual(pl[::k], ul[::k], 'slice [::%d]' % (k)) def test02_setslice(self): 'Slice assignment' def setfcn(x, i, j, k, L): x[i:j:k] = range(L) pl, ul = self.lists_of_len() for slen in range(self.limit + 1): ssl = nextRange(slen) ul[:] = ssl pl[:] = ssl self.assertEqual(pl, ul[:], 'set slice [:]') for i in self.limits_plus(1): ssl = nextRange(slen) ul[i:] = ssl pl[i:] = ssl self.assertEqual(pl, ul[:], 'set slice [%d:]' % (i)) ssl = nextRange(slen) ul[:i] = ssl pl[:i] = ssl self.assertEqual(pl, ul[:], 'set slice [:%d]' % (i)) for j in self.limits_plus(1): ssl = nextRange(slen) ul[i:j] = ssl pl[i:j] = ssl self.assertEqual(pl, ul[:], 'set slice [%d:%d]' % (i, j)) for k in self.step_range(): ssl = nextRange(len(ul[i:j:k])) ul[i:j:k] = ssl pl[i:j:k] = ssl self.assertEqual(pl, ul[:], 'set slice [%d:%d:%d]' % (i, j, k)) sliceLen = len(ul[i:j:k]) with self.assertRaises(ValueError): setfcn(ul, i, j, k, sliceLen + 1) if sliceLen > 2: with self.assertRaises(ValueError): setfcn(ul, i, j, k, sliceLen - 1) for k in self.step_range(): ssl = nextRange(len(ul[i::k])) ul[i::k] = ssl pl[i::k] = ssl self.assertEqual(pl, ul[:], 'set slice [%d::%d]' % (i, k)) ssl = nextRange(len(ul[:i:k])) ul[:i:k] = ssl pl[:i:k] = ssl self.assertEqual(pl, ul[:], 'set slice [:%d:%d]' % (i, k)) for k in self.step_range(): ssl = nextRange(len(ul[::k])) ul[::k] = ssl pl[::k] = ssl self.assertEqual(pl, ul[:], 'set slice [::%d]' % (k)) def test03_delslice(self): 'Delete slice' for Len in range(self.limit): pl, ul = self.lists_of_len(Len) del pl[:] del ul[:] self.assertEqual(pl[:], ul[:], 'del slice [:]') for i in range(-Len - 1, Len + 1): pl, ul = self.lists_of_len(Len) del pl[i:] del ul[i:] self.assertEqual(pl[:], ul[:], 'del slice [%d:]' % (i)) pl, ul = self.lists_of_len(Len) del pl[:i] del ul[:i] self.assertEqual(pl[:], ul[:], 'del slice [:%d]' % (i)) for j in range(-Len - 1, Len + 1): pl, ul = self.lists_of_len(Len) del pl[i:j] del ul[i:j] self.assertEqual(pl[:], ul[:], 'del slice [%d:%d]' % (i, j)) for k in [*range(-Len - 1, 0), *range(1, Len)]: pl, ul = self.lists_of_len(Len) del pl[i:j:k] del ul[i:j:k] self.assertEqual(pl[:], ul[:], 'del slice [%d:%d:%d]' % (i, j, k)) for k in [*range(-Len - 1, 0), *range(1, Len)]: pl, ul = self.lists_of_len(Len) del pl[:i:k] del ul[:i:k] self.assertEqual(pl[:], ul[:], 'del slice [:%d:%d]' % (i, k)) pl, ul = self.lists_of_len(Len) del pl[i::k] del ul[i::k] self.assertEqual(pl[:], ul[:], 'del slice [%d::%d]' % (i, k)) for k in [*range(-Len - 1, 0), *range(1, Len)]: pl, ul = self.lists_of_len(Len) del pl[::k] del ul[::k] self.assertEqual(pl[:], ul[:], 'del slice [::%d]' % (k)) def test04_get_set_del_single(self): 'Get/set/delete single item' pl, ul = self.lists_of_len() for i in self.limits_plus(0): self.assertEqual(pl[i], ul[i], 'get single item [%d]' % i) for i in self.limits_plus(0): pl, ul = self.lists_of_len() pl[i] = 100 ul[i] = 100 self.assertEqual(pl[:], ul[:], 'set single item [%d]' % i) for i in self.limits_plus(0): pl, ul = self.lists_of_len() del pl[i] del ul[i] self.assertEqual(pl[:], ul[:], 'del single item [%d]' % i) def test05_out_of_range_exceptions(self): 'Out of range exceptions' def setfcn(x, i): x[i] = 20 def getfcn(x, i): return x[i] def delfcn(x, i): del x[i] pl, ul = self.lists_of_len() for i in (-1 - self.limit, self.limit): with self.assertRaises(IndexError): # 'set index %d' % i) setfcn(ul, i) with self.assertRaises(IndexError): # 'get index %d' % i) getfcn(ul, i) with self.assertRaises(IndexError): # 'del index %d' % i) delfcn(ul, i) def test06_list_methods(self): 'List methods' pl, ul = self.lists_of_len() pl.append(40) ul.append(40) self.assertEqual(pl[:], ul[:], 'append') pl.extend(range(50, 55)) ul.extend(range(50, 55)) self.assertEqual(pl[:], ul[:], 'extend') pl.reverse() ul.reverse() self.assertEqual(pl[:], ul[:], 'reverse') for i in self.limits_plus(1): pl, ul = self.lists_of_len() pl.insert(i, 50) ul.insert(i, 50) self.assertEqual(pl[:], ul[:], 'insert at %d' % i) for i in self.limits_plus(0): pl, ul = self.lists_of_len() self.assertEqual(pl.pop(i), ul.pop(i), 'popped value at %d' % i) self.assertEqual(pl[:], ul[:], 'after pop at %d' % i) pl, ul = self.lists_of_len() self.assertEqual(pl.pop(), ul.pop(i), 'popped value') self.assertEqual(pl[:], ul[:], 'after pop') pl, ul = self.lists_of_len() def popfcn(x, i): x.pop(i) with self.assertRaises(IndexError): popfcn(ul, self.limit) with self.assertRaises(IndexError): popfcn(ul, -1 - self.limit) pl, ul = self.lists_of_len() for val in range(self.limit): self.assertEqual(pl.index(val), ul.index(val), 'index of %d' % val) for val in self.limits_plus(2): self.assertEqual(pl.count(val), ul.count(val), 'count %d' % val) for val in range(self.limit): pl, ul = self.lists_of_len() pl.remove(val) ul.remove(val) self.assertEqual(pl[:], ul[:], 'after remove val %d' % val) def indexfcn(x, v): return x.index(v) def removefcn(x, v): return x.remove(v) with self.assertRaises(ValueError): indexfcn(ul, 40) with self.assertRaises(ValueError): removefcn(ul, 40) def test07_allowed_types(self): 'Type-restricted list' pl, ul = self.lists_of_len() ul._allowed = int ul[1] = 50 ul[:2] = [60, 70, 80] def setfcn(x, i, v): x[i] = v with self.assertRaises(TypeError): setfcn(ul, 2, 'hello') with self.assertRaises(TypeError): setfcn(ul, slice(0, 3, 2), ('hello', 'goodbye')) def test08_min_length(self): 'Length limits' pl, ul = self.lists_of_len(5) ul._minlength = 3 def delfcn(x, i): del x[:i] def setfcn(x, i): x[:i] = [] for i in range(len(ul) - ul._minlength + 1, len(ul)): with self.assertRaises(ValueError): delfcn(ul, i) with self.assertRaises(ValueError): setfcn(ul, i) del ul[:len(ul) - ul._minlength] ul._maxlength = 4 for i in range(0, ul._maxlength - len(ul)): ul.append(i) with self.assertRaises(ValueError): ul.append(10) def test09_iterable_check(self): 'Error on assigning non-iterable to slice' pl, ul = self.lists_of_len(self.limit + 1) def setfcn(x, i, v): x[i] = v with self.assertRaises(TypeError): setfcn(ul, slice(0, 3, 2), 2) def test10_checkindex(self): 'Index check' pl, ul = self.lists_of_len() for i in self.limits_plus(0): if i < 0: self.assertEqual(ul._checkindex(i), i + self.limit, '_checkindex(neg index)') else: self.assertEqual(ul._checkindex(i), i, '_checkindex(pos index)') for i in (-self.limit - 1, self.limit): with self.assertRaises(IndexError): ul._checkindex(i) def test_11_sorting(self): 'Sorting' pl, ul = self.lists_of_len() pl.insert(0, pl.pop()) ul.insert(0, ul.pop()) pl.sort() ul.sort() self.assertEqual(pl[:], ul[:], 'sort') mid = pl[len(pl) // 2] pl.sort(key=lambda x: (mid - x) ** 2) ul.sort(key=lambda x: (mid - x) ** 2) self.assertEqual(pl[:], ul[:], 'sort w/ key') pl.insert(0, pl.pop()) ul.insert(0, ul.pop()) pl.sort(reverse=True) ul.sort(reverse=True) self.assertEqual(pl[:], ul[:], 'sort w/ reverse') mid = pl[len(pl) // 2] pl.sort(key=lambda x: (mid - x) ** 2) ul.sort(key=lambda x: (mid - x) ** 2) self.assertEqual(pl[:], ul[:], 'sort w/ key') def test_12_arithmetic(self): 'Arithmetic' pl, ul = self.lists_of_len() al = list(range(10, 14)) self.assertEqual(list(pl + al), list(ul + al), 'add') self.assertEqual(type(ul), type(ul + al), 'type of add result') self.assertEqual(list(al + pl), list(al + ul), 'radd') self.assertEqual(type(al), type(al + ul), 'type of radd result') objid = id(ul) pl += al ul += al self.assertEqual(pl[:], ul[:], 'in-place add') self.assertEqual(objid, id(ul), 'in-place add id') for n in (-1, 0, 1, 3): pl, ul = self.lists_of_len() self.assertEqual(list(pl * n), list(ul * n), 'mul by %d' % n) self.assertEqual(type(ul), type(ul * n), 'type of mul by %d result' % n) self.assertEqual(list(n * pl), list(n * ul), 'rmul by %d' % n) self.assertEqual(type(ul), type(n * ul), 'type of rmul by %d result' % n) objid = id(ul) pl *= n ul *= n self.assertEqual(pl[:], ul[:], 'in-place mul by %d' % n) self.assertEqual(objid, id(ul), 'in-place mul by %d id' % n) pl, ul = self.lists_of_len() self.assertEqual(pl, ul, 'cmp for equal') self.assertNotEqual(ul, pl + [2], 'cmp for not equal') self.assertGreaterEqual(pl, ul, 'cmp for gte self') self.assertLessEqual(pl, ul, 'cmp for lte self') self.assertGreaterEqual(ul, pl, 'cmp for self gte') self.assertLessEqual(ul, pl, 'cmp for self lte') self.assertGreater(pl + [5], ul, 'cmp') self.assertGreaterEqual(pl + [5], ul, 'cmp') self.assertLess(pl, ul + [2], 'cmp') self.assertLessEqual(pl, ul + [2], 'cmp') self.assertGreater(ul + [5], pl, 'cmp') self.assertGreaterEqual(ul + [5], pl, 'cmp') self.assertLess(ul, pl + [2], 'cmp') self.assertLessEqual(ul, pl + [2], 'cmp') pl[1] = 20 self.assertGreater(pl, ul, 'cmp for gt self') self.assertLess(ul, pl, 'cmp for self lt') pl[1] = -20 self.assertLess(pl, ul, 'cmp for lt self') self.assertGreater(ul, pl, 'cmp for gt self') class ListMixinTestSingle(ListMixinTest): listType = UserListB