diff --git a/cat_merge/qc_diff_utils.py b/cat_merge/qc_diff_utils.py index c73db21..01adc76 100644 --- a/cat_merge/qc_diff_utils.py +++ b/cat_merge/qc_diff_utils.py @@ -111,19 +111,30 @@ def diff_type( @validate_diff_args def diff_dict(a: Union[Dict, None], b: Union[Dict, None], flags: Dict) -> Dict: + if a is None or b is None: + change = True + else: + change = False + diff = {} a = {} if a is None else a b = {} if b is None else b - missing = "" - change = False - for key in dict.fromkeys(list(a.keys()), list(b.keys())): + missing = "" + for key in dict.fromkeys(list(a.keys()) + list(b.keys())): if key not in a.keys(): missing = "-" elif key not in b.keys(): missing = "+" - diff_value = diff_type(a.get(key), b.get(key), flags) - if flags["change"] or flags["show_all"]: + + if a.get(key) is None and b.get(key) is None: + diff_value = None + if not (key in a.keys() and key in b.keys()): + flags['change'] = True + else: + diff_value = diff_type(a.get(key), b.get(key), flags) + + if flags["change"] or flags["show_all"] or missing != "": diff[missing + key] = diff_value change = any([change, flags["change"]]) flags["change"] = False @@ -137,6 +148,12 @@ def diff_list(a: Union[List, None], b: Union[List, None], flags: Dict) -> List: diff = [] a = [] if a is None else a b = [] if b is None else b + + # Check if either list contains a list + if any(isinstance(n, list) and len(n) == 0 for n in a + b): + message = "diff_list: found list containing list, structure not supported." + raise NotImplementedError(message) + a_as_keys = dict(zip(a, a)) b_as_keys = dict(zip(b, b)) @@ -230,6 +247,11 @@ def sources_dict(a: Union[Dict, List[Dict]]) -> Dict: case None: pass case list(): + if not all(isinstance(x, dict) for x in a): + # all list entries must be dict + message = "sources_dict: List contains non-dict entries, aborting" + raise ValueError(message) + for i in a: if i.get("name") is not None: a_dict[i.get("name")] = i diff --git a/tests/test_utils.py b/tests/test_utils.py index ea298df..8cc5260 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -20,10 +20,12 @@ def value(df: DataFrame, id: str, column: str): def flags_params(): - params = {"change_T_show_T": {"change": True, "show_all": True}, - "change_F_show_T": {"change": False, "show_all": True}, - "change_T_show_F": {"change": True, "show_all": False}, - "change_F_show_F": {"change": False, "show_all": False}} + params = { + # "change_T_show_T": {"change": True, "show_all": True}, + "change_F_show_T": {"change": False, "show_all": True}, + # "change_T_show_F": {"change": True, "show_all": False}, + "change_F_show_F": {"change": False, "show_all": False}, + } return copy.deepcopy(params) diff --git a/tests/unit/test_diff_dict.py b/tests/unit/test_diff_dict.py new file mode 100644 index 0000000..caff6ff --- /dev/null +++ b/tests/unit/test_diff_dict.py @@ -0,0 +1,105 @@ +import pytest +from tests.test_utils import * +from cat_merge.qc_diff_utils import diff_dict +from typing import Dict + + +@pytest.fixture +def dict1() -> Dict: + return {'item1': None, 'item7': 'item7', 'item2': 'item2'} + + +def test_diff_dict_none(dict1, flags): + assert diff_dict(None, dict1, flags) == {'-item1': None, '-item7': '-item7', '-item2': '-item2'} + assert flags["change"] is True + flags['change'] = False + + assert diff_dict(dict1, None, flags) == {'+item1': None, '+item7': '+item7', '+item2': '+item2'} + assert flags["change"] is True + + +@pytest.fixture +def dict1_copy() -> Dict: + return {'item1': None, 'item7': 'item7', 'item2': 'item2'} + + +def test_diff_dict_match(dict1, dict1_copy, flags): + if flags["show_all"]: + assert diff_dict(dict1, dict1_copy, flags) == {'item1': None, 'item7': 'item7', 'item2': 'item2'} + assert flags["change"] is False + assert diff_dict(dict1_copy, dict1, flags) == {'item1': None, 'item7': 'item7', 'item2': 'item2'} + assert flags["change"] is False + else: + assert diff_dict(dict1, dict1_copy, flags) == dict() + assert flags["change"] is False + assert diff_dict(dict1_copy, dict1, flags) == dict() + assert flags["change"] is False + + +@pytest.fixture +def empty_dict() -> Dict: + return dict() + + +def test_diff_dict_empty(empty_dict, dict1, flags): + assert diff_dict(None, empty_dict, flags) == dict() + assert flags["change"] is True + flags['change'] = False + + assert diff_dict(empty_dict, None, flags) == dict() + assert flags["change"] is True + flags['change'] = False + + assert diff_dict(empty_dict, dict1, flags) == {'-item1': None, '-item7': '-item7', '-item2': '-item2'} + assert flags["change"] is True + flags['change'] = False + + assert diff_dict(dict1, empty_dict, flags) == {'+item1': None, '+item7': '+item7', '+item2': '+item2'} + assert flags["change"] is True + flags['change'] = False + + +@pytest.fixture +def dict_val_none() -> Dict: + return {"one": None} + + +def test_diff_dict_val_none(dict_val_none, empty_dict, flags): + assert diff_dict(dict_val_none, empty_dict, flags) == {"+one": None} + assert flags['change'] is True + flags["change"] = False + + assert diff_dict(empty_dict, dict_val_none, flags) == {"-one": None} + assert flags['change'] is True + flags["change"] = False + + assert diff_dict(None, dict_val_none, flags) == {"-one": None} + assert flags['change'] is True + flags["change"] = False + + assert diff_dict(dict_val_none, None, flags) == {"+one": None} + assert flags['change'] is True + flags["change"] = False + + +@pytest.fixture +def dict2() -> Dict: + return {'item7': 'item7', 'item1': None, 'item3': 'item3'} + + +def test_diff_dict_partial_match(dict1, dict2, flags): + if flags["show_all"]: + assert diff_dict(dict1, dict2, flags) == \ + {'item1': None, 'item7': 'item7', '+item2': '+item2', '-item3': '-item3'} + assert flags["change"] is True + + flags["change"] = False + assert list(diff_dict(dict1, dict2, flags).keys()) == ['item1', 'item7', '+item2', '-item3'] + assert flags["change"] is True + else: + assert diff_dict(dict1, dict2, flags) == {'+item2': '+item2', '-item3': '-item3'} + assert flags["change"] is True + + flags["change"] = False + assert list(diff_dict(dict1, dict2, flags).keys()) == ['+item2', '-item3'] + assert flags["change"] is True diff --git a/tests/unit/test_diff_type.py b/tests/unit/test_diff_type.py index fe3dbea..7bc3a48 100644 --- a/tests/unit/test_diff_type.py +++ b/tests/unit/test_diff_type.py @@ -1,6 +1,6 @@ from tests.test_utils import * from cat_merge.qc_diff_utils import diff_type -from typing import List +from typing import List, Dict @pytest.fixture @@ -18,12 +18,16 @@ def test_diff_type_str(str1, str2, flags): assert diff_type(str1, str1, flags) == "str1" else: assert diff_type(str1, str1, flags) is None - assert flags["change"] is False + assert flags['change'] is False assert diff_type(None, str1, flags) == "-str1" assert flags["change"] is True + + flags['change'] = False assert diff_type(str1, None, flags) == "+str1" assert flags["change"] is True + + flags['change'] = False assert diff_type(str1, str2, flags) == ["+str1", "-str2"] assert flags["change"] is True @@ -47,66 +51,140 @@ def test_diff_type_int(int1, int2, flags): assert diff_type(None, int1, flags) == "-0" assert flags["change"] is True + + flags['change'] = False assert diff_type(int1, None, flags) == "+0" assert flags["change"] is True + + flags['change'] = False assert diff_type(int1, int2, flags) == {"change": -10, "new": 0, "old": 10} assert flags["change"] is True -# @pytest.fixture -# def empty_dict() -> Dict: -# return dict() -# -# -# @pytest.fixture -# def dict_of_none() -> Dict: -# return {"one": None} -# -# -# def test_diff_type_dict(empty_dict, dict_of_none): -# assert diff_type(empty_dict, empty_dict) == dict() -# -# -# def test_diff_type_dict_of_none(dict_of_none): -# assert diff_type(dict_of_none) == {"one": None} -# -# -# @pytest.fixture -# def dict_of_str() -> Dict: -# return {"one": ""} -# -# -# def test_diff_type_dict_of_str(dict_of_str): -# assert diff_type(dict_of_str) == {"one": None} -# -# -# @pytest.fixture -# def dict_of_int() -> Dict: -# return {"one": 0} -# -# -# def test_diff_type_dict_of_int(dict_of_int): -# assert diff_type(dict_of_int) == {"one": None} -# -# -# @pytest.fixture -# def dict_of_list() -> Dict: -# return {"one": []} -# -# -# def test_diff_type_dict_of_list(dict_of_list): -# assert diff_type(dict_of_list) == {"one": []} -# -# -# @pytest.fixture -# def dict_of_dict() -> Dict: -# return {"one": {}} -# -# -# def test_diff_type_dict_of_dict(dict_of_dict): -# assert diff_type(dict_of_dict) == {"one": {}} -# -# +@pytest.fixture +def empty_dict() -> Dict: + return dict() + + +def test_diff_type_dict_empty(empty_dict, flags): + assert diff_type(None, empty_dict, flags) == dict() + assert flags['change'] is True + flags["change"] = False + + assert diff_type(empty_dict, None, flags) == dict() + assert flags['change'] is True + flags["change"] = False + + assert diff_type(empty_dict, empty_dict, flags) == dict() + assert flags['change'] is False + + +@pytest.fixture +def dict_of_none() -> Dict: + return {'one': None} + + +def test_diff_type_dict_none(dict_of_none, empty_dict, flags): + assert diff_type(None, dict_of_none, flags) == {'-one': None} + assert flags['change'] is True + flags['change'] = False + + assert diff_type(dict_of_none, None, flags) == {'+one': None} + assert flags['change'] is True + flags['change'] = False + + if flags['show_all']: + assert diff_type(dict_of_none, dict_of_none, flags) == {'one': None} + else: + assert diff_type(dict_of_none, dict_of_none, flags) == dict() + assert flags['change'] is False + + assert diff_type(empty_dict, dict_of_none, flags) == {"-one": None} + assert flags['change'] is True + + flags['change'] = False + assert diff_type(dict_of_none, empty_dict, flags) == {"+one": None} + assert flags['change'] is True + + +@pytest.fixture +def dict_of_empty_str() -> Dict: + return {'one': ''} + + +def test_diff_type_dict_of_empty_str(dict_of_empty_str, flags): + if flags['show_all']: + assert diff_type(dict_of_empty_str, dict_of_empty_str, flags) == {'one': ''} + else: + assert diff_type(dict_of_empty_str, dict_of_empty_str, flags) == dict() + assert flags['change'] is False + + assert diff_type(None, dict_of_empty_str, flags) == {'-one': '-'} + assert flags['change'] is True + flags['change'] = False + + assert diff_type(dict_of_empty_str, None, flags) == {'+one': '+'} + assert flags['change'] is True + + +@pytest.fixture +def dict_of_int() -> Dict: + return {'one': 0} + + +def test_diff_type_dict_of_int(dict_of_int, flags): + if flags['show_all']: + assert diff_type(dict_of_int, dict_of_int, flags) == {'one': 0} + else: + assert diff_type(dict_of_int, dict_of_int, flags) == dict() + assert flags['change'] is False + + assert diff_type(None, dict_of_int, flags) == {'-one': '-0'} + assert flags['change'] is True + + flags['change'] = False + assert diff_type(dict_of_int, None, flags) == {'+one': '+0'} + assert flags['change'] is True + + +@pytest.fixture +def dict_of_empty_list() -> Dict: + return {"one": []} + + +def test_diff_type_dict_of_empty_list(dict_of_empty_list, flags): + if flags['show_all']: + assert diff_type(dict_of_empty_list, dict_of_empty_list, flags) == {"one": []} + else: + assert diff_type(dict_of_empty_list, dict_of_empty_list, flags) == {} + assert flags["change"] is False + + assert diff_type(None, dict_of_empty_list, flags) == {"-one": []} + assert flags["change"] is True + + flags["change"] = False + assert diff_type(dict_of_empty_list, None, flags) == {"+one": []} + assert flags["change"] is True + + +@pytest.fixture +def dict_of_empty_dict() -> Dict: + return {"one": {}} + + +def test_diff_type_dict_of_empty_dict(dict_of_empty_dict, flags): + if flags['show_all']: + assert diff_type(dict_of_empty_dict, dict_of_empty_dict, flags) == {"one": {}} + else: + assert diff_type(dict_of_empty_dict, dict_of_empty_dict, flags) == {} + assert flags['change'] is False + + assert diff_type(None, dict_of_empty_dict, flags) == {"-one": {}} + assert flags['change'] is True + + flags['change'] = False + assert diff_type(dict_of_empty_dict, None, flags) == {"+one": {}} + assert flags['change'] is True @pytest.fixture @@ -123,37 +201,73 @@ def test_diff_type_list(empty_list, flags): assert flags["change"] is False -# @pytest.fixture -# def list_of_str() -> List: -# return [""] -# -# -# def test_diff_type_list_of_str(list_of_str): -# assert diff_type(list_of_str) == [] -# -# -# @pytest.fixture -# def list_of_int() -> List: -# return [0] -# -# -# def test_diff_type_list_of_int(list_of_int): -# assert diff_type(list_of_int) == [] -# -# -# @pytest.fixture -# def list_of_dict() -> List[Dict]: -# return [{}] -# -# -# def test_diff_type_list_of_dict(list_of_dict): -# assert diff_type(list_of_dict) == [{}] -# -# -# @pytest.fixture -# def list_of_list() -> List[List]: -# return [[]] -# -# -# def test_diff_type_list_of_list(list_of_list): -# assert diff_type(list_of_list) == [[]] +@pytest.fixture +def list_of_str() -> List: + return [''] + + +def test_diff_type_list_of_str(list_of_str, flags): + if flags['show_all']: + assert diff_type(list_of_str, list_of_str, flags) == [''] + else: + assert diff_type(list_of_str, list_of_str, flags) == [] + + assert diff_type(None, list_of_str, flags) == ['-'] + assert flags['change'] is True + + flags['change'] = False + assert diff_type(list_of_str, None, flags) == ['+'] + assert flags['change'] is True + + +@pytest.fixture +def list_of_int() -> List: + return [0] + + +def test_diff_type_list_of_int(list_of_int, flags): + if flags['show_all']: + assert diff_type(list_of_int, list_of_int, flags) == [0] + else: + assert diff_type(list_of_int, list_of_int, flags) == [] + assert flags['change'] is False + + assert diff_type(None, list_of_int, flags) == ['-0'] + assert flags['change'] is True + + flags['change'] = False + assert diff_type(list_of_int, None, flags) == ['+0'] + assert flags['change'] is True + + +@pytest.fixture +def list_of_empty_dict() -> List[Dict]: + return [{}] + + +def test_diff_type_list_of_dict(list_of_empty_dict, flags): + with pytest.raises(NotImplementedError): + assert diff_type(list_of_empty_dict, list_of_empty_dict, flags) + + with pytest.raises(NotImplementedError): + assert diff_type(None, list_of_empty_dict, flags) + + with pytest.raises(NotImplementedError): + assert diff_type(list_of_empty_dict, None, flags) + + +@pytest.fixture +def list_of_list() -> List[List]: + return [[]] + + +def test_diff_type_list_of_list(list_of_list, flags): + with pytest.raises(NotImplementedError): + assert diff_type(list_of_list, list_of_list, flags) + + with pytest.raises(NotImplementedError): + assert diff_type(None, list_of_list, flags) + + with pytest.raises(NotImplementedError): + assert diff_type(list_of_list, None, flags) + diff --git a/tests/unit/test_sources_dict.py b/tests/unit/test_sources_dict.py new file mode 100644 index 0000000..39a984c --- /dev/null +++ b/tests/unit/test_sources_dict.py @@ -0,0 +1,79 @@ +import pytest +from tests.test_utils import * +from cat_merge.qc_diff_utils import sources_dict +from typing import Dict, List + + +@pytest.fixture +def empty_dict() -> Dict: + return {} + + +def test_sources_dict_empty_dict(empty_dict): + assert sources_dict(empty_dict) == {} + + +@pytest.fixture +def empty_list() -> List: + return list() + + +def test_sources_dict_empty_list(empty_list): + assert sources_dict(empty_list) == {} + + +@pytest.fixture +def list_dict_name() -> List: + return [{'name': 'name'}] + + +def test_sources_dict_list_dict_name(list_dict_name): + assert sources_dict(list_dict_name) == {'name': {'name': 'name'}} + + +@pytest.fixture +def list_dict_uri() -> List: + return [{'uri': 'uri'}] + + +def test_sources_dict_list_dict_uri(list_dict_uri): + assert sources_dict(list_dict_uri) == {'uri': {'uri': 'uri'}} + + +@pytest.fixture +def list_dict_name_uri() -> List: + return [{'name': 'name', 'uri': 'uri'}] + + +def test_sources_dict_list_dict_name_uri(list_dict_name_uri): + assert sources_dict(list_dict_name_uri) == {'name': {'name': 'name', 'uri': 'uri'}} + + +@pytest.fixture +def list_dict_other() -> List: + return [{'other': 'other'}] + + +def test_sources_dict_list_dict_other(list_dict_other): + with pytest.raises(NotImplementedError): + assert sources_dict(list_dict_other) + + +@pytest.fixture +def list_wrong_type() -> List: + return [''] + + +def test_sources_dict_list_wrong_type(list_wrong_type): + with pytest.raises(ValueError): + assert sources_dict(list_wrong_type) + + +@pytest.fixture +def wrong_type() -> str: + return '' + + +def test_sources_dict_wrong_type(wrong_type): + with pytest.raises(TypeError): + assert sources_dict(wrong_type)