Files
Melo/test/services/baka_auth_test.dart
T
Hermes (Server)andClaude Sonnet 5 c3f541f266 BakaAuth.abmelden() setzt auch Kontingent-Anzeige zurück
Review-Fix: abmelden() setzte _verbleibend bisher nicht zurück,
anders als GastZugang.verwerfen() (_verbleibend = null). Ohne den
Fix bliebe nach einem Account-Wechsel (z.B. Baka -> Tinker) der
alte Kontingent-Stand sichtbar, bis der nächste Download einen
frischen Stand liefert. Aktuell folgenlos (verbleibend ist bis zum
Server-Rollout ohnehin immer null), aber ein latenter Bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012A2pmbnVNPiHdyf2GW8eLP
2026-08-29 13:27:44 +02:00

179 lines
5.7 KiB
Dart

import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:melo/services/baka_auth.dart';
/// Einfacher Speicher im Arbeitsspeicher — FlutterSecureStorage braucht
/// Plattform-Kanäle und ist im Test nicht verfügbar.
class _MemorySpeicher implements TokenSpeicher {
final Map<String, String> werte = {};
@override
Future<String?> lesen(String key) async => werte[key];
@override
Future<void> schreiben(String key, String wert) async => werte[key] = wert;
@override
Future<void> loeschen(String key) async => werte.remove(key);
}
void main() {
test('Anmeldung mit gültigen Daten speichert den Token', () async {
final speicher = _MemorySpeicher();
late String gesendet;
final client = MockClient((req) async {
gesendet = req.body;
return http.Response(jsonEncode({'token': 'jwt-abc'}), 200);
});
final auth = BakaAuth(client: client, speicher: speicher);
final fehler = await auth.anmelden('Baka', 'geheim');
expect(fehler, isNull);
expect(auth.istAngemeldet, isTrue);
expect(auth.benutzer, 'Baka');
expect(speicher.werte['baka_token'], 'jwt-abc');
expect(jsonDecode(gesendet), {'username': 'Baka', 'password': 'geheim'});
});
test('Auth-Header trägt den Token als Bearer', () async {
final client = MockClient(
(_) async => http.Response(jsonEncode({'token': 'jwt-abc'}), 200));
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
await auth.anmelden('Baka', 'geheim');
expect(auth.authHeader['Authorization'], 'Bearer jwt-abc');
});
test('Falsches Passwort liefert die Server-Meldung, obwohl HTTP 200 kommt',
() async {
// Der Baka-Auth-Server antwortet auch bei Fehlern mit Status 200.
final client = MockClient((_) async => http.Response(
jsonEncode({'status': 'error', 'message': 'Falscher Benutzer'}), 200));
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
final fehler = await auth.anmelden('Baka', 'falsch');
expect(fehler, 'Falscher Benutzer');
expect(auth.istAngemeldet, isFalse);
});
test('Nicht erreichbarer Server meldet einen Verbindungsfehler', () async {
final client = MockClient((_) async => throw const SocketAusfall());
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
final fehler = await auth.anmelden('Baka', 'geheim');
expect(fehler, 'Keine Verbindung zum Anmelde-Server');
expect(auth.istAngemeldet, isFalse);
});
test('laden() stellt einen gespeicherten Token wieder her', () async {
final speicher = _MemorySpeicher();
speicher.werte['baka_token'] = 'jwt-alt';
speicher.werte['baka_user'] = 'Baka';
final auth = BakaAuth(
client: MockClient((_) async => http.Response('', 500)),
speicher: speicher);
await auth.laden();
expect(auth.istAngemeldet, isTrue);
expect(auth.benutzer, 'Baka');
});
test('autoAnmelden meldet mit den übergebenen Zugangsdaten an', () async {
late String gesendet;
final client = MockClient((req) async {
gesendet = req.body;
return http.Response(jsonEncode({'token': 'jwt-server'}), 200);
});
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
await auth.autoAnmelden('Tinker', 'geheim2');
expect(auth.istAngemeldet, isTrue);
expect(auth.benutzer, 'Tinker');
expect(jsonDecode(gesendet), {'username': 'Tinker', 'password': 'geheim2'});
});
test('autoAnmelden greift nicht ein, wenn schon angemeldet', () async {
var aufrufe = 0;
final client = MockClient((_) async {
aufrufe++;
return http.Response(jsonEncode({'token': 'jwt-abc'}), 200);
});
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
await auth.anmelden('Baka', 'geheim');
await auth.autoAnmelden('Tinker', 'geheim2');
expect(aufrufe, 1);
expect(auth.benutzer, 'Baka');
});
test('autoAnmelden tut nichts ohne Zugangsdaten', () async {
var aufrufe = 0;
final client = MockClient((_) async {
aufrufe++;
return http.Response(jsonEncode({'token': 'jwt'}), 200);
});
final auth = BakaAuth(client: client, speicher: _MemorySpeicher());
await auth.autoAnmelden('', '');
expect(aufrufe, 0);
expect(auth.istAngemeldet, isFalse);
});
test('merkeVerbleibend übernimmt den Kontingent-Stand und meldet Listener',
() async {
final auth = BakaAuth(
client: MockClient((_) async => http.Response('', 500)),
speicher: _MemorySpeicher());
var benachrichtigt = 0;
auth.addListener(() => benachrichtigt++);
auth.merkeVerbleibend(37);
expect(auth.verbleibend, 37);
expect(benachrichtigt, 1);
});
test('Abmelden setzt auch den Kontingent-Stand zurück', () async {
final speicher = _MemorySpeicher();
final auth = BakaAuth(
client: MockClient(
(_) async => http.Response(jsonEncode({'token': 'jwt-abc'}), 200)),
speicher: speicher);
await auth.anmelden('Baka', 'geheim');
auth.merkeVerbleibend(42);
await auth.abmelden();
expect(auth.verbleibend, isNull);
});
test('Abmelden löscht Token und Benutzer aus dem Speicher', () async {
final speicher = _MemorySpeicher();
final auth = BakaAuth(
client: MockClient(
(_) async => http.Response(jsonEncode({'token': 'jwt-abc'}), 200)),
speicher: speicher);
await auth.anmelden('Baka', 'geheim');
await auth.abmelden();
expect(auth.istAngemeldet, isFalse);
expect(speicher.werte, isEmpty);
});
}
/// Steht im Test für einen Netzwerkausfall.
class SocketAusfall implements Exception {
const SocketAusfall();
}