Repository: jameslamb/doppel-cli

Issue:
No uniqueness guarantees on "name" in PackageCollection
`PackageAPI` asks you to provide a "name" for a package dictionary. `PackageCollection` holds multiple instances of `PackageAPI`.

Currently, you can provide multiple `PackageAPI` instances with *the same "name"* to the `PackageCollection` constructor and it won't complain. It should!

To close this issue, add a check in `PackageCollection` and make it throw a fatal error if multiple packages in `pkgs` have the same name.

Comments:

Patch:
diff --git a/doppel/PackageCollection.py b/doppel/PackageCollection.py
index bca655d..f56fe9a 100644
--- a/doppel/PackageCollection.py
+++ b/doppel/PackageCollection.py
@@ -8,6 +8,12 @@ class PackageCollection:
     def __init__(self, packages):
         for pkg in packages:
             assert isinstance(pkg, PackageAPI)
+
+        pkg_names = [pkg.name() for pkg in packages]
+        if (len(set(pkg_names)) < len(packages)):
+            msg = "All packages provided to PackageCollection must have unique names"
+            raise ValueError(msg)
+
         self.pkgs = packages
 
     def package_names(self) -> List[str]:


Test patch:
diff --git a/tests/test_package_collection.py b/tests/test_package_collection.py
index 5a9b668..4f879ce 100644
--- a/tests/test_package_collection.py
+++ b/tests/test_package_collection.py
@@ -97,3 +97,19 @@ class TestPackageAPI(unittest.TestCase):
             sorted(shared["LupeFiasco"]),
             sorted(["~~CONSTRUCTOR~~", "coast"])
         )
+
+    def test_same_names(self):
+        """
+        PackageCollection should reject attempts
+        to add two packages with the same name
+        """
+        self.assertRaisesRegex(
+            ValueError,
+            "All packages provided to PackageCollection must have unique names",
+            lambda: PackageCollection(
+                packages=[
+                    PackageAPI.from_json(self.py_pkg_file),
+                    PackageAPI.from_json(self.py_pkg_file)
+                ]
+            )
+        )
diff --git a/tests/test_reporters.py b/tests/test_reporters.py
index 01e2221..5356494 100644
--- a/tests/test_reporters.py
+++ b/tests/test_reporters.py
@@ -31,6 +31,9 @@ BASE_PACKAGE = {
     "classes": {}
 }
 
+BASE_PACKAGE2 = copy.deepcopy(BASE_PACKAGE)
+BASE_PACKAGE2['name'] = 'pkg2'
+
 # testing different function stuff
 PACKAGE_WITH_DIFFERENT_ARG_NUMBER = copy.deepcopy(BASE_PACKAGE)
 PACKAGE_WITH_DIFFERENT_ARG_NUMBER['name'] = 'pkg2'
@@ -89,6 +92,8 @@ PACKAGE_EMPTY = {
     "functions": {},
     "classes": {}
 }
+PACKAGE_EMPTY2 = copy.deepcopy(PACKAGE_EMPTY)
+PACKAGE_EMPTY2['name'] = 'pkg2'
 
 
 PACKAGE_BEEFY = copy.deepcopy(BASE_PACKAGE)
@@ -108,6 +113,9 @@ for i in range(5):
         }
     }
 
+PACKAGE_BEEFY2 = copy.deepcopy(PACKAGE_BEEFY)
+PACKAGE_BEEFY2['name'] = 'pkg2'
+
 
 class TestSimpleReporter(unittest.TestCase):
 
@@ -206,7 +214,7 @@ class TestSimpleReporter(unittest.TestCase):
         if the shared function is the same in both packages.
         """
         reporter = SimpleReporter(
-            pkgs=[PackageAPI(BASE_PACKAGE), PackageAPI(BASE_PACKAGE)],
+            pkgs=[PackageAPI(BASE_PACKAGE), PackageAPI(BASE_PACKAGE2)],
             errors_allowed=0
         )
         reporter._check_function_args()
@@ -288,7 +296,7 @@ class TestSimpleReporter(unittest.TestCase):
         are totally empty.
         """
         reporter = SimpleReporter(
-            pkgs=[PackageAPI(PACKAGE_EMPTY), PackageAPI(PACKAGE_EMPTY)],
+            pkgs=[PackageAPI(PACKAGE_EMPTY), PackageAPI(PACKAGE_EMPTY2)],
             errors_allowed=0
         )
         reporter._check_function_args()
@@ -319,7 +327,7 @@ class TestSimpleReporter(unittest.TestCase):
         on shared classes and functions)
         """
         reporter = SimpleReporter(
-            pkgs=[PackageAPI(PACKAGE_BEEFY), PackageAPI(PACKAGE_BEEFY)],
+            pkgs=[PackageAPI(PACKAGE_BEEFY), PackageAPI(PACKAGE_BEEFY2)],
             errors_allowed=100
         )