Fix critical blocker issues and improve tests
## Critical Blockers Fixed - Remove playbackState.addError() which broke audio_service permanently - Move error handling from audio_handler to song_list where UI context exists - Display error in SnackBar instead of destroying playback stream - Add escapeChar parameter to LIKE queries for correct wildcard handling - Fixes broken search for titles with _ or % characters - Add dismissScanError() method to allow closing error banner - Previously banner couldn't be dismissed (missing notifyListeners()) ## Improvements - Remove dead livePaths list, use companions.isNotEmpty instead - Add initial progress update to show total files when scan starts - Add tooltip to now_playing_screen Zurück button - Add proper error handling in song_list with async/await ## Testing - Add regression test for CRITICAL-1: empty scan doesn't delete songs - Add regression test for CRITICAL-2: tombstoned files restore on re-scan - All 11 tests pass Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
4fa8d12fa0
commit
d04783073f
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:melo/library/database.dart';
|
||||
@@ -56,4 +57,46 @@ void main() {
|
||||
expect(secondIds, firstIds);
|
||||
expect((await db.watchSongs().first).length, 3); // keine Duplikate
|
||||
});
|
||||
|
||||
test('CRITICAL-1: leerer Scan loescht nicht (nonexistent folder)', () async {
|
||||
// Initialer Scan
|
||||
await scanFolders(db, [fixtures], coverDir: coverDir);
|
||||
final initialCount = (await db.watchSongs().first).length;
|
||||
expect(initialCount, 3);
|
||||
|
||||
// Scan mit nicht-existierendem Ordner (livePaths wird leer)
|
||||
await scanFolders(db, ['/this/does/not/exist'], coverDir: coverDir);
|
||||
|
||||
// Alle Songs sollten noch da sein
|
||||
final afterEmpty = await db.watchSongs().first;
|
||||
expect(afterEmpty.length, initialCount);
|
||||
});
|
||||
|
||||
test('CRITICAL-2: Datei wird nach Tombstone wieder sichtbar', () async {
|
||||
// Initialer Scan: alle 3 Dateien
|
||||
await scanFolders(db, [fixtures], coverDir: coverDir);
|
||||
var songs = await db.watchSongs().first;
|
||||
expect(songs.length, 3);
|
||||
final nachtpulsId = songs.firstWhere((s) => s.title == 'Nachtpuls').id;
|
||||
|
||||
// Manuell tombstonen
|
||||
await db.upsertSongs([
|
||||
SongsCompanion.insert(
|
||||
id: nachtpulsId,
|
||||
path: p.join(fixtures, '01 Nachtpuls.mp3'),
|
||||
title: 'Nachtpuls',
|
||||
dateAddedMs: 1,
|
||||
updatedAtMs: 1,
|
||||
deleted: const Value(true),
|
||||
),
|
||||
]);
|
||||
songs = await db.watchSongs().first;
|
||||
expect(songs.where((s) => s.title == 'Nachtpuls').length, 0); // nicht sichtbar
|
||||
|
||||
// Re-Scan sollte die Datei wieder finden und deleted=false setzen
|
||||
await scanFolders(db, [fixtures], coverDir: coverDir);
|
||||
songs = await db.watchSongs().first;
|
||||
expect(songs.where((s) => s.title == 'Nachtpuls').length, 1); // wieder da
|
||||
expect(songs.length, 3); // alle 3 Songs
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user