import 'package:audio_service/audio_service.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:melo/library/database.dart'; import 'package:melo/library/song_media.dart'; import 'package:melo/player/audio_handler.dart'; import 'package:melo/services/navidrome_service.dart'; Song _lokalerSong() => Song( id: 'uuid-1', path: '/storage/emulated/0/Music/Nightcore.mp3', title: 'No Friends', dateAddedMs: 0, updatedAtMs: 0, deleted: false, playCount: 0, categoriesEdited: false, metadataEdited: false, ); void main() { group('Titel vom Gerät werden nie als Server-Titel behandelt', () { test('ein lokaler Song trägt keine Navidrome-ID', () { expect(navidromeIdOf(songToMediaItem(_lokalerSong())), isNull); }); test('für einen lokalen Song wird der Server-Cache nicht befragt', () { // Wurzel-Ursache von "Wiedergabe fehlgeschlagen: (0) Source error": // die file://-URI wurde als Navidrome-Song-ID an den Server geschickt. expect(nutztServerCache(songToMediaItem(_lokalerSong())), isFalse); }); test('ein lokaler Song bringt seine UUID für die lokale Historie mit', () { expect(songIdOf(songToMediaItem(_lokalerSong())), 'uuid-1'); }); test('ein lokaler Song wird direkt von seinem Dateipfad gespielt', () { expect( quelleFuer(songToMediaItem(_lokalerSong())), Uri.file('/storage/emulated/0/Music/Nightcore.mp3'), ); }); }); group('Server-Titel', () { final serverTitel = MediaItem( id: 'https://musik.baka-net.de/rest/stream.view?id=abc123', title: 'Serverlied', extras: const {'navidromeId': 'abc123'}, ); test('trägt seine Navidrome-ID getrennt von der Abspiel-URI', () { expect(navidromeIdOf(serverTitel), 'abc123'); expect(songIdOf(serverTitel), isNull); }); test('darf im Server-Cache nachgesehen werden', () { expect(nutztServerCache(serverTitel), isTrue); }); test('läuft ohne Cache-Treffer direkt vom Stream', () { expect(quelleFuer(serverTitel), Uri.parse(serverTitel.id)); }); test('läuft mit Cache-Treffer aus der lokalen Datei', () { expect( quelleFuer(serverTitel, cacheTreffer: '/cache/abc.mp3'), Uri.file('/cache/abc.mp3'), ); }); }); group('NavidromeService.cacheSchluessel', () { test('hängt nur an der Song-ID, nicht an der Stream-Adresse', () { // Die Stream-Adresse trägt Token und Salt und ist bei jedem App-Start // eine andere — als Cache-Schlüssel wäre ein Titel nie wiederzufinden. expect(NavidromeService.cacheSchluessel('abc123'), NavidromeService.cacheSchluessel('abc123')); expect(NavidromeService.cacheSchluessel('abc123'), isNot(NavidromeService.cacheSchluessel('xyz789'))); }); }); group('NavidromeService.istAudioAntwort', () { test('Subsonic-Fehler kommt mit HTTP 200 und JSON — nie in den Cache', () { // Genau diese Antwort landete als ".mp3" im Cache und machte den Titel // dauerhaft unabspielbar. expect( NavidromeService.istAudioAntwort(200, 'application/json'), isFalse, ); }); test('HTML-Fehlerseite ist keine Musik', () { expect( NavidromeService.istAudioAntwort(200, 'text/html; charset=utf-8'), isFalse, ); }); test('fehlender Content-Type ist keine Musik', () { expect(NavidromeService.istAudioAntwort(200, null), isFalse); }); test('HTTP 404 ist keine Musik', () { expect(NavidromeService.istAudioAntwort(404, 'audio/mpeg'), isFalse); }); test('audio/mpeg darf in den Cache', () { expect(NavidromeService.istAudioAntwort(200, 'audio/mpeg'), isTrue); }); test('application/octet-stream darf in den Cache', () { expect( NavidromeService.istAudioAntwort(200, 'application/octet-stream'), isTrue, ); }); }); }