fix(radio): treat custom-station path resolution as part of the IO surface
_cargarEmisorasCustom resolved the file path outside the IO guard, so a throw from the resolver escaped into _init()'s Future.wait and took the sibling loads (populares, favoritos, grupos) down with it — a gap the old catch-all used to cover. Path resolution now gets the same IO-fail treatment as an unreadable file: degraded flag, logged skip, siblings unaffected.
This commit is contained in:
@@ -529,7 +529,22 @@ class EstadoRadio extends ChangeNotifier {
|
||||
/// shared [parseListaTolerante] (D1): survivors are kept, no flag/
|
||||
/// quarantine at all.
|
||||
Future<void> _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.
|
||||
|
||||
|
||||
@@ -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)',
|
||||
|
||||
Reference in New Issue
Block a user