Ajoute la section [home_assistant] au TOML et sa validation au chargement via get_home_assistant_config(). La section est facultative pour préserver la compatibilité avec les configurations existantes, mais si elle est présente elle doit être complète et référencer un type de journée, un trajet et un véhicule à moteur existants, sous peine de refuser le démarrage de l'application. La configuration validée est exposée dans app.config['HOME_ASSISTANT']. Co-authored-by: OpenAI/GPT-5.6-Luna-Pro <vibecoder@antoineve.me>
168 lines
4.6 KiB
Python
168 lines
4.6 KiB
Python
import pytest
|
|
|
|
from app import create_app
|
|
|
|
_MINIMAL_CONFIG = """
|
|
[vehicles.citadine]
|
|
name = "Citadine"
|
|
type = "moteur"
|
|
|
|
[vehicles.velo]
|
|
name = "Vélo"
|
|
type = "velo"
|
|
|
|
[journeys.moteur_seul]
|
|
name = "Moteur seul"
|
|
distances = {{ moteur = 1 }}
|
|
|
|
[home_assistant]
|
|
timezone = "{timezone}"
|
|
default_day_type = "{day_type}"
|
|
default_journey_profile_id = "{journey_id}"
|
|
default_motor_vehicle_id = "{vehicle_id}"
|
|
"""
|
|
|
|
|
|
def _create_app_with_home_assistant_config(tmp_path, **values):
|
|
config_path = tmp_path / "config.toml"
|
|
config_path.write_text(_MINIMAL_CONFIG.format(**values), encoding="utf-8")
|
|
return create_app(config_path=str(config_path))
|
|
|
|
|
|
def test_get_vehicles_returns_configured_vehicles(app):
|
|
with app.app_context():
|
|
from app.config_loader import get_vehicles
|
|
|
|
vehicles = get_vehicles()
|
|
assert "familiale" in vehicles
|
|
assert vehicles["familiale"]["co2_per_km"] == 142
|
|
|
|
|
|
def test_get_motor_vehicles_excludes_velo(app):
|
|
with app.app_context():
|
|
from app.config_loader import get_motor_vehicles
|
|
|
|
motor = get_motor_vehicles()
|
|
assert "familiale" in motor
|
|
assert "citadine" in motor
|
|
assert "moto" in motor
|
|
assert "velo" not in motor
|
|
|
|
|
|
def test_get_journeys_returns_profiles(app):
|
|
with app.app_context():
|
|
from app.config_loader import get_journeys
|
|
|
|
journeys = get_journeys()
|
|
assert "moteur_seul" in journeys
|
|
assert journeys["moteur_seul"]["distances"]["moteur"] == 25
|
|
|
|
|
|
def test_journey_has_motor_true(app):
|
|
with app.app_context():
|
|
from app.config_loader import journey_has_motor
|
|
|
|
assert journey_has_motor("moteur_seul") is True
|
|
assert journey_has_motor("moteur_velo") is True
|
|
|
|
|
|
def test_journey_has_motor_false(app):
|
|
with app.app_context():
|
|
from app.config_loader import journey_has_motor
|
|
|
|
assert journey_has_motor("velo_seul") is False
|
|
assert journey_has_motor(None) is False
|
|
|
|
|
|
def test_get_bareme_returns_tranches(app):
|
|
with app.app_context():
|
|
from app.config_loader import get_bareme
|
|
|
|
tranches = get_bareme(2025, 5)
|
|
assert len(tranches) == 3
|
|
assert tranches[0]["taux"] == 0.548
|
|
|
|
|
|
def test_day_types_without_journey(app):
|
|
with app.app_context():
|
|
from app.config_loader import day_types_without_journey
|
|
|
|
types = day_types_without_journey()
|
|
assert "TT" in types
|
|
assert "WORK" not in types
|
|
|
|
|
|
def test_get_home_assistant_config_returns_validated_defaults(app):
|
|
with app.app_context():
|
|
from app.config_loader import get_home_assistant_config
|
|
|
|
assert get_home_assistant_config() == {
|
|
"timezone": "Europe/Paris",
|
|
"default_day_type": "WORK",
|
|
"default_journey_profile_id": "moteur_seul",
|
|
"default_motor_vehicle_id": "citadine",
|
|
}
|
|
assert app.config["HOME_ASSISTANT"]["default_motor_vehicle_id"] == "citadine"
|
|
|
|
|
|
def test_home_assistant_section_absent_is_allowed(app):
|
|
with app.app_context():
|
|
from app.config_loader import get_home_assistant_config
|
|
|
|
app.config["TOML"].pop("home_assistant")
|
|
assert get_home_assistant_config() is None
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("field", "value", "message"),
|
|
[
|
|
("timezone", "Mars/NoSuchPlace", "fuseau horaire"),
|
|
("day_type", "UNKNOWN", "type de journée"),
|
|
("journey_id", "unknown_journey", "trajet inconnu"),
|
|
("vehicle_id", "unknown_vehicle", "véhicule inconnu"),
|
|
],
|
|
)
|
|
def test_invalid_home_assistant_config_prevents_startup(tmp_path, field, value, message):
|
|
values = {
|
|
"timezone": "Europe/Paris",
|
|
"day_type": "WORK",
|
|
"journey_id": "moteur_seul",
|
|
"vehicle_id": "citadine",
|
|
}
|
|
values[field] = value
|
|
|
|
with pytest.raises(ValueError, match=message):
|
|
_create_app_with_home_assistant_config(tmp_path, **values)
|
|
|
|
|
|
def test_home_assistant_default_vehicle_must_be_motor_vehicle(tmp_path):
|
|
values = {
|
|
"timezone": "Europe/Paris",
|
|
"day_type": "WORK",
|
|
"journey_id": "moteur_seul",
|
|
"vehicle_id": "velo",
|
|
}
|
|
|
|
with pytest.raises(ValueError, match="véhicule moteur"):
|
|
_create_app_with_home_assistant_config(tmp_path, **values)
|
|
|
|
|
|
def test_incomplete_home_assistant_config_prevents_startup(tmp_path):
|
|
config_path = tmp_path / "config.toml"
|
|
config_path.write_text(
|
|
"""
|
|
[vehicles.citadine]
|
|
type = "moteur"
|
|
|
|
[journeys.moteur_seul]
|
|
distances = { moteur = 1 }
|
|
|
|
[home_assistant]
|
|
timezone = "Europe/Paris"
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="clé.*manquante"):
|
|
create_app(config_path=str(config_path))
|