Neuer YouTube-Bereich im Online-Tab: Adresse einfuegen, herunterladen, der Titel landet in Meine Musik. - BakaAuth: Anmeldung gegen baka-net.de/auth, Token verschluesselt auf dem Geraet. Der Server meldet Fehler mit HTTP 200 und Text im Rumpf, deshalb wird der Inhalt geprueft statt nur der Statuscode. - YtDownloadService: Proxy fragen, MP3 abholen, halbe Dateien aufraeumen. Kuenstler nur aus "Kuenstler - Lied", sonst leer statt geraten. - MediaStoreBridge (Kotlin): legt die Datei in Music/Melo ab und meldet sie dem MediaStore. Noetig, weil der Android-Scan sonst beim naechsten Lauf alles wieder als verschwunden markiert. - SubTabs nach shared/ gezogen (jetzt in Meine Musik und Online genutzt). 177 Tests gruen, flutter analyze ohne Befund, Release-APK baut. Der Weg ueber den echten Proxy ist noch nicht auf dem Geraet erprobt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NLW1q1hzEC9goDQ1dJ98d
107 lines
3.5 KiB
Dart
107 lines
3.5 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('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();
|
|
}
|