| -- Test cases for vec[t] where t is a boxed, non-vec type (PyObject *). |
| -- Also tests for vec[t | None], which uses the same representation. |
| |
| [case testVecTBasicOps_librt] |
| from typing import Final, Any, Iterable, Optional, Tuple |
| |
| from mypy_extensions import i64 |
| from librt.vecs import vec, append, extend, remove, pop |
| |
| from testutil import assertRaises |
| |
| def test_create_empty() -> None: |
| v = vec[str]() |
| assert len(v) == 0 |
| v2 = vec[Optional[str]]() |
| assert len(v2) == 0 |
| |
| def test_create_from_list_and_get_item() -> None: |
| v = vec[str]([]) |
| assert len(v) == 0 |
| |
| v = vec[str](["xyz", "0" + str(), str(), "foo"]) |
| assert len(v) == 4 |
| assert v[0] == "xyz" |
| assert v[1] == "0" |
| assert v[2] == "" |
| assert v[3] == "foo" |
| |
| v = vec[str](["1", "2", "3", "4", "5", "6", "7", "8", "9"]) |
| assert len(v) == 9 |
| for i in range(i64(9)): |
| assert v[i] == str(i + 1) |
| |
| def test_create_optional_and_get_item() -> None: |
| v = vec[Optional[str]](["xyz", None]) |
| assert len(v) == 2 |
| assert v[0] == "xyz" |
| assert v[1] is None |
| |
| def test_append() -> None: |
| v = vec[str]() |
| v = append(v, str() + "3") |
| assert len(v) == 1 |
| x = "xyz" + str() |
| v = append(v, x) |
| assert len(v) == 2 |
| assert v[0] == "3" |
| assert v[1] == "xyz" |
| v = vec[str]() |
| for i in range(1024): |
| v = append(v, str(i * 3)) |
| assert len(v) == 1024 |
| for i in range(1024): |
| assert v[i] == str(i * 3) |
| |
| def test_get_item() -> None: |
| v = vec[str](["3", "4"]) |
| x: i64 = int() |
| assert v[x] == "3" |
| assert v[int()] == "3" |
| x += 1 |
| assert v[x] == "4" |
| assert v[int() + 1] == "4" |
| with assertRaises(IndexError): |
| v[x + 1] |
| with assertRaises(IndexError): |
| v[2] |
| with assertRaises(IndexError): |
| v[2**63 - 1] |
| |
| def test_set_item() -> None: |
| v = vec[str](["3", "4"]) |
| v[0] = "0" |
| assert v[0] == "0" |
| |
| x: i64 = int() |
| |
| v[x] = "4" |
| assert v[x] == "4" |
| |
| v[int()] = "5" |
| assert v[int()] == "5" |
| |
| x += 1 |
| |
| v[x] = "-5" |
| assert v[x] == "-5" |
| |
| v[1 + int()] = "xyz" |
| assert v[1] == "xyz" |
| |
| with assertRaises(IndexError): |
| v[1 + x] = "6" |
| with assertRaises(IndexError): |
| v[2 + int()] = "6" |
| |
| def test_set_item_optional() -> None: |
| v = vec[Optional[str]](["3", None]) |
| v[1] = str() + "a" |
| assert v[1] == "a" |
| v[0] = None |
| assert v[0] is None |
| |
| def test_box_and_unbox() -> None: |
| v = vec[str](["3", "5"]) |
| o: Any = v |
| assert len(o) == 2 |
| assert o[0] == "3" |
| assert o[1] == "5" |
| o[1] = "6" |
| v2: vec[str] = o |
| assert len(v2) == 2 |
| assert v2[0] == "3" |
| assert v2[1] == "6" |
| o2: Any = None |
| with assertRaises(TypeError, "vec[str] object expected; got None"): |
| v2 = o2 |
| o3: Any = vec[bytes]([]) |
| with assertRaises(TypeError, "vec[str] object expected; got vec"): |
| v2 = o3 |
| |
| def test_box_and_unbox_optional() -> None: |
| v = vec[Optional[str]](["3", "4"]) |
| o: Any = v |
| o[0] = None |
| v = o |
| assert v == vec[Optional[str]]([None, "4"]) |
| |
| v2 = vec[str](["4"]) |
| o2: Any = v2 |
| o2[0] = "5" |
| v2 = o2 |
| assert v2 == vec[str](["5"]) |
| |
| o3: Any = vec[str]() |
| with assertRaises(TypeError, "vec[str | None] object expected; got vec"): |
| v = o3 |
| |
| o4: Any = vec[Optional[str]](["3"]) |
| with assertRaises(TypeError, "vec[str] object expected; got vec"): |
| v2 = o4 |
| |
| def test_construct_from_list_multiply() -> None: |
| for i in range(50): |
| v = vec[str]([str(i + 1)] * i) |
| assert len(v) == i |
| for j in range(i): |
| assert v[j] == str(i + 1) |
| for i in range(50): |
| v = vec[str](i * [str(i - 1)]) |
| assert len(v) == i |
| for j in range(i): |
| assert v[j] == str(i - 1) |
| |
| def test_construct_from_list_comprehension() -> None: |
| for i in range(50): |
| l = [i * i for i in range(i)] |
| v = vec[str]([str(n + 5) for n in l]) |
| assert len(v) == i |
| for j in range(i): |
| assert v[j] == str(j * j + 5) |
| |
| def test_construct_from_list() -> None: |
| a: list[str] = [] |
| assert vec[str](a) == vec[str]() |
| b = ["x", "y"] |
| v = vec[str](b) |
| assert len(v) == 2 |
| assert v[0] == "x" |
| assert v[1] == "y" |
| for i in range(50): |
| c = [str(j * j) for j in range(i)] |
| v = vec[str](c) |
| assert len(v) == i |
| for j in range(i): |
| assert v[j] == str(j * j) |
| |
| def test_construct_from_tuple() -> None: |
| a: tuple[str, ...] = () |
| assert vec[str](a) == vec[str]() |
| b: tuple[str, ...] = ("x", "y") |
| v = vec[str](b) |
| assert len(v) == 2 |
| assert v[0] == "x" |
| assert v[1] == "y" |
| |
| def test_construct_from_iterable() -> None: |
| for i in range(50): |
| it: Iterable[str] = iter([str(i * i) for i in range(i)]) |
| v = vec[str](it) |
| assert len(v) == i |
| for j in range(i): |
| assert v[j] == str(j * j) |
| |
| def test_equality() -> None: |
| v0 = vec[str]() |
| v0b = vec[str]() |
| v1 = vec[str](["1"]) |
| v1b = vec[str](["3"]) |
| assert v0 == v0 |
| assert v1 == v1 |
| assert v0 == v0b |
| assert v0 != v1 |
| assert v1 != v1b |
| assert v1 != v0 |
| |
| def test_equality_optional() -> None: |
| v = vec[str]() |
| vo = vec[Optional[str]]() |
| assert v != vo |
| assert vo == vo |
| vo2 = vec[Optional[str]](["x", None]) |
| assert vo2 == vec[Optional[str]](["x", None]) |
| assert vo2 != vec[Optional[str]](["x", "y"]) |
| assert vo2 != vec[Optional[str]]([None, None]) |
| assert vo2 != vec[Optional[str]](["x", None, None]) |
| |
| def test_str_conversion() -> None: |
| v = vec[str]() |
| assert str(v) == "vec[str]([])" |
| assert repr(v) == "vec[str]([])" |
| v = vec[str](["126"]) |
| assert str(v) == "vec[str](['126'])" |
| v = append(v, "5") |
| assert str(v) == "vec[str](['126', '5'])" |
| v = append(v, "xyz") |
| assert str(v) == "vec[str](['126', '5', 'xyz'])" |
| v2 = vec[Optional[str]]() |
| assert str(v2) == "vec[str | None]([])" |
| v2 = vec[Optional[str]](["x", None]) |
| assert str(v2) == "vec[str | None](['x', None])" |
| |
| def test_for_loop() -> None: |
| for n in vec[str](): |
| assert False |
| a = [] |
| for n in vec[str](["5"]): |
| a.append(n) |
| assert a == ["5"] |
| v = vec[str](["xyz", "9", "8"]) |
| a = [] |
| for n in v: |
| a.append(n) |
| assert a == ["xyz", "9", "8"] |
| assert len(v) == 3 |
| |
| def test_contains() -> None: |
| v = vec[str]() |
| x = str() |
| assert x not in v |
| v = vec[str](["x"]) |
| assert x + "x" in v |
| assert x not in v |
| v2 = vec[str](["xyz", "7", "9"]) |
| assert x + "xyz" in v2 |
| assert x + "7" in v2 |
| assert x + "9" in v2 |
| assert x not in v2 |
| assert x + "x" not in v2 |
| |
| def test_slicing() -> None: |
| v = vec[str]() |
| assert v[:] == vec[str]([]) |
| assert v[1:] == vec[str]([]) |
| assert v[:-5] == vec[str]([]) |
| v = vec[str](["0", "1", "2", "3", "4"]) |
| assert v[1:4] == vec[str](["1", "2", "3"]) |
| assert v[2:-1] == vec[str](["2", "3"]) |
| assert v[-2:-1] == vec[str](["3"]) |
| assert v[1:] == vec[str](["1", "2", "3", "4"]) |
| assert v[:-1] == vec[str](["0", "1", "2", "3"]) |
| assert v[:] == v |
| assert v[:] is not v |
| assert v[5:] == vec[str]() |
| assert v[100:] == vec[str]() |
| assert v[0:5] ==v |
| assert v[0:5] is not v |
| assert v[2:100] == vec[str](["2", "3", "4"]) |
| assert v[-100:2] == vec[str](["0", "1"]) |
| assert v[5:100] == vec[str]([]) |
| assert v[50:100] == vec[str]([]) |
| assert v[-100:-50] == vec[str]([]) |
| |
| def test_slicing_with_step() -> None: |
| v = vec[str](["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) |
| assert v[1:5:2] == vec[str](["1", "3"]) |
| assert v[1:6:2] == vec[str](["1", "3", "5"]) |
| assert v[5:1:-2] == vec[str](["5", "3"]) |
| assert v[6:1:-2] == vec[str](["6", "4", "2"]) |
| v = vec[str](["0", "1", "2", "3", "4"]) |
| assert v[::-1] == vec[str](["4", "3", "2", "1", "0"]) |
| with assertRaises(ValueError): |
| v[1:3:0] |
| |
| def test_remove() -> None: |
| a = ["4", "7", "xyz"] |
| for i in a: |
| v = vec[str](a) |
| v = remove(v, i) |
| assert v == vec[str]([j for j in a if j != i]) |
| v = vec[str](a) |
| v = remove(v, "4") |
| v = remove(v, "7") |
| v = remove(v, "xyz") |
| assert v == vec[str]() |
| with assertRaises(ValueError): |
| remove(v, "4") |
| v = append(v, "5") |
| with assertRaises(ValueError): |
| remove(v, "7") |
| v = remove(v, "5") |
| assert len(v) == 0 |
| v = vec[str](["1", "1", "1"]) |
| v = remove(v, "1") |
| assert v == vec[str](["1", "1"]) |
| v = remove(v, "1") |
| assert v == vec[str](["1"]) |
| v = remove(v, "1") |
| assert v == vec[str]() |
| f: Any = 1.1 |
| with assertRaises(TypeError): |
| remove(v, f) |
| s: Any = None |
| with assertRaises(TypeError): |
| remove(v, s) |
| |
| def test_pop_last() -> None: |
| v = vec[str](["4", "7", "xyz"]) |
| v, n = pop(v) |
| assert n == "xyz" |
| assert v == vec[str](["4", "7"]) |
| v, n = pop(v) |
| assert n == "7" |
| assert v == vec[str](["4"]) |
| v, n = pop(v) |
| assert n == "4" |
| assert v == vec[str]() |
| with assertRaises(IndexError): |
| pop(v) |
| |
| def test_pop_index() -> None: |
| v = vec[str](["4", "7", "9", "15", "22"]) |
| v, n = pop(v, 0) |
| assert n == "4" |
| assert v == vec[str](["7", "9", "15", "22"]) |
| v, n = pop(v, -1) |
| assert n == "22" |
| assert v == vec[str](["7", "9", "15"]) |
| v, n = pop(v, 1) |
| assert n == "9" |
| assert v == vec[str](["7", "15"]) |
| |
| with assertRaises(IndexError): |
| pop(v, 2) |
| |
| with assertRaises(IndexError): |
| pop(v, -3) |
| |
| v, n = pop(v, -2) |
| assert n == "7" |
| assert v == vec[str](["15"]) |
| v, n = pop(v, 0) |
| assert n == "15" |
| assert v == vec[str]() |
| |
| def test_pop_optional() -> None: |
| v = vec[Optional[str]](["x" + str(), None]) |
| v, s = pop(v) |
| assert s is None |
| v, s = pop(v) |
| assert s == "x" |
| assert len(v) == 0 |
| v = vec[Optional[str]](["x" + str(), None]) |
| v, s = pop(v, 0) |
| assert s == "x" |
| v, s = pop(v, -1) |
| assert s is None |
| |
| def test_iter_and_next() -> None: |
| v = vec[str](["s1" + str(), "s2" + str(), "s3" + str()]) |
| it = iter(v) |
| assert next(it) == "s1" |
| assert next(it) == "s2" |
| assert next(it) == "s3" |
| with assertRaises(StopIteration): |
| next(it) |
| |
| def f(x: vec[str]) -> None: |
| pass |
| |
| def test_wrapper_arg_check() -> None: |
| f_any: Any = f |
| with assertRaises(TypeError): |
| f_any([]) |
| |
| v: Final = vec[str](["x", "y"]) |
| |
| def test_final() -> None: |
| assert v == vec[str](["x", "y"]) |
| |
| def fdefault(v: vec[str] = vec[str](["x"])) -> vec[str]: |
| return v |
| |
| def test_default_arg() -> None: |
| assert fdefault() == vec[str](["x"]) |
| assert fdefault(vec[str](["y"])) == vec[str](["y"]) |
| f_any: Any = fdefault |
| assert f_any() == vec[str](["x"]) |
| assert f_any(vec[str](["y"])) == vec[str](["y"]) |
| |
| def ftuple(b: bool) -> Tuple[vec[str], vec[str]]: |
| if b: |
| raise RuntimeError() |
| return vec[str](["x"]), vec[str]() |
| |
| def test_tuple() -> None: |
| t = ftuple(False) |
| assert len(t) == 2 |
| assert t[0] == vec[str](["x"]) |
| assert t[1] == vec[str]() |
| a, b = t |
| assert a == t[0] |
| assert b == t[1] |
| with assertRaises(RuntimeError): |
| ftuple(True) |
| f_any: Any = ftuple |
| t2 = f_any(False) |
| assert t == t2 |
| with assertRaises(RuntimeError): |
| f_any(True) |
| |
| def test_optional_item_new_syntax() -> None: |
| v = vec[str | None]() |
| assert len(v) == 0 |
| assert str(v) == "vec[str | None]([])" |
| v = append(v, 'x') |
| v = append(v, None) |
| assert str(v) == "vec[str | None](['x', None])" |
| |
| class Foo: |
| def __init__(self, s: str) -> None: |
| self.s = s |
| |
| def len_union(x: vec[str] | vec[Optional[Foo]]) -> int: |
| return len(x) |
| |
| def test_union_of_vecs() -> None: |
| assert len_union(vec[str]()) == 0 |
| assert len_union(vec[str](["x", "y"])) == 2 |
| assert len_union(vec[Optional[Foo]]([Foo("x"), None, Foo("y")])) == 3 |
| with assertRaises(TypeError): |
| a1: Any = vec[Optional[str]]() |
| len_union(a1) |
| with assertRaises(TypeError): |
| a2: Any = [] |
| len_union(a2) |
| with assertRaises(TypeError): |
| a3: Any = vec[bytes]() |
| len_union(a3) |
| with assertRaises(TypeError): |
| a4: Any = vec[Foo]() |
| len_union(a4) |
| |
| def test_append_with_alias() -> None: |
| v = vec[str]() |
| v = append(v, 'a') |
| alias = v |
| v = append(v, 'b') |
| v = append(v, 'c') |
| v = append(v, 'd') |
| assert alias[0] == 'a' |
| assert len(alias) == 1 |
| assert v[0] == 'a' |
| assert len(v) == 4 |
| |
| def test_cap_empty() -> None: |
| v = vec[str](capacity=3) |
| assert len(v) == 0 |
| assert v == vec[str]() |
| |
| def test_cap_with_initializer() -> None: |
| v = vec[str](['a', 'b'], capacity=3) |
| assert len(v) == 2 |
| assert v[0] == 'a' |
| assert v[1] == 'b' |
| |
| def test_cap_from_comprehension_and_iterable() -> None: |
| v = vec[str]([str(i) for i in range(2)], capacity=3) |
| old = v |
| v = append(v, '2') |
| v[0] = 'x' |
| assert old[0] == 'x' |
| assert v == vec[str](['x', '1', '2']) |
| |
| v = vec[str]((str(i) for i in range(2)), capacity=3) |
| old = v |
| v = append(v, '2') |
| v[0] = 'y' |
| assert old[0] == 'y' |
| assert v == vec[str](['y', '1', '2']) |
| |
| def test_cap_variable(n: i64 = 3) -> None: |
| v = vec[str](capacity=n) |
| assert len(v) == 0 |
| v = append(v, 'x') |
| assert v[0] == 'x' |
| |
| def test_cap_buffer_reuse() -> None: |
| v = vec[str](['a', 'b'], capacity=3) |
| old = v |
| v = append(v, 'c') |
| v[0] = 'z' |
| assert old[0] == 'z' # shared buffer |
| |
| def test_cap_below_initializer_length() -> None: |
| v = vec[str](['a', 'b', 'c'], capacity=1) |
| assert len(v) == 3 |
| assert v[0] == 'a' |
| assert v[1] == 'b' |
| assert v[2] == 'c' |
| |
| def test_cap_negative() -> None: |
| with assertRaises(ValueError): |
| vec[str](capacity=-1) |
| with assertRaises(ValueError): |
| vec[str](['x'], capacity=-1) |
| |
| def extend_vec(v: vec[str], v2: vec[str]) -> vec[str]: |
| return extend(v, v2) |
| |
| def extend_iterable(v: vec[str], it: Iterable[str]) -> vec[str]: |
| return extend(v, it) |
| |
| def test_extend_vec() -> None: |
| v = extend_vec(vec[str](['a', 'b']), vec[str](['c', 'd'])) |
| assert v == vec[str](['a', 'b', 'c', 'd']) |
| |
| def test_extend_vec_empty_src() -> None: |
| v = extend_vec(vec[str](['a']), vec[str]()) |
| assert v == vec[str](['a']) |
| |
| def test_extend_vec_empty_dst() -> None: |
| v = extend_vec(vec[str](), vec[str](['x', 'y'])) |
| assert v == vec[str](['x', 'y']) |
| |
| def test_extend_vec_fits_in_capacity() -> None: |
| v = vec[str](['a', 'b'], capacity=3) |
| v = extend_vec(v, vec[str](['c'])) |
| assert v == vec[str](['a', 'b', 'c']) |
| |
| def test_extend_vec_exceeds_capacity() -> None: |
| v = vec[str](['a', 'b'], capacity=3) |
| v = extend_vec(v, vec[str](['c', 'd', 'e'])) |
| assert v == vec[str](['a', 'b', 'c', 'd', 'e']) |
| |
| def test_extend_vec_multiple_doublings() -> None: |
| v = vec[str](['x'], capacity=1) |
| src = vec[str]() |
| for i in range(20): |
| src = append(src, str(i)) |
| v = extend_vec(v, src) |
| assert len(v) == 21 |
| assert v[0] == 'x' |
| assert v[20] == '19' |
| |
| def test_extend_vec_self() -> None: |
| v = vec[str]() |
| v = append(v, 'a') |
| v = append(v, 'b') |
| v = extend_vec(v, v) |
| assert v == vec[str](['a', 'b', 'a', 'b']) |
| |
| def test_extend_vec_shared_buffer_after_pop() -> None: |
| v0 = vec[str]() |
| v0 = append(v0, 'a') |
| v0 = append(v0, 'b') |
| v0 = append(v0, 'c') |
| v1, _ = pop(v0) |
| # v1 and v0 share a buffer; v1.len=2, v0.len=3 |
| v = extend_vec(v1, v0) |
| assert v == vec[str](['a', 'b', 'a', 'b', 'c']) |
| # src (v0) must not be corrupted |
| assert v0 == vec[str](['a', 'b', 'c']) |
| |
| def test_extend_iterable_runtime_vec_shared_buffer_after_pop() -> None: |
| v0 = vec[str]() |
| v0 = append(v0, 'a') |
| v0 = append(v0, 'b') |
| v0 = append(v0, 'c') |
| v1, _ = pop(v0) |
| # Statically this uses VecTApi.extend, but at runtime the iterable is a vec. |
| it: Iterable[str] = v0 |
| v = extend_iterable(v1, it) |
| assert v == vec[str](['a', 'b', 'a', 'b', 'c']) |
| assert v0 == vec[str](['a', 'b', 'c']) |
| |
| def to_list(v: vec[str]) -> list[str]: |
| return list(v) |
| |
| def to_list_optional(v: vec[Optional[str]]) -> list[Optional[str]]: |
| return list(v) |
| |
| def test_to_list_empty() -> None: |
| assert to_list(vec[str]()) == [] |
| |
| def test_to_list_single() -> None: |
| assert to_list(vec[str](['hello'])) == ['hello'] |
| |
| def test_to_list_multiple() -> None: |
| assert to_list(vec[str](['a', 'b', 'c'])) == ['a', 'b', 'c'] |
| |
| def test_to_list_optional() -> None: |
| assert to_list_optional(vec[Optional[str]](['x', None, 'y'])) == ['x', None, 'y'] |
| |
| def test_to_list_does_not_consume() -> None: |
| v = vec[str](['a', 'b']) |
| l1 = to_list(v) |
| l2 = to_list(v) |
| assert l1 == l2 == ['a', 'b'] |
| |
| def test_to_list_shared_buffer() -> None: |
| v0 = vec[str](['a', 'b', 'c']) |
| v1, item = pop(v0) |
| assert item == 'c' |
| # v0 and v1 share a buffer (v0.len=3, v1.len=2) |
| result = to_list(v1) |
| assert result == ['a', 'b'] |
| # v0 must still be valid |
| assert v0 == vec[str](['a', 'b', 'c']) |
| |
| def to_tuple(v: vec[str]) -> Tuple[str, ...]: |
| return tuple(v) |
| |
| def to_tuple_optional(v: vec[Optional[str]]) -> Tuple[Optional[str], ...]: |
| return tuple(v) |
| |
| def test_to_tuple_empty() -> None: |
| assert to_tuple(vec[str]()) == () |
| |
| def test_to_tuple_single() -> None: |
| assert to_tuple(vec[str](['hello'])) == ('hello',) |
| |
| def test_to_tuple_multiple() -> None: |
| assert to_tuple(vec[str](['a', 'b', 'c'])) == ('a', 'b', 'c') |
| |
| def test_to_tuple_optional() -> None: |
| assert to_tuple_optional(vec[Optional[str]](['x', None, 'y'])) == ('x', None, 'y') |
| |
| def test_to_tuple_does_not_consume() -> None: |
| v = vec[str](['a', 'b']) |
| t1 = to_tuple(v) |
| t2 = to_tuple(v) |
| assert t1 == t2 == ('a', 'b') |
| |
| def test_to_tuple_shared_buffer() -> None: |
| v0 = vec[str](['a', 'b', 'c']) |
| v1, item = pop(v0) |
| assert item == 'c' |
| # v0 and v1 share a buffer (v0.len=3, v1.len=2) |
| result = to_tuple(v1) |
| assert result == ('a', 'b') |
| # v0 must still be valid |
| assert v0 == vec[str](['a', 'b', 'c']) |