Skip to content

Commit

Permalink
Test helper functions, replace use of deprecated logging function
Browse files Browse the repository at this point in the history
  • Loading branch information
pederhan committed Dec 12, 2024
1 parent d24171f commit 01e2cfd
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 4 deletions.
2 changes: 1 addition & 1 deletion mreg_cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def start_logging(
try:
logging.basicConfig(
filename=logfile,
level=logging.getLevelName(level),
level=level.as_int(),
format=LOGGING_FORMAT,
datefmt="%Y-%m-%d %H:%M:%S",
)
Expand Down
6 changes: 3 additions & 3 deletions mreg_cli/outputmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from mreg_cli.errorbuilder import build_error_message
from mreg_cli.exceptions import CliError, FileError
from mreg_cli.types import JsonMapping, RecordingEntry, TimeInfo
from mreg_cli.types import Json, JsonMapping, RecordingEntry, TimeInfo

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -77,8 +77,8 @@ def remove_comments(line: str) -> str:
return find_char_outside_quotes(line, "#", False).rstrip(" ")


def remove_dict_key_recursive(obj: object, key: str) -> None:
"""Remove a key from a dict, recursively.
def remove_dict_key_recursive(obj: Json, key: str) -> None:
"""Remove a key from a dict or list of dicts, recursively.
This is a destructive operation, and will modify the object in place.
"""
Expand Down
13 changes: 13 additions & 0 deletions mreg_cli/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import argparse
import ipaddress
import logging
from collections.abc import Callable
from enum import StrEnum
from functools import lru_cache
Expand Down Expand Up @@ -161,6 +162,18 @@ def choices(cls) -> list[str]:
"""Return a list of all log levels as strings."""
return [str(c) for c in list(cls)]

def as_int(self) -> int:
"""Convert the log level to an integer."""
# logging.getLevelName considered a mistake - let's implement our own
_nameToLevel = {
self.CRITICAL: logging.CRITICAL,
self.ERROR: logging.ERROR,
self.WARNING: logging.WARNING,
self.INFO: logging.INFO,
self.DEBUG: logging.DEBUG,
}
return _nameToLevel[self]


T = TypeVar("T")

Expand Down
101 changes: 101 additions & 0 deletions tests/test_outputmanager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from __future__ import annotations

from copy import deepcopy

import pytest

from mreg_cli.outputmanager import remove_dict_key_recursive
from mreg_cli.types import Json


@pytest.mark.parametrize(
"inp,key,expected",
[
pytest.param(
{"a": 1, "b": 2},
"a",
{"b": 2},
id="simple_single_key_dict",
),
pytest.param(
{"a": {"b": 2, "c": 3}, "d": 4},
"b",
{"a": {"c": 3}, "d": 4},
id="nested_dict_removal",
),
pytest.param(
[{"a": 1}, {"a": 2}, {"b": 3}],
"a",
[{}, {}, {"b": 3}],
id="list_of_dicts",
),
pytest.param(
{"a": [{"b": 1, "c": 2}, {"b": 3, "d": 4}], "e": {"b": 5, "f": {"b": 6}}},
"b",
{"a": [{"c": 2}, {"d": 4}], "e": {"f": {}}},
id="complex_nested_structure",
),
pytest.param(
{"a": 1, "b": 2},
"c",
{"a": 1, "b": 2},
id="key_not_present",
),
pytest.param(
{},
"a",
{},
id="empty_dict",
),
pytest.param(
[],
"a",
[],
id="empty_list",
),
pytest.param(
{"a": 1, "b": "string", "c": True, "d": None, "e": 1.5, "f": {"a": 2}},
"a",
{"b": "string", "c": True, "d": None, "e": 1.5, "f": {}},
id="mixed_types_with_nested_removal",
),
pytest.param(
[[[{"a": 1}]], [[{"a": 2}]]],
"a",
[[[{}]], [[{}]]],
id="deeply_nested_lists",
),
], # type: ignore
)
def test_remove_dict_key_recursive(inp: Json, key: str, expected: Json) -> None:
"""Test remove_dict_key_recursive with a variety of inputs."""
# Call the function
remove_dict_key_recursive(inp, key)

# Assert the result matches expected
assert inp == expected


def test_none_value_handling() -> None:
"""Test that the function handles None values appropriately"""
obj: Json = None
remove_dict_key_recursive(obj, "any_key") # Should not raise any exception
assert obj is None


@pytest.mark.parametrize(
"inp",
[
"string",
123,
1.5,
True,
False,
None,
],
)
def test_primitive_value_handling(inp: Json) -> None:
"""Test that the function handles primitive values appropriately."""
original = deepcopy(inp)
remove_dict_key_recursive(inp, "any_key") # Should not raise any exception
assert inp == original # Should not modify primitive values
15 changes: 15 additions & 0 deletions tests/test_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from __future__ import annotations

from inline_snapshot import snapshot

from mreg_cli.types import LogLevel


def test_loglevel_as_int() -> None:
"""Test that all LogLevel members have an integer representation."""
for level in list(LogLevel):
# If it doesn't implement as_int, this will raise a KeyError
assert level.as_int() is not None

# Snapshot so we can see if any values are changed
assert [lvl.as_int() for lvl in list(LogLevel)] == snapshot([10, 20, 30, 40, 50])

0 comments on commit 01e2cfd

Please sign in to comment.