diff --git a/lib/estado/estado_radio.dart b/lib/estado/estado_radio.dart index 7a53953..d052a22 100644 --- a/lib/estado/estado_radio.dart +++ b/lib/estado/estado_radio.dart @@ -529,7 +529,22 @@ class EstadoRadio extends ChangeNotifier { /// shared [parseListaTolerante] (D1): survivors are kept, no flag/ /// quarantine at all. Future _cargarEmisorasCustom() async { - final archivo = await _archivoCustom(); + // Resolving the path itself is part of the IO surface: a throw here must + // get the same IO-fail treatment as an unreadable file, not escape into + // _init()'s Future.wait and take the sibling loads down with it. + final File archivo; + try { + archivo = await _archivoCustom(); + } catch (e) { + _customDegradado = true; + registrarSaltoPersistencia( + subsistema: 'emisoras_custom', + detalle: 'resolucion de ruta', + razon: e.toString(), + ); + notifyListeners(); + return; + } final contenido = await _leerContenidoCustom(archivo); if (contenido == null) return; // ya resuelto: vacio o degradado por IO. diff --git a/test/estado/estado_radio_test.dart b/test/estado/estado_radio_test.dart index 451b49c..977d165 100644 --- a/test/estado/estado_radio_test.dart +++ b/test/estado/estado_radio_test.dart @@ -408,6 +408,30 @@ void main() { }, ); + test( + 'si resolver la ruta del archivo custom falla, la inicializacion ' + 'sobrevive y las cargas hermanas no se pierden (D5 IO-fail)', + () async { + final estado = EstadoRadio( + audio: FakeServicioAudio(), + favoritos: FakeServicioFavoritos(), + radio: FakeServicioRadio(), + servicioEcualizador: FakeServicioEcualizador(), + resolverArchivoCustom: + () async => throw const FileSystemException('sin storage'), + iniciarAutomaticamente: false, + ); + + // Path resolution failing must be treated as an IO-fail, not + // escape _cargarEmisorasCustom: it runs inside _init()'s + // Future.wait, so an uncaught throw would also reject the + // sibling loads (populares/favoritos/grupos). + await estado.inicializar(); + + expect(estado.emisorasCustom, isEmpty); + }, + ); + test( 'JSON invalido al nivel superior pone en cuarentena el archivo ' 'original (D5 parse-fail)',