Files
pluriwave/test/helpers/fakes_alarmas.dart
T
FreeTLab 6acbd7ca93
Build & Deploy PluriWave / Análisis de código (push) Successful in 47s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m1s
fix(alarm): handle snooze reschedule failures instead of silently dropping them
posponerAlarma() and posponerProximaDesdePreaviso() called the native
scheduler with no error handling, unlike guardarAlarma(). When the
native call failed (e.g. revoked exact-alarm permission), the
exception escaped before notifyListeners() ran, leaving the alarm
list stuck on stale data with no real alarm scheduled and no snooze
countdown notification.

Both methods now mirror guardarAlarma()'s pattern: permission
pre-check, try/catch into _error, and an unconditional
notifyListeners() so the UI always reflects the outcome. Failures
surface via SnackBar in the ringing screen and in app.dart's
postpone-next handler.
2026-07-01 00:22:58 +02:00

119 lines
3.4 KiB
Dart

import 'dart:async';
import 'package:pluriwave/l10n/gen/app_localizations.dart';
import 'package:pluriwave/modelos/alarma_musical.dart';
import 'package:pluriwave/servicios/servicio_alarmas_android.dart';
import 'package:pluriwave/servicios/servicio_grabacion_radio.dart';
/// Shared fake of the Android alarm bridge for alarm-related tests.
class FakePuertoAlarmasAndroid implements PuertoAlarmasAndroid {
final programadas = <AlarmaMusical>[];
final canceladas = <String>[];
final detenidas = <String>[];
final ocultadas = <String>[];
final ejecucionesNativas = <EjecucionAlarmaNativa>[];
final snoozesNativos = <EstadoSnoozeNativo>[];
final _eventos = StreamController<EventoAlarmaAndroid>.broadcast();
bool ignoraOptimizacionBateria = true;
int solicitudesExencionBateria = 0;
/// Test-only failure switch (Design D7): when true, [programar] throws
/// instead of scheduling, enabling failure-path coverage that the fake
/// could not otherwise produce.
bool fallaProgramar = false;
/// Simulates a native -> Flutter `alarmFired` MethodChannel event.
void emitirEvento(EventoAlarmaAndroid evento) => _eventos.add(evento);
@override
Stream<EventoAlarmaAndroid> get eventosAlarma => _eventos.stream;
@override
void configurarLocalizaciones(AppLocalizations l10n) {}
@override
Future<void> programar(AlarmaMusical alarma) async {
if (fallaProgramar) {
throw StateError('fake programar failure');
}
programadas.add(alarma);
}
@override
Future<void> cancelar(String alarmaId) async {
canceladas.add(alarmaId);
}
@override
Future<void> detenerSonidoNativo(String alarmaId) async {
detenidas.add(alarmaId);
}
@override
Future<void> ocultarNotificacionAlarma(String alarmaId) async {
ocultadas.add(alarmaId);
}
@override
Future<void> confirmarAudioFlutter(String alarmaId) async {
detenidas.add(alarmaId);
}
@override
Future<DiagnosticoAlarmasAndroid> diagnostico() async =>
DiagnosticoAlarmasAndroid(
puedeProgramarExactas: true,
notificacionesPermitidas: true,
puedeUsarPantallaCompleta: true,
ignoraOptimizacionBateria: ignoraOptimizacionBateria,
alarmasNativasPendientes: 0,
fabricante: 'test',
versionSdk: 35,
);
@override
Future<bool> solicitarExencionBateria() async {
solicitudesExencionBateria++;
return true;
}
@override
Future<EventoAlarmaAndroid?> obtenerEventoInicial() async => null;
@override
Future<List<EjecucionAlarmaNativa>>
obtenerEjecucionesNativasGestionadas() async => ejecucionesNativas;
@override
Future<List<EstadoSnoozeNativo>> obtenerEstadoSnoozeNativo() async =>
List.of(snoozesNativos);
@override
Future<bool> solicitarPermisoAlarmasExactas() async => true;
@override
Future<bool> solicitarPermisoNotificaciones() async => true;
@override
Future<bool> solicitarPermisoPantallaCompleta() async => true;
Future<void> dispose() => _eventos.close();
}
/// Inactive recording service fake, safe for widget tests.
class FakeServicioGrabacionRadioInactiva extends ServicioGrabacionRadio {
final _controller = StreamController<EstadoGrabacionRadio>.broadcast();
@override
EstadoGrabacionRadio get estado => const EstadoGrabacionRadio.inactiva();
@override
Stream<EstadoGrabacionRadio> get estadoStream => _controller.stream;
@override
Future<void> inicializar() async {}
@override
Future<void> dispose() => _controller.close();
}