Skip to content

Commit

Permalink
Updated comments and covered all reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
Frank2446-dotcom committed Jan 11, 2025
1 parent 675d7e9 commit 5e555c6
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 14 deletions.
38 changes: 24 additions & 14 deletions solutions/merge_dictionaries.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# solutions/merge_dictionaries.py
"""
This module contains the implementation of the `merge_dictionaries` function.
The `merge_dictionaries` function allows merging two dictionaries into one,
with support for resolving key conflicts through a custom resolution function.
Created on 03 01 2025
@author: Frankline Ambetsa
"""


def merge_dictionaries(dict1, dict2, conflict_resolution=None):
Expand All @@ -18,12 +26,26 @@ def merge_dictionaries(dict1, dict2, conflict_resolution=None):
Returns:
dict: A merged dictionary.
Example:
Raises:
AssertionError: If `dict1` or `dict2` is not a dictionary.
AssertionError: If `conflict_resolution` is not callable when provided.
Examples:
>>> merge_dictionaries({'a': 1}, {'a': 2, 'b': 3})
{'a': 2, 'b': 3}
>>> merge_dictionaries({'a': 1}, {'a': 2, 'b': 3}, max)
{'a': 2, 'b': 3}
>>> merge_dictionaries({'x': 1}, {'y': 2})
{'x': 1, 'y': 2}
"""
# Defensive assertions
assert isinstance(dict1, dict), "dict1 must be a dictionary."
assert isinstance(dict2, dict), "dict2 must be a dictionary."
if conflict_resolution is not None:
assert callable(conflict_resolution), (
"conflict_resolution must be a callable function."
)

merged = dict1.copy() # Start with a copy of the first dictionary

for key, value in dict2.items():
Expand All @@ -35,15 +57,3 @@ def merge_dictionaries(dict1, dict2, conflict_resolution=None):
merged[key] = value

return merged


if __name__ == "__main__":
# Example usage
dict_a = {"x": 1, "y": 2}
dict_b = {"y": 3, "z": 4}

print("Default merge (dict_b overwrites):")
print(merge_dictionaries(dict_a, dict_b))

print("\nMerge with conflict resolution (max value):")
print(merge_dictionaries(dict_a, dict_b, max))
31 changes: 31 additions & 0 deletions solutions/tests/test_merge_dictionaries.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,83 @@
# solutions/tests/test_merge_dictionaries.py

"""
Unit tests for the `merge_dictionaries` function.
These tests ensure correct behavior of the `merge_dictionaries` function,
including standard merging, conflict resolution, edge cases, and input validation.
Created on 03 01 2025
@author: Frankline Ambetsa
"""

import unittest
from solutions.merge_dictionaries import merge_dictionaries


class TestMergeDictionaries(unittest.TestCase):
"""Unit tests for the `merge_dictionaries` function."""

def test_no_conflicts(self):
"""It should merge dictionaries with no conflicting keys."""
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
expected = {"a": 1, "b": 2, "c": 3, "d": 4}
self.assertEqual(merge_dictionaries(dict1, dict2), expected)

def test_overwrite_conflicts(self):
"""It should overwrite conflicting keys with values from dict2."""
dict1 = {"a": 1, "b": 2}
dict2 = {"b": 3, "c": 4}
expected = {"a": 1, "b": 3, "c": 4}
self.assertEqual(merge_dictionaries(dict1, dict2), expected)

def test_conflict_resolution_max(self):
"""It should resolve conflicts using the max function."""
dict1 = {"a": 1, "b": 5}
dict2 = {"b": 3, "c": 4}
expected = {"a": 1, "b": 5, "c": 4}
self.assertEqual(merge_dictionaries(dict1, dict2, max), expected)

def test_conflict_resolution_min(self):
"""It should resolve conflicts using the min function."""
dict1 = {"a": 1, "b": 5}
dict2 = {"b": 3, "c": 4}
expected = {"a": 1, "b": 3, "c": 4}
self.assertEqual(merge_dictionaries(dict1, dict2, min), expected)

def test_empty_dicts(self):
"""It should return an empty dictionary when both inputs are empty."""
dict1 = {}
dict2 = {}
expected = {}
self.assertEqual(merge_dictionaries(dict1, dict2), expected)

def test_one_empty_dict(self):
"""It should return the non-empty dictionary when one input is empty."""
dict1 = {"a": 1, "b": 2}
dict2 = {}
expected = {"a": 1, "b": 2}
self.assertEqual(merge_dictionaries(dict1, dict2), expected)

def test_only_conflicts(self):
"""It should overwrite keys with values from dict2 for conflicting keys."""
dict1 = {"a": 1}
dict2 = {"a": 2}
expected = {"a": 2}
self.assertEqual(merge_dictionaries(dict1, dict2), expected)

def test_non_dict_inputs(self):
"""It should raise a TypeError for non-dictionary inputs."""
with self.assertRaises(AssertionError):
merge_dictionaries([], {"a": 1})
with self.assertRaises(AssertionError):
merge_dictionaries({"a": 1}, 42)

def test_invalid_conflict_resolution(self):
"""It should raise a ValueError for non-callable conflict resolution."""
with self.assertRaises(AssertionError):
merge_dictionaries({"a": 1}, {"a": 2}, conflict_resolution=42)


if __name__ == "__main__":
unittest.main()

0 comments on commit 5e555c6

Please sign in to comment.