Files
atm/tests/test_calibrate.py
Marius Mutu 9c44eb6e31 feat: mută secretele Discord/Telegram din TOML în .env
TOML-urile din configs/ rămân 100% calibrare — safe to commit. Secretele
(ATM_DISCORD_URL, ATM_TG_TOKEN, ATM_TG_CHAT) trăiesc în .env la rădăcină
(ignored), cu loader stdlib (shell wins peste file). Validare fail-fast
pentru env lipsă, placeholder REPLACE_ME, chat_id non-numeric.

Include .env.example + secţiune README §Secrets. Tests: 19 noi (env loader +
missing-env + placeholder + chat_id + regression post-migrate snapshot).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 09:37:24 +03:00

84 lines
3.1 KiB
Python

"""Tests for atm.calibrate."""
from __future__ import annotations
from pathlib import Path
import pytest
@pytest.fixture(autouse=True)
def _secrets_env(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("ATM_DISCORD_URL", "https://example.com/hook")
monkeypatch.setenv("ATM_TG_TOKEN", "123:abc")
monkeypatch.setenv("ATM_TG_CHAT", "456")
def _minimal_config_data() -> dict:
return {
"window_title": "Test Chart",
"dot_roi": {"x": 0, "y": 0, "w": 100, "h": 100},
"chart_roi": {"x": 0, "y": 0, "w": 800, "h": 600},
"colors": {
"turquoise": {"rgb": [0, 200, 200], "tolerance": 30.0},
"yellow": {"rgb": [255, 255, 0], "tolerance": 30.0},
"dark_green": {"rgb": [0, 128, 0], "tolerance": 30.0},
"dark_red": {"rgb": [139, 0, 0], "tolerance": 30.0},
"light_green": {"rgb": [144, 238, 144], "tolerance": 30.0},
"light_red": {"rgb": [255, 182, 193], "tolerance": 30.0},
"gray": {"rgb": [128, 128, 128], "tolerance": 30.0},
},
"y_axis": {"p1_y": 100, "p1_price": 10000.0, "p2_y": 200, "p2_price": 9000.0},
"canary": {
"roi": {"x": 0, "y": 0, "w": 50, "h": 50},
"baseline_phash": "abc123",
"drift_threshold": 8,
},
}
def test_write_config_and_marker(tmp_path: Path) -> None:
from atm.calibrate import write_config
from atm.config import Config
config_path = write_config(_minimal_config_data(), tmp_path)
assert config_path.exists()
assert config_path.suffix == ".toml"
# Must be loadable by Config.load
cfg = Config.load(config_path)
assert cfg.window_title == "Test Chart"
assert cfg.y_axis.p1_price == pytest.approx(10000.0)
# Marker must point at the filename (basename only)
marker = tmp_path / "current.txt"
assert marker.exists()
assert marker.read_text(encoding="utf-8").strip() == config_path.name
# Config.load_current should also work
cfg2 = Config.load_current(tmp_path)
assert cfg2.window_title == cfg.window_title
def test_write_config_omits_secrets(tmp_path: Path) -> None:
"""Calibration output must NOT contain Discord/Telegram secret fields."""
from atm.calibrate import write_config
config_path = write_config(_minimal_config_data(), tmp_path)
text = config_path.read_text(encoding="utf-8")
for marker in ("[discord]", "[telegram]", "webhook_url", "bot_token", "chat_id"):
assert marker not in text, f"calibrated TOML leaked secret marker: {marker}"
def test_import_safe() -> None:
"""Importing atm.calibrate must succeed in a headless environment (no tkinter at top-level)."""
import importlib # noqa: F401
import importlib.util
spec = importlib.util.find_spec("atm.calibrate")
assert spec is not None, "atm.calibrate module not found"
# Actually importing must not raise (tkinter is only used inside run_calibration)
mod = importlib.import_module("atm.calibrate")
assert hasattr(mod, "write_config")
assert hasattr(mod, "run_calibration")