"""Assets UseCase 单元测试.""" from __future__ import annotations from unittest.mock import MagicMock import pytest from packages.application.assets import ( CreateAssetCommand, CreateAssetUseCase, ListAssetsUseCase, ) from packages.domain import Asset, AssetStatus, ClassificationStatus @pytest.fixture def mock_asset_repo(): return MagicMock() @pytest.fixture def sample_asset(): asset = Asset.create( project_id="proj_001", library_id="lib_001", name="test_video.mp4", storage_key="videos/test.mp4", mime_type="video/mp4", file_size=1024000, duration=15.5, width=1920, height=1080, ) asset.id = "asset_001" return asset class TestListAssetsUseCase: """ListAssetsUseCase 测试""" def test_list_returns_repo_results(self, mock_asset_repo, sample_asset): """正常返回 repository 的查询结果""" mock_asset_repo.find_by_library.return_value = [sample_asset] use_case = ListAssetsUseCase(mock_asset_repo) result = use_case.execute("lib_001") assert len(result) == 1 assert result[0].id == "asset_001" mock_asset_repo.find_by_library.assert_called_once_with("lib_001") def test_empty_library_id_raises_value_error(self, mock_asset_repo): """空 library_id 抛出 ValueError""" use_case = ListAssetsUseCase(mock_asset_repo) with pytest.raises(ValueError, match="library_id 不能为空"): use_case.execute("") mock_asset_repo.find_by_library.assert_not_called() def test_whitespace_library_id_raises_value_error(self, mock_asset_repo): """纯空格 library_id 抛出 ValueError""" use_case = ListAssetsUseCase(mock_asset_repo) with pytest.raises(ValueError, match="library_id 不能为空"): use_case.execute(" ") mock_asset_repo.find_by_library.assert_not_called() def test_library_id_stripped_before_query(self, mock_asset_repo, sample_asset): """library_id 会被 strip 后再查询""" mock_asset_repo.find_by_library.return_value = [sample_asset] use_case = ListAssetsUseCase(mock_asset_repo) use_case.execute(" lib_001 ") mock_asset_repo.find_by_library.assert_called_once_with("lib_001") def test_empty_list(self, mock_asset_repo): """素材库为空时返回空列表""" mock_asset_repo.find_by_library.return_value = [] use_case = ListAssetsUseCase(mock_asset_repo) result = use_case.execute("lib_001") assert result == [] mock_asset_repo.find_by_library.assert_called_once_with("lib_001") class TestCreateAssetUseCase: """CreateAssetUseCase 测试""" def test_create_asset_success(self, mock_asset_repo): """正常创建素材""" mock_asset_repo.create.side_effect = lambda a: a use_case = CreateAssetUseCase(mock_asset_repo) command = CreateAssetCommand( project_id="proj_001", library_id="lib_001", name="test.png", storage_key="images/test.png", mime_type="image/png", file_size=512000, ) result = use_case.execute(command) assert result.name == "test.png" assert result.library_id == "lib_001" assert result.mime_type == "image/png" assert result.status == AssetStatus.UPLOADING assert result.classification_status == ClassificationStatus.PENDING mock_asset_repo.create.assert_called_once() def test_create_asset_with_metadata(self, mock_asset_repo): """创建带 metadata 的素材""" mock_asset_repo.create.side_effect = lambda a: a use_case = CreateAssetUseCase(mock_asset_repo) command = CreateAssetCommand( project_id="proj_001", library_id="lib_001", name="test.mp3", storage_key="audio/test.mp3", mime_type="audio/mpeg", metadata={"bitrate": 320, "sample_rate": 44100}, duration=180.0, ) result = use_case.execute(command) assert result.metadata["bitrate"] == 320 assert result.duration == 180.0 def test_create_asset_with_quality_score(self, mock_asset_repo): """创建带质量分的素材""" mock_asset_repo.create.side_effect = lambda a: a use_case = CreateAssetUseCase(mock_asset_repo) command = CreateAssetCommand( project_id="proj_001", library_id="lib_001", name="high_quality.mp4", storage_key="videos/hq.mp4", mime_type="video/mp4", quality_score=95.5, uploaded_by_user_id="user_001", ) result = use_case.execute(command) assert result.quality_score == 95.5 assert result.uploaded_by_user_id == "user_001" def test_create_asset_custom_status(self, mock_asset_repo): """创建时指定自定义状态""" mock_asset_repo.create.side_effect = lambda a: a use_case = CreateAssetUseCase(mock_asset_repo) command = CreateAssetCommand( project_id="proj_001", library_id="lib_001", name="ready.mp4", storage_key="videos/ready.mp4", mime_type="video/mp4", status=AssetStatus.READY, classification_status=ClassificationStatus.COMPLETED, ) result = use_case.execute(command) assert result.status == AssetStatus.READY assert result.classification_status == ClassificationStatus.COMPLETED def test_create_asset_with_video_info(self, mock_asset_repo): """创建带视频参数的素材""" mock_asset_repo.create.side_effect = lambda a: a use_case = CreateAssetUseCase(mock_asset_repo) command = CreateAssetCommand( project_id="proj_001", library_id="lib_001", name="video.mp4", storage_key="videos/v.mp4", mime_type="video/mp4", width=1920, height=1080, fps=30.0, codec="h264", duration=60.0, thumbnail_url="https://cdn.example.com/thumb.jpg", ) result = use_case.execute(command) assert result.width == 1920 assert result.height == 1080 assert result.fps == 30.0 assert result.codec == "h264" assert result.thumbnail_url == "https://cdn.example.com/thumb.jpg"