diff options
Diffstat (limited to 'tests/units/tools')
-rw-r--r-- | tests/units/tools/__init__.py | 3 | ||||
-rw-r--r-- | tests/units/tools/test_get_dict_superset.py | 149 | ||||
-rw-r--r-- | tests/units/tools/test_get_item.py | 72 | ||||
-rw-r--r-- | tests/units/tools/test_get_value.py | 50 | ||||
-rw-r--r-- | tests/units/tools/test_misc.py | 38 | ||||
-rw-r--r-- | tests/units/tools/test_utils.py | 57 |
6 files changed, 369 insertions, 0 deletions
diff --git a/tests/units/tools/__init__.py b/tests/units/tools/__init__.py new file mode 100644 index 0000000..e772bee --- /dev/null +++ b/tests/units/tools/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) 2023-2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. diff --git a/tests/units/tools/test_get_dict_superset.py b/tests/units/tools/test_get_dict_superset.py new file mode 100644 index 0000000..63e08b5 --- /dev/null +++ b/tests/units/tools/test_get_dict_superset.py @@ -0,0 +1,149 @@ +# Copyright (c) 2023-2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. + +"""Tests for `anta.tools.get_dict_superset`.""" +from __future__ import annotations + +from contextlib import nullcontext as does_not_raise +from typing import Any + +import pytest + +from anta.tools.get_dict_superset import get_dict_superset + +# pylint: disable=duplicate-code +DUMMY_DATA = [ + ("id", 0), + { + "id": 1, + "name": "Alice", + "age": 30, + "email": "alice@example.com", + }, + { + "id": 2, + "name": "Bob", + "age": 35, + "email": "bob@example.com", + }, + { + "id": 3, + "name": "Charlie", + "age": 40, + "email": "charlie@example.com", + }, +] + + +@pytest.mark.parametrize( + "list_of_dicts, input_dict, default, required, var_name, custom_error_msg, expected_result, expected_raise", + [ + pytest.param([], {"id": 1, "name": "Alice"}, None, False, None, None, None, does_not_raise(), id="empty list"), + pytest.param( + [], + {"id": 1, "name": "Alice"}, + None, + True, + None, + None, + None, + pytest.raises(ValueError, match="not found in the provided list."), + id="empty list and required", + ), + pytest.param(DUMMY_DATA, {"id": 10, "name": "Jack"}, None, False, None, None, None, does_not_raise(), id="missing item"), + pytest.param(DUMMY_DATA, {"id": 1, "name": "Alice"}, None, False, None, None, DUMMY_DATA[1], does_not_raise(), id="found item"), + pytest.param(DUMMY_DATA, {"id": 10, "name": "Jack"}, "default_value", False, None, None, "default_value", does_not_raise(), id="default value"), + pytest.param( + DUMMY_DATA, {"id": 10, "name": "Jack"}, None, True, None, None, None, pytest.raises(ValueError, match="not found in the provided list."), id="required" + ), + pytest.param( + DUMMY_DATA, + {"id": 10, "name": "Jack"}, + None, + True, + "custom_var_name", + None, + None, + pytest.raises(ValueError, match="custom_var_name not found in the provided list."), + id="custom var_name", + ), + pytest.param( + DUMMY_DATA, {"id": 1, "name": "Alice"}, None, True, "custom_var_name", "Custom error message", DUMMY_DATA[1], does_not_raise(), id="custom error message" + ), + pytest.param( + DUMMY_DATA, + {"id": 10, "name": "Jack"}, + None, + True, + "custom_var_name", + "Custom error message", + None, + pytest.raises(ValueError, match="Custom error message"), + id="custom error message and required", + ), + pytest.param(DUMMY_DATA, {"id": 1, "name": "Jack"}, None, False, None, None, None, does_not_raise(), id="id ok but name not ok"), + pytest.param( + "not a list", + {"id": 1, "name": "Alice"}, + None, + True, + None, + None, + None, + pytest.raises(ValueError, match="not found in the provided list."), + id="non-list input for list_of_dicts", + ), + pytest.param( + DUMMY_DATA, "not a dict", None, True, None, None, None, pytest.raises(ValueError, match="not found in the provided list."), id="non-dictionary input" + ), + pytest.param(DUMMY_DATA, {}, None, False, None, None, None, does_not_raise(), id="empty dictionary input"), + pytest.param( + DUMMY_DATA, + {"id": 1, "name": "Alice", "extra_key": "extra_value"}, + None, + True, + None, + None, + None, + pytest.raises(ValueError, match="not found in the provided list."), + id="input dictionary with extra keys", + ), + pytest.param( + DUMMY_DATA, + {"id": 1}, + None, + False, + None, + None, + DUMMY_DATA[1], + does_not_raise(), + id="input dictionary is a subset of more than one dictionary in list_of_dicts", + ), + pytest.param( + DUMMY_DATA, + {"id": 1, "name": "Alice", "age": 30, "email": "alice@example.com", "extra_key": "extra_value"}, + None, + True, + None, + None, + None, + pytest.raises(ValueError, match="not found in the provided list."), + id="input dictionary is a superset of a dictionary in list_of_dicts", + ), + ], +) +def test_get_dict_superset( + list_of_dicts: list[dict[Any, Any]], + input_dict: Any, + default: Any | None, + required: bool, + var_name: str | None, + custom_error_msg: str | None, + expected_result: str, + expected_raise: Any, +) -> None: + """Test get_dict_superset.""" + # pylint: disable=too-many-arguments + with expected_raise: + assert get_dict_superset(list_of_dicts, input_dict, default, required, var_name, custom_error_msg) == expected_result diff --git a/tests/units/tools/test_get_item.py b/tests/units/tools/test_get_item.py new file mode 100644 index 0000000..7d75e9c --- /dev/null +++ b/tests/units/tools/test_get_item.py @@ -0,0 +1,72 @@ +# Copyright (c) 2023-2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. + +"""Tests for `anta.tools.get_item`.""" +from __future__ import annotations + +from contextlib import nullcontext as does_not_raise +from typing import Any + +import pytest + +from anta.tools.get_item import get_item + +DUMMY_DATA = [ + ("id", 0), + { + "id": 1, + "name": "Alice", + "age": 30, + "email": "alice@example.com", + }, + { + "id": 2, + "name": "Bob", + "age": 35, + "email": "bob@example.com", + }, + { + "id": 3, + "name": "Charlie", + "age": 40, + "email": "charlie@example.com", + }, +] + + +@pytest.mark.parametrize( + "list_of_dicts, key, value, default, required, case_sensitive, var_name, custom_error_msg, expected_result, expected_raise", + [ + pytest.param([], "name", "Bob", None, False, False, None, None, None, does_not_raise(), id="empty list"), + pytest.param([], "name", "Bob", None, True, False, None, None, None, pytest.raises(ValueError, match="name"), id="empty list and required"), + pytest.param(DUMMY_DATA, "name", "Jack", None, False, False, None, None, None, does_not_raise(), id="missing item"), + pytest.param(DUMMY_DATA, "name", "Alice", None, False, False, None, None, DUMMY_DATA[1], does_not_raise(), id="found item"), + pytest.param(DUMMY_DATA, "name", "Jack", "default_value", False, False, None, None, "default_value", does_not_raise(), id="default value"), + pytest.param(DUMMY_DATA, "name", "Jack", None, True, False, None, None, None, pytest.raises(ValueError, match="name"), id="required"), + pytest.param(DUMMY_DATA, "name", "Bob", None, False, True, None, None, DUMMY_DATA[2], does_not_raise(), id="case sensitive"), + pytest.param(DUMMY_DATA, "name", "charlie", None, False, False, None, None, DUMMY_DATA[3], does_not_raise(), id="case insensitive"), + pytest.param( + DUMMY_DATA, "name", "Jack", None, True, False, "custom_var_name", None, None, pytest.raises(ValueError, match="custom_var_name"), id="custom var_name" + ), + pytest.param( + DUMMY_DATA, "name", "Jack", None, True, False, None, "custom_error_msg", None, pytest.raises(ValueError, match="custom_error_msg"), id="custom error msg" + ), + ], +) +def test_get_item( + list_of_dicts: list[dict[Any, Any]], + key: Any, + value: Any, + default: Any | None, + required: bool, + case_sensitive: bool, + var_name: str | None, + custom_error_msg: str | None, + expected_result: str, + expected_raise: Any, +) -> None: + """Test get_item.""" + # pylint: disable=too-many-arguments + with expected_raise: + assert get_item(list_of_dicts, key, value, default, required, case_sensitive, var_name, custom_error_msg) == expected_result diff --git a/tests/units/tools/test_get_value.py b/tests/units/tools/test_get_value.py new file mode 100644 index 0000000..73344d1 --- /dev/null +++ b/tests/units/tools/test_get_value.py @@ -0,0 +1,50 @@ +# Copyright (c) 2023-2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. +""" +Tests for anta.tools.get_value +""" + +from __future__ import annotations + +from contextlib import nullcontext as does_not_raise +from typing import Any + +import pytest + +from anta.tools.get_value import get_value + +INPUT_DICT = {"test_value": 42, "nested_test": {"nested_value": 43}} + + +@pytest.mark.parametrize( + "input_dict, key, default, required, org_key, separator, expected_result, expected_raise", + [ + pytest.param({}, "test", None, False, None, None, None, does_not_raise(), id="empty dict"), + pytest.param(INPUT_DICT, "test_value", None, False, None, None, 42, does_not_raise(), id="simple key"), + pytest.param(INPUT_DICT, "nested_test.nested_value", None, False, None, None, 43, does_not_raise(), id="nested_key"), + pytest.param(INPUT_DICT, "missing_value", None, False, None, None, None, does_not_raise(), id="missing_value"), + pytest.param(INPUT_DICT, "missing_value_with_default", "default_value", False, None, None, "default_value", does_not_raise(), id="default"), + pytest.param(INPUT_DICT, "missing_required", None, True, None, None, None, pytest.raises(ValueError), id="required"), + pytest.param(INPUT_DICT, "missing_required", None, True, "custom_org_key", None, None, pytest.raises(ValueError), id="custom org_key"), + pytest.param(INPUT_DICT, "nested_test||nested_value", None, None, None, "||", 43, does_not_raise(), id="custom separator"), + ], +) +def test_get_value( + input_dict: dict[Any, Any], + key: str, + default: str | None, + required: bool, + org_key: str | None, + separator: str | None, + expected_result: str, + expected_raise: Any, +) -> None: + """ + Test get_value + """ + # pylint: disable=too-many-arguments + kwargs = {"default": default, "required": required, "org_key": org_key, "separator": separator} + kwargs = {k: v for k, v in kwargs.items() if v is not None} + with expected_raise: + assert get_value(input_dict, key, **kwargs) == expected_result # type: ignore diff --git a/tests/units/tools/test_misc.py b/tests/units/tools/test_misc.py new file mode 100644 index 0000000..c453c21 --- /dev/null +++ b/tests/units/tools/test_misc.py @@ -0,0 +1,38 @@ +# Copyright (c) 2023-2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. +""" +Tests for anta.tools.misc +""" +from __future__ import annotations + +import pytest + +from anta.tools.misc import exc_to_str, tb_to_str + + +def my_raising_function(exception: Exception) -> None: + """ + dummy function to raise Exception + """ + raise exception + + +@pytest.mark.parametrize("exception, expected_output", [(ValueError("test"), "ValueError (test)"), (ValueError(), "ValueError")]) +def test_exc_to_str(exception: Exception, expected_output: str) -> None: + """ + Test exc_to_str + """ + assert exc_to_str(exception) == expected_output + + +def test_tb_to_str() -> None: + """ + Test tb_to_str + """ + try: + my_raising_function(ValueError("test")) + except ValueError as e: + output = tb_to_str(e) + assert "Traceback" in output + assert 'my_raising_function(ValueError("test"))' in output diff --git a/tests/units/tools/test_utils.py b/tests/units/tools/test_utils.py new file mode 100644 index 0000000..448324f --- /dev/null +++ b/tests/units/tools/test_utils.py @@ -0,0 +1,57 @@ +# Copyright (c) 2023-2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. + +"""Tests for `anta.tools.utils`.""" +from __future__ import annotations + +from contextlib import nullcontext as does_not_raise +from typing import Any + +import pytest + +from anta.tools.utils import get_failed_logs + +EXPECTED_OUTPUTS = [ + {"id": 1, "name": "Alice", "age": 30, "email": "alice@example.com"}, + {"id": 2, "name": "Bob", "age": 35, "email": "bob@example.com"}, + {"id": 3, "name": "Charlie", "age": 40, "email": "charlie@example.com"}, + {"id": 4, "name": "Jon", "age": 25, "email": "Jon@example.com"}, +] + +ACTUAL_OUTPUTS = [ + {"id": 1, "name": "Alice", "age": 30, "email": "alice@example.com"}, + {"id": 2, "name": "Bob", "age": 35, "email": "bob@example.com"}, + {"id": 3, "name": "Charlie", "age": 40, "email": "charlie@example.com"}, + {"id": 4, "name": "Rob", "age": 25, "email": "Jon@example.com"}, +] + + +@pytest.mark.parametrize( + "expected_output, actual_output, expected_result, expected_raise", + [ + pytest.param(EXPECTED_OUTPUTS[0], ACTUAL_OUTPUTS[0], "", does_not_raise(), id="no difference"), + pytest.param( + EXPECTED_OUTPUTS[0], + ACTUAL_OUTPUTS[1], + "\nExpected `1` as the id, but found `2` instead.\nExpected `Alice` as the name, but found `Bob` instead.\n" + "Expected `30` as the age, but found `35` instead.\nExpected `alice@example.com` as the email, but found `bob@example.com` instead.", + does_not_raise(), + id="different data", + ), + pytest.param( + EXPECTED_OUTPUTS[0], + {}, + "\nExpected `1` as the id, but it was not found in the actual output.\nExpected `Alice` as the name, but it was not found in the actual output.\n" + "Expected `30` as the age, but it was not found in the actual output.\nExpected `alice@example.com` as the email, but it was not found in " + "the actual output.", + does_not_raise(), + id="empty actual output", + ), + pytest.param(EXPECTED_OUTPUTS[3], ACTUAL_OUTPUTS[3], "\nExpected `Jon` as the name, but found `Rob` instead.", does_not_raise(), id="different name"), + ], +) +def test_get_failed_logs(expected_output: dict[Any, Any], actual_output: dict[Any, Any], expected_result: str, expected_raise: Any) -> None: + """Test get_failed_logs.""" + with expected_raise: + assert get_failed_logs(expected_output, actual_output) == expected_result |