Fix: Server-Bibliothek lädt nicht + Tab '🌐 Server' abgeschnitten
Bug 2 (Laden schlägt fehl trotz 'ping ok'): Der Code ignorierte das Subsonic-
status-Feld. Navidrome liefert bei falschem Passwort HTTP 200 mit
status:"failed" — ping() meldete dadurch fälschlich Erfolg, getAlben/getArtists
behandelten die Fehlerantwort still als leer ("Erneut versuchen").
- parseSubsonic() wirft NavidromeException bei status:"failed" (mit Servermsg).
- ping() prüft jetzt den Body statt nur HTTP 200.
- getAlben/getArtists reichen den Fehler durch (rethrow) statt [] zu liefern.
- getAlben nutzt getAlbumList2 (ID3, wie getArtists) statt getAlbumList (Folder).
- Server-Tab zeigt die echte Fehlermeldung statt "Keine Alben geladen".
Bug 1 (Tab abgeschnitten -> nur "Serve"): TabBar labelPadding verkleinert
(engere Abstände), Schriftgröße unverändert.
Neue Tests: test/navidrome_parse_test.dart (5). 84/84 grün, analyze sauber.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tr2UwurtxyJUpWpBSeVmBm
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
61e28d128f
commit
3d39e8b922
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:melo/services/navidrome_service.dart';
|
||||
|
||||
/// Tests für die Subsonic-Antwort-Auswertung. Kern des Bugfixes:
|
||||
/// Navidrome liefert bei Fehlern (z. B. falsches Passwort) HTTP 200 mit
|
||||
/// {"subsonic-response":{"status":"failed","error":{...}}}. Diese Antworten
|
||||
/// dürfen NICHT stillschweigend als „leer" behandelt werden.
|
||||
void main() {
|
||||
group('NavidromeService.parseSubsonic', () {
|
||||
test('status:failed wirft NavidromeException mit Server-Meldung', () {
|
||||
const body =
|
||||
'{"subsonic-response":{"status":"failed","version":"1.16.1",'
|
||||
'"error":{"code":40,"message":"Wrong username or password"}}}';
|
||||
expect(
|
||||
() => NavidromeService.parseSubsonic(body),
|
||||
throwsA(isA<NavidromeException>()
|
||||
.having((e) => e.message, 'message', 'Wrong username or password')
|
||||
.having((e) => e.code, 'code', 40)),
|
||||
);
|
||||
});
|
||||
|
||||
test('status:ok liefert den subsonic-response-Block zurück', () {
|
||||
const body =
|
||||
'{"subsonic-response":{"status":"ok","version":"1.16.1",'
|
||||
'"albumList2":{"album":[]}}}';
|
||||
final resp = NavidromeService.parseSubsonic(body);
|
||||
expect(resp['status'], 'ok');
|
||||
expect(resp['albumList2'], isNotNull);
|
||||
});
|
||||
|
||||
test('fehlender subsonic-response wirft NavidromeException', () {
|
||||
expect(() => NavidromeService.parseSubsonic('{"foo":1}'),
|
||||
throwsA(isA<NavidromeException>()));
|
||||
});
|
||||
});
|
||||
|
||||
group('NavidromeService.parseAlben (ID3 / getAlbumList2)', () {
|
||||
test('liest albumList2.album korrekt', () {
|
||||
const body = '{"subsonic-response":{"status":"ok","albumList2":{"album":['
|
||||
'{"id":"a1","name":"Erstes Album","coverArt":"c1","songCount":9},'
|
||||
'{"id":"a2","title":"Zweites","songCount":3}'
|
||||
']}}}';
|
||||
final resp = NavidromeService.parseSubsonic(body);
|
||||
final alben = NavidromeService.parseAlben(resp);
|
||||
expect(alben.length, 2);
|
||||
expect(alben[0].id, 'a1');
|
||||
expect(alben[0].name, 'Erstes Album');
|
||||
expect(alben[0].songCount, 9);
|
||||
expect(alben[1].name, 'Zweites');
|
||||
});
|
||||
|
||||
test('leere albumList2 liefert leere Liste (kein Fehler)', () {
|
||||
final resp = NavidromeService.parseSubsonic(
|
||||
'{"subsonic-response":{"status":"ok","albumList2":{}}}');
|
||||
expect(NavidromeService.parseAlben(resp), isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user