from copy import deepcopy from pathlib import Path from types import SimpleNamespace import pytest from openpyxl.utils.exceptions import InvalidFileException from app.services.agent_asset_spreadsheet import ( COMPANY_TRAVEL_EXPENSE_RULE_CODE, AgentAssetSpreadsheetManager, ) from app.services.expense_rule_runtime import ExpenseRuleRuntimeService from app.services.expense_rule_runtime_models import build_default_expense_rule_catalog def _spreadsheet_asset() -> SimpleNamespace: return SimpleNamespace( code=COMPANY_TRAVEL_EXPENSE_RULE_CODE, config_json={ "detail_mode": "spreadsheet", "rule_document": {"storage_key": "corrupted.xlsx"}, }, current_version="v1.0.0", name="临时损坏规则", ) def _spreadsheet_version() -> SimpleNamespace: return SimpleNamespace(content="", version="v1.0.0") def _assert_unreadable_workbook_is_skipped( monkeypatch: pytest.MonkeyPatch, workbook_path: Path, ) -> None: monkeypatch.setattr( AgentAssetSpreadsheetManager, "resolve_storage_path", lambda _manager, _storage_key: workbook_path, ) catalog = build_default_expense_rule_catalog() default_catalog = deepcopy(catalog) ExpenseRuleRuntimeService(db=None)._apply_spreadsheet_runtime_payload( catalog, asset=_spreadsheet_asset(), version=_spreadsheet_version(), ) assert catalog == default_catalog assert catalog.travel_policy is not None assert catalog.scene_policies def test_corrupted_spreadsheet_is_skipped_without_breaking_default_catalog( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: corrupted_workbook = tmp_path / "corrupted.xlsx" corrupted_workbook.write_bytes(b"not-an-xlsx-archive") _assert_unreadable_workbook_is_skipped(monkeypatch, corrupted_workbook) def test_invalid_spreadsheet_format_is_skipped_without_breaking_catalog( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: invalid_workbook = tmp_path / "invalid.xlsx" invalid_workbook.touch() monkeypatch.setattr( "app.services.expense_rule_runtime.load_workbook", lambda *_args, **_kwargs: (_ for _ in ()).throw( InvalidFileException("unsupported workbook format") ), ) _assert_unreadable_workbook_is_skipped(monkeypatch, invalid_workbook)