test: AuthLog-Regressionstests (wirft nie, 500-Zeilen-Kappung)
AuthLog.write ist der einzige Aufruf im catch-Pfad des Soft-Logout-Guards; ein Throw dort würde im SDK zu logout()+clear() eskalieren. 4 neue Tests sichern genau das ab (kaputte Plattform, leeres Log, Zeitstempel, Kappung). path_provider_platform_interface als dev_dependency (war schon transitiv). Alle 14 Tests grün auf dem Pi, flutter analyze unverändert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1205,3 +1205,7 @@
|
|||||||
2026-07-03 22:22 [Edit] /home/steggi/pyramid/PROGRESS.md
|
2026-07-03 22:22 [Edit] /home/steggi/pyramid/PROGRESS.md
|
||||||
2026-07-03 22:23 [Write] /home/steggi/.claude-pyramid/projects/-home-steggi-pyramid/memory/pyramid-arbeitsstand.md
|
2026-07-03 22:23 [Write] /home/steggi/.claude-pyramid/projects/-home-steggi-pyramid/memory/pyramid-arbeitsstand.md
|
||||||
2026-07-03 22:23 [Edit] /home/steggi/pyramid/docs/PC_TESTPLAN.md
|
2026-07-03 22:23 [Edit] /home/steggi/pyramid/docs/PC_TESTPLAN.md
|
||||||
|
2026-07-03 22:48 [Edit] /home/steggi/pyramid/PROGRESS.md
|
||||||
|
2026-07-03 22:50 [Write] /home/steggi/pyramid/test/auth_log_test.dart
|
||||||
|
2026-07-03 22:50 [Edit] /home/steggi/pyramid/pubspec.yaml
|
||||||
|
2026-07-03 22:51 [Edit] /home/steggi/pyramid/PROGRESS.md
|
||||||
|
|||||||
+40
@@ -13,6 +13,46 @@ Schritt (und beim Abbruch mitten im Schritt den Zwischenstand). Format:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-03 – Review-Nachzügler abgeschlossen + AuthLog-Regressionstests
|
||||||
|
|
||||||
|
**Erledigt:**
|
||||||
|
- **Fable-5-Review vervollständigt (eebf8ae):** Die drei seit Review-Abschluss
|
||||||
|
dazugekommenen erledigten Arbeiten kritisch geprüft und als Punkte (e)–(g) im
|
||||||
|
Review-Abschnitt abgehakt: Unit-Tests 99cde9a (korrekt, Fake-Clients schlagen
|
||||||
|
bei jedem Fremd-Aufruf laut fehl), Doku-Commits 16561bb/566938f (alle
|
||||||
|
Behauptungen gegen Code/pubspec/matrix-6.2.0 verifiziert – Factory-Stellen,
|
||||||
|
Tabellenname `box_inbound_group_session`), Autopilot-Konto-Wechsel bfe5876
|
||||||
|
(kein App-Code, Logik in Ordnung; harmloser False-Positive der
|
||||||
|
Limit-Erkennung dokumentiert). **Kein Befund, keine Code-Änderung nötig.**
|
||||||
|
Damit sind ALLE als erledigt markierten Punkte reviewt.
|
||||||
|
- **`test/auth_log_test.dart` (4 Tests):** `AuthLog` ist die einzige weitere
|
||||||
|
öffentliche Schnittstelle auf dem heiligen Pfad, die headless testbar ist
|
||||||
|
(der Soft-Logout-Guard ruft `AuthLog.write` im catch-Pfad auf – würde es
|
||||||
|
werfen, eskalierte das SDK zu `logout()`+`clear()`). Getestet: write/read
|
||||||
|
werfen NIE, auch wenn die Plattform fehlt (kaputter PathProvider);
|
||||||
|
Platzhalter statt Fehler bei leerem Log; ISO-Zeitstempel pro Zeile;
|
||||||
|
500-Zeilen-Kappung (älteste Einträge fliegen raus, neueste überleben).
|
||||||
|
Dafür `path_provider_platform_interface ^2.1.2` als dev_dependency ergänzt –
|
||||||
|
offizieller Mock-Weg, war schon transitiv im Lockfile, kein neues externes
|
||||||
|
Paket. `flutter test`: **alle 14 Tests grün auf dem Pi**, `flutter analyze`
|
||||||
|
unverändert (1 bekannter Hinweis `chat_provider.dart:42`).
|
||||||
|
|
||||||
|
**Offen/Nächster Schritt:** Unverändert blockiert: Alle offenen ROADMAP-Punkte
|
||||||
|
(M0 SQLCipher, M1 Härtetest, M2 Call-Schicht/State-Management) brauchen PC/GUI
|
||||||
|
oder Bernds Antworten (Call-Pilot, SQLCipher-Priorität) – siehe
|
||||||
|
`docs/PC_TESTPLAN.md` und die Fragen an Bernd weiter unten. Weitere sichere
|
||||||
|
Pi-Testkandidaten sind erschöpft (Rest ist bibliotheksprivat oder braucht
|
||||||
|
Widget-Tests mit gemocktem Matrix-Client – lohnt erst nach dem M2-Modulschnitt
|
||||||
|
mit echten öffentlichen Schnittstellen).
|
||||||
|
|
||||||
|
**Stolperfallen:** `AuthLog` cached sein File-Handle statisch – der Test für
|
||||||
|
„Plattform kaputt" muss deshalb VOR den Tests mit funktionierender Plattform
|
||||||
|
laufen (im Testfile kommentiert). Bei künftigen Tests an Singletons mit
|
||||||
|
statischem Zustand auf Testreihenfolge/Isolate-Grenzen achten (flutter test
|
||||||
|
isoliert pro Datei, nicht pro Test).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-07-03 – Erste Unit-Tests: Regressionsnetz für die zwei heiligsten Codepfade
|
## 2026-07-03 – Erste Unit-Tests: Regressionsnetz für die zwei heiligsten Codepfade
|
||||||
|
|
||||||
**Erledigt:** Eine Vorsession hatte (unprotokolliert, Abbruch vor dem Testlauf –
|
**Erledigt:** Eine Vorsession hatte (unprotokolliert, Abbruch vor dem Testlauf –
|
||||||
|
|||||||
+7
-7
@@ -801,10 +801,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.18.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -918,7 +918,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.2.1"
|
||||||
path_provider_platform_interface:
|
path_provider_platform_interface:
|
||||||
dependency: transitive
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: path_provider_platform_interface
|
name: path_provider_platform_interface
|
||||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||||
@@ -1294,18 +1294,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
|
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.11"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
|
sha256: "1991d4cfe85d5043241acac92962c3977c8d2f2add1ee73130c7b286417d1d34"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.16"
|
version: "0.6.17"
|
||||||
timezone:
|
timezone:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ dev_dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_lints: ^6.0.0
|
flutter_lints: ^6.0.0
|
||||||
flutter_launcher_icons: ^0.13.1
|
flutter_launcher_icons: ^0.13.1
|
||||||
|
# Nur für Tests: offizieller Weg, path_provider ohne echte Plattform zu
|
||||||
|
# mocken (PathProviderPlatform.instance überschreiben). War schon transitiv
|
||||||
|
# im Lockfile, kein neues externes Paket.
|
||||||
|
path_provider_platform_interface: ^2.1.2
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
webcrypto:
|
webcrypto:
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
|
||||||
|
import 'package:pyramid/core/auth_log.dart';
|
||||||
|
|
||||||
|
/// Plattform kaputt/nicht verfügbar (z. B. sehr früher App-Start, exotischer
|
||||||
|
/// Fehler): genau der Fall, in dem AuthLog.write NIEMALS werfen darf – der
|
||||||
|
/// Soft-Logout-Guard ruft es in seinem catch-Pfad auf, und ein Throw dort
|
||||||
|
/// würde im SDK zu logout()+clear() eskalieren (der Uta-Bug).
|
||||||
|
class _BrokenPathProvider extends PathProviderPlatform {
|
||||||
|
@override
|
||||||
|
Future<String?> getApplicationSupportPath() async =>
|
||||||
|
throw StateError('Plattform nicht verfügbar');
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TempPathProvider extends PathProviderPlatform {
|
||||||
|
_TempPathProvider(this.path);
|
||||||
|
final String path;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String?> getApplicationSupportPath() async => path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// WICHTIG: Reihenfolge der Tests ist Absicht. AuthLog cached sein File-Handle
|
||||||
|
// statisch; der Kaputt-Plattform-Test muss laufen, BEVOR ein Test mit
|
||||||
|
// funktionierender Plattform das Handle in den Cache legt.
|
||||||
|
late Directory tempDir;
|
||||||
|
|
||||||
|
setUpAll(() {
|
||||||
|
tempDir = Directory.systemTemp.createTempSync('pyramid_auth_log_test');
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDownAll(() {
|
||||||
|
tempDir.deleteSync(recursive: true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'write/read werfen NIE, auch wenn die Plattform fehlt '
|
||||||
|
'(CLAUDE.md: Fehlerpfade dürfen nie in einem stillen Logout enden)',
|
||||||
|
() async {
|
||||||
|
PathProviderPlatform.instance = _BrokenPathProvider();
|
||||||
|
// Darf normal zurückkehren, obwohl getApplicationSupportPath wirft.
|
||||||
|
await AuthLog.write('darf nicht werfen');
|
||||||
|
expect(await AuthLog.read(), startsWith('Log konnte nicht gelesen werden'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('read ohne bisherige Einträge liefert Platzhalter statt Fehler',
|
||||||
|
() async {
|
||||||
|
PathProviderPlatform.instance = _TempPathProvider(tempDir.path);
|
||||||
|
expect(await AuthLog.read(), '(noch keine Einträge)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('write hängt Zeile mit ISO-Zeitstempel an, read liefert sie zurück',
|
||||||
|
() async {
|
||||||
|
PathProviderPlatform.instance = _TempPathProvider(tempDir.path);
|
||||||
|
await AuthLog.write('Hallo Log');
|
||||||
|
final content = await AuthLog.read();
|
||||||
|
expect(content, contains('Hallo Log'));
|
||||||
|
expect(
|
||||||
|
RegExp(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}').hasMatch(content),
|
||||||
|
isTrue,
|
||||||
|
reason: 'jede Zeile beginnt mit einem ISO-8601-Zeitstempel',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'Log wird auf 500 Zeilen gekappt (älteste fliegen raus), '
|
||||||
|
'damit es nie unbegrenzt wächst', () async {
|
||||||
|
PathProviderPlatform.instance = _TempPathProvider(tempDir.path);
|
||||||
|
for (var i = 0; i < 520; i++) {
|
||||||
|
await AuthLog.write('Zeile $i');
|
||||||
|
}
|
||||||
|
final lines = (await AuthLog.read()).trimRight().split('\n');
|
||||||
|
expect(lines.length, 500);
|
||||||
|
expect(lines.last, contains('Zeile 519'),
|
||||||
|
reason: 'neueste Einträge müssen überleben');
|
||||||
|
expect((await AuthLog.read()).contains('Hallo Log'), isFalse,
|
||||||
|
reason: 'ältester Eintrag (aus dem Test davor) muss weggekappt sein');
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user