import json from pathlib import Path import pytest from app.api.v1 import task_actions from app.core.response import CloverHTTPException from app.services.fission_service import _source_copy_from_payload class _Query: def __init__(self, rows): self._rows = rows def filter(self, *args, **kwargs): return self def all(self): return self._rows def count(self): return len(self._rows) class _Db: def __init__(self, text_rows, image_rows): self._queries = [_Query(text_rows), _Query(image_rows)] def query(self, *args, **kwargs): return self._queries.pop(0) class _Task: id = 7 image_count = 3 def test_submit_review_requires_at_least_one_text_and_one_image(): db = _Db(text_rows=[], image_rows=[]) with pytest.raises(CloverHTTPException) as exc: task_actions._validate_strategy_selection(db, _Task()) assert "请至少选择 1 条文案" in exc.value.biz_message assert "请至少选择 1 张图片" in exc.value.biz_message def test_submit_review_requires_at_least_one_image(): db = _Db(text_rows=[("A",)], image_rows=[]) with pytest.raises(CloverHTTPException) as exc: task_actions._validate_strategy_selection(db, _Task()) assert exc.value.biz_message == "请至少选择 1 张图片" def test_submit_review_requires_at_least_one_text(): db = _Db(text_rows=[], image_rows=[("A", 1)]) with pytest.raises(CloverHTTPException) as exc: task_actions._validate_strategy_selection(db, _Task()) assert exc.value.biz_message == "请至少选择 1 条文案" def test_submit_review_passes_with_one_text_and_one_image(): db = _Db(text_rows=[("B",)], image_rows=[("C", 7)]) task_actions._validate_strategy_selection(db, _Task()) def test_submit_review_does_not_require_all_strategies_or_full_image_count(): db = _Db( text_rows=[("A",)], image_rows=[("B", 4)], ) task_actions._validate_strategy_selection(db, _Task()) def test_fission_source_extracts_copy_body_from_json_candidate(): payload = json.dumps({ "title": "早八伪素颜", "content": "通勤前快速提亮,不卡粉。", "selling_points": ["黄皮友好", "妆感轻"], }, ensure_ascii=False) source = _source_copy_from_payload(payload) assert "早八伪素颜" in source assert "通勤前快速提亮" in source assert "selling_points" not in source assert "{" not in source def test_delivery_status_get_is_read_only_contract(): from app.api.v1 import delivery assert "commit" not in delivery.get_package_download.__code__.co_names assert "commit" not in delivery.download_package_file.__code__.co_names assert "commit" in delivery.mark_package_downloaded.__code__.co_names def test_workspace_switch_response_includes_role_contract(): from app.api.v1 import workspaces constants = workspaces.switch_workspace.__code__.co_consts assert ("current_workspace_id", "role", "token") in constants def test_production_cors_filters_wildcard(): source = Path("main.py").read_text() assert "CORS_ALLOW_ORIGINS" in Path("app/core/config.py").read_text() assert 'origin != "*"' in source assert "allow_origins=_cors_origins()" in source def test_production_rejects_default_seed_password_contract(): source = Path("app/services/auth_service.py").read_text() seed_source = Path("scripts/seed_data.py").read_text() assert 'DEFAULT_SEED_PASSWORD = "Clover2026!"' in source assert 'APP_ENV == "production"' in source assert "默认密码已禁用" in source assert "Production seed requires CLOVER_SEED_PASSWORD" in seed_source