diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py index 1215fa494..973be40b1 100644 --- a/tests/helpers/__init__.py +++ b/tests/helpers/__init__.py @@ -1,5 +1,6 @@ from ._assertions import ( assert_cell_operation_works, + assert_row_operation_works, assert_tables_equal, assert_that_tabular_datasets_are_equal, ) @@ -38,6 +39,7 @@ __all__ = [ "assert_cell_operation_works", + "assert_row_operation_works", "assert_tables_equal", "assert_that_tabular_datasets_are_equal", "configure_test_with_device", diff --git a/tests/helpers/_assertions.py b/tests/helpers/_assertions.py index 16cb4f3cf..fd02c6fa6 100644 --- a/tests/helpers/_assertions.py +++ b/tests/helpers/_assertions.py @@ -80,3 +80,25 @@ def assert_cell_operation_works( column = Column("A", [input_value]) transformed_column = column.transform(transformer) assert transformed_column == Column("A", [expected_value]), f"Expected: {expected_value}\nGot: {transformed_column}" + + +def assert_row_operation_works( + input_value: Any, + transformer: Callable[[Table], Table], + expected_value: Any, +) -> None: + """ + Assert that a row operation works as expected. + + Parameters + ---------- + input_value: + The value in the input row. + transformer: + The transformer to apply to the rows. + expected_value: + The expected value of the transformed row. + """ + table = Table(input_value) + transformed_table = transformer(table) + assert transformed_table == Table(expected_value), f"Expected: {expected_value}\nGot: {transformed_table}" diff --git a/tests/safeds/data/tabular/containers/_row/__init__.py b/tests/safeds/data/tabular/containers/_row/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/safeds/data/tabular/containers/_row/test_column_count.py b/tests/safeds/data/tabular/containers/_row/test_column_count.py new file mode 100644 index 000000000..dacf2dbf8 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_column_count.py @@ -0,0 +1,19 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table", "expected"), + [ + (Table(), 0), + (Table({"A": [1, 2, 3]}), 1), + ], + ids=[ + "empty", + "non-empty", + ], +) +def test_should_return_the_number_of_columns(table: Table, expected: int) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + assert row.column_count == expected diff --git a/tests/safeds/data/tabular/containers/_row/test_column_names.py b/tests/safeds/data/tabular/containers/_row/test_column_names.py new file mode 100644 index 000000000..c5f55b6e2 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_column_names.py @@ -0,0 +1,24 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table", "expected"), + [ + (Table({}), []), + (Table({"A": [1, 2, 3]}), ["A"]), + ( + Table({"A": [1, 2, 3], "B": ["A", "A", "Bla"], "C": [True, True, False], "D": [1.0, 2.1, 4.5]}), + ["A", "B", "C", "D"], + ), + ], + ids=[ + "empty", + "one-column", + "four-column", + ], +) +def test_should_return_the_column_names(table: Table, expected: list[str]) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + assert row.column_names == expected diff --git a/tests/safeds/data/tabular/containers/_row/test_contains.py b/tests/safeds/data/tabular/containers/_row/test_contains.py new file mode 100644 index 000000000..216cbbcde --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_contains.py @@ -0,0 +1,23 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table", "column_name", "expected"), + [ + (Table({}), "A", False), + (Table({"A": [1, 2, 3]}), "A", True), + (Table({"A": [1, 2, 3], "B": ["A", "A", "Bla"]}), "C", False), + (Table({"col1": [1, 2, 3], "B": ["A", "A", "Bla"]}), 1, False), + ], + ids=[ + "empty row", + "column exists", + "column does not exist", + "not a string", + ], +) +def test_should_return_whether_the_row_has_the_column(table: Table, column_name: str, expected: bool) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + assert (column_name in row) == expected diff --git a/tests/safeds/data/tabular/containers/_row/test_eq.py b/tests/safeds/data/tabular/containers/_row/test_eq.py new file mode 100644 index 000000000..1bcfb3470 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_eq.py @@ -0,0 +1,58 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table1", "table2", "expected"), + [ + (Table({"col1": []}), Table({"col1": []}), True), + (Table({"col1": [1, 2]}), Table({"col1": [1, 2]}), True), + (Table({"col1": [1, 2]}), Table({"col1": [2, 3]}), False), + (Table({"col1": [1, 2]}), Table({"col2": [1, 2]}), False), + (Table({"col1": ["1", "2"]}), Table({"col1": [1, 2]}), False), + ], + ids=[ + "empty rows", + "equal rows", + "different values", + "different columns", + "different types", + ], +) +def test_should_return_whether_two_rows_are_equal(table1: Table, table2: Table, expected: bool) -> None: + row1: Row[any] = _LazyVectorizedRow(table=table1) + row2: Row[any] = _LazyVectorizedRow(table=table2) + assert (row1.__eq__(row2)) == expected + + +@pytest.mark.parametrize( + ("table", "expected"), + [ + (Table({"col1": []}), True), + (Table({"col1": [1, 2]}), True), + ], + ids=[ + "empty table", + "filled table", + ], +) +def test_should_return_true_if_rows_are_strict_equal(table: Table, expected: bool) -> None: + row1: Row[any] = _LazyVectorizedRow(table=table) + assert (row1.__eq__(row1)) == expected + + +@pytest.mark.parametrize( + ("table1", "table2"), + [ + (Table({"col1": []}), Table({"col1": []})), + (Table({"col1": [1, 2]}), Table({"col1": [1, 2]})), + ], + ids=[ + "empty tables", + "filled tables", + ], +) +def test_should_return_false_if_object_is_other_type(table1: Table, table2: Table) -> None: + row1: Row[any] = _LazyVectorizedRow(table=table1) + assert (row1.__eq__(table2)) == NotImplemented diff --git a/tests/safeds/data/tabular/containers/_row/test_get_column_type.py b/tests/safeds/data/tabular/containers/_row/test_get_column_type.py new file mode 100644 index 000000000..f5cd78a25 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_get_column_type.py @@ -0,0 +1,20 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow +from safeds.data.tabular.typing import DataType + + +@pytest.mark.parametrize( + ("table", "column_name", "expected"), + [ + (Table({"col1": ["A"]}), "col1", "String"), + (Table({"col1": ["a"], "col2": [1]}), "col2", "Int64"), + ], + ids=[ + "one column", + "two columns", + ], +) +def test_should_return_the_type_of_the_column(table: Table, column_name: str, expected: DataType) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + assert str(row.get_column_type(column_name)) == expected diff --git a/tests/safeds/data/tabular/containers/_row/test_get_value.py b/tests/safeds/data/tabular/containers/_row/test_get_value.py new file mode 100644 index 000000000..dac4f8ee7 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_get_value.py @@ -0,0 +1,46 @@ +import re + +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow +from safeds.exceptions import ColumnNotFoundError + +from tests.helpers import assert_row_operation_works + + +@pytest.mark.parametrize( + ("table_data", "column_name", "target", "expected"), + [ + ({"A": [1, 2]}, "A", 1, {"A": [2]}), + ({"A": [1, 2, 3], "B": [4, 5, 2]}, "B", 2, {"A": [1, 2], "B": [4, 5]}), + ], + ids=[ + "one column", + "two columns", + ], +) +def test_should_get_correct_item(table_data: dict, column_name: str, target: int, expected: dict) -> None: + assert_row_operation_works( + table_data, + lambda table: table.remove_rows(lambda row: row.get_value(column_name).eq(target)), + expected, + ) + + +@pytest.mark.parametrize( + ("table", "column_name"), + [ + (Table(), "A"), + (Table({"A": ["a", "aa", "aaa"]}), "B"), + (Table({"A": ["b", "aa", "aaa"], "C": ["b", "aa", "aaa"]}), "B"), + ], + ids=[ + "empty table", + "table with one column", + "table with two columns", + ], +) +def test_should_raise_column_not_found_error(table: Table, column_name: str) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + with pytest.raises(ColumnNotFoundError, match=re.escape(f"Could not find column(s):\n - '{column_name}'")): + row.get_value(column_name) diff --git a/tests/safeds/data/tabular/containers/_row/test_getitem.py b/tests/safeds/data/tabular/containers/_row/test_getitem.py new file mode 100644 index 000000000..93f668ad8 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_getitem.py @@ -0,0 +1,46 @@ +import re + +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow +from safeds.exceptions import ColumnNotFoundError + +from tests.helpers import assert_row_operation_works + + +@pytest.mark.parametrize( + ("table_data", "column_name", "target", "expected"), + [ + ({"A": [1, 2]}, "A", 1, {"A": [2]}), + ({"A": [1, 2, 3], "B": [4, 5, 2]}, "B", 2, {"A": [1, 2], "B": [4, 5]}), + ], + ids=[ + "table one column", + "table two columns", + ], +) +def test_should_get_correct_item(table_data: dict, column_name: str, target: int, expected: dict) -> None: + assert_row_operation_works( + table_data, + lambda table: table.remove_rows(lambda row: row[column_name].eq(target)), + expected, + ) + + +@pytest.mark.parametrize( + ("table", "column_name"), + [ + (Table(), "A"), + (Table({"A": ["a", "aa", "aaa"]}), "B"), + (Table({"A": ["b", "aa", "aaa"], "C": ["b", "aa", "aaa"]}), "B"), + ], + ids=[ + "empty table", + "table with one column", + "table with two columns", + ], +) +def test_should_raise_column_not_found_error(table: Table, column_name: str) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + with pytest.raises(ColumnNotFoundError, match=re.escape(f"Could not find column(s):\n - '{column_name}'")): + row[column_name] diff --git a/tests/safeds/data/tabular/containers/_row/test_has_column.py b/tests/safeds/data/tabular/containers/_row/test_has_column.py new file mode 100644 index 000000000..3d496ceda --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_has_column.py @@ -0,0 +1,21 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table", "column_name", "expected"), + [ + (Table(), "A", False), + (Table({"A": ["a", "aa", "aaa"]}), "A", True), + (Table({"A": ["a", "aa", "aaa"]}), "B", False), + ], + ids=[ + "empty table", + "table with existing column_name", + "table with non existing column_name", + ], +) +def test_should_have_column_name(table: Table, column_name: str, expected: bool) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + assert row.has_column(column_name) == expected diff --git a/tests/safeds/data/tabular/containers/_row/test_hash.py b/tests/safeds/data/tabular/containers/_row/test_hash.py new file mode 100644 index 000000000..9ec756db3 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_hash.py @@ -0,0 +1,24 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table1", "table2", "expected"), + [ + (Table(), Table({"A": ["a", "aa", "aaa"]}), False), + (Table(), Table(), True), + (Table({"A": ["a", "aa", "aaa"]}), Table({"A": ["a", "aa", "aaa"]}), True), + (Table({"A": ["a", "aa", "aaa"]}), Table({"B": ["a", "aa", "aaa"]}), False), + ], + ids=[ + "empty and different table", + "same empty tables", + "same tables", + "different tables", + ], +) +def test_should_return_consistent_hashes(table1: Table, table2: Table, expected: bool) -> None: + row1: Row[any] = _LazyVectorizedRow(table=table1) + row2: Row[any] = _LazyVectorizedRow(table=table2) + assert (hash(row1) == hash(row2)) == expected diff --git a/tests/safeds/data/tabular/containers/_row/test_iter.py b/tests/safeds/data/tabular/containers/_row/test_iter.py new file mode 100644 index 000000000..e68aefea9 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_iter.py @@ -0,0 +1,22 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table", "expected"), + [ + (Table(), []), + (Table({"A": ["a", "aa", "aaa"]}), ["A"]), + (Table({"A": ["a", "aa", "aaa"], "B": ["b", "bb", "bbb"], "C": ["c", "cc", "ccc"]}), ["A", "B", "C"]), + ], + ids=[ + "empty", + "one column", + "three columns", + ], +) +def test_should_return_same_list_of_column_name_with_iter(table: Table, expected: list) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + iterable = iter(row) + assert list(iterable) == expected diff --git a/tests/safeds/data/tabular/containers/_row/test_len.py b/tests/safeds/data/tabular/containers/_row/test_len.py new file mode 100644 index 000000000..6a9f9f0db --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_len.py @@ -0,0 +1,21 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table", "expected"), + [ + (Table(), 0), + (Table({"A": ["a", "aa", "aaa"]}), 1), + (Table({"A": ["a", "aa", "aaa"], "B": ["b", "bb", "bbb"]}), 2), + ], + ids=[ + "empty", + "one column", + "two columns", + ], +) +def test_should_have_same_length_as_number_of_columns(table: Table, expected: int) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + assert len(row) == expected diff --git a/tests/safeds/data/tabular/containers/_row/test_schema.py b/tests/safeds/data/tabular/containers/_row/test_schema.py new file mode 100644 index 000000000..4ebdc68f2 --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_schema.py @@ -0,0 +1,21 @@ +import pytest +from safeds.data.tabular.containers import Row, Table +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + + +@pytest.mark.parametrize( + ("table"), + [ + (Table()), + (Table({"A": ["a", "aa", "aaa"]})), + (Table({"A": ["a", "aa", "aaa"], "B": ["b", "bb", "bbb"]})), + ], + ids=[ + "empty", + "one column", + "two columns", + ], +) +def test_should_return_same_schema(table: Table) -> None: + row: Row[any] = _LazyVectorizedRow(table=table) + assert table.schema == row.schema diff --git a/tests/safeds/data/tabular/containers/_row/test_sizeof.py b/tests/safeds/data/tabular/containers/_row/test_sizeof.py new file mode 100644 index 000000000..d252a310a --- /dev/null +++ b/tests/safeds/data/tabular/containers/_row/test_sizeof.py @@ -0,0 +1,13 @@ +import sys +from typing import TYPE_CHECKING, Any + +import polars as pl +from safeds.data.tabular.containers._lazy_vectorized_row import _LazyVectorizedRow + +if TYPE_CHECKING: + from safeds.data.tabular.containers import Row + + +def test_should_return_size_greater_than_normal_object() -> None: + cell: Row[Any] = _LazyVectorizedRow(pl.col("a")) + assert sys.getsizeof(cell) > sys.getsizeof(object())