import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/estado/estado_alarmas.dart'; import 'package:pluriwave/modelos/alarma_musical.dart'; import 'package:pluriwave/servicios/servicio_alarmas.dart'; import 'package:pluriwave/servicios/servicio_alarmas_android.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../helpers/fakes_alarmas.dart'; /// fix/alarmas-fallos-silenciosos, item 3: "verify the alarm is actually /// registered, and say so if it is not". `android.programar` returning /// without throwing is not proof enough by itself -- this is the check that /// would have caught the reported case immediately (the native side can /// silently fail to persist the registration even when the channel call /// itself reports success). void main() { setUp(() { SharedPreferences.setMockInitialValues({}); }); test('guardarAlarma detecta que el conteo nativo no refleja la alarma ' 'guardada, aunque android.programar no haya lanzado', () async { // Fixed at 0 regardless of what programar() does internally -- // simulates the native side accepting the channel call but never // actually persisting the registration. final android = FakePuertoAlarmasAndroid()..alarmasNativasPendientes = 0; final estado = EstadoAlarmas( servicio: ServicioAlarmas(reloj: () => DateTime(2026, 5, 25, 7)), android: android, iniciarAutomaticamente: false, ); addTearDown(estado.dispose); addTearDown(android.dispose); await estado.guardarAlarma( const AlarmaMusical( id: 'silenciosa1', nombre: 'Diaria', hora: 7, minuto: 30, tipoProgramacion: TipoProgramacionAlarma.diaria, diasSemana: [], ), ); final excepcion = estado.ultimaExcepcionPara('silenciosa1'); expect(excepcion, isNotNull); expect(excepcion!.tipo, ExcepcionAlarma.tipoFalloProgramacion); expect(estado.error, isNotNull); }); test('guardarAlarma en el camino feliz (conteo nativo coincide) no registra ' 'fallo alguno', () async { final android = FakePuertoAlarmasAndroid(); final estado = EstadoAlarmas( servicio: ServicioAlarmas(reloj: () => DateTime(2026, 5, 25, 7)), android: android, iniciarAutomaticamente: false, ); addTearDown(estado.dispose); addTearDown(android.dispose); await estado.guardarAlarma( const AlarmaMusical( id: 'sana1', nombre: 'Diaria', hora: 7, minuto: 30, tipoProgramacion: TipoProgramacionAlarma.diaria, diasSemana: [], ), ); expect(estado.ultimaExcepcionPara('sana1'), isNull); expect(estado.error, isNull); }); test( 'inicializar importa los fallos nativos (pre-aviso, servicio en primer ' 'plano, reprogramacion tras arranque) como excepciones por alarma', () async { final android = FakePuertoAlarmasAndroid() ..fallosProgramacionNativos.addAll([ FalloProgramacionNativo( alarmaId: 'con-preaviso-roto', tipo: ExcepcionAlarma.tipoFalloPreaviso, ocurridoEn: DateTime(2026, 5, 25, 7), ), FalloProgramacionNativo( alarmaId: 'servicio-rechazado', tipo: ExcepcionAlarma.tipoFalloServicioSonido, ocurridoEn: DateTime(2026, 5, 25, 7), ), ]); final servicio = ServicioAlarmas( reloj: () => DateTime(2026, 5, 25, 7, 30), ); await servicio.guardarAlarma( AlarmaMusical( id: 'con-preaviso-roto', nombre: 'Diaria', hora: 7, minuto: 30, tipoProgramacion: TipoProgramacionAlarma.diaria, diasSemana: const [], ), ); await servicio.guardarAlarma( AlarmaMusical( id: 'servicio-rechazado', nombre: 'Diaria', hora: 8, minuto: 0, tipoProgramacion: TipoProgramacionAlarma.diaria, diasSemana: const [], ), ); final estado = EstadoAlarmas( servicio: servicio, android: android, iniciarAutomaticamente: false, ); addTearDown(estado.dispose); addTearDown(android.dispose); await estado.inicializar(); final falloPreaviso = estado.ultimaExcepcionPara('con-preaviso-roto'); expect(falloPreaviso, isNotNull); expect(falloPreaviso!.tipo, ExcepcionAlarma.tipoFalloPreaviso); final falloServicio = estado.ultimaExcepcionPara('servicio-rechazado'); expect(falloServicio, isNotNull); expect(falloServicio!.tipo, ExcepcionAlarma.tipoFalloServicioSonido); }, ); }