|
7 | 7 | import json |
8 | 8 | from collections.abc import Callable |
9 | 9 | from pathlib import Path |
| 10 | +from typing import Any, cast |
10 | 11 |
|
11 | 12 | import pytest |
12 | 13 |
|
@@ -225,6 +226,16 @@ def test_baseline_load_legacy_payload(tmp_path: Path) -> None: |
225 | 226 | assert exc.value.status == "missing_fields" |
226 | 227 |
|
227 | 228 |
|
| 229 | +def test_baseline_load_rejects_non_object_preloaded_payload(tmp_path: Path) -> None: |
| 230 | + baseline_path = tmp_path / "baseline.json" |
| 231 | + _write_payload(baseline_path, _trusted_payload()) |
| 232 | + baseline = Baseline(baseline_path) |
| 233 | + |
| 234 | + with pytest.raises(BaselineValidationError, match="must be an object") as exc: |
| 235 | + baseline.load(preloaded_payload=cast(Any, [])) |
| 236 | + assert exc.value.status == "invalid_type" |
| 237 | + |
| 238 | + |
228 | 239 | def test_baseline_load_missing_top_level_key(tmp_path: Path) -> None: |
229 | 240 | baseline_path = tmp_path / "baseline.json" |
230 | 241 | _write_payload(baseline_path, {"meta": {}}) |
@@ -784,6 +795,25 @@ def _boom_stat(self: Path) -> object: |
784 | 795 | assert exc.value.status == "invalid_type" |
785 | 796 |
|
786 | 797 |
|
| 798 | +def test_baseline_atomic_write_json_cleans_up_temp_file_on_replace_failure( |
| 799 | + tmp_path: Path, |
| 800 | + monkeypatch: pytest.MonkeyPatch, |
| 801 | +) -> None: |
| 802 | + path = tmp_path / "baseline.json" |
| 803 | + temp_holder: dict[str, Path] = {} |
| 804 | + |
| 805 | + def _boom_replace(src: str | Path, dst: str | Path) -> None: |
| 806 | + temp_holder["path"] = Path(src) |
| 807 | + raise OSError("replace failed") |
| 808 | + |
| 809 | + monkeypatch.setattr("codeclone.baseline.os.replace", _boom_replace) |
| 810 | + |
| 811 | + with pytest.raises(OSError, match="replace failed"): |
| 812 | + baseline_mod._atomic_write_json(path, _trusted_payload()) |
| 813 | + |
| 814 | + assert temp_holder["path"].exists() is False |
| 815 | + |
| 816 | + |
787 | 817 | def test_baseline_load_json_read_error( |
788 | 818 | tmp_path: Path, monkeypatch: pytest.MonkeyPatch |
789 | 819 | ) -> None: |
@@ -818,6 +848,22 @@ def test_baseline_optional_str_paths(tmp_path: Path) -> None: |
818 | 848 | assert exc.value.status == "invalid_type" |
819 | 849 |
|
820 | 850 |
|
| 851 | +def test_baseline_require_utc_iso8601_z_rejects_invalid_calendar_date( |
| 852 | + tmp_path: Path, |
| 853 | +) -> None: |
| 854 | + path = tmp_path / "baseline.json" |
| 855 | + with pytest.raises( |
| 856 | + BaselineValidationError, |
| 857 | + match="'created_at' must be UTC ISO-8601 with Z", |
| 858 | + ) as exc: |
| 859 | + baseline_mod._require_utc_iso8601_z( |
| 860 | + {"created_at": "2026-02-31T00:00:00Z"}, |
| 861 | + "created_at", |
| 862 | + path=path, |
| 863 | + ) |
| 864 | + assert exc.value.status == "invalid_type" |
| 865 | + |
| 866 | + |
821 | 867 | def test_baseline_load_legacy_codeclone_version_alias(tmp_path: Path) -> None: |
822 | 868 | baseline_path = tmp_path / "baseline.json" |
823 | 869 | payload = _trusted_payload(generator_version="1.4.0") |
|
0 commit comments