|
1 | 1 | import datetime |
2 | 2 | import json |
| 3 | +from argparse import ArgumentError |
3 | 4 | from pathlib import Path |
4 | 5 | from typing import Any, Literal |
5 | 6 | from unittest.mock import AsyncMock, MagicMock, patch |
@@ -326,3 +327,71 @@ async def test_GenerateOciImageCommand__soft_validate_content_cdx( |
326 | 327 | command._content = CycloneDX1BomWrapper(sbom=cdx_sbom_object) |
327 | 328 | await command._soft_validate_content() |
328 | 329 | mock_logger.warning.assert_called() |
| 330 | + |
| 331 | + |
| 332 | +@pytest.mark.asyncio |
| 333 | +@pytest.mark.parametrize( |
| 334 | + ["syft_boms", "hermeto_bom", "expected_action"], |
| 335 | + [ |
| 336 | + # no SBOMs |
| 337 | + (None, None, "raise_error"), |
| 338 | + # single syft |
| 339 | + ([Path("syft.json")], None, "load_syft"), |
| 340 | + # multiple syft |
| 341 | + ([Path("syft1.json"), Path("syft2.json")], None, "merge"), |
| 342 | + # syft + hermeto |
| 343 | + ([Path("syft.json")], Path("hermeto.json"), "merge"), |
| 344 | + # multiple syft + hermeto |
| 345 | + ([Path("syft1.json"), Path("syft2.json")], Path("hermeto.json"), "merge"), |
| 346 | + # only hermeto |
| 347 | + (None, Path("hermeto.json"), "load_hermeto"), |
| 348 | + ], |
| 349 | +) |
| 350 | +@patch("builtins.open") |
| 351 | +@patch("json.load") |
| 352 | +@patch("mobster.cmd.generate.oci_image.merge_sboms") |
| 353 | +async def test_GenerateOciImageCommand__handle_bom_inputs( |
| 354 | + mock_merge: MagicMock, |
| 355 | + mock_json_load: MagicMock, |
| 356 | + mock_open: MagicMock, |
| 357 | + syft_boms: list[Path] | None, |
| 358 | + hermeto_bom: Path | None, |
| 359 | + expected_action: Literal["raise_error", "load_syft", "load_hermeto", "merge"], |
| 360 | +) -> None: |
| 361 | + command = GenerateOciImageCommand(MagicMock()) |
| 362 | + |
| 363 | + mock_syft_data = {"name": "syft_data"} |
| 364 | + mock_hermeto_data = {"name": "hermeto_data"} |
| 365 | + mock_merged_data = {"name": "merged_data"} |
| 366 | + |
| 367 | + mock_file = MagicMock() |
| 368 | + mock_open.return_value.__enter__.return_value = mock_file |
| 369 | + mock_json_load.side_effect = ( |
| 370 | + lambda _: mock_syft_data if hermeto_bom is None else mock_hermeto_data |
| 371 | + ) |
| 372 | + mock_merge.return_value = mock_merged_data |
| 373 | + |
| 374 | + if expected_action == "raise_error": |
| 375 | + with pytest.raises(ArgumentError): |
| 376 | + command._handle_bom_inputs(syft_boms, hermeto_bom) |
| 377 | + else: |
| 378 | + result = command._handle_bom_inputs(syft_boms, hermeto_bom) |
| 379 | + |
| 380 | + if expected_action == "load_syft": |
| 381 | + assert syft_boms is not None |
| 382 | + assert hermeto_bom is None |
| 383 | + mock_open.assert_called_once() |
| 384 | + assert result == mock_syft_data |
| 385 | + mock_merge.assert_not_called() |
| 386 | + |
| 387 | + elif expected_action == "load_hermeto": |
| 388 | + assert hermeto_bom is not None |
| 389 | + assert syft_boms is None |
| 390 | + mock_open.assert_called_once() |
| 391 | + assert result == mock_hermeto_data |
| 392 | + mock_merge.assert_not_called() |
| 393 | + |
| 394 | + elif expected_action == "merge": |
| 395 | + mock_merge.assert_called_once_with(syft_boms, hermeto_bom) |
| 396 | + assert result == mock_merged_data |
| 397 | + mock_open.assert_not_called() |
0 commit comments