diff --git a/AGENTS.md b/AGENTS.md
index 750dfff..0590f64 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -12336,3 +12336,74 @@ wertlos; entweder auf `link.sheet` warten oder ein zweites Mal messen.
Live geprüft (2026.9.6.1, beide Oberflächen): Reichweite 700, Nächster Service
300, Kilometerstand 300, geladene Wide-Schnitte nur noch 300 und 700,
Reservebalken `rgb(245, 5, 55)`.
+
+## DE. Verschlafene Kilometer zurückholen (2026.9.6.2)
+
+Der FMM003 kommt aus dem Deep Sleep nur über seinen Beschleunigungssensor hoch:
+die eingestellte Zündungsquelle ist die Motordrehzahl, die liegt am CAN, und
+CAN ist im Schlaf abgeschaltet. Gemessene Weckzeiten vom 18.08. bis 05.09.2026:
+**28 s bis 1170 s**. Am 05.09. fehlten dadurch **9 Minuten und 6 Kilometer** am
+Anfang der Rückfahrt — belegt am geräteeigenen GNSS-Wegzähler, der in fünf
+Stunden um 244 m weiterlief, während das Auto 6 km fuhr.
+
+Alle geräteseitigen Auswege sind vom Eigentümer geprüft und verworfen:
+Dauerbetrieb und GPS-Schlaf wegen des Ruhestroms, Periodic Wakeup ebenso, die
+Empfindlichkeit des Beschleunigungssensors ist am FMM003 nicht einstellbar, und
+die Bordspannung taugt an diesem Fahrzeug nicht als Zündungsquelle — bei
+laufendem Motor liegen **87,6 % von 2089 Messwerten** im Spannungsbereich des
+stehenden Wagens (Rekuperationsmanagement des RS 4).
+
+### Was jetzt passiert
+
+`verlauf.aufzeichnungsluecke_km()` — reine Funktion, sieben Tests in
+`tests/verlauf/test_aufzeichnungsluecke.py`. Zwischen zwei Fahrten steht das
+Fahrzeug; ist der Startkilometerstand trotzdem höher als der Endstand der
+Vorgängerin, wurden diese Kilometer gefahren, ohne dass ein Datensatz entstand.
+`screening._aufzeichnungsluecken_schliessen()` holt sie zurück und schreibt sie
+nach `luecke_km` (plus `luecke_unsicher`, wenn schon das Ende der Vorgängerin
+vorläufig war).
+
+**Keine Sperre der GNSS-Verfeinerung, sondern eine Zerlegung.** Der Eigentümer:
+„das macht die gesamte Nutzbarkeit des Fahrtenbuchs sehr grob". Richtig ist:
+
+```
+Strecke = verschlafener Anfang (ganze km, Tacho)
+ + aufgezeichneter Rest (metergenau, GNSS-Zähler)
+```
+
+Die Summe wird wie sonst gegen den Tacho geprüft. Die Unschärfe steckt damit
+nur im verschlafenen Stück; Fahrten ohne Lücke bleiben unverändert metergenau.
+Ohne die Zerlegung wäre die feine Zahl systematisch zu klein — und bei einer
+kleinen Lücke läge sie noch innerhalb von `GNSS_TOLERANZ_KM` und kassierte die
+Korrektur stillschweigend wieder ein. Genau dafür gibt es einen Test.
+
+### Zwei Schutzgitter, beide durch Schaden gelernt
+
+Der erste Lauf am 06.09.2026 griff sofort daneben und hat **drei Fahrten aus
+der Testphase beschädigt** (Kilometerstände auf `None`):
+
+* **`LUECKE_MAX_KM = 50.0`** — die längste gemessene Weckverzögerung sind
+ 19,5 min, bei Autobahntempo rund 42 km. Ohne die Grenze fand die Regel
+ 1078 km zwischen zwei Fahrten vom 27.08. (dort fehlen Fahrten in der Liste)
+ und 187831 km am 29.08. (Sprung zwischen den Zahlenbändern des Geräts).
+* **Rückfall, wenn `_vollstaendig()` die Werte verwirft.** Macht die Korrektur
+ die Strecke unplausibel, war die Annahme falsch, dass die beiden Fahrten
+ aufeinanderfolgen — dann bleibt der Bestand, wie er war.
+
+Die drei beschädigten Fahrten wurden aus `backups/20260901_072541/` von Hand
+wiederhergestellt. **Merkposten:** eine Regel, die rückwirkend auf den ganzen
+Bestand läuft, gehört vor dem ersten Lauf gegen den Bestand simuliert, nicht
+danach repariert.
+
+### Stand
+
+Live in `audi_ha_test`, 0 Tracebacks, 303 App-Tests grün. Die Rückfahrt vom
+05.09. steht jetzt mit **7,922 km statt ~1 km**, Zeile „Nicht aufgezeichnet:
+6 km am Anfang" in beiden Oberflächen (am gerenderten Panel nachgemessen).
+
+**Offen, im selben Zug gefunden:** dieselbe Fahrt hat ein **falsches Ende**.
+Das gepufferte Zündung-Aus kam am 06.09. um 14:28 mit Gerätezeit 23:21:29 an,
+`_echtes_ende()` hat daraus aber **14:27:25** gemacht — 15 h Dauer, 0,1 km/h
+Schnitt. Die Umstempelung auf Gerätezeit hat hier nicht gegriffen
+(`ZUORDNUNG_MAX_S = 1.0`). Das ist dieselbe Familie wie der Befund zu
+`_letztes_lebenszeichen()` und noch nicht behoben.
diff --git a/companion-app/src/api/types.ts b/companion-app/src/api/types.ts
index d6c2c31..7653bdb 100644
--- a/companion-app/src/api/types.ts
+++ b/companion-app/src/api/types.ts
@@ -71,6 +71,10 @@ export interface Fahrt {
/** Das Ende steht nur vorlaeufig fest (Knopf "Fahrt beenden", das Geraet
hat sein Zuendungs-Aus noch nicht gemeldet). */
ende_vorlaeufig?: boolean;
+ /** Kilometer am Anfang der Fahrt, die das Geraet verschlafen hat. */
+ luecke_km?: number | null;
+ /** Die Zuordnung dieser Luecke ist unsicher - siehe screening.py. */
+ luecke_unsicher?: boolean;
pausen?: unknown[];
}
diff --git a/companion-app/src/screens/FahrtDetail.tsx b/companion-app/src/screens/FahrtDetail.tsx
index a80f0c8..46788da 100644
--- a/companion-app/src/screens/FahrtDetail.tsx
+++ b/companion-app/src/screens/FahrtDetail.tsx
@@ -169,6 +169,23 @@ export function FahrtDetail({ id, geheZu }: { id: string | undefined; geheZu: (n
label="Endkilometer"
wert={fahrt.odo_end != null ? `${de(fahrt.odo_end)} km` : "noch offen"}
/>
+ {/* Der Dongle kommt aus dem Schlaf nur ueber seinen Beschleunigungssensor hoch
+ und braucht dafuer gemessene 28 s bis 19,5 min. Was in dieser Zeit gefahren
+ wird, zeichnet er nicht auf. Die Kilometer holt das Screening aus dem
+ Endkilometerstand der Vorgaengerin zurueck (verlauf.aufzeichnungsluecke_km),
+ die Route ist unwiederbringlich weg. Deshalb steht es hier: eine Fahrt, die
+ auf den ersten Metern keine Spur hat, soll nicht so aussehen, als waere sie
+ vollstaendig aufgezeichnet. */}
+ {fahrt.luecke_km ? (
+
+ ) : null}
@@ -4649,6 +4650,18 @@ function vTrip(id) {
`;
}
+/* Der Dongle kommt aus dem Schlaf nur ueber seinen Beschleunigungssensor hoch
+ und braucht dafuer gemessene 28 s bis 19,5 min. Was in dieser Zeit gefahren
+ wird, zeichnet er nicht auf. Die Kilometer holt das Screening aus dem
+ Endkilometerstand der Vorgaengerin zurueck (verlauf.aufzeichnungsluecke_km),
+ die Route ist unwiederbringlich weg. Deshalb steht es hier: eine Fahrt, die
+ auf den ersten Metern keine Spur hat, soll nicht so aussehen, als waere sie
+ vollstaendig aufgezeichnet. */
+function luecketext(t) {
+ const km = de(t.luecke_km) + " km";
+ return t.luecke_unsicher ? `${km} am Anfang · Zuordnung unsicher` : `${km} am Anfang`;
+}
+
function quad(t, v) { return `${t}
${v.map((x) => `
${x[0]}
${x[1]}
`).join("")}
`; }
/* Der Kachelkopf traegt seit der Designpruefung 2026-08-30 denselben
diff --git a/custom_components/audi_dashboard/manifest.json b/custom_components/audi_dashboard/manifest.json
index 2e50ac4..930aeb4 100644
--- a/custom_components/audi_dashboard/manifest.json
+++ b/custom_components/audi_dashboard/manifest.json
@@ -1,7 +1,7 @@
{
"domain": "audi_dashboard",
"name": "Audi Dashboard",
- "version": "2026.9.6.1",
+ "version": "2026.9.6.2",
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
"codeowners": [
diff --git a/custom_components/audi_dashboard/screening.py b/custom_components/audi_dashboard/screening.py
index 917976b..a8ff68c 100644
--- a/custom_components/audi_dashboard/screening.py
+++ b/custom_components/audi_dashboard/screening.py
@@ -47,6 +47,7 @@ from .verlauf import (
verbrauch_aus_literstaenden,
verlauf_lesen,
wert_ab,
+ aufzeichnungsluecke_km,
wert_bei,
)
@@ -189,6 +190,11 @@ async def durchfuehren(k: Koordinator) -> None:
)
fahrt["avg_speed_kmh"] = schnitt
+ # Vor der Verfeinerung: eine Fahrt mit Aufzeichnungsluecke bekommt hier
+ # ihren richtigen Startkilometerstand, und die Verfeinerung darf sie
+ # danach nicht mehr anfassen.
+ await _aufzeichnungsluecken_schliessen(k, fahrten)
+
# Erst nach den Kilometerstaenden: die Verfeinerung braucht die grobe
# Strecke als Anker und laeuft nur auf Fahrten, die sie schon haben.
gnss_sensor = k.zuordnung.werte.GNSS_KM_SENSOR
@@ -338,6 +344,22 @@ async def _gnss_verfeinern(k: Koordinator, gnss_sensor: str, fahrt: dict) -> Non
k.hass, gnss_sensor, start - SUCHFENSTER, ende, k.zuordnung.werte.MELDEZEIT_SENSOR
)
fein = zaehlerstrecke(punkte, start, ende)
+
+ # Bei einer Aufzeichnungsluecke hat der GNSS-Zaehler nur den Teil gesehen,
+ # in dem das Geraet wach war - seine Zahl waere allein also systematisch zu
+ # klein, und bei einer kleinen Luecke laege sie sogar noch innerhalb von
+ # GNSS_TOLERANZ_KM und kassierte die gerade erst geholte Strecke wieder.
+ #
+ # Deshalb keine Sperre, sondern eine Zerlegung: der verschlafene Anfang in
+ # ganzen Kilometern aus dem Tacho, der aufgezeichnete Rest metergenau aus
+ # dem Zaehler. Die Unschaerfe bleibt damit im verschlafenen Stueck statt in
+ # der ganzen Fahrt (Eigentuemer am 06.09.2026: "das macht die gesamte
+ # Nutzbarkeit des Fahrtenbuchs sehr grob"). Die Summe wird unten wie sonst
+ # auch gegen den Tacho geprueft - passt sie nicht, gilt weiter der Tacho.
+ luecke = fahrt.get("luecke_km")
+ if fein is not None and luecke:
+ fein = round(fein + luecke, 3)
+
gewaehlt, genommen = strecke_waehlen(grob, fein)
if not genommen:
if fein is not None:
@@ -352,8 +374,9 @@ async def _gnss_verfeinern(k: Koordinator, gnss_sensor: str, fahrt: dict) -> Non
await k.ablage.fahrt_aktualisieren(fahrt["trip_id"], aenderungen)
fahrt.update(aenderungen)
_LOGGER.info(
- "Fahrt %s: Strecke auf %s km verfeinert (Kilometerstand sagte %s km)",
+ "Fahrt %s: Strecke auf %s km verfeinert (Kilometerstand sagte %s km)%s",
fahrt.get("trip_id"), gewaehlt, grob,
+ f", davon {luecke} km unaufgezeichnet" if luecke else "",
)
@@ -509,6 +532,108 @@ async def _vmax_screenen(k: Koordinator, tempo_sensor: str, fahrt: dict) -> None
fahrt["vmax_kmh"] = vmax
+# Wie viele Kilometer eine Aufzeichnungsluecke hoechstens haben darf, um noch
+# als solche zu gelten.
+#
+# Die Luecke entsteht, waehrend das Geraet nach dem Motorstart noch schlaeft.
+# Gemessen ueber alle Aufwachvorgaenge vom 18.08. bis 05.09.2026 dauert das
+# zwischen 28 s und 1170 s; die laengste gemessene Verzoegerung sind also
+# 19,5 Minuten, bei Autobahntempo rund 42 km. 50 km lassen das durch und
+# sperren alles, was keine Weckverzoegerung mehr sein kann.
+#
+# Ohne diese Grenze griff die Regel am 06.09.2026 sofort daneben: sie fand
+# 1078 km zwischen zwei Fahrten vom 27.08. (dort fehlen schlicht Fahrten in der
+# Liste) und 187831 km am 29.08. (dort sprang der Kilometerstand zwischen den
+# beiden Zahlenbaendern des Geraets, siehe Abschnitt zum Fahrzeugwechsel in
+# _vollstaendig). Beide Male ist die Differenz echt, aber sie gehoert nicht an
+# den Anfang der naechsten Fahrt.
+LUECKE_MAX_KM = 50.0
+
+
+async def _aufzeichnungsluecken_schliessen(
+ k: Koordinator, fahrten: list[dict]
+) -> None:
+ """Holt die Kilometer zurueck, die das Geraet am Anfang einer Fahrt
+ verschlafen hat.
+
+ Das Screening nimmt als Startkilometerstand den zuletzt VOR dem
+ Fahrtbeginn gemeldeten Wert (wert_bei). Beginnt die Fahrt aber erst in dem
+ Moment, in dem sich das Geraet zurueckmeldet, ist dieser Wert schon der
+ Stand NACH den verschlafenen Kilometern - am 05.09.2026 stand dort 21353
+ statt 21347, und die Fahrt haette 1 km statt 7 km bekommen.
+
+ Der ehrliche Anker ist der Endkilometerstand der Vorgaengerin: dazwischen
+ stand das Fahrzeug. Die Strecke stimmt danach auf ganze Kilometer genau -
+ mehr gibt der CAN-Tacho nicht her, und die Route der verschlafenen Minuten
+ ist unwiederbringlich weg. luecke_km haelt fest, wie viel davon betroffen
+ ist, damit die Oberflaeche es zeigen kann und die GNSS-Verfeinerung die
+ Finger davon laesst."""
+ sortiert = sorted(fahrten, key=lambda f: f.get("ts_start") or "")
+ for vorherige, fahrt in zip(sortiert, sortiert[1:]):
+ fehlt = aufzeichnungsluecke_km(
+ vorherige.get("odo_end"), fahrt.get("odo_start")
+ )
+ if fehlt is None:
+ continue
+ if fehlt > LUECKE_MAX_KM:
+ _LOGGER.info(
+ "Fahrt %s: %s km Unterschied zur Vorgaengerin - zu viel fuer "
+ "eine Weckverzoegerung (Grenze %s km), bleibt unangetastet",
+ fahrt.get("trip_id"), fehlt, LUECKE_MAX_KM,
+ )
+ continue
+ # Der Anker ist nur so gut wie das ENDE der Vorgaengerin. Wurde die von
+ # Hand beendet, steht ihr Endkilometerstand auf einem vorlaeufigen Ende
+ # - dann koennen die Kilometer auch ihr gehoeren und nur falsch
+ # zugeschlagen sein. Die Gesamtleistung stimmt in beiden Faellen, die
+ # Aufteilung zwischen zwei Fahrten nicht (Einwand des Eigentuemers,
+ # 06.09.2026). Deshalb wird es vermerkt statt still verrechnet.
+ alt_start = fahrt.get("odo_start")
+ alt_quelle = fahrt.get("km_quelle")
+ fahrt.update({
+ "luecke_km": fehlt,
+ "luecke_unsicher": bool(vorherige.get("ende_vorlaeufig")),
+ "odo_start": vorherige["odo_end"],
+ "km_quelle": "odometer",
+ })
+ aenderungen = _vollstaendig(
+ {
+ "luecke_km": fehlt,
+ "luecke_unsicher": fahrt["luecke_unsicher"],
+ "odo_start": fahrt["odo_start"],
+ "odo_end": fahrt.get("odo_end"),
+ },
+ fahrt,
+ )
+ # Letzte Sicherung: _vollstaendig() verwirft beide Kilometerstaende,
+ # wenn die Strecke daraus unplausibel wird (Rueckwaertssprung oder
+ # unmoegliche Durchschnittsgeschwindigkeit). Passiert das durch UNSERE
+ # Korrektur, war die Annahme falsch, dass die beiden Fahrten wirklich
+ # aufeinanderfolgen - dann darf sie den Bestand nicht schlechter
+ # zuruecklassen, als sie ihn vorgefunden hat. Am 06.09.2026 genau so
+ # eingetreten, an einer Fahrt aus der Testphase vom 27.08.
+ if aenderungen.get("odo_start") is None:
+ fahrt["odo_start"] = alt_start
+ fahrt["km_quelle"] = alt_quelle
+ fahrt["luecke_km"] = None
+ fahrt["luecke_unsicher"] = False
+ _LOGGER.info(
+ "Fahrt %s: %s km Unterschied zur Vorgaengerin ergaeben eine "
+ "unplausible Strecke - Korrektur verworfen, Bestand bleibt",
+ fahrt.get("trip_id"), fehlt,
+ )
+ continue
+
+ await k.ablage.fahrt_aktualisieren(fahrt["trip_id"], aenderungen)
+ fahrt.update(aenderungen)
+ _LOGGER.info(
+ "Fahrt %s: %s km am Anfang nicht aufgezeichnet - Startkilometer "
+ "von der Vorgaengerin uebernommen (%s statt %s)",
+ fahrt.get("trip_id"), fehlt, vorherige["odo_end"],
+ round(vorherige["odo_end"] + fehlt, 1),
+ )
+
+
async def _lueckenlos_verketten(k: Koordinator) -> None:
"""Fahrt-Ende(N) == Fahrt-Start(N+1), solange dazwischen nicht gefahren
wurde.
diff --git a/custom_components/audi_dashboard/verlauf.py b/custom_components/audi_dashboard/verlauf.py
index 726295d..f156e14 100644
--- a/custom_components/audi_dashboard/verlauf.py
+++ b/custom_components/audi_dashboard/verlauf.py
@@ -543,6 +543,41 @@ def strecke_waehlen(
return grob, False
+def aufzeichnungsluecke_km(
+ vorheriges_ende: float | None, eigener_start: float | None
+) -> float | None:
+ """Die Kilometer am Anfang einer Fahrt, die das Geraet nicht mitbekommen hat.
+
+ Zwischen zwei aufeinanderfolgenden Fahrten steht das Fahrzeug, der
+ Kilometerstand aendert sich also nicht - dieselbe Annahme, auf der
+ _lueckenlos_verketten() in screening.py seit jeher beruht. Steht der
+ Startkilometerstand einer Fahrt trotzdem HOEHER als der Endstand ihrer
+ Vorgaengerin, sind diese Kilometer gefahren worden, ohne dass ein einziger
+ Datensatz entstanden ist.
+
+ WARUM ES DAS GIBT: der FMM003 kommt aus dem Deep Sleep nur ueber seinen
+ Beschleunigungssensor hoch. Die eingestellte Zuendungsquelle ist die
+ Motordrehzahl, die liegt am CAN - und CAN ist im Schlaf abgeschaltet
+ (Teltonika: "In deep sleep mode, OBD, CAN and Eventual I/O activity is
+ disabled"). Die Bordspannung taugt an diesem Fahrzeug nicht als Ersatz:
+ das Rekuperationsmanagement des RS 4 laedt in Schueben, und von 2089
+ Messwerten bei laufendem Motor liegen 87,6 % im Spannungsbereich des
+ stehenden Wagens (gemessen 06.09.2026). Gemessene Weckzeiten reichen von
+ 39 s bis 19,5 min; am 05.09.2026 fehlten 9 Minuten und 6 Kilometer.
+
+ Der Eigentuemer hat alle geraeteseitigen Auswege ausgeschlossen
+ (Dauerbetrieb und GPS-Schlaf wegen des Ruhestroms, Periodic Wakeup ebenso,
+ die Empfindlichkeit des Beschleunigungssensors ist am FMM003 nicht
+ einstellbar). Die Luecke bleibt also - sie soll aber wenigstens die
+ Streckenlaenge nicht kosten und sichtbar sein.
+
+ Reine Funktion, damit sie ohne Home Assistant pruefbar ist."""
+ if vorheriges_ende is None or eigener_start is None:
+ return None
+ fehlt = round(eigener_start - vorheriges_ende, 1)
+ return fehlt if fehlt > 0 else None
+
+
def ist_gefahren(distanz: float | None) -> bool:
"""Hat sich das Fahrzeug bewegt?
diff --git a/tests/verlauf/test_aufzeichnungsluecke.py b/tests/verlauf/test_aufzeichnungsluecke.py
new file mode 100644
index 0000000..c4ec382
--- /dev/null
+++ b/tests/verlauf/test_aufzeichnungsluecke.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+"""Die Kilometer, die der Dongle am Anfang einer Fahrt verschlaeft.
+
+Der FMM003 kommt aus dem Deep Sleep nur ueber seinen Beschleunigungssensor
+hoch: die eingestellte Zuendungsquelle ist die Motordrehzahl, die liegt am CAN,
+und CAN ist im Schlaf abgeschaltet. Gemessene Weckzeiten am 31.08. bis
+05.09.2026: 28 s, 144 s, 182 s, 484 s, 543 s, 632 s, 1131 s, 1170 s.
+
+Die Zahlen hier sind gemessen, nicht erfunden - Rueckfahrt Eichstaett -
+Adelschlag am 05.09.2026: Motorstart 23:04:16 (aus der Motorlaufzeit 543 s im
+ersten Datensatz), erster Datensatz aber erst 23:13:19. Der Tacho stand vorher
+auf 21347 und im ersten Datensatz danach bereits auf 21353.
+
+Aufruf: python3 tests/verlauf/test_aufzeichnungsluecke.py
+"""
+
+import os
+import sys
+import unittest
+
+_HIER = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, os.path.dirname(os.path.dirname(_HIER)))
+
+from custom_components.audi_dashboard import verlauf as v # noqa: E402
+
+
+class Luecke(unittest.TestCase):
+ def test_echter_fall_vom_05_09(self):
+ """21347 am Ende der Hinfahrt, 21353 im ersten Datensatz der Rueckfahrt."""
+ self.assertEqual(v.aufzeichnungsluecke_km(21347.0, 21353.0), 6.0)
+
+ def test_keine_luecke_ist_none(self):
+ """Der Normalfall: die Rueckfahrt beginnt, wo die Hinfahrt endete."""
+ self.assertIsNone(v.aufzeichnungsluecke_km(21347.0, 21347.0))
+
+ def test_rueckwaerts_ist_keine_luecke(self):
+ """Ein niedrigerer Start ist ein Fahrzeugwechsel des Geraets oder ein
+ Ausreisser - jedenfalls keine verschlafene Strecke. _vollstaendig()
+ faengt den Fall an anderer Stelle ab; hier darf er nur nicht als
+ Luecke durchgehen."""
+ self.assertIsNone(v.aufzeichnungsluecke_km(21353.0, 21347.0))
+
+ def test_unbekannte_werte(self):
+ self.assertIsNone(v.aufzeichnungsluecke_km(None, 21353.0))
+ self.assertIsNone(v.aufzeichnungsluecke_km(21347.0, None))
+ self.assertIsNone(v.aufzeichnungsluecke_km(None, None))
+
+
+class Zerlegung(unittest.TestCase):
+ """Verschlafener Anfang in ganzen Kilometern, aufgezeichneter Rest
+ metergenau - und die Summe muss den Tacho-Anker weiterhin bestehen.
+
+ Ohne die Zerlegung waere die feine Zahl allein systematisch zu klein, und
+ bei einer kleinen Luecke laege sie sogar noch innerhalb der Toleranz und
+ kassierte die gerade erst geholte Strecke wieder ein. Genau das soll hier
+ nicht passieren."""
+
+ def test_summe_wird_genommen(self):
+ """6 km verschlafen, 1,428 km aufgezeichnet, Tacho sagt 7 km."""
+ fein = round(1.428 + 6.0, 3)
+ gewaehlt, genommen = v.strecke_waehlen(7.0, fein)
+ self.assertTrue(genommen)
+ self.assertEqual(gewaehlt, 7.428)
+
+ def test_ohne_zerlegung_wuerde_der_tacho_gewinnen(self):
+ """Zur Abgrenzung: die feine Zahl allein liegt 5,57 km daneben und
+ wird verworfen - die Fahrt bekaeme 7 statt 7,428 km."""
+ gewaehlt, genommen = v.strecke_waehlen(7.0, 1.428)
+ self.assertFalse(genommen)
+ self.assertEqual(gewaehlt, 7.0)
+
+ def test_kleine_luecke_ist_der_gefaehrliche_fall(self):
+ """Eine Luecke von 1 km: die feine Zahl allein (5,1 gegen 6) laege
+ INNERHALB der Toleranz und wuerde stillschweigend gewinnen - 0,9 km
+ weniger, ohne dass es jemand merkt. Mit Zerlegung stimmt es."""
+ ohne, genommen_ohne = v.strecke_waehlen(6.0, 5.1)
+ self.assertTrue(genommen_ohne, "ohne Zerlegung schluepft der Fehler durch")
+ self.assertEqual(ohne, 5.1)
+
+ mit, genommen_mit = v.strecke_waehlen(6.0, round(5.1 + 1.0, 3))
+ self.assertTrue(genommen_mit)
+ self.assertEqual(mit, 6.1)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)