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'; import 'package:melo/services/melo_cloud_service.dart'; class _MemorySpeicher implements TokenSpeicher { _MemorySpeicher(this.werte); final Map werte; @override Future lesen(String key) async => werte[key]; @override Future schreiben(String key, String wert) async => werte[key] = wert; @override Future loeschen(String key) async => werte.remove(key); } Future baue( Future Function(http.Request) antwort) async { final auth = BakaAuth( speicher: _MemorySpeicher({'baka_token': 'tok', 'baka_user': 'Baka'}), ); await auth.laden(); return MeloCloudService(auth: auth, client: MockClient(antwort)); } void main() { test('legePlaylistAn liefert die Server-ID', () async { final dienst = await baue((anfrage) async { expect(anfrage.method, 'POST'); expect(anfrage.url.path, endsWith('/playlists')); expect(jsonDecode(anfrage.body), {'name': 'Road Trip'}); // handle_playlist_create verpackt die ID unter „playlist" — genau so // antwortet der echte Server, und genau daran ist der Vertrag geknüpft. return http.Response( jsonEncode({ 'status': 'ok', 'playlist': {'id': 7, 'name': 'Road Trip', 'song_count': 0} }), 200, ); }); expect(await dienst.legePlaylistAn('Road Trip'), '7'); }); test('eine Antwort ohne playlist-Block ist ein Fehler', () async { // Die ID auf oberster Ebene zu suchen wäre der naheliegende Fehler; er // fiele am echten Server als „null" auf und sonst nirgends. final dienst = await baue( (_) async => http.Response(jsonEncode({'status': 'ok'}), 200)); expect(() => dienst.legePlaylistAn('Road Trip'), throwsA(isA())); }); test('ein Fehler im 200er-Körper wird geworfen', () async { final dienst = await baue((_) async => http.Response(jsonEncode({'error': 'kein Name'}), 200)); expect(() => dienst.legePlaylistAn(''), throwsA(isA())); }); test('fuegePlaylistSongsHinzu meldet die Song-IDs', () async { Map? gesendet; final dienst = await baue((anfrage) async { expect(anfrage.url.path, endsWith('/playlists/7/songs')); gesendet = jsonDecode(anfrage.body) as Map; return http.Response(jsonEncode({'status': 'ok'}), 200); }); await dienst.fuegePlaylistSongsHinzu('7', ['c1', 'c2']); expect(gesendet, { 'song_ids': ['c1', 'c2'] }); }); test('entfernePlaylistSong benutzt DELETE auf dem Song-Pfad', () async { String? pfad; String? methode; final dienst = await baue((anfrage) async { pfad = anfrage.url.path; methode = anfrage.method; return http.Response(jsonEncode({'status': 'ok'}), 200); }); await dienst.entfernePlaylistSong('7', 'c1'); expect(methode, 'DELETE'); expect(pfad, endsWith('/playlists/7/songs/c1')); }); test('setzePlaylistReihenfolge benutzt PUT auf /positions', () async { String? methode; Map? gesendet; final dienst = await baue((anfrage) async { methode = anfrage.method; expect(anfrage.url.path, endsWith('/playlists/7/positions')); gesendet = jsonDecode(anfrage.body) as Map; return http.Response(jsonEncode({'status': 'ok'}), 200); }); await dienst.setzePlaylistReihenfolge('7', ['c2', 'c1']); expect(methode, 'PUT'); // Der Router liest „positions", der Handler erwartet Paare. Unter // „song_ids" bekäme der Server eine leere Liste und antwortete stumm // „ok" — die Reihenfolge käme nie an, ohne jede Fehlermeldung. expect(gesendet, { 'positions': [ {'id': 'c2', 'position': 0}, {'id': 'c1', 'position': 1}, ] }); }); test('playlisten liest Name und ID', () async { final dienst = await baue((_) async => http.Response( jsonEncode({ 'playlists': [ {'id': 7, 'name': 'Road Trip'} ] }), 200, )); final listen = await dienst.playlisten(); expect(listen.single.id, '7'); expect(listen.single.name, 'Road Trip'); }); test('playlistSongs liefert die Song-IDs in Reihenfolge', () async { final dienst = await baue((_) async => http.Response( jsonEncode({ 'songs': [ {'id': 'c1'}, {'id': 'c2'}, ] }), 200, )); expect(await dienst.playlistSongs('7'), ['c1', 'c2']); }); }