File size: 2,111 Bytes
0623ff0
3c35b12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0623ff0
3c35b12
 
 
 
0623ff0
3c35b12
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"""Tests for src/models/train_final.py's `_load_validation_metrics`, using a synthetic tmp_path file rather than the real data/models/logo_cv_metrics.json so tests don't depend on notebooks/03 having been re-run recently."""

from __future__ import annotations

import json

import pytest

from src.models import train_final
from src.models.train_final import _load_validation_metrics


class TestLoadValidationMetrics:
    def test_returns_none_when_file_absent(self, tmp_path):
        missing = tmp_path / "logo_cv_metrics.json"
        assert _load_validation_metrics(missing) is None

    def test_returns_parsed_dict_when_present(self, tmp_path):
        path = tmp_path / "logo_cv_metrics.json"
        payload = {"primary": {"mape": 0.234, "smape": 0.212, "n_folds": 5}}
        path.write_text(json.dumps(payload))
        assert _load_validation_metrics(path) == payload

    def test_default_path_does_not_raise(self):
        # Whether or not the real file exists on this machine, calling with no argument must never raise — it's a best-effort informational read, not a hard requirement of train_and_save().
        result = _load_validation_metrics()
        assert result is None or isinstance(result, dict)

    def test_refuses_symlinked_file(self, tmp_path):
        """Same guard predictor.py applies to feature_metadata.json/prophet_v1.json — a symlinked metrics file could point at attacker-controlled content committed into validation_metrics with no warning."""
        real = tmp_path / "real.json"
        real.write_text(json.dumps({"primary": {"mape": 0.0}}))
        link = tmp_path / "link.json"
        link.symlink_to(real)
        with pytest.raises(ValueError, match="symlink"):
            _load_validation_metrics(link)

    def test_refuses_oversized_file(self, tmp_path, monkeypatch):
        monkeypatch.setattr(train_final, "_MAX_VALIDATION_METRICS_BYTES", 10)
        p = tmp_path / "logo_cv_metrics.json"
        p.write_text(json.dumps({"primary": {"mape": 0.234}}))
        with pytest.raises(ValueError, match="too large"):
            _load_validation_metrics(p)