diff --git a/pyproject.toml b/pyproject.toml index e878716..1a7cac1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,8 +12,11 @@ dependencies = [ "corelibs-encryption>=1.0.0", "corelibs-enum-base>=1.0.0", "corelibs-file>=1.0.0", + "corelibs-hash>=1.0.0", + "corelibs-iterator>=1.0.0", "corelibs-json>=1.0.0", "corelibs-regex-checks>=1.0.0", + "corelibs-search>=1.0.0", "corelibs-stack-trace>=1.0.0", "corelibs-text-colors>=1.0.0", "corelibs-var>=1.0.0", diff --git a/src/corelibs/file_handling/file_bom_encoding.py b/src/corelibs/file_handling/file_bom_encoding.py index 0712f03..2c75d93 100644 --- a/src/corelibs/file_handling/file_bom_encoding.py +++ b/src/corelibs/file_handling/file_bom_encoding.py @@ -25,7 +25,7 @@ def is_bom_encoded(file_path: Path) -> bool: return is_bom_encoding_ng(file_path) -@deprecated("Use corelibs_file.file_bom_encoding.is_bom_encoded_info instead") +@deprecated("Use corelibs_file.file_bom_encoding.get_bom_encoding_info instead") def is_bom_encoded_info(file_path: Path) -> BomEncodingInfo: """ Enhanced BOM detection with additional file analysis diff --git a/src/corelibs/iterator_handling/data_search.py b/src/corelibs/iterator_handling/data_search.py index 5dc550d..357c367 100644 --- a/src/corelibs/iterator_handling/data_search.py +++ b/src/corelibs/iterator_handling/data_search.py @@ -2,27 +2,31 @@ wrapper around search path """ -from typing import Any, TypedDict, NotRequired +from typing import Any from warnings import deprecated +from corelibs_search.data_search import ( + ArraySearchList as CorelibsArraySearchList, + find_in_array_from_list as corelibs_find_in_array_from_list, + key_lookup as corelibs_key_lookup, + value_lookup as corelibs_value_lookup +) -class ArraySearchList(TypedDict): +class ArraySearchList(CorelibsArraySearchList): """find in array from list search dict""" - key: str - value: str | bool | int | float | list[str | None] - case_sensitive: NotRequired[bool] -@deprecated("Use find_in_array_from_list()") +@deprecated("Use corelibs_search.data_search.find_in_array_from_list instead") def array_search( search_params: list[ArraySearchList], data: list[dict[str, Any]], return_index: bool = False ) -> list[dict[str, Any]]: """depreacted, old call order""" - return find_in_array_from_list(data, search_params, return_index) + return corelibs_find_in_array_from_list(data, search_params, return_index) +@deprecated("Use corelibs_search.data_search.find_in_array_from_list instead") def find_in_array_from_list( data: list[dict[str, Any]], search_params: list[ArraySearchList], @@ -48,69 +52,14 @@ def find_in_array_from_list( list: list of found elements, or if return index list of dics with "index" and "data", where "data" holds the result list """ - if not isinstance(search_params, list): # type: ignore - raise ValueError("search_params must be a list") - keys: list[str] = [] - # check that key and value exist and are set - for search in search_params: - if not search.get('key') or not search.get('value'): - raise KeyError( - f"Either Key '{search.get('key', '')}' or " - f"Value '{search.get('value', '')}' is missing or empty" - ) - # if double key -> abort - if search.get("key") in keys: - raise KeyError( - f"Key {search.get('key', '')} already exists in search_params" - ) - keys.append(str(search['key'])) - - return_items: list[dict[str, Any]] = [] - for si_idx, search_item in enumerate(data): - # for each search entry, all must match - matching = 0 - for search in search_params: - # either Value direct or if Value is list then any of those items can match - # values are compared in lower case if case senstive is off - # lower case left side - # TODO: allow nested Keys. eg "Key: ["Key a", "key b"]" to be ["Key a"]["key b"] - if search.get("case_sensitive", True) is False: - search_value = search_item.get(str(search['key']), "").lower() - else: - search_value = search_item.get(str(search['key']), "") - # lower case right side - if isinstance(search['value'], list): - search_in = [ - str(k).lower() - if search.get("case_sensitive", True) is False else k - for k in search['value'] - ] - elif search.get("case_sensitive", True) is False: - search_in = str(search['value']).lower() - else: - search_in = search['value'] - # compare check - if ( - ( - isinstance(search_in, list) and - search_value in search_in - ) or - search_value == search_in - ): - matching += 1 - if len(search_params) == matching: - if return_index is True: - # the data is now in "data sub set" - return_items.append({ - "index": si_idx, - "data": search_item - }) - else: - return_items.append(search_item) - # return all found or empty list - return return_items + return corelibs_find_in_array_from_list( + data, + search_params, + return_index + ) +@deprecated("Use corelibs_search.data_search.key_lookup instead") def key_lookup(haystack: dict[str, str], key: str) -> str: """ simple key lookup in haystack, erturns empty string if not found @@ -122,9 +71,10 @@ def key_lookup(haystack: dict[str, str], key: str) -> str: Returns: str: _description_ """ - return haystack.get(key, "") + return corelibs_key_lookup(haystack, key) +@deprecated("Use corelibs_search.data_search.value_lookup instead") def value_lookup(haystack: dict[str, str], value: str, raise_on_many: bool = False) -> str: """ find by value, if not found returns empty, if not raise on many returns the first one @@ -140,11 +90,6 @@ def value_lookup(haystack: dict[str, str], value: str, raise_on_many: bool = Fal Returns: str: _description_ """ - keys = [__key for __key, __value in haystack.items() if __value == value] - if not keys: - return "" - if raise_on_many is True and len(keys) > 1: - raise ValueError("More than one element found with the same name") - return keys[0] + return corelibs_value_lookup(haystack, value, raise_on_many) # __END__ diff --git a/src/corelibs/iterator_handling/dict_helpers.py b/src/corelibs/iterator_handling/dict_helpers.py index e12c812..a35e447 100644 --- a/src/corelibs/iterator_handling/dict_helpers.py +++ b/src/corelibs/iterator_handling/dict_helpers.py @@ -2,9 +2,16 @@ Various helper functions for type data clean up """ -from typing import Any, cast +from warnings import deprecated +from typing import Any +from corelibs_iterator.dict_support import ( + delete_keys_from_set as corelibs_delete_keys_from_set, + convert_to_dict_type, + set_entry as corelibs_set_entry +) +@deprecated("Use corelibs_iterator.dict_support.delete_keys_from_set instead") def delete_keys_from_set( set_data: dict[str, Any] | list[Any] | str, keys: list[str] ) -> dict[str, Any] | list[Any] | Any: @@ -19,24 +26,10 @@ def delete_keys_from_set( dict[str, Any] | list[Any] | None: _description_ """ # skip everything if there is no keys list - if not keys: - return set_data - if isinstance(set_data, dict): - for key, value in set_data.copy().items(): - if key in keys: - del set_data[key] - if isinstance(value, (dict, list)): - delete_keys_from_set(value, keys) # type: ignore Partly unknown - elif isinstance(set_data, list): - for value in set_data: - if isinstance(value, (dict, list)): - delete_keys_from_set(value, keys) # type: ignore Partly unknown - else: - set_data = [set_data] - - return set_data + return corelibs_delete_keys_from_set(set_data, keys) +@deprecated("Use corelibs_iterator.dict_support.convert_to_dict_type instead") def build_dict( any_dict: Any, ignore_entries: list[str] | None = None ) -> dict[str, Any | list[Any] | dict[Any, Any]]: @@ -49,18 +42,10 @@ def build_dict( Returns: dict[str, Any | list[Any]]: _description_ """ - if ignore_entries is None: - return cast(dict[str, Any | list[Any] | dict[Any, Any]], any_dict) - # ignore entries can be one key or key nested - # return { - # key: value for key, value in any_dict.items() if key not in ignore_entries - # } - return cast( - dict[str, Any | list[Any] | dict[Any, Any]], - delete_keys_from_set(any_dict, ignore_entries) - ) + return convert_to_dict_type(any_dict, ignore_entries) +@deprecated("Use corelibs_iterator.dict_support.set_entry instead") def set_entry(dict_set: dict[str, Any], key: str, value_set: Any) -> dict[str, Any]: """ set a new entry in the dict set @@ -73,9 +58,6 @@ def set_entry(dict_set: dict[str, Any], key: str, value_set: Any) -> dict[str, A Returns: dict[str, Any] -- _description_ """ - if not dict_set.get(key): - dict_set[key] = {} - dict_set[key] = value_set - return dict_set + return corelibs_set_entry(dict_set, key, value_set) # __END__ diff --git a/src/corelibs/iterator_handling/dict_mask.py b/src/corelibs/iterator_handling/dict_mask.py index 4740be7..9ef1916 100644 --- a/src/corelibs/iterator_handling/dict_mask.py +++ b/src/corelibs/iterator_handling/dict_mask.py @@ -2,8 +2,11 @@ Dict helpers """ - -from typing import TypeAlias, Union, Dict, List, Any, cast +from warnings import deprecated +from typing import TypeAlias, Union, Dict, List, Any +from corelibs_dump_data.dict_mask import ( + mask as corelibs_mask +) # definitions for the mask run below MaskableValue: TypeAlias = Union[str, int, float, bool, None] @@ -11,6 +14,7 @@ NestedDict: TypeAlias = Dict[str, Union[MaskableValue, List[Any], 'NestedDict']] ProcessableValue: TypeAlias = Union[MaskableValue, List[Any], NestedDict] +@deprecated("use corelibs_dump_data.dict_mask.mask instead") def mask( data_set: dict[str, Any], mask_keys: list[str] | None = None, @@ -26,7 +30,7 @@ def mask( and end with '_', remove to search string in string Arguments: - data_set {dict[str, str]} -- _description_ + data_set {dict[str, Any]} -- _description_ Keyword Arguments: mask_keys {list[str] | None} -- _description_ (default: {None}) @@ -37,49 +41,12 @@ def mask( Returns: dict[str, str] -- _description_ """ - if skip is True: - return data_set - if mask_keys is None: - mask_keys = ["encryption", "password", "secret"] - else: - # make sure it is lower case - mask_keys = [mask_key.lower() for mask_key in mask_keys] - - def should_mask_key(key: str) -> bool: - """Check if a key should be masked""" - __key_lower = key.lower() - return any( - __key_lower.startswith(mask_key) or - __key_lower.endswith(mask_key) or - f"{mask_str_edges}{mask_key}{mask_str_edges}" in __key_lower - for mask_key in mask_keys - ) - - def mask_recursive(obj: ProcessableValue) -> ProcessableValue: - """Recursively mask values in nested structures""" - if isinstance(obj, dict): - return { - key: mask_value(value) if should_mask_key(key) else mask_recursive(value) - for key, value in obj.items() - } - if isinstance(obj, list): - return [mask_recursive(item) for item in obj] - return obj - - def mask_value(value: Any) -> Any: - """Handle masking based on value type""" - if isinstance(value, list): - # Mask each individual value in the list - return [mask_str for _ in cast('list[Any]', value)] - if isinstance(value, dict): - # Recursively process the dictionary instead of masking the whole thing - return mask_recursive(cast('ProcessableValue', value)) - # Mask primitive values - return mask_str - - return { - key: mask_value(value) if should_mask_key(key) else mask_recursive(value) - for key, value in data_set.items() - } + return corelibs_mask( + data_set, + mask_keys, + mask_str, + mask_str_edges, + skip + ) # __END__ diff --git a/src/corelibs/iterator_handling/fingerprint.py b/src/corelibs/iterator_handling/fingerprint.py index 932cd62..ab98f3e 100644 --- a/src/corelibs/iterator_handling/fingerprint.py +++ b/src/corelibs/iterator_handling/fingerprint.py @@ -2,11 +2,16 @@ Various dictionary, object and list hashers """ -import json -import hashlib -from typing import Any, cast, Sequence +from warnings import deprecated +from typing import Any +from corelibs_hash.fingerprint import ( + hash_object as corelibs_hash_object, + dict_hash_frozen as corelibs_dict_hash_frozen, + dict_hash_crc as corelibs_dict_hash_crc +) +@deprecated("use corelibs_hash.fingerprint.hash_object instead") def hash_object(obj: Any) -> str: """ RECOMMENDED for new use @@ -18,20 +23,10 @@ def hash_object(obj: Any) -> str: Returns: str -- _description_ """ - def normalize(o: Any) -> Any: - if isinstance(o, dict): - # Sort by repr of keys to handle mixed types (str, int, etc.) - o = cast(dict[Any, Any], o) - return tuple(sorted((repr(k), normalize(v)) for k, v in o.items())) - if isinstance(o, (list, tuple)): - o = cast(Sequence[Any], o) - return tuple(normalize(item) for item in o) - return repr(o) - - normalized = normalize(obj) - return hashlib.sha256(str(normalized).encode()).hexdigest() + return corelibs_hash_object(obj) +@deprecated("use corelibs_hash.fingerprint.hash_object instead") def dict_hash_frozen(data: dict[Any, Any]) -> int: """ NOT RECOMMENDED, use dict_hash_crc or hash_object instead @@ -44,9 +39,10 @@ def dict_hash_frozen(data: dict[Any, Any]) -> int: Returns: str: _description_ """ - return hash(frozenset(data.items())) + return corelibs_dict_hash_frozen(data) +@deprecated("use corelibs_hash.fingerprint.dict_hash_crc and for new use hash_object instead") def dict_hash_crc(data: dict[Any, Any] | list[Any]) -> str: """ LEGACY METHOD, must be kept for fallback, if used by other code, DO NOT CHANGE @@ -60,14 +56,6 @@ def dict_hash_crc(data: dict[Any, Any] | list[Any]) -> str: Returns: str: sha256 hash, prefiex with HO_ if fallback used """ - try: - return hashlib.sha256( - # IT IS IMPORTANT THAT THE BELOW CALL STAYS THE SAME AND DOES NOT CHANGE OR WE WILL GET DIFFERENT HASHES - # separators=(',', ':') to get rid of spaces, but if this is used the hash will be different, DO NOT ADD - json.dumps(data, sort_keys=True, ensure_ascii=True, default=str).encode('utf-8') - ).hexdigest() - except TypeError: - # Fallback tod different hasher, will return DIFFERENT hash than above, so only usable in int/str key mixes - return "HO_" + hash_object(data) + return corelibs_dict_hash_crc(data) # __END__ diff --git a/src/corelibs/iterator_handling/list_helpers.py b/src/corelibs/iterator_handling/list_helpers.py index ec7d1ab..cc122ef 100644 --- a/src/corelibs/iterator_handling/list_helpers.py +++ b/src/corelibs/iterator_handling/list_helpers.py @@ -2,10 +2,16 @@ List type helpers """ -import json +from warnings import deprecated from typing import Any, Sequence +from corelibs_iterator.list_support import ( + convert_to_list as corelibs_convert_to_list, + is_list_in_list as corelibs_is_list_in_list, + make_unique_list_of_dicts as corelibs_make_unique_list_of_dicts +) +@deprecated("use corelibs_iterator.list_support.convert_to_list instead") def convert_to_list( entry: str | int | float | bool | Sequence[str | int | float | bool | Sequence[Any]] ) -> Sequence[str | int | float | bool | Sequence[Any]]: @@ -18,11 +24,10 @@ def convert_to_list( Returns: list[str | int | float | bool] -- _description_ """ - if isinstance(entry, list): - return entry - return [entry] + return corelibs_convert_to_list(entry) +@deprecated("use corelibs_iterator.list_support.is_list_in_list instead") def is_list_in_list( list_a: Sequence[str | int | float | bool | Sequence[Any]], list_b: Sequence[str | int | float | bool | Sequence[Any]] @@ -38,14 +43,10 @@ def is_list_in_list( Returns: list[Any] -- _description_ """ - # Create sets of (value, type) tuples - set_a = set((item, type(item)) for item in list_a) - set_b = set((item, type(item)) for item in list_b) - - # Get the difference and extract just the values - return [item for item, _ in set_a - set_b] + return corelibs_is_list_in_list(list_a, list_b) +@deprecated("use corelibs_iterator.list_support.make_unique_list_of_dicts instead") def make_unique_list_of_dicts(dict_list: list[Any]) -> list[Any]: """ Create a list of unique dictionary entries @@ -56,20 +57,6 @@ def make_unique_list_of_dicts(dict_list: list[Any]) -> list[Any]: Returns: list[Any] -- _description_ """ - try: - # try json dumps, can fail with int and str index types - return list( - { - json.dumps(d, sort_keys=True, ensure_ascii=True, separators=(',', ':')): d - for d in dict_list - }.values() - ) - except TypeError: - # Fallback for non-serializable entries, slow but works - unique: list[Any] = [] - for d in dict_list: - if d not in unique: - unique.append(d) - return unique + return corelibs_make_unique_list_of_dicts(dict_list) # __END__ diff --git a/src/corelibs/json_handling/jmespath_helper.py b/src/corelibs/json_handling/jmespath_helper.py index 0d1bd54..121e08c 100644 --- a/src/corelibs/json_handling/jmespath_helper.py +++ b/src/corelibs/json_handling/jmespath_helper.py @@ -4,10 +4,10 @@ helper functions for jmespath interfaces from warnings import deprecated from typing import Any -from corelibs_json.jmespath_support import jmespath_search as jmespath_search_ng +from corelibs_search.jmespath_search import jmespath_search as jmespath_search_ng -@deprecated("Use corelibs_json.jmespath_support.jmespath_search instead") +@deprecated("Use corelibs_search.jmespath_search.jmespath_search instead") def jmespath_search(search_data: dict[Any, Any] | list[Any], search_params: str) -> Any: """ jmespath search wrapper diff --git a/src/corelibs/math_handling/math_helpers.py b/src/corelibs/math_handling/math_helpers.py index 2355f80..112bc8e 100644 --- a/src/corelibs/math_handling/math_helpers.py +++ b/src/corelibs/math_handling/math_helpers.py @@ -2,9 +2,11 @@ Various math helpers """ +from warnings import deprecated import math +@deprecated("Use math.gcd instead") def gcd(a: int, b: int): """ Calculate: Greatest Common Divisor @@ -19,6 +21,7 @@ def gcd(a: int, b: int): return math.gcd(a, b) +@deprecated("Use math.lcm instead") def lcd(a: int, b: int): """ Calculate: Least Common Denominator diff --git a/tests/unit/iterator_handling/test_data_search.py b/tests/unit/iterator_handling/test_data_search.py deleted file mode 100644 index 6e42a91..0000000 --- a/tests/unit/iterator_handling/test_data_search.py +++ /dev/null @@ -1,601 +0,0 @@ -""" -tests for corelibs.iterator_handling.data_search -""" - -# pylint: disable=use-implicit-booleaness-not-comparison - -from typing import Any -import pytest -from corelibs.iterator_handling.data_search import ( - find_in_array_from_list, - key_lookup, - value_lookup, - ArraySearchList -) - - -class TestFindInArrayFromList: - """Tests for find_in_array_from_list function""" - - def test_basic_single_key_match(self): - """Test basic search with single key-value pair""" - data = [ - {"name": "Alice", "age": 30}, - {"name": "Bob", "age": 25}, - {"name": "Charlie", "age": 35} - ] - search_params: list[ArraySearchList] = [ - {"key": "name", "value": "Bob"} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 1 - assert result[0]["name"] == "Bob" - assert result[0]["age"] == 25 - - def test_multiple_key_match(self): - """Test search with multiple key-value pairs (AND logic)""" - data = [ - {"name": "Alice", "age": 30, "city": "New York"}, - {"name": "Bob", "age": 25, "city": "London"}, - {"name": "Charlie", "age": 30, "city": "Paris"} - ] - search_params: list[ArraySearchList] = [ - {"key": "age", "value": 30}, - {"key": "city", "value": "New York"} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 1 - assert result[0]["name"] == "Alice" - - def test_value_list_or_match(self): - """Test search with list of values (OR logic)""" - data = [ - {"name": "Alice", "status": "active"}, - {"name": "Bob", "status": "inactive"}, - {"name": "Charlie", "status": "pending"} - ] - search_params: list[ArraySearchList] = [ - {"key": "status", "value": ["active", "pending"]} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["name"] == "Alice" - assert result[1]["name"] == "Charlie" - - def test_case_sensitive_true(self): - """Test case-sensitive search (default behavior)""" - data = [ - {"name": "Alice"}, - {"name": "alice"}, - {"name": "ALICE"} - ] - search_params: list[ArraySearchList] = [ - {"key": "name", "value": "Alice"} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 1 - assert result[0]["name"] == "Alice" - - def test_case_insensitive_search(self): - """Test case-insensitive search""" - data = [ - {"name": "Alice"}, - {"name": "alice"}, - {"name": "ALICE"} - ] - search_params: list[ArraySearchList] = [ - {"key": "name", "value": "alice", "case_sensitive": False} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 3 - - def test_case_insensitive_with_list_values(self): - """Test case-insensitive search with list of values""" - data = [ - {"status": "ACTIVE"}, - {"status": "Pending"}, - {"status": "inactive"} - ] - search_params: list[ArraySearchList] = [ - {"key": "status", "value": ["active", "pending"], "case_sensitive": False} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["status"] == "ACTIVE" - assert result[1]["status"] == "Pending" - - def test_return_index_true(self): - """Test returning results with index""" - data = [ - {"name": "Alice"}, - {"name": "Bob"}, - {"name": "Charlie"} - ] - search_params: list[ArraySearchList] = [ - {"key": "name", "value": "Bob"} - ] - - result = find_in_array_from_list(data, search_params, return_index=True) - - assert len(result) == 1 - assert result[0]["index"] == 1 - assert result[0]["data"]["name"] == "Bob" - - def test_return_index_multiple_results(self): - """Test returning multiple results with indices""" - data = [ - {"status": "active"}, - {"status": "inactive"}, - {"status": "active"} - ] - search_params: list[ArraySearchList] = [ - {"key": "status", "value": "active"} - ] - - result = find_in_array_from_list(data, search_params, return_index=True) - - assert len(result) == 2 - assert result[0]["index"] == 0 - assert result[0]["data"]["status"] == "active" - assert result[1]["index"] == 2 - assert result[1]["data"]["status"] == "active" - - def test_no_match_returns_empty_list(self): - """Test that no match returns empty list""" - data = [ - {"name": "Alice"}, - {"name": "Bob"} - ] - search_params: list[ArraySearchList] = [ - {"key": "name", "value": "Charlie"} - ] - - result = find_in_array_from_list(data, search_params) - - assert result == [] - - def test_empty_data_returns_empty_list(self): - """Test that empty data list returns empty list""" - data: list[dict[str, Any]] = [] - search_params: list[ArraySearchList] = [ - {"key": "name", "value": "Alice"} - ] - - result = find_in_array_from_list(data, search_params) - - assert result == [] - - def test_missing_key_in_data(self): - """Test search when key doesn't exist in some data items""" - data = [ - {"name": "Alice", "age": 30}, - {"name": "Bob"}, # Missing 'age' key - {"name": "Charlie", "age": 30} - ] - search_params: list[ArraySearchList] = [ - {"key": "age", "value": 30} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["name"] == "Alice" - assert result[1]["name"] == "Charlie" - - def test_numeric_values(self): - """Test search with numeric values""" - data = [ - {"id": 1, "score": 95}, - {"id": 2, "score": 87}, - {"id": 3, "score": 95} - ] - search_params: list[ArraySearchList] = [ - {"key": "score", "value": 95} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["id"] == 1 - assert result[1]["id"] == 3 - - def test_boolean_values(self): - """Test search with boolean values""" - data = [ - {"name": "Alice", "active": True}, - {"name": "Bob", "active": False}, - {"name": "Charlie", "active": True} - ] - search_params: list[ArraySearchList] = [ - {"key": "active", "value": True} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["name"] == "Alice" - assert result[1]["name"] == "Charlie" - - def test_float_values(self): - """Test search with float values""" - data = [ - {"name": "Product A", "price": 19.99}, - {"name": "Product B", "price": 29.99}, - {"name": "Product C", "price": 19.99} - ] - search_params: list[ArraySearchList] = [ - {"key": "price", "value": 19.99} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["name"] == "Product A" - assert result[1]["name"] == "Product C" - - def test_mixed_value_types_in_list(self): - """Test search with mixed types in value list""" - data = [ - {"id": "1", "value": "active"}, - {"id": 2, "value": "pending"}, - {"id": "3", "value": "active"} - ] - search_params: list[ArraySearchList] = [ - {"key": "id", "value": ["1", "3"]} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["id"] == "1" - assert result[1]["id"] == "3" - - def test_complex_multi_criteria_search(self): - """Test complex search with multiple criteria""" - data = [ - {"name": "Alice", "age": 30, "city": "New York", "status": "active"}, - {"name": "Bob", "age": 25, "city": "London", "status": "active"}, - {"name": "Charlie", "age": 30, "city": "Paris", "status": "inactive"}, - {"name": "David", "age": 30, "city": "New York", "status": "active"} - ] - search_params: list[ArraySearchList] = [ - {"key": "age", "value": 30}, - {"key": "city", "value": "New York"}, - {"key": "status", "value": "active"} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["name"] == "Alice" - assert result[1]["name"] == "David" - - def test_invalid_search_params_not_list(self): - """Test that non-list search_params raises ValueError""" - data = [{"name": "Alice"}] - search_params = {"key": "name", "value": "Alice"} # type: ignore - - with pytest.raises(ValueError, match="search_params must be a list"): - find_in_array_from_list(data, search_params) # type: ignore - - def test_missing_key_in_search_params(self): - """Test that missing 'key' in search_params raises KeyError""" - data = [{"name": "Alice"}] - search_params: list[dict[str, Any]] = [ - {"value": "Alice"} # Missing 'key' - ] - - with pytest.raises(KeyError, match="Either Key '' or Value 'Alice' is missing or empty"): - find_in_array_from_list(data, search_params) # type: ignore - - def test_missing_value_in_search_params(self): - """Test that missing 'value' in search_params raises KeyError""" - data = [{"name": "Alice"}] - search_params: list[dict[str, Any]] = [ - {"key": "name"} # Missing 'value' - ] - - with pytest.raises(KeyError, match="Either Key 'name' or Value"): - find_in_array_from_list(data, search_params) # type: ignore - - def test_empty_key_in_search_params(self): - """Test that empty 'key' in search_params raises KeyError""" - data = [{"name": "Alice"}] - search_params: list[dict[str, Any]] = [ - {"key": "", "value": "Alice"} - ] - - with pytest.raises(KeyError, match="Either Key '' or Value 'Alice' is missing or empty"): - find_in_array_from_list(data, search_params) # type: ignore - - def test_empty_value_in_search_params(self): - """Test that empty 'value' in search_params raises KeyError""" - data = [{"name": "Alice"}] - search_params: list[dict[str, Any]] = [ - {"key": "name", "value": ""} - ] - - with pytest.raises(KeyError, match="Either Key 'name' or Value '' is missing or empty"): - find_in_array_from_list(data, search_params) # type: ignore - - def test_duplicate_key_in_search_params(self): - """Test that duplicate keys in search_params raises KeyError""" - data = [{"name": "Alice", "age": 30}] - search_params: list[ArraySearchList] = [ - {"key": "name", "value": "Alice"}, - {"key": "name", "value": "Bob"} # Duplicate key - ] - - with pytest.raises(KeyError, match="Key name already exists in search_params"): - find_in_array_from_list(data, search_params) - - def test_partial_match_fails(self): - """Test that partial match (not all criteria) returns no result""" - data = [ - {"name": "Alice", "age": 30, "city": "New York"} - ] - search_params: list[ArraySearchList] = [ - {"key": "name", "value": "Alice"}, - {"key": "age", "value": 25} # Doesn't match - ] - - result = find_in_array_from_list(data, search_params) - - assert result == [] - - def test_none_value_in_list(self): - """Test search with None in value list""" - data = [ - {"name": "Alice", "nickname": "Ally"}, - {"name": "Bob", "nickname": None}, - {"name": "Charlie", "nickname": "Chuck"} - ] - search_params: list[ArraySearchList] = [ - {"key": "nickname", "value": [None, "Chuck"]} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == 2 - assert result[0]["name"] == "Bob" - assert result[1]["name"] == "Charlie" - - @pytest.mark.parametrize("test_value,expected_count", [ - ("active", 1), - ("inactive", 1), - ("pending", 1), - ("archived", 0) - ]) - def test_parametrized_status_search(self, test_value: str, expected_count: int): - """Parametrized test for different status values""" - data = [ - {"id": 1, "status": "active"}, - {"id": 2, "status": "inactive"}, - {"id": 3, "status": "pending"} - ] - search_params: list[ArraySearchList] = [ - {"key": "status", "value": test_value} - ] - - result = find_in_array_from_list(data, search_params) - - assert len(result) == expected_count - - -class TestKeyLookup: - """Tests for key_lookup function""" - - def test_key_exists(self): - """Test lookup when key exists""" - haystack = {"name": "Alice", "age": "30", "city": "New York"} - - result = key_lookup(haystack, "name") - - assert result == "Alice" - - def test_key_not_exists(self): - """Test lookup when key doesn't exist returns empty string""" - haystack = {"name": "Alice", "age": "30"} - - result = key_lookup(haystack, "city") - - assert result == "" - - def test_empty_dict(self): - """Test lookup in empty dictionary""" - haystack: dict[str, str] = {} - - result = key_lookup(haystack, "name") - - assert result == "" - - def test_multiple_lookups(self): - """Test multiple lookups in same dictionary""" - haystack = {"first": "John", "last": "Doe", "email": "john@example.com"} - - assert key_lookup(haystack, "first") == "John" - assert key_lookup(haystack, "last") == "Doe" - assert key_lookup(haystack, "email") == "john@example.com" - assert key_lookup(haystack, "phone") == "" - - def test_numeric_string_values(self): - """Test lookup with numeric string values""" - haystack = {"count": "42", "price": "19.99"} - - assert key_lookup(haystack, "count") == "42" - assert key_lookup(haystack, "price") == "19.99" - - def test_empty_string_value(self): - """Test lookup when value is empty string""" - haystack = {"name": "", "city": "New York"} - - result = key_lookup(haystack, "name") - - assert result == "" - - def test_whitespace_value(self): - """Test lookup when value contains whitespace""" - haystack = {"name": " Alice ", "message": " "} - - assert key_lookup(haystack, "name") == " Alice " - assert key_lookup(haystack, "message") == " " - - @pytest.mark.parametrize("key,expected", [ - ("a", "1"), - ("b", "2"), - ("c", "3"), - ("d", "") - ]) - def test_parametrized_lookup(self, key: str, expected: str): - """Parametrized test for key lookup""" - haystack = {"a": "1", "b": "2", "c": "3"} - - result = key_lookup(haystack, key) - - assert result == expected - - -class TestValueLookup: - """Tests for value_lookup function""" - - def test_value_exists_single(self): - """Test lookup when value exists once""" - haystack = {"name": "Alice", "username": "alice123", "email": "alice@example.com"} - - result = value_lookup(haystack, "Alice") - - assert result == "name" - - def test_value_not_exists(self): - """Test lookup when value doesn't exist returns empty string""" - haystack = {"name": "Alice", "username": "alice123"} - - result = value_lookup(haystack, "Bob") - - assert result == "" - - def test_value_exists_multiple_no_raise(self): - """Test lookup when value exists multiple times, returns first""" - haystack = {"key1": "duplicate", "key2": "unique", "key3": "duplicate"} - - result = value_lookup(haystack, "duplicate") - - assert result in ["key1", "key3"] # Order may vary in dict - - def test_value_exists_multiple_raise_on_many_false(self): - """Test lookup with multiple matches and raise_on_many=False""" - haystack = {"a": "same", "b": "same", "c": "different"} - - result = value_lookup(haystack, "same", raise_on_many=False) - - assert result in ["a", "b"] - - def test_value_exists_multiple_raise_on_many_true(self): - """Test lookup with multiple matches and raise_on_many=True raises ValueError""" - haystack = {"a": "same", "b": "same", "c": "different"} - - with pytest.raises(ValueError, match="More than one element found with the same name"): - value_lookup(haystack, "same", raise_on_many=True) - - def test_value_exists_single_raise_on_many_true(self): - """Test lookup with single match and raise_on_many=True works fine""" - haystack = {"name": "Alice", "username": "alice123"} - - result = value_lookup(haystack, "Alice", raise_on_many=True) - - assert result == "name" - - def test_empty_dict(self): - """Test lookup in empty dictionary""" - haystack: dict[str, str] = {} - - result = value_lookup(haystack, "Alice") - - assert result == "" - - def test_empty_dict_raise_on_many(self): - """Test lookup in empty dictionary with raise_on_many=True""" - haystack: dict[str, str] = {} - - result = value_lookup(haystack, "Alice", raise_on_many=True) - - assert result == "" - - def test_numeric_string_values(self): - """Test lookup with numeric string values""" - haystack = {"id": "123", "count": "456", "score": "123"} - - result = value_lookup(haystack, "456") - - assert result == "count" - - def test_empty_string_value(self): - """Test lookup for empty string value""" - haystack = {"name": "", "city": "New York", "country": ""} - - result = value_lookup(haystack, "") - - assert result in ["name", "country"] - - def test_whitespace_value(self): - """Test lookup for whitespace value""" - haystack = {"a": " spaces ", "b": "normal", "c": " spaces "} - - result = value_lookup(haystack, " spaces ") - - assert result in ["a", "c"] - - def test_case_sensitive_lookup(self): - """Test that lookup is case-sensitive""" - haystack = {"name": "Alice", "username": "alice", "email": "ALICE"} - - assert value_lookup(haystack, "Alice") == "name" - assert value_lookup(haystack, "alice") == "username" - assert value_lookup(haystack, "ALICE") == "email" - assert value_lookup(haystack, "aLiCe") == "" - - def test_special_characters(self): - """Test lookup with special characters""" - haystack = {"key1": "test@example.com", "key2": "test#value", "key3": "test@example.com"} - - result = value_lookup(haystack, "test@example.com") - - assert result in ["key1", "key3"] - - @pytest.mark.parametrize("value,expected_key", [ - ("value1", "a"), - ("value2", "b"), - ("value3", "c"), - ("nonexistent", "") - ]) - def test_parametrized_lookup(self, value: str, expected_key: str): - """Parametrized test for value lookup""" - haystack = {"a": "value1", "b": "value2", "c": "value3"} - - result = value_lookup(haystack, value) - - assert result == expected_key - - def test_duplicate_values_consistent_return(self): - """Test that lookup with duplicates consistently returns one of the keys""" - haystack = {"x": "dup", "y": "dup", "z": "dup"} - - # Should return same key consistently - result1 = value_lookup(haystack, "dup") - result2 = value_lookup(haystack, "dup") - result3 = value_lookup(haystack, "dup") - - assert result1 == result2 == result3 - assert result1 in ["x", "y", "z"] diff --git a/tests/unit/iterator_handling/test_dict_helpers.py b/tests/unit/iterator_handling/test_dict_helpers.py deleted file mode 100644 index ede3ec4..0000000 --- a/tests/unit/iterator_handling/test_dict_helpers.py +++ /dev/null @@ -1,652 +0,0 @@ -""" -iterator_handling.dict_helper tests -""" - -# pylint: disable=use-implicit-booleaness-not-comparison - -from typing import Any -import pytest -from corelibs.iterator_handling.dict_helpers import ( - delete_keys_from_set, - build_dict, - set_entry, -) - - -class TestDeleteKeysFromSet: - """Test cases for delete_keys_from_set function""" - - def test_delete_single_key_from_dict(self): - """Test deleting a single key from a dictionary""" - set_data = {"a": 1, "b": 2, "c": 3} - keys = ["b"] - result = delete_keys_from_set(set_data, keys) - assert result == {"a": 1, "c": 3} - assert "b" not in result - - def test_delete_multiple_keys_from_dict(self): - """Test deleting multiple keys from a dictionary""" - set_data = {"a": 1, "b": 2, "c": 3, "d": 4} - keys = ["b", "d"] - result = delete_keys_from_set(set_data, keys) - assert result == {"a": 1, "c": 3} - assert "b" not in result - assert "d" not in result - - def test_delete_all_keys_from_dict(self): - """Test deleting all keys from a dictionary""" - set_data = {"a": 1, "b": 2} - keys = ["a", "b"] - result = delete_keys_from_set(set_data, keys) - assert result == {} - - def test_delete_nonexistent_key(self): - """Test deleting a key that doesn't exist""" - set_data = {"a": 1, "b": 2} - keys = ["c", "d"] - result = delete_keys_from_set(set_data, keys) - assert result == {"a": 1, "b": 2} - - def test_delete_keys_from_nested_dict(self): - """Test deleting keys from nested dictionaries""" - set_data = { - "a": 1, - "b": {"c": 2, "d": 3, "e": 4}, - "f": 5 - } - keys = ["d", "f"] - result = delete_keys_from_set(set_data, keys) - assert result == {"a": 1, "b": {"c": 2, "e": 4}} - assert "d" not in result["b"] # type: ignore - assert "f" not in result - - def test_delete_keys_from_deeply_nested_dict(self): - """Test deleting keys from deeply nested structures""" - set_data = { - "a": 1, - "b": { - "c": 2, - "d": { - "e": 3, - "f": 4 - } - }, - "g": 5 - } - keys = ["f", "g"] - result = delete_keys_from_set(set_data, keys) - assert result == {"a": 1, "b": {"c": 2, "d": {"e": 3}}} - assert "g" not in result - - def test_delete_keys_from_list(self): - """Test with list containing dictionaries""" - set_data = [ - {"a": 1, "b": 2}, - {"c": 3, "d": 4}, - {"e": 5, "f": 6} - ] - keys = ["b", "d", "f"] - result = delete_keys_from_set(set_data, keys) - assert result == [ - {"a": 1}, - {"c": 3}, - {"e": 5} - ] - - def test_delete_keys_from_list_with_nested_dicts(self): - """Test with list containing nested dictionaries""" - set_data = [ - {"a": 1, "b": {"c": 2, "d": 3}}, - {"e": 4, "f": {"g": 5, "h": 6}} - ] - keys = ["d", "h"] - result = delete_keys_from_set(set_data, keys) - assert result == [ - {"a": 1, "b": {"c": 2}}, - {"e": 4, "f": {"g": 5}} - ] - - def test_delete_keys_from_dict_with_list_values(self): - """Test with dictionary containing list values""" - set_data = { - "a": [{"b": 1, "c": 2}, {"d": 3, "e": 4}], - "f": 5 - } - keys = ["c", "e"] - result = delete_keys_from_set(set_data, keys) - assert result == { - "a": [{"b": 1}, {"d": 3}], - "f": 5 - } - - def test_empty_keys_list(self): - """Test with empty keys list - should return data unchanged""" - set_data = {"a": 1, "b": 2, "c": 3} - keys: list[str] = [] - result = delete_keys_from_set(set_data, keys) - assert result == set_data - - def test_empty_dict(self): - """Test with empty dictionary""" - set_data: dict[str, Any] = {} - keys = ["a", "b"] - result = delete_keys_from_set(set_data, keys) - assert result == {} - - def test_empty_list(self): - """Test with empty list""" - set_data: list[Any] = [] - keys = ["a", "b"] - result = delete_keys_from_set(set_data, keys) - assert result == [] - - def test_string_input(self): - """Test with string input - should convert to list""" - set_data = "hello" - keys = ["a"] - result = delete_keys_from_set(set_data, keys) - assert result == ["hello"] - - def test_complex_mixed_structure(self): - """Test with complex mixed structure""" - set_data = { - "users": [ - { - "name": "Alice", - "age": 30, - "password": "secret1", - "profile": { - "email": "alice@example.com", - "password": "secret2" - } - }, - { - "name": "Bob", - "age": 25, - "password": "secret3", - "profile": { - "email": "bob@example.com", - "password": "secret4" - } - } - ], - "metadata": { - "count": 2, - "password": "admin" - } - } - keys = ["password"] - result = delete_keys_from_set(set_data, keys) - - # Check that all password fields are removed - assert "password" not in result["metadata"] # type: ignore - for user in result["users"]: # type: ignore - assert "password" not in user - assert "password" not in user["profile"] - - # Check that other fields remain - assert result["users"][0]["name"] == "Alice" # type: ignore - assert result["users"][1]["name"] == "Bob" # type: ignore - assert result["metadata"]["count"] == 2 # type: ignore - - def test_dict_with_none_values(self): - """Test with dictionary containing None values""" - set_data = {"a": 1, "b": None, "c": 3} - keys = ["b"] - result = delete_keys_from_set(set_data, keys) - assert result == {"a": 1, "c": 3} - - def test_dict_with_various_value_types(self): - """Test with dictionary containing various value types""" - set_data = { - "int": 42, - "float": 3.14, - "bool": True, - "str": "hello", - "list": [1, 2, 3], - "dict": {"nested": "value"}, - "none": None - } - keys = ["bool", "none"] - result = delete_keys_from_set(set_data, keys) - assert "bool" not in result - assert "none" not in result - assert len(result) == 5 - - -class TestBuildDict: - """Test cases for build_dict function""" - - def test_build_dict_without_ignore_entries(self): - """Test build_dict without ignore_entries (None)""" - input_dict = {"a": 1, "b": 2, "c": 3} - result = build_dict(input_dict) - assert result == input_dict - assert result is input_dict # Should return same object - - def test_build_dict_with_ignore_entries_single(self): - """Test build_dict with single ignore entry""" - input_dict = {"a": 1, "b": 2, "c": 3} - ignore = ["b"] - result = build_dict(input_dict, ignore) - assert result == {"a": 1, "c": 3} - assert "b" not in result - - def test_build_dict_with_ignore_entries_multiple(self): - """Test build_dict with multiple ignore entries""" - input_dict = {"a": 1, "b": 2, "c": 3, "d": 4} - ignore = ["b", "d"] - result = build_dict(input_dict, ignore) - assert result == {"a": 1, "c": 3} - - def test_build_dict_with_nested_ignore(self): - """Test build_dict with nested structures""" - input_dict = { - "a": 1, - "b": {"c": 2, "d": 3}, - "e": 4 - } - ignore = ["d", "e"] - result = build_dict(input_dict, ignore) - assert result == {"a": 1, "b": {"c": 2}} - assert "e" not in result - assert "d" not in result["b"] # type: ignore - - def test_build_dict_with_empty_ignore_list(self): - """Test build_dict with empty ignore list""" - input_dict = {"a": 1, "b": 2} - ignore: list[str] = [] - result = build_dict(input_dict, ignore) - assert result == input_dict - - def test_build_dict_with_nonexistent_ignore_keys(self): - """Test build_dict with keys that don't exist""" - input_dict = {"a": 1, "b": 2} - ignore = ["c", "d"] - result = build_dict(input_dict, ignore) - assert result == {"a": 1, "b": 2} - - def test_build_dict_ignore_all_keys(self): - """Test build_dict ignoring all keys""" - input_dict = {"a": 1, "b": 2} - ignore = ["a", "b"] - result = build_dict(input_dict, ignore) - assert result == {} - - def test_build_dict_with_complex_structure(self): - """Test build_dict with complex nested structure""" - input_dict = { - "ResponseMetadata": { - "RequestId": "12345", - "HTTPStatusCode": 200, - "RetryAttempts": 0 - }, - "data": { - "id": 1, - "name": "Test", - "ResponseMetadata": {"internal": "value"} - }, - "status": "success" - } - ignore = ["ResponseMetadata", "RetryAttempts"] - result = build_dict(input_dict, ignore) - - # ResponseMetadata should be removed at all levels - assert "ResponseMetadata" not in result - assert "ResponseMetadata" not in result["data"] # type: ignore - assert result["data"]["name"] == "Test" # type: ignore - assert result["status"] == "success" # type: ignore - - def test_build_dict_with_list_values(self): - """Test build_dict with lists containing dictionaries""" - input_dict = { - "items": [ - {"id": 1, "temp": "remove"}, - {"id": 2, "temp": "remove"} - ], - "temp": "also_remove" - } - ignore = ["temp"] - result = build_dict(input_dict, ignore) - - assert "temp" not in result - assert "temp" not in result["items"][0] # type: ignore - assert "temp" not in result["items"][1] # type: ignore - assert result["items"][0]["id"] == 1 # type: ignore - assert result["items"][1]["id"] == 2 # type: ignore - - def test_build_dict_empty_input(self): - """Test build_dict with empty dictionary""" - input_dict: dict[str, Any] = {} - result = build_dict(input_dict, ["a", "b"]) - assert result == {} - - def test_build_dict_preserves_type_annotation(self): - """Test that build_dict preserves proper type""" - input_dict = {"a": 1, "b": [1, 2, 3], "c": {"nested": "value"}} - result = build_dict(input_dict) - assert isinstance(result, dict) - assert isinstance(result["b"], list) - assert isinstance(result["c"], dict) - - -class TestSetEntry: - """Test cases for set_entry function""" - - def test_set_entry_new_key(self): - """Test setting a new key in dictionary""" - dict_set: dict[str, Any] = {} - key = "new_key" - value = "new_value" - result = set_entry(dict_set, key, value) - assert result[key] == value - assert len(result) == 1 - - def test_set_entry_existing_key(self): - """Test overwriting an existing key""" - dict_set = {"key": "old_value"} - key = "key" - value = "new_value" - result = set_entry(dict_set, key, value) - assert result[key] == value - assert result[key] != "old_value" - - def test_set_entry_with_dict_value(self): - """Test setting a dictionary as value""" - dict_set: dict[str, Any] = {} - key = "config" - value = {"setting1": True, "setting2": "value"} - result = set_entry(dict_set, key, value) - assert result[key] == value - assert isinstance(result[key], dict) - - def test_set_entry_with_list_value(self): - """Test setting a list as value""" - dict_set: dict[str, Any] = {} - key = "items" - value = [1, 2, 3, 4] - result = set_entry(dict_set, key, value) - assert result[key] == value - assert isinstance(result[key], list) - - def test_set_entry_with_none_value(self): - """Test setting None as value""" - dict_set: dict[str, Any] = {} - key = "nullable" - value = None - result = set_entry(dict_set, key, value) - assert result[key] is None - assert key in result - - def test_set_entry_with_integer_value(self): - """Test setting integer value""" - dict_set: dict[str, Any] = {} - key = "count" - value = 42 - result = set_entry(dict_set, key, value) - assert result[key] == 42 - assert isinstance(result[key], int) - - def test_set_entry_with_float_value(self): - """Test setting float value""" - dict_set: dict[str, Any] = {} - key = "price" - value = 19.99 - result = set_entry(dict_set, key, value) - assert result[key] == 19.99 - assert isinstance(result[key], float) - - def test_set_entry_with_boolean_value(self): - """Test setting boolean value""" - dict_set: dict[str, Any] = {} - key = "enabled" - value = True - result = set_entry(dict_set, key, value) - assert result[key] is True - assert isinstance(result[key], bool) - - def test_set_entry_multiple_times(self): - """Test setting multiple entries""" - dict_set: dict[str, Any] = {} - set_entry(dict_set, "key1", "value1") - set_entry(dict_set, "key2", "value2") - set_entry(dict_set, "key3", "value3") - - assert len(dict_set) == 3 - assert dict_set["key1"] == "value1" - assert dict_set["key2"] == "value2" - assert dict_set["key3"] == "value3" - - def test_set_entry_overwrites_existing(self): - """Test that setting an existing key overwrites it""" - dict_set = {"key": {"old": "data"}} - value = {"new": "data"} - result = set_entry(dict_set, "key", value) - assert result["key"] == {"new": "data"} - assert "old" not in result["key"] - - def test_set_entry_modifies_original_dict(self): - """Test that set_entry modifies the original dictionary""" - dict_set: dict[str, Any] = {} - result = set_entry(dict_set, "key", "value") - assert result is dict_set - assert dict_set["key"] == "value" - - def test_set_entry_with_empty_string_value(self): - """Test setting empty string as value""" - dict_set: dict[str, Any] = {} - key = "empty" - value = "" - result = set_entry(dict_set, key, value) - assert result[key] == "" - assert key in result - - def test_set_entry_with_complex_nested_structure(self): - """Test setting complex nested structure""" - dict_set: dict[str, Any] = {} - key = "complex" - value = { - "level1": { - "level2": { - "level3": ["a", "b", "c"] - } - } - } - result = set_entry(dict_set, key, value) - assert result[key]["level1"]["level2"]["level3"] == ["a", "b", "c"] - - -# Parametrized tests for more comprehensive coverage -class TestParametrized: - """Parametrized tests for better coverage""" - - @pytest.mark.parametrize("set_data,keys,expected", [ - ({"a": 1, "b": 2}, ["b"], {"a": 1}), - ({"a": 1, "b": 2, "c": 3}, ["a", "c"], {"b": 2}), - ({"a": 1}, ["a"], {}), - ({"a": 1, "b": 2}, ["c"], {"a": 1, "b": 2}), - ({}, ["a"], {}), - ({"a": {"b": 1, "c": 2}}, ["c"], {"a": {"b": 1}}), - ]) - def test_delete_keys_parametrized( - self, - set_data: dict[str, Any], - keys: list[str], - expected: dict[str, Any] - ): - """Test delete_keys_from_set with various inputs""" - result = delete_keys_from_set(set_data, keys) - assert result == expected - - @pytest.mark.parametrize("input_dict,ignore,expected", [ - ({"a": 1, "b": 2}, ["b"], {"a": 1}), - ({"a": 1, "b": 2}, ["c"], {"a": 1, "b": 2}), - ({"a": 1, "b": 2}, [], {"a": 1, "b": 2}), - ({"a": 1}, ["a"], {}), - ({}, ["a"], {}), - ]) - def test_build_dict_parametrized( - self, - input_dict: dict[str, Any], - ignore: list[str], - expected: dict[str, Any] - ): - """Test build_dict with various inputs""" - result = build_dict(input_dict, ignore) - assert result == expected - - @pytest.mark.parametrize("key,value", [ - ("string_key", "string_value"), - ("int_key", 42), - ("float_key", 3.14), - ("bool_key", True), - ("list_key", [1, 2, 3]), - ("dict_key", {"nested": "value"}), - ("none_key", None), - ("empty_key", ""), - ("zero_key", 0), - ("false_key", False), - ]) - def test_set_entry_parametrized(self, key: str, value: Any): - """Test set_entry with various value types""" - dict_set: dict[str, Any] = {} - result = set_entry(dict_set, key, value) - assert result[key] == value - - -# Edge cases and integration tests -class TestEdgeCases: - """Test edge cases and special scenarios""" - - def test_delete_keys_preserves_modification(self): - """Test that original dict is modified""" - set_data = {"a": 1, "b": 2, "c": 3} - keys = ["b"] - result = delete_keys_from_set(set_data, keys) - # The function modifies the original dict - assert result is set_data - assert "b" not in set_data - - def test_build_dict_with_aws_typedef_scenario(self): - """Test build_dict mimicking AWS TypedDict usage""" - # Simulating AWS response with ResponseMetadata - aws_response: dict[str, Any] = { - "Items": [ - {"id": "1", "name": "Item1"}, - {"id": "2", "name": "Item2"} - ], - "Count": 2, - "ScannedCount": 2, - "ResponseMetadata": { - "RequestId": "abc123", - "HTTPStatusCode": 200, - "HTTPHeaders": {}, - "RetryAttempts": 0 - } - } - result = build_dict(aws_response, ["ResponseMetadata"]) - - assert "ResponseMetadata" not in result - assert result["Count"] == 2 # type: ignore - assert len(result["Items"]) == 2 # type: ignore - - def test_set_entry_idempotency(self): - """Test that calling set_entry multiple times with same value is idempotent""" - dict_set: dict[str, Any] = {} - value = "test_value" - - result1 = set_entry(dict_set, "key", value) - result2 = set_entry(dict_set, "key", value) - result3 = set_entry(dict_set, "key", value) - - assert result1 is result2 is result3 - assert result1["key"] == value - assert len(result1) == 1 - - def test_delete_keys_with_circular_reference_protection(self): - """Test that function handles normal cases without circular issues""" - # Python dicts can't have true circular references easily - # but we can test deep nesting - set_data = { - "level1": { - "level2": { - "level3": { - "level4": { - "data": "value", - "remove": "this" - } - } - } - } - } - keys = ["remove"] - result = delete_keys_from_set(set_data, keys) - assert "remove" not in result["level1"]["level2"]["level3"]["level4"] # type: ignore - assert result["level1"]["level2"]["level3"]["level4"]["data"] == "value" # type: ignore - - def test_build_dict_none_ignore_vs_empty_ignore(self): - """Test difference between None and empty list for ignore_entries""" - input_dict = {"a": 1, "b": 2} - - result_none = build_dict(input_dict, None) - result_empty = build_dict(input_dict, []) - - assert result_none == input_dict - assert result_empty == input_dict - # With None, it returns the same object - assert result_none is input_dict - # With empty list, it goes through delete_keys_from_set - assert result_empty is input_dict - - -# Integration tests -class TestIntegration: - """Integration tests combining multiple functions""" - - def test_build_dict_then_set_entry(self): - """Test using build_dict followed by set_entry""" - original = { - "a": 1, - "b": 2, - "remove_me": "gone" - } - cleaned = build_dict(original, ["remove_me"]) - result = set_entry(cleaned, "c", 3) - - assert result == {"a": 1, "b": 2, "c": 3} - assert "remove_me" not in result - - def test_delete_keys_then_set_entry(self): - """Test using delete_keys_from_set followed by set_entry""" - data = {"a": 1, "b": 2, "c": 3} - cleaned = delete_keys_from_set(data, ["b"]) - result = set_entry(cleaned, "d", 4) # type: ignore - - assert result == {"a": 1, "c": 3, "d": 4} - - def test_multiple_operations_chain(self): - """Test chaining multiple operations""" - data = { - "user": { - "name": "Alice", - "password": "secret", - "email": "alice@example.com" - }, - "metadata": { - "created": "2024-01-01", - "password": "admin" - } - } - - # Remove passwords - cleaned = build_dict(data, ["password"]) - - # Add new field - result = set_entry(cleaned, "processed", True) - - assert "password" not in result["user"] # type: ignore - assert "password" not in result["metadata"] # type: ignore - assert result["processed"] is True # type: ignore - assert result["user"]["name"] == "Alice" # type: ignore - -# __END__ diff --git a/tests/unit/iterator_handling/test_dict_mask.py b/tests/unit/iterator_handling/test_dict_mask.py deleted file mode 100644 index 15be1b5..0000000 --- a/tests/unit/iterator_handling/test_dict_mask.py +++ /dev/null @@ -1,291 +0,0 @@ -""" -tests for corelibs.iterator_handling.dict_helpers -""" - -from typing import Any -import pytest -from corelibs.iterator_handling.dict_mask import mask - - -def test_mask_default_behavior(): - """Test masking with default mask_keys""" - data = { - "username": "john_doe", - "password": "secret123", - "email": "john@example.com", - "api_secret": "abc123", - "encryption_key": "xyz789" - } - - result = mask(data) - - assert result["username"] == "john_doe" - assert result["password"] == "***" - assert result["email"] == "john@example.com" - assert result["api_secret"] == "***" - assert result["encryption_key"] == "***" - - -def test_mask_custom_keys(): - """Test masking with custom mask_keys""" - data = { - "username": "john_doe", - "token": "abc123", - "api_key": "xyz789", - "password": "secret123" - } - - result = mask(data, mask_keys=["token", "api"]) - - assert result["username"] == "john_doe" - assert result["token"] == "***" - assert result["api_key"] == "***" - assert result["password"] == "secret123" # Not masked with custom keys - - -def test_mask_custom_mask_string(): - """Test masking with custom mask string""" - data = {"password": "secret123"} - - result = mask(data, mask_str="[HIDDEN]") - - assert result["password"] == "[HIDDEN]" - - -def test_mask_case_insensitive(): - """Test that masking is case insensitive""" - data = { - "PASSWORD": "secret123", - "Secret_Key": "abc123", - "ENCRYPTION_data": "xyz789" - } - - result = mask(data) - - assert result["PASSWORD"] == "***" - assert result["Secret_Key"] == "***" - assert result["ENCRYPTION_data"] == "***" - - -def test_mask_key_patterns(): - """Test different key matching patterns (start, end, contains)""" - data = { - "password_hash": "hash123", # starts with - "user_password": "secret123", # ends with - "my_secret_key": "abc123", # contains with edges - "secretvalue": "xyz789", # contains without edges - "startsecretvalue": "xyz123", # contains without edges - "normal_key": "normal_value" - } - - result = mask(data) - - assert result["password_hash"] == "***" - assert result["user_password"] == "***" - assert result["my_secret_key"] == "***" - assert result["secretvalue"] == "***" # will mask beacuse starts with - assert result["startsecretvalue"] == "xyz123" # will not mask - assert result["normal_key"] == "normal_value" - - -def test_mask_custom_edges(): - """Test masking with custom edge characters""" - data = { - "my-secret-key": "abc123", - "my_secret_key": "xyz789" - } - - result = mask(data, mask_str_edges="-") - - assert result["my-secret-key"] == "***" - assert result["my_secret_key"] == "xyz789" # Underscore edges don't match - - -def test_mask_empty_edges(): - """Test masking with empty edge characters (substring matching)""" - data = { - "secretvalue": "abc123", - "mysecretkey": "xyz789", - "normal_key": "normal_value" - } - - result = mask(data, mask_str_edges="") - - assert result["secretvalue"] == "***" - assert result["mysecretkey"] == "***" - assert result["normal_key"] == "normal_value" - - -def test_mask_nested_dict(): - """Test masking nested dictionaries""" - data = { - "user": { - "name": "john", - "password": "secret123", - "profile": { - "email": "john@example.com", - "encryption_key": "abc123" - } - }, - "api_secret": "xyz789" - } - - result = mask(data) - - assert result["user"]["name"] == "john" - assert result["user"]["password"] == "***" - assert result["user"]["profile"]["email"] == "john@example.com" - assert result["user"]["profile"]["encryption_key"] == "***" - assert result["api_secret"] == "***" - - -def test_mask_lists(): - """Test masking lists and nested structures with lists""" - data = { - "users": [ - {"name": "john", "password": "secret1"}, - {"name": "jane", "password": "secret2"} - ], - "secrets": ["secret1", "secret2", "secret3"] - } - - result = mask(data) - print(f"R {result['secrets']}") - - assert result["users"][0]["name"] == "john" - assert result["users"][0]["password"] == "***" - assert result["users"][1]["name"] == "jane" - assert result["users"][1]["password"] == "***" - assert result["secrets"] == ["***", "***", "***"] - - -def test_mask_mixed_types(): - """Test masking with different value types""" - data = { - "password": "string_value", - "secret_number": 12345, - "encryption_flag": True, - "secret_float": 3.14, - "password_none": None, - "normal_key": "normal_value" - } - - result = mask(data) - - assert result["password"] == "***" - assert result["secret_number"] == "***" - assert result["encryption_flag"] == "***" - assert result["secret_float"] == "***" - assert result["password_none"] == "***" - assert result["normal_key"] == "normal_value" - - -def test_mask_skip_true(): - """Test that skip=True returns original data unchanged""" - data = { - "password": "secret123", - "encryption_key": "abc123", - "normal_key": "normal_value" - } - - result = mask(data, skip=True) - - assert result == data - assert result is data # Should return the same object - - -def test_mask_empty_dict(): - """Test masking empty dictionary""" - data: dict[str, Any] = {} - - result = mask(data) - - assert result == {} - - -def test_mask_none_mask_keys(): - """Test explicit None mask_keys uses defaults""" - data = {"password": "secret123", "token": "abc123"} - - result = mask(data, mask_keys=None) - - assert result["password"] == "***" - assert result["token"] == "abc123" # Not in default keys - - -def test_mask_empty_mask_keys(): - """Test empty mask_keys list""" - data = {"password": "secret123", "secret": "abc123"} - - result = mask(data, mask_keys=[]) - - assert result["password"] == "secret123" - assert result["secret"] == "abc123" - - -def test_mask_complex_nested_structure(): - """Test masking complex nested structure""" - data = { - "config": { - "database": { - "host": "localhost", - "password": "db_secret", - "users": [ - {"name": "admin", "password": "admin123"}, - {"name": "user", "secret_key": "user456"} - ] - }, - "api": { - "endpoints": ["api1", "api2"], - "encryption_settings": { - "enabled": True, - "secret": "api_secret" - } - } - } - } - - result = mask(data) - - assert result["config"]["database"]["host"] == "localhost" - assert result["config"]["database"]["password"] == "***" - assert result["config"]["database"]["users"][0]["name"] == "admin" - assert result["config"]["database"]["users"][0]["password"] == "***" - assert result["config"]["database"]["users"][1]["name"] == "user" - assert result["config"]["database"]["users"][1]["secret_key"] == "***" - assert result["config"]["api"]["endpoints"] == ["api1", "api2"] - assert result["config"]["api"]["encryption_settings"]["enabled"] is True - assert result["config"]["api"]["encryption_settings"]["secret"] == "***" - - -def test_mask_preserves_original_data(): - """Test that original data is not modified""" - original_data = { - "password": "secret123", - "username": "john_doe" - } - data_copy = original_data.copy() - - result = mask(original_data) - - assert original_data == data_copy # Original unchanged - assert result != original_data # Result is different - assert result["password"] == "***" - assert original_data["password"] == "secret123" - - -@pytest.mark.parametrize("mask_key,expected_keys", [ - (["pass"], ["password", "user_pass", "my_pass_key"]), - (["key"], ["api_key", "secret_key", "my_key_value"]), - (["token"], ["token", "auth_token", "my_token_here"]), -]) -def test_mask_parametrized_keys(mask_key: list[str], expected_keys: list[str]): - """Parametrized test for different mask key patterns""" - data = {key: "value" for key in expected_keys} - data["normal_entry"] = "normal_value" - - result = mask(data, mask_keys=mask_key) - - for key in expected_keys: - assert result[key] == "***" - assert result["normal_entry"] == "normal_value" diff --git a/tests/unit/iterator_handling/test_fingerprint.py b/tests/unit/iterator_handling/test_fingerprint.py deleted file mode 100644 index bde74ae..0000000 --- a/tests/unit/iterator_handling/test_fingerprint.py +++ /dev/null @@ -1,565 +0,0 @@ -""" -tests for corelibs.iterator_handling.fingerprint -""" - -from typing import Any -import pytest -from corelibs.iterator_handling.fingerprint import dict_hash_frozen, dict_hash_crc, hash_object - - -class TestHashObject: - """Tests for hash_object function""" - - def test_hash_object_simple_dict(self): - """Test hashing a simple dictionary with hash_object""" - data = {"key1": "value1", "key2": "value2"} - result = hash_object(data) - - assert isinstance(result, str) - assert len(result) == 64 # SHA256 produces 64 hex characters - - def test_hash_object_mixed_keys(self): - """Test hash_object with mixed int and string keys""" - data = {"key1": "value1", 1: "value2", 2: "value3"} - result = hash_object(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_hash_object_consistency(self): - """Test that hash_object produces consistent results""" - data = {"str_key": "value", 123: "number_key"} - hash1 = hash_object(data) - hash2 = hash_object(data) - - assert hash1 == hash2 - - def test_hash_object_order_independence(self): - """Test that hash_object is order-independent""" - data1 = {"a": 1, 1: "one", "b": 2, 2: "two"} - data2 = {2: "two", "b": 2, 1: "one", "a": 1} - hash1 = hash_object(data1) - hash2 = hash_object(data2) - - assert hash1 == hash2 - - def test_hash_object_list_of_dicts_mixed_keys(self): - """Test hash_object with list of dicts containing mixed keys""" - data = [ - {"name": "item1", 1: "value1"}, - {"name": "item2", 2: "value2"} - ] - result = hash_object(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_hash_object_nested_mixed_keys(self): - """Test hash_object with nested structures containing mixed keys""" - data = { - "outer": { - "inner": "value", - 1: "mixed_key" - }, - 2: "another_mixed" - } - result = hash_object(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_hash_object_different_data(self): - """Test that different data produces different hashes""" - data1 = {"key": "value", 1: "one"} - data2 = {"key": "value", 2: "two"} - hash1 = hash_object(data1) - hash2 = hash_object(data2) - - assert hash1 != hash2 - - def test_hash_object_complex_nested(self): - """Test hash_object with complex nested structures""" - data = { - "level1": { - "level2": { - 1: "value", - "key": [1, 2, {"nested": "deep", 3: "int_key"}] - } - } - } - result = hash_object(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_hash_object_list_with_tuples(self): - """Test hash_object with lists containing tuples""" - data = [("a", 1), ("b", 2), {1: "mixed", "key": "value"}] - result = hash_object(data) - - assert isinstance(result, str) - assert len(result) == 64 - - -class TestDictHashFrozen: - """Tests for dict_hash_frozen function""" - - def test_dict_hash_frozen_simple_dict(self): - """Test hashing a simple dictionary""" - data = {"key1": "value1", "key2": "value2"} - result = dict_hash_frozen(data) - - assert isinstance(result, int) - assert result != 0 - - def test_dict_hash_frozen_consistency(self): - """Test that same dict produces same hash""" - data = {"name": "John", "age": 30, "city": "Tokyo"} - hash1 = dict_hash_frozen(data) - hash2 = dict_hash_frozen(data) - - assert hash1 == hash2 - - def test_dict_hash_frozen_order_independence(self): - """Test that dict order doesn't affect hash""" - data1 = {"a": 1, "b": 2, "c": 3} - data2 = {"c": 3, "a": 1, "b": 2} - hash1 = dict_hash_frozen(data1) - hash2 = dict_hash_frozen(data2) - - assert hash1 == hash2 - - def test_dict_hash_frozen_empty_dict(self): - """Test hashing an empty dictionary""" - data: dict[Any, Any] = {} - result = dict_hash_frozen(data) - - assert isinstance(result, int) - - def test_dict_hash_frozen_different_dicts(self): - """Test that different dicts produce different hashes""" - data1 = {"key1": "value1"} - data2 = {"key2": "value2"} - hash1 = dict_hash_frozen(data1) - hash2 = dict_hash_frozen(data2) - - assert hash1 != hash2 - - def test_dict_hash_frozen_various_types(self): - """Test hashing dict with various value types""" - data = { - "string": "value", - "int": 42, - "float": 3.14, - "bool": True, - "none": None - } - result = dict_hash_frozen(data) - - assert isinstance(result, int) - - def test_dict_hash_frozen_numeric_keys(self): - """Test hashing dict with numeric keys""" - data = {1: "one", 2: "two", 3: "three"} - result = dict_hash_frozen(data) - - assert isinstance(result, int) - - def test_dict_hash_frozen_tuple_values(self): - """Test hashing dict with tuple values""" - data = {"coord1": (1, 2), "coord2": (3, 4)} - result = dict_hash_frozen(data) - - assert isinstance(result, int) - - def test_dict_hash_frozen_value_change_changes_hash(self): - """Test that changing a value changes the hash""" - data1 = {"key": "value1"} - data2 = {"key": "value2"} - hash1 = dict_hash_frozen(data1) - hash2 = dict_hash_frozen(data2) - - assert hash1 != hash2 - - -class TestDictHashCrc: - """Tests for dict_hash_crc function""" - - def test_dict_hash_crc_simple_dict(self): - """Test hashing a simple dictionary""" - data = {"key1": "value1", "key2": "value2"} - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 # SHA256 produces 64 hex characters - - def test_dict_hash_crc_simple_list(self): - """Test hashing a simple list""" - data = ["item1", "item2", "item3"] - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_consistency_dict(self): - """Test that same dict produces same hash""" - data = {"name": "John", "age": 30, "city": "Tokyo"} - hash1 = dict_hash_crc(data) - hash2 = dict_hash_crc(data) - - assert hash1 == hash2 - - def test_dict_hash_crc_consistency_list(self): - """Test that same list produces same hash""" - data = [1, 2, 3, 4, 5] - hash1 = dict_hash_crc(data) - hash2 = dict_hash_crc(data) - - assert hash1 == hash2 - - def test_dict_hash_crc_order_independence_dict(self): - """Test that dict order doesn't affect hash (sort_keys=True)""" - data1 = {"a": 1, "b": 2, "c": 3} - data2 = {"c": 3, "a": 1, "b": 2} - hash1 = dict_hash_crc(data1) - hash2 = dict_hash_crc(data2) - - assert hash1 == hash2 - - def test_dict_hash_crc_order_dependence_list(self): - """Test that list order affects hash""" - data1 = [1, 2, 3] - data2 = [3, 2, 1] - hash1 = dict_hash_crc(data1) - hash2 = dict_hash_crc(data2) - - assert hash1 != hash2 - - def test_dict_hash_crc_empty_dict(self): - """Test hashing an empty dictionary""" - data: dict[Any, Any] = {} - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_empty_list(self): - """Test hashing an empty list""" - data: list[Any] = [] - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_different_dicts(self): - """Test that different dicts produce different hashes""" - data1 = {"key1": "value1"} - data2 = {"key2": "value2"} - hash1 = dict_hash_crc(data1) - hash2 = dict_hash_crc(data2) - - assert hash1 != hash2 - - def test_dict_hash_crc_different_lists(self): - """Test that different lists produce different hashes""" - data1 = ["item1", "item2"] - data2 = ["item3", "item4"] - hash1 = dict_hash_crc(data1) - hash2 = dict_hash_crc(data2) - - assert hash1 != hash2 - - def test_dict_hash_crc_nested_dict(self): - """Test hashing nested dictionaries""" - data = { - "user": { - "name": "John", - "address": { - "city": "Tokyo", - "country": "Japan" - } - } - } - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_nested_list(self): - """Test hashing nested lists""" - data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_mixed_nested(self): - """Test hashing mixed nested structures""" - data = { - "items": [1, 2, 3], - "meta": { - "count": 3, - "tags": ["a", "b", "c"] - } - } - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_various_types_dict(self): - """Test hashing dict with various value types""" - data = { - "string": "value", - "int": 42, - "float": 3.14, - "bool": True, - "none": None, - "list": [1, 2, 3], - "nested_dict": {"inner": "value"} - } - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_various_types_list(self): - """Test hashing list with various value types""" - data = ["string", 42, 3.14, True, None, [1, 2], {"key": "value"}] - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_value_change_changes_hash(self): - """Test that changing a value changes the hash""" - data1 = {"key": "value1"} - data2 = {"key": "value2"} - hash1 = dict_hash_crc(data1) - hash2 = dict_hash_crc(data2) - - assert hash1 != hash2 - - def test_dict_hash_crc_hex_format(self): - """Test that hash is in hexadecimal format""" - data = {"test": "data"} - result = dict_hash_crc(data) - - # All characters should be valid hex - assert all(c in "0123456789abcdef" for c in result) - - def test_dict_hash_crc_unicode_handling(self): - """Test hashing dict with unicode characters""" - data = { - "japanese": "ζ—₯本θͺž", - "emoji": "πŸŽ‰", - "chinese": "δΈ­ζ–‡" - } - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_special_characters(self): - """Test hashing dict with special characters""" - data = { - "quotes": "\"quoted\"", - "newline": "line1\nline2", - "tab": "col1\tcol2", - "backslash": "path\\to\\file" - } - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert len(result) == 64 - - def test_dict_hash_crc_fallback_mixed_keys(self): - """Test dict_hash_crc fallback with mixed int and string keys""" - data = {"key1": "value1", 1: "value2", 2: "value3"} - result = dict_hash_crc(data) - - assert isinstance(result, str) - # Fallback prefixes with "HO_" - assert result.startswith("HO_") - # Hash should be 64 chars + 3 char prefix = 67 total - assert len(result) == 67 - - def test_dict_hash_crc_fallback_consistency(self): - """Test that fallback produces consistent hashes""" - data = {"str_key": "value", 123: "number_key", 456: "another"} - hash1 = dict_hash_crc(data) - hash2 = dict_hash_crc(data) - - assert hash1 == hash2 - assert hash1.startswith("HO_") - - def test_dict_hash_crc_fallback_order_independence(self): - """Test that fallback is order-independent for mixed-key dicts""" - data1 = {"a": 1, 1: "one", "b": 2, 2: "two"} - data2 = {2: "two", "b": 2, 1: "one", "a": 1} - hash1 = dict_hash_crc(data1) - hash2 = dict_hash_crc(data2) - - assert hash1 == hash2 - assert hash1.startswith("HO_") - - def test_dict_hash_crc_fallback_list_of_dicts_mixed_keys(self): - """Test fallback with list of dicts containing mixed keys""" - data = [ - {"name": "item1", 1: "value1"}, - {"name": "item2", 2: "value2"}, - {3: "value3", "type": "mixed"} - ] - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert result.startswith("HO_") - assert len(result) == 67 - - def test_dict_hash_crc_fallback_nested_mixed_keys(self): - """Test fallback with nested dicts containing mixed keys""" - data = { - "outer": { - "inner": "value", - 1: "mixed_key" - }, - 2: "another_mixed" - } - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert result.startswith("HO_") - assert len(result) == 67 - - def test_dict_hash_crc_fallback_different_data(self): - """Test that different mixed-key data produces different hashes""" - data1 = {"key": "value", 1: "one"} - data2 = {"key": "value", 2: "two"} - hash1 = dict_hash_crc(data1) - hash2 = dict_hash_crc(data2) - - assert hash1 != hash2 - assert hash1.startswith("HO_") - assert hash2.startswith("HO_") - - def test_dict_hash_crc_fallback_complex_structure(self): - """Test fallback with complex nested structure with mixed keys""" - data = [ - { - "id": 1, - 1: "first", - "data": { - "nested": "value", - 100: "nested_int_key" - } - }, - { - "id": 2, - 2: "second", - "items": [1, 2, 3] - } - ] - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert result.startswith("HO_") - assert len(result) == 67 - - def test_dict_hash_crc_no_fallback_string_keys_only(self): - """Test that string-only keys don't trigger fallback""" - data = {"key1": "value1", "key2": "value2", "key3": "value3"} - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert not result.startswith("HO_") - assert len(result) == 64 - - def test_dict_hash_crc_no_fallback_int_keys_only(self): - """Test that int-only keys don't trigger fallback""" - data = {1: "one", 2: "two", 3: "three"} - result = dict_hash_crc(data) - - assert isinstance(result, str) - assert not result.startswith("HO_") - assert len(result) == 64 - - -class TestComparisonBetweenHashFunctions: - """Tests comparing dict_hash_frozen and dict_hash_crc""" - - def test_both_functions_are_deterministic(self): - """Test that both functions produce consistent results""" - data = {"a": 1, "b": 2, "c": 3} - - frozen_hash1 = dict_hash_frozen(data) - frozen_hash2 = dict_hash_frozen(data) - crc_hash1 = dict_hash_crc(data) - crc_hash2 = dict_hash_crc(data) - - assert frozen_hash1 == frozen_hash2 - assert crc_hash1 == crc_hash2 - - def test_both_functions_handle_empty_dict(self): - """Test that both functions can hash empty dict""" - data: dict[Any, Any] = {} - - frozen_result = dict_hash_frozen(data) - crc_result = dict_hash_crc(data) - - assert isinstance(frozen_result, int) - assert isinstance(crc_result, str) - - def test_both_functions_detect_changes(self): - """Test that both functions detect value changes""" - data1 = {"key": "value1"} - data2 = {"key": "value2"} - - frozen_hash1 = dict_hash_frozen(data1) - frozen_hash2 = dict_hash_frozen(data2) - crc_hash1 = dict_hash_crc(data1) - crc_hash2 = dict_hash_crc(data2) - - assert frozen_hash1 != frozen_hash2 - assert crc_hash1 != crc_hash2 - - def test_both_functions_handle_order_independence(self): - """Test that both functions are order-independent for dicts""" - data1 = {"x": 10, "y": 20, "z": 30} - data2 = {"z": 30, "x": 10, "y": 20} - - frozen_hash1 = dict_hash_frozen(data1) - frozen_hash2 = dict_hash_frozen(data2) - crc_hash1 = dict_hash_crc(data1) - crc_hash2 = dict_hash_crc(data2) - - assert frozen_hash1 == frozen_hash2 - assert crc_hash1 == crc_hash2 - - -@pytest.mark.parametrize("data,expected_type,expected_length", [ - ({"key": "value"}, str, 64), - ([1, 2, 3], str, 64), - ({"nested": {"key": "value"}}, str, 64), - ([[1, 2], [3, 4]], str, 64), - ({}, str, 64), - ([], str, 64), -]) -def test_dict_hash_crc_parametrized(data: dict[Any, Any] | list[Any], expected_type: type, expected_length: int): - """Parametrized test for dict_hash_crc with various inputs""" - result = dict_hash_crc(data) - - assert isinstance(result, expected_type) - assert len(result) == expected_length - - -@pytest.mark.parametrize("data", [ - {"key": "value"}, - {"a": 1, "b": 2}, - {"x": 10, "y": 20, "z": 30}, - {}, -]) -def test_dict_hash_frozen_parametrized(data: dict[Any, Any]): - """Parametrized test for dict_hash_frozen with various inputs""" - result = dict_hash_frozen(data) - - assert isinstance(result, int) diff --git a/tests/unit/iterator_handling/test_list_helpers.py b/tests/unit/iterator_handling/test_list_helpers.py deleted file mode 100644 index 476b701..0000000 --- a/tests/unit/iterator_handling/test_list_helpers.py +++ /dev/null @@ -1,522 +0,0 @@ -""" -iterator_handling.list_helepr tests -""" - -from typing import Any -import pytest -from corelibs.iterator_handling.list_helpers import convert_to_list, is_list_in_list, make_unique_list_of_dicts - - -class TestConvertToList: - """Test cases for convert_to_list function""" - - def test_string_input(self): - """Test with string inputs""" - assert convert_to_list("hello") == ["hello"] - assert convert_to_list("") == [""] - assert convert_to_list("123") == ["123"] - assert convert_to_list("true") == ["true"] - - def test_integer_input(self): - """Test with integer inputs""" - assert convert_to_list(42) == [42] - assert convert_to_list(0) == [0] - assert convert_to_list(-10) == [-10] - assert convert_to_list(999999) == [999999] - - def test_float_input(self): - """Test with float inputs""" - assert convert_to_list(3.14) == [3.14] - assert convert_to_list(0.0) == [0.0] - assert convert_to_list(-2.5) == [-2.5] - assert convert_to_list(1.0) == [1.0] - - def test_boolean_input(self): - """Test with boolean inputs""" - assert convert_to_list(True) == [True] - assert convert_to_list(False) == [False] - - def test_list_input_unchanged(self): - """Test that list inputs are returned unchanged""" - # String lists - str_list = ["a", "b", "c"] - assert convert_to_list(str_list) == str_list - assert convert_to_list(str_list) is str_list # Same object reference - - # Integer lists - int_list = [1, 2, 3] - assert convert_to_list(int_list) == int_list - assert convert_to_list(int_list) is int_list - - # Float lists - float_list = [1.1, 2.2, 3.3] - assert convert_to_list(float_list) == float_list - assert convert_to_list(float_list) is float_list - - # Boolean lists - bool_list = [True, False, True] - assert convert_to_list(bool_list) == bool_list - assert convert_to_list(bool_list) is bool_list - - # Mixed lists - mixed_list = [1, "hello", 3.14, True] - assert convert_to_list(mixed_list) == mixed_list - assert convert_to_list(mixed_list) is mixed_list - - # Empty list - empty_list: list[int] = [] - assert convert_to_list(empty_list) == empty_list - assert convert_to_list(empty_list) is empty_list - - def test_nested_lists(self): - """Test with nested lists (should still return the same list)""" - nested_list: list[list[int]] = [[1, 2], [3, 4]] - assert convert_to_list(nested_list) == nested_list - assert convert_to_list(nested_list) is nested_list - - def test_single_element_lists(self): - """Test with single element lists""" - single_str = ["hello"] - assert convert_to_list(single_str) == single_str - assert convert_to_list(single_str) is single_str - - single_int = [42] - assert convert_to_list(single_int) == single_int - assert convert_to_list(single_int) is single_int - - -class TestIsListInList: - """Test cases for is_list_in_list function""" - - def test_string_lists(self): - """Test with string lists""" - list_a = ["a", "b", "c", "d"] - list_b = ["b", "d", "e"] - result = is_list_in_list(list_a, list_b) - assert set(result) == {"a", "c"} - assert isinstance(result, list) - - def test_integer_lists(self): - """Test with integer lists""" - list_a = [1, 2, 3, 4, 5] - list_b = [2, 4, 6] - result = is_list_in_list(list_a, list_b) - assert set(result) == {1, 3, 5} - assert isinstance(result, list) - - def test_float_lists(self): - """Test with float lists""" - list_a = [1.1, 2.2, 3.3, 4.4] - list_b = [2.2, 4.4, 5.5] - result = is_list_in_list(list_a, list_b) - assert set(result) == {1.1, 3.3} - assert isinstance(result, list) - - def test_boolean_lists(self): - """Test with boolean lists""" - list_a = [True, False, True] - list_b = [True] - result = is_list_in_list(list_a, list_b) - assert set(result) == {False} - assert isinstance(result, list) - - def test_mixed_type_lists(self): - """Test with mixed type lists""" - list_a = [1, "hello", 3.14, True, "world"] - list_b = ["hello", True, 42] - result = is_list_in_list(list_a, list_b) - assert set(result) == {1, 3.14, "world"} - assert isinstance(result, list) - - def test_empty_lists(self): - """Test with empty lists""" - # Empty list_a - assert is_list_in_list([], [1, 2, 3]) == [] - - # Empty list_b - list_a = [1, 2, 3] - result = is_list_in_list(list_a, []) - assert set(result) == {1, 2, 3} - - # Both empty - assert is_list_in_list([], []) == [] - - def test_no_common_elements(self): - """Test when lists have no common elements""" - list_a = [1, 2, 3] - list_b = [4, 5, 6] - result = is_list_in_list(list_a, list_b) - assert set(result) == {1, 2, 3} - - def test_all_elements_common(self): - """Test when all elements in list_a are in list_b""" - list_a = [1, 2, 3] - list_b = [1, 2, 3, 4, 5] - result = is_list_in_list(list_a, list_b) - assert result == [] - - def test_identical_lists(self): - """Test with identical lists""" - list_a = [1, 2, 3] - list_b = [1, 2, 3] - result = is_list_in_list(list_a, list_b) - assert result == [] - - def test_duplicate_elements(self): - """Test with duplicate elements in lists""" - list_a = [1, 2, 2, 3, 3, 3] - list_b = [2, 4] - result = is_list_in_list(list_a, list_b) - # Should return unique elements only (set behavior) - assert set(result) == {1, 3} - assert isinstance(result, list) - - def test_list_b_larger_than_list_a(self): - """Test when list_b is larger than list_a""" - list_a = [1, 2] - list_b = [2, 3, 4, 5, 6, 7, 8] - result = is_list_in_list(list_a, list_b) - assert set(result) == {1} - - def test_order_independence(self): - """Test that order doesn't matter due to set operations""" - list_a = [3, 1, 4, 1, 5] - list_b = [1, 2, 6] - result = is_list_in_list(list_a, list_b) - assert set(result) == {3, 4, 5} - - -# Parametrized tests for more comprehensive coverage -class TestParametrized: - """Parametrized tests for better coverage""" - - @pytest.mark.parametrize("input_value,expected", [ - ("hello", ["hello"]), - (42, [42]), - (3.14, [3.14]), - (True, [True]), - (False, [False]), - ("", [""]), - (0, [0]), - (0.0, [0.0]), - (-1, [-1]), - (-2.5, [-2.5]), - ]) - def test_convert_to_list_parametrized(self, input_value: Any, expected: Any): - """Test convert_to_list with various single values""" - assert convert_to_list(input_value) == expected - - @pytest.mark.parametrize("input_list", [ - [1, 2, 3], - ["a", "b", "c"], - [1.1, 2.2, 3.3], - [True, False], - [1, "hello", 3.14, True], - [], - [42], - [[1, 2], [3, 4]], - ]) - def test_convert_to_list_with_lists_parametrized(self, input_list: Any): - """Test convert_to_list with various list inputs""" - result = convert_to_list(input_list) - assert result == input_list - assert result is input_list # Same object reference - - @pytest.mark.parametrize("list_a,list_b,expected_set", [ - ([1, 2, 3], [2], {1, 3}), - (["a", "b", "c"], ["b", "d"], {"a", "c"}), - ([1, 2, 3], [4, 5, 6], {1, 2, 3}), - ([1, 2, 3], [1, 2, 3], set[int]()), - ([], [1, 2, 3], set[int]()), - ([1, 2, 3], [], {1, 2, 3}), - ([True, False], [True], {False}), - ([1.1, 2.2, 3.3], [2.2], {1.1, 3.3}), - ]) - def test_is_list_in_list_parametrized(self, list_a: list[Any], list_b: list[Any], expected_set: Any): - """Test is_list_in_list with various input combinations""" - result = is_list_in_list(list_a, list_b) - assert set(result) == expected_set - assert isinstance(result, list) - - -# Edge cases and special scenarios -class TestEdgeCases: - """Test edge cases and special scenarios""" - - def test_convert_to_list_with_none_like_values(self): - """Test convert_to_list with None-like values (if function supports them)""" - # Note: Based on type hints, None is not supported, but testing behavior - # This test might need to be adjusted based on actual function behavior - # pass - - def test_is_list_in_list_preserves_type_distinctions(self): - """Test that different types are treated as different""" - list_a = [1, "1", 1.0, True] - list_b = [1] # Only integer 1 - result = is_list_in_list(list_a, list_b) - - # Note: This test depends on how Python's set handles type equality - # 1, 1.0, and True are considered equal in sets - # "1" is different from 1 - # expected_items = {"1"} # String "1" should remain - assert "1" in result - assert isinstance(result, list) - - def test_large_lists(self): - """Test with large lists""" - large_list_a = list(range(1000)) - large_list_b = list(range(500, 1500)) - result = is_list_in_list(large_list_a, large_list_b) - expected = list(range(500)) # 0 to 499 - assert set(result) == set(expected) - - def test_memory_efficiency(self): - """Test that convert_to_list doesn't create unnecessary copies""" - original_list = [1, 2, 3, 4, 5] - result = convert_to_list(original_list) - - # Should be the same object, not a copy - assert result is original_list - - # Modifying the original should affect the result - original_list.append(6) - assert 6 in result - - -# Performance tests (optional) -class TestPerformance: - """Performance-related tests""" - - def test_is_list_in_list_with_duplicates_performance(self): - """Test that function handles duplicates efficiently""" - # List with many duplicates - list_a = [1, 2, 3] * 100 # 300 elements, many duplicates - list_b = [2] * 50 # 50 elements, all the same - - result = is_list_in_list(list_a, list_b) - - # Should still work correctly despite duplicates - assert set(result) == {1, 3} - assert isinstance(result, list) - - -class TestMakeUniqueListOfDicts: - """Test cases for make_unique_list_of_dicts function""" - - def test_basic_duplicate_removal(self): - """Test basic removal of duplicate dictionaries""" - dict_list = [ - {"a": 1, "b": 2}, - {"a": 1, "b": 2}, - {"a": 3, "b": 4} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - assert {"a": 1, "b": 2} in result - assert {"a": 3, "b": 4} in result - - def test_order_independent_duplicates(self): - """Test that dictionaries with different key orders are treated as duplicates""" - dict_list = [ - {"a": 1, "b": 2}, - {"b": 2, "a": 1}, # Same content, different order - {"a": 3, "b": 4} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - assert {"a": 1, "b": 2} in result - assert {"a": 3, "b": 4} in result - - def test_empty_list(self): - """Test with empty list""" - result = make_unique_list_of_dicts([]) - assert result == [] - assert isinstance(result, list) - - def test_single_dict(self): - """Test with single dictionary""" - dict_list = [{"a": 1, "b": 2}] - result = make_unique_list_of_dicts(dict_list) - assert result == [{"a": 1, "b": 2}] - - def test_all_unique(self): - """Test when all dictionaries are unique""" - dict_list = [ - {"a": 1}, - {"b": 2}, - {"c": 3}, - {"d": 4} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 4 - for d in dict_list: - assert d in result - - def test_all_duplicates(self): - """Test when all dictionaries are duplicates""" - dict_list = [ - {"a": 1, "b": 2}, - {"a": 1, "b": 2}, - {"a": 1, "b": 2}, - {"b": 2, "a": 1} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 1 - assert result[0] == {"a": 1, "b": 2} - - def test_nested_values(self): - """Test with nested structures as values""" - dict_list = [ - {"a": [1, 2], "b": 3}, - {"a": [1, 2], "b": 3}, - {"a": [1, 3], "b": 3} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - assert {"a": [1, 2], "b": 3} in result - assert {"a": [1, 3], "b": 3} in result - - def test_different_value_types(self): - """Test with different value types""" - dict_list = [ - {"str": "hello", "int": 42, "float": 3.14, "bool": True}, - {"str": "hello", "int": 42, "float": 3.14, "bool": True}, - {"str": "world", "int": 99, "float": 2.71, "bool": False} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - - def test_empty_dicts(self): - """Test with empty dictionaries""" - dict_list: list[Any] = [ - {}, - {}, - {"a": 1} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - assert {} in result - assert {"a": 1} in result - - def test_single_key_dicts(self): - """Test with single key dictionaries""" - dict_list = [ - {"a": 1}, - {"a": 1}, - {"a": 2}, - {"b": 1} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 3 - assert {"a": 1} in result - assert {"a": 2} in result - assert {"b": 1} in result - - def test_many_keys(self): - """Test with dictionaries containing many keys""" - dict1 = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} - dict2 = {"e": 5, "d": 4, "c": 3, "b": 2, "a": 1} # Same, different order - dict3 = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 6} # Different value - dict_list = [dict1, dict2, dict3] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - - def test_numeric_keys(self): - """Test with numeric keys""" - dict_list = [ - {1: "one", 2: "two"}, - {2: "two", 1: "one"}, - {1: "one", 2: "three"} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - - def test_none_values(self): - """Test with None values""" - dict_list = [ - {"a": None, "b": 2}, - {"a": None, "b": 2}, - {"a": 1, "b": None} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - assert {"a": None, "b": 2} in result - assert {"a": 1, "b": None} in result - - def test_mixed_key_types(self): - """Test with mixed key types (string and numeric)""" - dict_list = [ - {"a": 1, 1: "one"}, - {1: "one", "a": 1}, - {"a": 2, 1: "one"} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - - @pytest.mark.parametrize("dict_list,expected_length", [ - ([{"a": 1}, {"a": 1}, {"a": 1}], 1), - ([{"a": 1}, {"a": 2}, {"a": 3}], 3), - ([{"a": 1, "b": 2}, {"b": 2, "a": 1}], 1), - ([{}, {}], 1), - ([{"x": [1, 2]}, {"x": [1, 2]}], 1), - ([{"a": 1}, {"b": 2}, {"c": 3}], 3), - ]) # pyright: ignore[reportUnknownArgumentType] - def test_parametrized_unique_dicts(self, dict_list: list[Any], expected_length: int): - """Test make_unique_list_of_dicts with various input combinations""" - result = make_unique_list_of_dicts(dict_list) - assert len(result) == expected_length - assert isinstance(result, list) - - def test_large_list(self): - """Test with a large list of dictionaries""" - dict_list = [{"id": i % 100, "value": f"val_{i % 100}"} for i in range(1000)] - result = make_unique_list_of_dicts(dict_list) - # Should have 100 unique dicts (0-99) - assert len(result) == 100 - - def test_preserves_last_occurrence(self): - """Test behavior with duplicate entries""" - # The function uses dict comprehension, which keeps last occurrence - dict_list = [ - {"a": 1, "b": 2}, - {"a": 3, "b": 4}, - {"a": 1, "b": 2} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - # Just verify correct unique count, order may vary - - def test_nested_dicts(self): - """Test with nested dictionaries""" - dict_list = [ - {"outer": {"inner": 1}}, - {"outer": {"inner": 1}}, - {"outer": {"inner": 2}} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - - def test_string_values_case_sensitive(self): - """Test that string values are case-sensitive""" - dict_list = [ - {"name": "John"}, - {"name": "john"}, - {"name": "JOHN"}, - {"name": "John"} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 3 - - def test_boolean_values(self): - """Test with boolean values""" - dict_list = [ - {"flag": True, "count": 1}, - {"count": 1, "flag": True}, - {"flag": False, "count": 1} - ] - result = make_unique_list_of_dicts(dict_list) - assert len(result) == 2 - assert {"flag": True, "count": 1} in result - assert {"flag": False, "count": 1} in result - -# __END__ diff --git a/tests/unit/math_handling/__init__.py b/tests/unit/math_handling/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/math_handling/test_math_helpers.py b/tests/unit/math_handling/test_math_helpers.py deleted file mode 100644 index d8a296a..0000000 --- a/tests/unit/math_handling/test_math_helpers.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -Unit tests for math_helpers module -""" - -from corelibs.math_handling.math_helpers import gcd, lcd - - -class TestGcd: - """Test cases for the gcd (Greatest Common Divisor) function""" - - def test_gcd_basic_positive_numbers(self): - """Test GCD with basic positive numbers""" - assert gcd(12, 8) == 4 - assert gcd(15, 10) == 5 - assert gcd(21, 14) == 7 - - def test_gcd_coprime_numbers(self): - """Test GCD with coprime numbers (GCD should be 1)""" - assert gcd(13, 7) == 1 - assert gcd(17, 19) == 1 - assert gcd(25, 49) == 1 - - def test_gcd_same_numbers(self): - """Test GCD with same numbers""" - assert gcd(5, 5) == 5 - assert gcd(100, 100) == 100 - - def test_gcd_with_zero(self): - """Test GCD when one or both numbers are zero""" - assert gcd(0, 5) == 5 - assert gcd(5, 0) == 5 - assert gcd(0, 0) == 0 - - def test_gcd_with_one(self): - """Test GCD when one number is 1""" - assert gcd(1, 5) == 1 - assert gcd(100, 1) == 1 - - def test_gcd_large_numbers(self): - """Test GCD with large numbers""" - assert gcd(1000000, 500000) == 500000 - assert gcd(123456, 789012) == 12 - - def test_gcd_reversed_order(self): - """Test GCD is commutative (order doesn't matter)""" - assert gcd(12, 8) == gcd(8, 12) - assert gcd(100, 35) == gcd(35, 100) - - def test_gcd_negative_numbers(self): - """Test GCD with negative numbers""" - assert gcd(-12, 8) == 4 - assert gcd(12, -8) == 4 - assert gcd(-12, -8) == 4 - - def test_gcd_multiples(self): - """Test GCD when one number is a multiple of the other""" - assert gcd(10, 5) == 5 - assert gcd(100, 25) == 25 - assert gcd(7, 21) == 7 - - -class TestLcd: - """Test cases for the lcd (Least Common Denominator/Multiple) function""" - - def test_lcd_basic_positive_numbers(self): - """Test LCD with basic positive numbers""" - assert lcd(4, 6) == 12 - assert lcd(3, 5) == 15 - assert lcd(12, 8) == 24 - - def test_lcd_coprime_numbers(self): - """Test LCD with coprime numbers (should be their product)""" - assert lcd(7, 13) == 91 - assert lcd(11, 13) == 143 - assert lcd(5, 7) == 35 - - def test_lcd_same_numbers(self): - """Test LCD with same numbers""" - assert lcd(5, 5) == 5 - assert lcd(100, 100) == 100 - - def test_lcd_with_one(self): - """Test LCD when one number is 1""" - assert lcd(1, 5) == 5 - assert lcd(100, 1) == 100 - - def test_lcd_with_zero(self): - """Test LCD when one or both numbers are zero""" - assert lcd(0, 5) == 0 - assert lcd(5, 0) == 0 - assert lcd(0, 0) == 0 - - def test_lcd_large_numbers(self): - """Test LCD with large numbers""" - assert lcd(100, 150) == 300 - assert lcd(1000, 500) == 1000 - - def test_lcd_reversed_order(self): - """Test LCD is commutative (order doesn't matter)""" - assert lcd(4, 6) == lcd(6, 4) - assert lcd(12, 18) == lcd(18, 12) - - def test_lcd_negative_numbers(self): - """Test LCD with negative numbers""" - assert lcd(-4, 6) == 12 - assert lcd(4, -6) == 12 - assert lcd(-4, -6) == 12 - - def test_lcd_multiples(self): - """Test LCD when one number is a multiple of the other""" - assert lcd(5, 10) == 10 - assert lcd(3, 9) == 9 - assert lcd(25, 100) == 100 - - def test_lcd_gcd_relationship(self): - """Test the mathematical relationship between LCD and GCD: lcd(a,b) * gcd(a,b) = a * b""" - test_cases = [(12, 8), (15, 10), (21, 14), (100, 35)] - for a, b in test_cases: - assert lcd(a, b) * gcd(a, b) == a * b - -# __END__