|
16 | 16 | # Copyright (c) OWASP Foundation. All Rights Reserved.
|
17 | 17 |
|
18 | 18 |
|
19 |
| -from typing import Callable |
| 19 | +from typing import Callable, Tuple |
20 | 20 | from unittest import TestCase
|
21 | 21 | from uuid import uuid4
|
22 | 22 |
|
@@ -209,3 +209,79 @@ def test_get_component_by_purl(self) -> None:
|
209 | 209 |
|
210 | 210 | self.assertIs(result, setuptools_simple)
|
211 | 211 | self.assertIsNone(bom.get_component_by_purl(get_component_setuptools_simple_no_version().purl))
|
| 212 | + |
| 213 | + @named_data( |
| 214 | + ('none', tuple()), |
| 215 | + # a = anonymous - bom-ref auto-set |
| 216 | + # k = known - has bom-ref.value set |
| 217 | + # d = known duplicate - has bom-ref.value set same as another |
| 218 | + ('A(a), B(a)', ((Component(name='A'), tuple()), |
| 219 | + (Component(name='B'), tuple()))), |
| 220 | + ('A(k), B(k)', ((Component(name='A', bom_ref='A'), tuple()), |
| 221 | + (Component(name='B', bom_ref='B'), tuple()))), |
| 222 | + ('A(a) {A1(a)}, B(a) {B1(a)}', ((Component(name='A'), (Component(name='A1'),)), |
| 223 | + (Component(name='B'), (Component(name='B1'),)))), |
| 224 | + ('A(k) {A1(a)}', ((Component(name='A', bom_ref='A'), (Component(name='1'),)),)), |
| 225 | + ('A(a) {A1(a), A2(a)}', ((Component(name='A'), (Component(name='A1'), Component(name='A2'))),)), |
| 226 | + ('A(a) {A1(k)}', ((Component(name='A'), (Component(name='B', bom_ref='A1'),)),)), |
| 227 | + ('A(k) {A1(k)}', ((Component(name='A', bom_ref='A'), (Component(name='A1', bom_ref='A1'),)),)), |
| 228 | + ('A(d) {A1(d)}', ((Component(name='A', bom_ref='D'), (Component(name='B', bom_ref='D'),)),)), |
| 229 | + ('duplicate name(a)', ((Component(name='A'), tuple()), |
| 230 | + (Component(name='A'), tuple()),)), |
| 231 | + ('duplicate name(k)', ((Component(name='A', bom_ref='A1'), tuple()), |
| 232 | + (Component(name='A', bom_ref='A2'), tuple()))), |
| 233 | + ) |
| 234 | + def test_register_dependency(self, dependencies: Tuple[Tuple[Component, Tuple[Component, ...]], ...]) -> None: |
| 235 | + bom = Bom() |
| 236 | + for d1, d2 in dependencies: |
| 237 | + bom.components.update((d1,), d2) |
| 238 | + bom.register_dependency(d1, d2) |
| 239 | + bom_deps = tuple(bom.dependencies) |
| 240 | + for d1, d2 in dependencies: |
| 241 | + bom_dep = next((bd for bd in bom_deps if bd.ref is d1.bom_ref), None) |
| 242 | + self.assertIsNotNone(bom_dep, f'missing {d1.bom_ref!r} in {bom_deps!r}') |
| 243 | + self.assertEqual(len(d2), len(bom_dep.dependencies)) |
| 244 | + for dd in d2: |
| 245 | + self.assertIn(dd.bom_ref, bom_dep.dependencies_as_bom_refs()) |
| 246 | + |
| 247 | + def test_regression_issue_539(self) -> None: |
| 248 | + """regression test for issue #539 |
| 249 | + see https://github.com/CycloneDX/cyclonedx-python-lib/issues/539 |
| 250 | + """ |
| 251 | + # for showcasing purposes, bom-ref values MUST NOT be set |
| 252 | + bom = Bom() |
| 253 | + bom.metadata.component = root_component = Component( |
| 254 | + name='myApp', |
| 255 | + type=ComponentType.APPLICATION, |
| 256 | + ) |
| 257 | + component1 = Component( |
| 258 | + type=ComponentType.LIBRARY, |
| 259 | + name='some-component', |
| 260 | + ) |
| 261 | + component2 = Component( |
| 262 | + type=ComponentType.LIBRARY, |
| 263 | + name='some-library', |
| 264 | + ) |
| 265 | + component3 = Component( |
| 266 | + type=ComponentType.LIBRARY, |
| 267 | + name='another-library', |
| 268 | + ) |
| 269 | + bom.components.add(component1) |
| 270 | + bom.components.add(component2) |
| 271 | + bom.components.add(component3) |
| 272 | + bom.register_dependency(root_component, [component1]) |
| 273 | + bom.register_dependency(component1, [component2]) |
| 274 | + bom.register_dependency(root_component, [component3]) |
| 275 | + # region assert root_component |
| 276 | + d = next((d for d in bom.dependencies if d.ref is root_component.bom_ref), None) |
| 277 | + self.assertIsNotNone(d, f'missing {root_component.bom_ref!r} in {bom.dependencies!r}') |
| 278 | + self.assertEqual(2, len(d.dependencies)) |
| 279 | + self.assertIn(d.dependencies[0].ref, (component1.bom_ref, component3.bom_ref)) |
| 280 | + self.assertIn(d.dependencies[1].ref, (component1.bom_ref, component3.bom_ref)) |
| 281 | + # endregion assert root_component |
| 282 | + # region assert component1 |
| 283 | + d = next((d for d in bom.dependencies if d.ref is component1.bom_ref), None) |
| 284 | + self.assertIsNotNone(d, f'missing {component1.bom_ref!r} in {bom.dependencies!r}') |
| 285 | + self.assertEqual(1, len(d.dependencies)) |
| 286 | + self.assertIs(component2.bom_ref, d.dependencies[0].ref) |
| 287 | + # endregion assert component1 |
0 commit comments