fix(tests): la suite de simulation ne compilait plus depuis 639689b

Le lot E §12 a ajouté le paramètre minPowerW au constructeur
d'EtmVariableLoadAdapter sans le répercuter sur les cinq sites d'appel de
tests/auto/simulation. La suite ne compile donc plus depuis ce commit —
autrement dit, personne ne l'a exécutée depuis. Les cinq sites passent
désormais minPowerW = 0 explicitement.

Deux attentes avaient rouillé pendant ce temps, et les deux portent sur du
TEXTE publié — ce qui est précisément ce que ces tests doivent surveiller :

  - testEcsColdStartLockExpires attendait « insuffisant » là où f134048 a
    délibérément fait sortir BELOW_MIN_POWER. Le cas est « il y a un budget,
    il n'est pas au bon FORMAT » : le motif doit nommer le palier. Ce que le
    test éprouve reste le même — ce n'est pas le verrou.
  - testDecisionReasonRendering attendait « Surplus insuffisant » pour
    SG_NORMAL, reformulé en « Aucun surplus à allouer » par le même commit,
    parce que ce motif ne sort plus que pour un budget nul ou négatif.

Le catalogue de motifs avait dérivé au passage : BATTERY_RESERVE et
BELOW_MIN_POWER étaient entrés en 3g-1 sans ligne de rendu attendue ni entrée
dans la liste de clôture. Leur texte — celui sur lequel le banc s'appuie pour
distinguer « il n'y a rien » de « il y en a, mais pas au bon format » ou
« une règle le retient » — n'était donc éprouvé par rien. Refermé, avec les
deux formes de BELOW_MIN_POWER (avec et sans état).

Suite verte : simulation 24/24 fonctions, dont les 16 scénarios de `run`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017TVywtayEeoRJ2yWUW4iZj
This commit is contained in:
Patrick Schurig 2026-08-27 10:05:51 +02:00
parent a1f17c136b
commit 7d4e2351f4

View File

@ -201,7 +201,7 @@ void Simulation::testEcsSurplusPV()
EtmVariableLoadAdapter *ecs = new EtmVariableLoadAdapter(
thingManager, ecsId.toString(), "ECS variable",
QList<int>({0, 1200, 2400}), 2400, 1, LoadNeeds(), arbitrator);
QList<int>({0, 1200, 2400}), 2400, /* minPowerW */ 0, 1, LoadNeeds(), arbitrator);
arbitrator->registerEtmVariableLoadAdapter(ecs);
auto setMeterW = [&](double signedW){ meterThing->setStateValue("currentPower", signedW); }; // <0 = export
@ -249,7 +249,7 @@ void Simulation::testEcsSurplusPV()
rThing->setStateValue("currentPowerW", 0);
EtmVariableLoadAdapter *router = new EtmVariableLoadAdapter(
tm2, rId.toString(), "Routeur PV", QList<int>(), 3000, 1, LoadNeeds(), arb2); // powerLevels vide → dynamic
tm2, rId.toString(), "Routeur PV", QList<int>(), 3000, /* minPowerW */ 0, 1, LoadNeeds(), arb2); // powerLevels vide → dynamic
arb2->registerEtmVariableLoadAdapter(router);
m2->setStateValue("currentPower", -2000); arb2->simulationCallUpdate(t0); QCoreApplication::processEvents();
@ -290,7 +290,7 @@ void Simulation::testMeterSilentFallback()
EtmVariableLoadAdapter *ecs = new EtmVariableLoadAdapter(
thingManager, ecsId.toString(), "ECS repli",
QList<int>({0, 2400}), 2400, 1, LoadNeeds(), arbitrator);
QList<int>({0, 2400}), 2400, /* minPowerW */ 0, 1, LoadNeeds(), arbitrator);
arbitrator->registerEtmVariableLoadAdapter(ecs);
const QDateTime t0 = utcDateTime(QDate(2026, 6, 8), QTime(13, 0, 0));
@ -1415,7 +1415,11 @@ void Simulation::testEcsColdStartLockExpires()
RelayRouter *r3 = new RelayRouter(tm, "froid3", "Charge à froid 3",
QList<LoadConfigRelay>({ {rA.toString(), 1000} }), 0, 0, 1, LoadNeeds(), arb);
const QString mBudget = motifPour(r3, 200, t0); // 200 W < palier 1000 W
QVERIFY2(mBudget.contains("insuffisant", Qt::CaseInsensitive), qUtf8Printable("motif: " + mBudget));
// §12 / f134048 — ce cas n'est plus « surplus insuffisant » mais BELOW_MIN_POWER : il y a
// un budget, il n'est simplement pas au bon FORMAT. Le motif doit donc nommer le palier —
// la distinction envoie l'installateur attendre le soleil ou relire son câblage, pas la
// même chose. Ce qui reste inchangé, et qui est l'objet du test : ce n'est pas le verrou.
QVERIFY2(mBudget.contains("palier", Qt::CaseInsensitive), qUtf8Printable("motif: " + mBudget));
QVERIFY2(!mBudget.contains("Verrou"), qUtf8Printable("motif: " + mBudget));
// 3. Verrou minOn : palier maintenu AU-DESSUS du budget. Troisième cas, troisième texte.
@ -4022,8 +4026,31 @@ void Simulation::testDecisionReasonRendering()
{ { DecisionCode::SgRecommended, {{"budgetW", 2000}, {"estimatedW", 1500}} },
QStringLiteral("PAC test"),
QStringLiteral("Surplus PV 2000 W — PAC test recommandée (état 3, ~1500 W)") },
// §12 / f134048 — SG_NORMAL ne sort plus QUE pour un budget nul ou négatif : le cas
// « budget présent mais sous l'état 3 » est passé à BELOW_MIN_POWER. La phrase dit
// donc « aucun surplus », là où « insuffisant » couvrait aussi, et à tort, un budget
// de 933 W devant un état à 1 500 W.
{ { DecisionCode::SgNormal, {{"budgetW", 1000}} }, QStringLiteral("PAC test"),
QStringLiteral("Surplus insuffisant (1000 W) — PAC test en normal (état 2, non pilotée)") },
QStringLiteral("Aucun surplus à allouer (1000 W) — PAC test en normal (état 2, non pilotée)") },
// 3g-1 — les deux motifs sur lesquels le banc s'appuie pour distinguer « il n'y a
// rien » de « il y en a, mais pas au bon format » ou « une règle le retient ». Leur
// TEXTE n'était pas éprouvé : ils ont rejoint le catalogue sans ligne ici.
{ { DecisionCode::BatteryReserve,
{{"withheldW", 3200}, {"socPercent", 35}, {"reservePercent", 80}} },
QStringLiteral("Chauffe-eau"),
QStringLiteral("3200 W de surplus retenus — batterie à 35 %, sous la réserve de 80 % ; "
"aucune charge n'est servie") },
{ { DecisionCode::BelowMinPower, {{"budgetW", 1096}, {"minPowerW", 2070}} },
QStringLiteral("Borne du garage"),
QStringLiteral("Budget 1096 W sous le premier palier de Borne du garage (2070 W) — 0 W, "
"le budget passe à la charge suivante") },
// La variante à ÉTATS nomme l'état hors d'atteinte : sans lui, une phrase vague en
// remplacerait une autre (note de DecisionCode::BelowMinPower).
{ { DecisionCode::BelowMinPower, {{"budgetW", 933}, {"minPowerW", 1500}, {"state", 3}} },
QStringLiteral("PAC test"),
QStringLiteral("Budget 933 W sous l'état 3 de PAC test (1500 W estimés) — état 2, "
"le budget passe à la charge suivante") },
// --- Sécurité et cycle de vie ---
{ { DecisionCode::DegradedL2 }, QString(),
@ -4054,7 +4081,10 @@ void Simulation::testDecisionReasonRendering()
DecisionCode::SurplusSetpoint, DecisionCode::SurplusInsufficient,
DecisionCode::LockMinStateHold, DecisionCode::SgForced, DecisionCode::SgRecommended,
DecisionCode::SgNormal, DecisionCode::DegradedL2, DecisionCode::SafeStateRelay,
DecisionCode::SafeStateSetpoint, DecisionCode::SafeStateSgReady };
DecisionCode::SafeStateSetpoint, DecisionCode::SafeStateSgReady,
// 3g-1 : ajoutés au catalogue sans être ajoutés ICI — la clôture avait dérivé, donc
// la garantie « tout code a une ligne de rendu éprouvée » ne tenait plus.
DecisionCode::BatteryReserve, DecisionCode::BelowMinPower };
for (const QString &code : catalogue)
QVERIFY2(codesCouverts.contains(code),
qUtf8Printable(QStringLiteral("code %1 sans ligne de rendu attendue").arg(code)));
@ -4603,7 +4633,7 @@ void Simulation::testRuntimeViewIsSubstantial()
QVERIFY(varThing);
varThing->setStateValue("currentPowerW", 0);
EtmVariableLoadAdapter *continu = new EtmVariableLoadAdapter(
tm, varId.toString(), "Routeur PV", QList<int>(), 4000, 2, LoadNeeds(), arb);
tm, varId.toString(), "Routeur PV", QList<int>(), 4000, /* minPowerW */ 0, 2, LoadNeeds(), arb);
LoadAction consigne;
consigne.kind = LoadAction::Setpoint; consigne.funding = LoadAction::Surplus;
@ -4626,7 +4656,7 @@ void Simulation::testRuntimeViewIsSubstantial()
// Le code de défaut n'est pas du code mort : un thing absent de la configuration le lève.
EtmVariableLoadAdapter *fantome = new EtmVariableLoadAdapter(
tm, "{deadbeef-0000-0000-0000-000000000042}", "Charge fantôme",
QList<int>(), 1000, 3, LoadNeeds(), arb);
QList<int>(), 1000, /* minPowerW */ 0, 3, LoadNeeds(), arb);
QCOMPARE(fantome->runtimeView(t0).faultCode, QString("THING_MISSING"));
// ---- 3. SgReadyAdapter : état normé, estimation, verrou minStateHold ------------------
@ -4933,3 +4963,4 @@ QStringList Simulation::plotSpotMarketData(int powerBalanceCount)
QTEST_MAIN(Simulation)