import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; import 'package:melo/services/melo_cloud_service.dart'; void main() { group('parseListe', () { test('liest Titel inklusive Grabsteinen', () { final body = jsonEncode({ 'status': 'ok', 'songs': [ { 'id': 'abc', 'title': 'Nachtpuls', 'artist': 'Rotklang', 'duration': 210, 'size': 4200, 'deleted': false, }, {'id': 'def', 'title': 'Weg', 'deleted': true}, ], 'count': 1, }); final songs = MeloCloudService.parseListe(body); expect(songs, hasLength(2)); expect(songs.first.id, 'abc'); expect(songs.first.kuenstler, 'Rotklang'); expect(songs.first.dauerSekunden, 210); expect(songs.first.geloescht, isFalse); expect(songs.last.geloescht, isTrue); }); test('leere Liste ist kein Fehler', () { expect( MeloCloudService.parseListe(jsonEncode({'status': 'ok', 'songs': []})), isEmpty, ); }); test('Server-Fehler wird als CloudException gemeldet', () { expect( () => MeloCloudService.parseListe(jsonEncode({'error': 'Auth required'})), throwsA(isA()), ); }); test('fehlender Titel wird nicht zu einer leeren Zeile', () { final songs = MeloCloudService.parseListe(jsonEncode({ 'songs': [ {'id': 'x', 'title': ''} ] })); expect(songs.single.titel, 'Unbekannt'); }); }); group('parseUpload', () { test('liefert die vergebene Server-ID', () { final body = jsonEncode( {'status': 'ok', 'song_id': 'neu123', 'title': 'A', 'action': 'new'}); expect(MeloCloudService.parseUpload(body), 'neu123'); }); test('erkennt eine Dublette an derselben ID', () { // Der Server verknüpft dieselbe Datei mit dem bestehenden Titel, // statt eine zweite Kopie anzulegen. final body = jsonEncode( {'status': 'ok', 'song_id': 'alt999', 'action': 'linked'}); expect(MeloCloudService.parseUpload(body), 'alt999'); }); test('Fehler wird als CloudException gemeldet', () { expect( () => MeloCloudService.parseUpload( jsonEncode({'error': 'Datei zu groß (max 50 MB)'})), throwsA(isA()), ); }); }); group('parseFavoriten', () { test('liefert nur die IDs', () { final body = jsonEncode({ 'favorites': [ {'id': 'a', 'title': 'A'}, {'id': 'b', 'title': 'B'}, ] }); expect(MeloCloudService.parseFavoriten(body), ['a', 'b']); }); test('ohne Favoriten leere Liste', () { expect(MeloCloudService.parseFavoriten(jsonEncode({'status': 'ok'})), isEmpty); }); }); group('endungFuer', () { test('erkennt die gängigen Formate der Bibliothek', () { expect(MeloCloudService.endungFuer('audio/mpeg'), '.mp3'); expect(MeloCloudService.endungFuer('audio/mp4'), '.m4a'); expect(MeloCloudService.endungFuer('audio/flac'), '.flac'); expect(MeloCloudService.endungFuer('audio/ogg'), '.ogg'); }); test('ignoriert angehängte Parameter und Groß-/Kleinschreibung', () { expect(MeloCloudService.endungFuer('Audio/MP4; charset=binary'), '.m4a'); }); test('fällt ohne bekannte Zuordnung auf .mp3 zurück', () { expect(MeloCloudService.endungFuer(null), '.mp3'); expect(MeloCloudService.endungFuer('application/octet-stream'), '.mp3'); }); }); group('CloudVerlauf', () { test('meldet die Zeit als ISO-Zeit ohne Bruchteile', () { final eintrag = CloudVerlauf( cloudId: 'abc', gespieltAm: DateTime.utc(2026, 8, 21, 7, 28, 5, 123), positionSekunden: 42, ); expect(eintrag.toJson(), { 'song_id': 'abc', 'played_at': '2026-08-21T07:28:05', 'position': 42, }); }); }); }