1# Copyright (C) 2012-2020 Ben Kurtovic <ben.kurtovic@gmail.com> 2# 3# Permission is hereby granted, free of charge, to any person obtaining a copy 4# of this software and associated documentation files (the "Software"), to deal 5# in the Software without restriction, including without limitation the rights 6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7# copies of the Software, and to permit persons to whom the Software is 8# furnished to do so, subject to the following conditions: 9# 10# The above copyright notice and this permission notice shall be included in 11# all copies or substantial portions of the Software. 12# 13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19# SOFTWARE. 20 21""" 22Test cases for the SmartList class and its child, ListProxy. 23""" 24 25import pytest 26 27from mwparserfromhell.smart_list import SmartList 28from mwparserfromhell.smart_list.list_proxy import ListProxy 29 30 31def _test_get_set_del_item(builder): 32 """Run tests on __get/set/delitem__ of a list built with *builder*.""" 33 list1 = builder([0, 1, 2, 3, "one", "two"]) 34 list2 = builder(list(range(10))) 35 36 assert 1 == list1[1] 37 assert "one" == list1[-2] 38 assert [2, 3] == list1[2:4] 39 with pytest.raises(IndexError): 40 list1[6] 41 with pytest.raises(IndexError): 42 list1[-7] 43 44 assert [0, 1, 2] == list1[:3] 45 assert [0, 1, 2, 3, "one", "two"] == list1[:] 46 assert [3, "one", "two"] == list1[3:] 47 assert [3, "one", "two"] == list1[3:100] 48 assert ["one", "two"] == list1[-2:] 49 assert [0, 1] == list1[:-4] 50 assert [] == list1[6:] 51 assert [] == list1[4:2] 52 53 assert [0, 2, "one"] == list1[0:5:2] 54 assert [0, 2] == list1[0:-3:2] 55 assert [0, 1, 2, 3, "one", "two"] == list1[::] 56 assert [2, 3, "one", "two"] == list1[2::] 57 assert [0, 1, 2, 3] == list1[:4:] 58 assert [2, 3] == list1[2:4:] 59 assert [0, 2, 4, 6, 8] == list2[::2] 60 assert [2, 5, 8] == list2[2::3] 61 assert [0, 3] == list2[:6:3] 62 assert [2, 5, 8] == list2[-8:9:3] 63 assert [] == list2[100000:1000:-100] 64 65 list1[3] = 100 66 assert 100 == list1[3] 67 list1[-3] = 101 68 assert [0, 1, 2, 101, "one", "two"] == list1 69 list1[5:] = [6, 7, 8] 70 assert [6, 7, 8] == list1[5:] 71 assert [0, 1, 2, 101, "one", 6, 7, 8] == list1 72 list1[2:4] = [-1, -2, -3, -4, -5] 73 assert [0, 1, -1, -2, -3, -4, -5, "one", 6, 7, 8] == list1 74 list1[0:-3] = [99] 75 assert [99, 6, 7, 8] == list1 76 list2[0:6:2] = [100, 102, 104] 77 assert [100, 1, 102, 3, 104, 5, 6, 7, 8, 9] == list2 78 list2[::3] = [200, 203, 206, 209] 79 assert [200, 1, 102, 203, 104, 5, 206, 7, 8, 209] == list2 80 list2[::] = range(7) 81 assert [0, 1, 2, 3, 4, 5, 6] == list2 82 with pytest.raises(ValueError): 83 list2[0:5:2] = [100, 102, 104, 106] 84 with pytest.raises(IndexError): 85 list2[7] = "foo" 86 with pytest.raises(IndexError): 87 list2[-8] = "foo" 88 89 del list2[2] 90 assert [0, 1, 3, 4, 5, 6] == list2 91 del list2[-3] 92 assert [0, 1, 3, 5, 6] == list2 93 with pytest.raises(IndexError): 94 del list2[100] 95 with pytest.raises(IndexError): 96 del list2[-6] 97 list2[:] = range(10) 98 del list2[3:6] 99 assert [0, 1, 2, 6, 7, 8, 9] == list2 100 del list2[-2:] 101 assert [0, 1, 2, 6, 7] == list2 102 del list2[:2] 103 assert [2, 6, 7] == list2 104 list2[:] = range(10) 105 del list2[2:8:2] 106 assert [0, 1, 3, 5, 7, 8, 9] == list2 107 108 109def _test_add_radd_iadd(builder): 110 """Run tests on __r/i/add__ of a list built with *builder*.""" 111 list1 = builder(range(5)) 112 list2 = builder(range(5, 10)) 113 assert [0, 1, 2, 3, 4, 5, 6] == list1 + [5, 6] 114 assert [0, 1, 2, 3, 4] == list1 115 assert list(range(10)) == list1 + list2 116 assert [-2, -1, 0, 1, 2, 3, 4], [-2, -1] + list1 117 assert [0, 1, 2, 3, 4] == list1 118 list1 += ["foo", "bar", "baz"] 119 assert [0, 1, 2, 3, 4, "foo", "bar", "baz"] == list1 120 121 122def _test_other_magic_methods(builder): 123 """Run tests on other magic methods of a list built with *builder*.""" 124 list1 = builder([0, 1, 2, 3, "one", "two"]) 125 list2 = builder([]) 126 list3 = builder([0, 2, 3, 4]) 127 list4 = builder([0, 1, 2]) 128 129 assert "[0, 1, 2, 3, 'one', 'two']" == str(list1) 130 assert b"\x00\x01\x02" == bytes(list4) 131 assert "[0, 1, 2, 3, 'one', 'two']" == repr(list1) 132 133 assert list1 < list3 134 assert list1 <= list3 135 assert list1 != list3 136 assert list1 != list3 137 assert list1 <= list3 138 assert list1 < list3 139 140 other1 = [0, 2, 3, 4] 141 assert list1 < other1 142 assert list1 <= other1 143 assert list1 != other1 144 assert list1 != other1 145 assert list1 <= other1 146 assert list1 < other1 147 148 other2 = [0, 0, 1, 2] 149 assert list1 >= other2 150 assert list1 > other2 151 assert list1 != other2 152 assert list1 != other2 153 assert list1 > other2 154 assert list1 >= other2 155 156 other3 = [0, 1, 2, 3, "one", "two"] 157 assert list1 >= other3 158 assert list1 <= other3 159 assert list1 == other3 160 assert list1 == other3 161 assert list1 <= other3 162 assert list1 >= other3 163 164 assert bool(list1) is True 165 assert bool(list2) is False 166 167 assert 6 == len(list1) 168 assert 0 == len(list2) 169 170 out = [] 171 for obj in list1: 172 out.append(obj) 173 assert [0, 1, 2, 3, "one", "two"] == out 174 175 out = [] 176 for ch in list2: 177 out.append(ch) 178 assert [] == out 179 180 gen1 = iter(list1) 181 out = [] 182 for _ in range(len(list1)): 183 out.append(next(gen1)) 184 with pytest.raises(StopIteration): 185 next(gen1) 186 assert [0, 1, 2, 3, "one", "two"] == out 187 gen2 = iter(list2) 188 with pytest.raises(StopIteration): 189 next(gen2) 190 191 assert ["two", "one", 3, 2, 1, 0] == list(reversed(list1)) 192 assert [] == list(reversed(list2)) 193 194 assert "one" in list1 195 assert 3 in list1 196 assert 10 not in list1 197 assert 0 not in list2 198 199 assert [] == list2 * 5 200 assert [] == 5 * list2 201 assert [0, 1, 2, 0, 1, 2, 0, 1, 2] == list4 * 3 202 assert [0, 1, 2, 0, 1, 2, 0, 1, 2] == 3 * list4 203 list4 *= 2 204 assert [0, 1, 2, 0, 1, 2] == list4 205 206 207def _test_list_methods(builder): 208 """Run tests on the public methods of a list built with *builder*.""" 209 list1 = builder(range(5)) 210 list2 = builder(["foo"]) 211 list3 = builder([("a", 5), ("d", 2), ("b", 8), ("c", 3)]) 212 213 list1.append(5) 214 list1.append(1) 215 list1.append(2) 216 assert [0, 1, 2, 3, 4, 5, 1, 2] == list1 217 218 assert 0 == list1.count(6) 219 assert 2 == list1.count(1) 220 221 list1.extend(range(5, 8)) 222 assert [0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 7] == list1 223 224 assert 1 == list1.index(1) 225 assert 6 == list1.index(1, 3) 226 assert 6 == list1.index(1, 3, 7) 227 with pytest.raises(ValueError): 228 list1.index(1, 3, 5) 229 230 list1.insert(0, -1) 231 assert [-1, 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 7] == list1 232 list1.insert(-1, 6.5) 233 assert [-1, 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7] == list1 234 list1.insert(13, 8) 235 assert [-1, 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7, 8] == list1 236 237 assert 8 == list1.pop() 238 assert 7 == list1.pop() 239 assert [-1, 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5] == list1 240 assert -1 == list1.pop(0) 241 assert 5 == list1.pop(5) 242 assert 6.5 == list1.pop(-1) 243 assert [0, 1, 2, 3, 4, 1, 2, 5, 6] == list1 244 assert "foo" == list2.pop() 245 with pytest.raises(IndexError): 246 list2.pop() 247 assert [] == list2 248 249 list1.remove(6) 250 assert [0, 1, 2, 3, 4, 1, 2, 5] == list1 251 list1.remove(1) 252 assert [0, 2, 3, 4, 1, 2, 5] == list1 253 list1.remove(1) 254 assert [0, 2, 3, 4, 2, 5] == list1 255 with pytest.raises(ValueError): 256 list1.remove(1) 257 258 list1.reverse() 259 assert [5, 2, 4, 3, 2, 0] == list1 260 261 list1.sort() 262 assert [0, 2, 2, 3, 4, 5] == list1 263 list1.sort(reverse=True) 264 assert [5, 4, 3, 2, 2, 0] == list1 265 list3.sort(key=lambda i: i[1]) 266 assert [("d", 2), ("c", 3), ("a", 5), ("b", 8)] == list3 267 list3.sort(key=lambda i: i[1], reverse=True) 268 assert [("b", 8), ("a", 5), ("c", 3), ("d", 2)] == list3 269 270 271def _dispatch_test_for_children(meth): 272 """Run a test method on various different types of children.""" 273 meth(lambda L: SmartList(list(L))[:]) 274 meth(lambda L: SmartList([999] + list(L))[1:]) 275 meth(lambda L: SmartList(list(L) + [999])[:-1]) 276 meth(lambda L: SmartList([101, 102] + list(L) + [201, 202])[2:-2]) 277 278 279def test_docs(): 280 """make sure the methods of SmartList/ListProxy have docstrings""" 281 methods = [ 282 "append", 283 "count", 284 "extend", 285 "index", 286 "insert", 287 "pop", 288 "remove", 289 "reverse", 290 "sort", 291 ] 292 for meth in methods: 293 expected = getattr(list, meth).__doc__ 294 smartlist_doc = getattr(SmartList, meth).__doc__ 295 listproxy_doc = getattr(ListProxy, meth).__doc__ 296 assert expected == smartlist_doc 297 assert expected == listproxy_doc 298 299 300def test_doctest(): 301 """make sure the test embedded in SmartList's docstring passes""" 302 parent = SmartList([0, 1, 2, 3]) 303 assert [0, 1, 2, 3] == parent 304 child = parent[2:] 305 assert [2, 3] == child 306 child.append(4) 307 assert [2, 3, 4] == child 308 assert [0, 1, 2, 3, 4] == parent 309 310 311def test_parent_get_set_del(): 312 """make sure SmartList's getitem/setitem/delitem work""" 313 _test_get_set_del_item(SmartList) 314 315 316def test_parent_add(): 317 """make sure SmartList's add/radd/iadd work""" 318 _test_add_radd_iadd(SmartList) 319 320 321def test_parent_other_magics(): 322 """make sure SmartList's other magically implemented features work""" 323 _test_other_magic_methods(SmartList) 324 325 326def test_parent_methods(): 327 """make sure SmartList's non-magic methods work, like append()""" 328 _test_list_methods(SmartList) 329 330 331def test_child_get_set_del(): 332 """make sure ListProxy's getitem/setitem/delitem work""" 333 _dispatch_test_for_children(_test_get_set_del_item) 334 335 336def test_child_add(): 337 """make sure ListProxy's add/radd/iadd work""" 338 _dispatch_test_for_children(_test_add_radd_iadd) 339 340 341def test_child_other_magics(): 342 """make sure ListProxy's other magically implemented features work""" 343 _dispatch_test_for_children(_test_other_magic_methods) 344 345 346def test_child_methods(): 347 """make sure ListProxy's non-magic methods work, like append()""" 348 _dispatch_test_for_children(_test_list_methods) 349 350 351def test_influence(): 352 """make sure changes are propagated from parents to children""" 353 parent = SmartList([0, 1, 2, 3, 4, 5]) 354 child1 = parent[2:] 355 child2 = parent[2:5] 356 assert [0, 1, 2, 3, 4, 5] == parent 357 assert [2, 3, 4, 5] == child1 358 assert [2, 3, 4] == child2 359 assert 2 == len(parent._children) 360 361 parent.append(6) 362 child1.append(7) 363 child2.append(4.5) 364 assert [0, 1, 2, 3, 4, 4.5, 5, 6, 7] == parent 365 assert [2, 3, 4, 4.5, 5, 6, 7] == child1 366 assert [2, 3, 4, 4.5] == child2 367 368 parent.insert(0, -1) 369 parent.insert(4, 2.5) 370 parent.insert(10, 6.5) 371 assert [-1, 0, 1, 2, 2.5, 3, 4, 4.5, 5, 6, 6.5, 7] == parent 372 assert [2, 2.5, 3, 4, 4.5, 5, 6, 6.5, 7] == child1 373 assert [2, 2.5, 3, 4, 4.5] == child2 374 375 assert 7 == parent.pop() 376 assert 6.5 == child1.pop() 377 assert 4.5 == child2.pop() 378 assert [-1, 0, 1, 2, 2.5, 3, 4, 5, 6] == parent 379 assert [2, 2.5, 3, 4, 5, 6] == child1 380 assert [2, 2.5, 3, 4] == child2 381 382 parent.remove(-1) 383 child1.remove(2.5) 384 assert [0, 1, 2, 3, 4, 5, 6] == parent 385 assert [2, 3, 4, 5, 6] == child1 386 assert [2, 3, 4] == child2 387 388 assert 0 == parent.pop(0) 389 assert [1, 2, 3, 4, 5, 6] == parent 390 assert [2, 3, 4, 5, 6] == child1 391 assert [2, 3, 4] == child2 392 393 child2.reverse() 394 assert [1, 4, 3, 2, 5, 6] == parent 395 assert [4, 3, 2, 5, 6] == child1 396 assert [4, 3, 2] == child2 397 398 parent.extend([7, 8]) 399 child1.extend([8.1, 8.2]) 400 child2.extend([1.9, 1.8]) 401 assert [1, 4, 3, 2, 1.9, 1.8, 5, 6, 7, 8, 8.1, 8.2] == parent 402 assert [4, 3, 2, 1.9, 1.8, 5, 6, 7, 8, 8.1, 8.2] == child1 403 assert [4, 3, 2, 1.9, 1.8] == child2 404 405 child3 = parent[9:] 406 assert [8, 8.1, 8.2] == child3 407 408 del parent[8:] 409 assert [1, 4, 3, 2, 1.9, 1.8, 5, 6] == parent 410 assert [4, 3, 2, 1.9, 1.8, 5, 6] == child1 411 assert [4, 3, 2, 1.9, 1.8] == child2 412 assert [] == child3 413 assert 0 == len(child3) 414 415 del child1 416 assert [1, 4, 3, 2, 1.9, 1.8, 5, 6] == parent 417 assert [4, 3, 2, 1.9, 1.8] == child2 418 assert [] == child3 419 assert 2 == len(parent._children) 420 421 del child3 422 assert [1, 4, 3, 2, 1.9, 1.8, 5, 6] == parent 423 assert [4, 3, 2, 1.9, 1.8] == child2 424 assert 1 == len(parent._children) 425 426 parent.remove(1.9) 427 parent.remove(1.8) 428 assert [1, 4, 3, 2, 5, 6] == parent 429 assert [4, 3, 2] == child2 430 431 parent.reverse() 432 assert [6, 5, 2, 3, 4, 1] == parent 433 assert [4, 3, 2] == child2 434 assert 0 == len(parent._children) 435