From a0b3f63b8a999219da3aefa0a73c44bfc7875201 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Thu, 23 Jul 2026 19:57:16 +0800 Subject: [PATCH] =?UTF-8?q?test(p3-1):=20wave31=20=E7=B4=A0=E6=9D=90?= =?UTF-8?q?=E5=BA=93+=E7=B4=A0=E6=9D=90UseCase=E5=8D=95=E6=B5=8B20?= =?UTF-8?q?=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/unit/test_asset_library_use_cases.py | 342 +++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100755 tests/unit/test_asset_library_use_cases.py diff --git a/tests/unit/test_asset_library_use_cases.py b/tests/unit/test_asset_library_use_cases.py new file mode 100755 index 000000000..2fa9be82e --- /dev/null +++ b/tests/unit/test_asset_library_use_cases.py @@ -0,0 +1,342 @@ +"""素材库 + 素材 UseCase 单元测试(P3-1 第31波)。""" +from __future__ import annotations + +from unittest.mock import MagicMock + +import pytest + +from packages.application.asset_libraries import ( + CreateAssetLibraryCommand, + CreateAssetLibraryUseCase, + ListAssetLibrariesUseCase, +) +from packages.application.assets import ( + CreateAssetCommand, + CreateAssetUseCase, + ListAssetsUseCase, +) +from packages.domain import AssetLibraryKind, AssetStatus, ClassificationStatus + + +# ── ListAssetLibrariesUseCase ──────────────────────────────────────────────── + + +class TestListAssetLibrariesUseCase: + """ListAssetLibrariesUseCase 单元测试。""" + + def test_list_libraries_success(self): + """正常列出项目素材库。""" + mock_repo = MagicMock() + mock_repo.find_by_project.return_value = ["lib1", "lib2"] + use_case = ListAssetLibrariesUseCase(mock_repo) + + result = use_case.execute("proj_001") + + assert result == ["lib1", "lib2"] + mock_repo.find_by_project.assert_called_once_with("proj_001") + + def test_list_libraries_empty(self): + """项目无素材库返回空列表。""" + mock_repo = MagicMock() + mock_repo.find_by_project.return_value = [] + use_case = ListAssetLibrariesUseCase(mock_repo) + + result = use_case.execute("proj_001") + + assert result == [] + + def test_list_libraries_empty_project_id_raises(self): + """空 project_id 抛 ValueError。""" + mock_repo = MagicMock() + use_case = ListAssetLibrariesUseCase(mock_repo) + + with pytest.raises(ValueError, match="project_id 不能为空"): + use_case.execute("") + + def test_list_libraries_whitespace_project_id_raises(self): + """全空格 project_id 抛 ValueError。""" + mock_repo = MagicMock() + use_case = ListAssetLibrariesUseCase(mock_repo) + + with pytest.raises(ValueError, match="project_id 不能为空"): + use_case.execute(" ") + + def test_list_libraries_project_id_stripped(self): + """project_id 首尾空格被清理。""" + mock_repo = MagicMock() + mock_repo.find_by_project.return_value = [] + use_case = ListAssetLibrariesUseCase(mock_repo) + + use_case.execute(" proj_001 ") + + mock_repo.find_by_project.assert_called_once_with("proj_001") + + +# ── CreateAssetLibraryUseCase ──────────────────────────────────────────────── + + +class TestCreateAssetLibraryUseCase: + """CreateAssetLibraryUseCase 单元测试。""" + + def test_create_video_library_success(self): + """正常创建视频素材库。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetLibraryUseCase(mock_repo) + command = CreateAssetLibraryCommand( + project_id="proj_001", + name="我的视频", + kind=AssetLibraryKind.VIDEO, + ) + + result = use_case.execute(command) + + assert result.project_id == "proj_001" + assert result.name == "我的视频" + assert result.kind == AssetLibraryKind.VIDEO + mock_repo.create.assert_called_once() + + def test_create_audio_library_success(self): + """创建音频素材库。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetLibraryUseCase(mock_repo) + command = CreateAssetLibraryCommand( + project_id="proj_001", + name="配乐库", + kind=AssetLibraryKind.VOICE, + ) + + result = use_case.execute(command) + + assert result.kind == AssetLibraryKind.VOICE + assert result.asset_count == 0 + assert result.total_size == 0 + + def test_create_image_library_success(self): + """创建图片素材库。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetLibraryUseCase(mock_repo) + command = CreateAssetLibraryCommand( + project_id="proj_001", + name="图片素材", + kind=AssetLibraryKind.IMAGE, + ) + + result = use_case.execute(command) + + assert result.kind == AssetLibraryKind.IMAGE + + def test_create_library_name_stripped(self): + """素材库名称首尾空格被清理。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetLibraryUseCase(mock_repo) + command = CreateAssetLibraryCommand( + project_id="proj_001", + name=" 我的素材库 ", + kind=AssetLibraryKind.VIDEO, + ) + + result = use_case.execute(command) + + assert result.name == "我的素材库" + + +# ── ListAssetsUseCase ──────────────────────────────────────────────────────── + + +class TestListAssetsUseCase: + """ListAssetsUseCase 单元测试。""" + + def test_list_assets_success(self): + """正常列出素材库素材。""" + mock_repo = MagicMock() + mock_repo.find_by_library.return_value = ["asset1", "asset2"] + use_case = ListAssetsUseCase(mock_repo) + + result = use_case.execute("lib_001") + + assert result == ["asset1", "asset2"] + mock_repo.find_by_library.assert_called_once_with("lib_001") + + def test_list_assets_empty(self): + """素材库为空返回空列表。""" + mock_repo = MagicMock() + mock_repo.find_by_library.return_value = [] + use_case = ListAssetsUseCase(mock_repo) + + result = use_case.execute("lib_001") + + assert result == [] + + def test_list_assets_empty_library_id_raises(self): + """空 library_id 抛 ValueError。""" + mock_repo = MagicMock() + use_case = ListAssetsUseCase(mock_repo) + + with pytest.raises(ValueError, match="library_id 不能为空"): + use_case.execute("") + + def test_list_assets_whitespace_library_id_raises(self): + """全空格 library_id 抛 ValueError。""" + mock_repo = MagicMock() + use_case = ListAssetsUseCase(mock_repo) + + with pytest.raises(ValueError, match="library_id 不能为空"): + use_case.execute(" ") + + def test_list_assets_library_id_stripped(self): + """library_id 首尾空格被清理。""" + mock_repo = MagicMock() + mock_repo.find_by_library.return_value = [] + use_case = ListAssetsUseCase(mock_repo) + + use_case.execute(" lib_001 ") + + mock_repo.find_by_library.assert_called_once_with("lib_001") + + +# ── CreateAssetUseCase ────────────────────────────────────────────────────── + + +class TestCreateAssetUseCase: + """CreateAssetUseCase 单元测试。""" + + def test_create_video_asset_success(self): + """正常创建视频素材。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetUseCase(mock_repo) + command = CreateAssetCommand( + project_id="proj_001", + library_id="lib_001", + name="video.mp4", + storage_key="assets/video.mp4", + mime_type="video/mp4", + file_size=1024000, + duration=30.5, + width=1920, + height=1080, + fps=25.0, + codec="h264", + ) + + result = use_case.execute(command) + + assert result.name == "video.mp4" + assert result.project_id == "proj_001" + assert result.library_id == "lib_001" + assert result.storage_key == "assets/video.mp4" + assert result.mime_type == "video/mp4" + assert result.file_size == 1024000 + assert result.duration == 30.5 + assert result.width == 1920 + assert result.height == 1080 + assert result.fps == 25.0 + assert result.codec == "h264" + assert result.status == AssetStatus.UPLOADING + assert result.classification_status == ClassificationStatus.PENDING + mock_repo.create.assert_called_once() + + def test_create_audio_asset_success(self): + """创建音频素材。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetUseCase(mock_repo) + command = CreateAssetCommand( + project_id="proj_001", + library_id="lib_002", + name="bgm.mp3", + storage_key="audio/bgm.mp3", + mime_type="audio/mpeg", + file_size=512000, + duration=180.0, + ) + + result = use_case.execute(command) + + assert result.mime_type == "audio/mpeg" + assert result.duration == 180.0 + assert result.width is None + assert result.height is None + + def test_create_asset_default_status(self): + """默认状态为 UPLOADING + PENDING。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetUseCase(mock_repo) + command = CreateAssetCommand( + project_id="proj_001", + library_id="lib_001", + name="test.mp4", + storage_key="test.mp4", + mime_type="video/mp4", + ) + + result = use_case.execute(command) + + assert result.status == AssetStatus.UPLOADING + assert result.classification_status == ClassificationStatus.PENDING + + def test_create_asset_custom_status(self): + """可以指定自定义状态。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetUseCase(mock_repo) + command = CreateAssetCommand( + project_id="proj_001", + library_id="lib_001", + name="test.mp4", + storage_key="test.mp4", + mime_type="video/mp4", + status=AssetStatus.READY, + classification_status=ClassificationStatus.COMPLETED, + quality_score=85.5, + uploaded_by_user_id="user_001", + ) + + result = use_case.execute(command) + + assert result.status == AssetStatus.READY + assert result.classification_status == ClassificationStatus.COMPLETED + assert result.quality_score == 85.5 + assert result.uploaded_by_user_id == "user_001" + + def test_create_asset_with_metadata(self): + """带 metadata 创建素材。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetUseCase(mock_repo) + metadata = {"location": "beijing", "camera": "sony"} + command = CreateAssetCommand( + project_id="proj_001", + library_id="lib_001", + name="test.mp4", + storage_key="test.mp4", + mime_type="video/mp4", + metadata=metadata, + ) + + result = use_case.execute(command) + + assert result.metadata == metadata + + def test_create_asset_with_thumbnail(self): + """带缩略图创建素材。""" + mock_repo = MagicMock() + mock_repo.create.side_effect = lambda x: x + use_case = CreateAssetUseCase(mock_repo) + command = CreateAssetCommand( + project_id="proj_001", + library_id="lib_001", + name="test.mp4", + storage_key="test.mp4", + mime_type="video/mp4", + thumbnail_url="http://cdn.com/thumb.jpg", + ) + + result = use_case.execute(command) + + assert result.thumbnail_url == "http://cdn.com/thumb.jpg"