summaryrefslogtreecommitdiffstats
path: root/tests/units/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tests/units/tools')
-rw-r--r--tests/units/tools/__init__.py3
-rw-r--r--tests/units/tools/test_get_dict_superset.py149
-rw-r--r--tests/units/tools/test_get_item.py72
-rw-r--r--tests/units/tools/test_get_value.py50
-rw-r--r--tests/units/tools/test_misc.py38
-rw-r--r--tests/units/tools/test_utils.py57
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