import 'package:audio_service/audio_service.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:just_audio/just_audio.dart'; import 'package:pluriwave/servicios/servicio_audio.dart'; /// fix/notificacion-media — commit 2: exhaustive matrix for /// [mapearEstadoProceso], the pure seam extracted out of the handler's /// private `_mapProcState`. /// /// The handler itself cannot be instantiated in a unit test (MethodChannels), /// which is exactly why the mapping decision was lifted out: the one line /// that decides whether `audio_service` tears the foreground service — and /// with it the media notification — down is now testable on its own. void main() { /// The pre-change `_mapProcState` mapping, transcribed literally. Every /// `cambiandoFuente: false` expectation below is checked against THIS, so a /// future edit to the production switch that alters any non-masked case /// fails here instead of silently changing playback semantics. const mapeoHeredado = { ProcessingState.idle: AudioProcessingState.idle, ProcessingState.loading: AudioProcessingState.loading, ProcessingState.buffering: AudioProcessingState.buffering, ProcessingState.ready: AudioProcessingState.ready, ProcessingState.completed: AudioProcessingState.completed, }; group('mapearEstadoProceso', () { test('la tabla heredada cubre TODOS los ProcessingState — si just_audio ' 'anade uno nuevo, este test cae antes que la matriz', () { expect(mapeoHeredado.keys, containsAll(ProcessingState.values)); expect(ProcessingState.values, hasLength(mapeoHeredado.length)); }); group('cambiandoFuente: false (sin cambio de fuente en vuelo)', () { for (final proc in ProcessingState.values) { test('$proc mapea a ${mapeoHeredado[proc]}, igual que antes', () { expect( mapearEstadoProceso(proc, cambiandoFuente: false), mapeoHeredado[proc], ); }); } }); group('cambiandoFuente: true (cambio de emisora en vuelo)', () { for (final proc in ProcessingState.values) { final esperado = proc == ProcessingState.idle ? AudioProcessingState.loading : mapeoHeredado[proc]; test('$proc mapea a $esperado', () { expect(mapearEstadoProceso(proc, cambiandoFuente: true), esperado); }); } }); // ── Las dos direcciones, explicitas ────────────────────────────────── test('un stop REAL sigue produciendo idle: `stop()` limpia la bandera ' 'antes de `_player.stop()`, asi que audio_service puede seguir ' 'cerrando el foreground service', () { expect( mapearEstadoProceso(ProcessingState.idle, cambiandoFuente: false), AudioProcessingState.idle, ); }); test('el idle transitorio del player recien creado produce loading: la ' 'notificacion no se cancela a mitad de un cambio de emisora', () { expect( mapearEstadoProceso(ProcessingState.idle, cambiandoFuente: true), AudioProcessingState.loading, ); }); test('la mascara NO toca ningun estado distinto de idle', () { for (final proc in ProcessingState.values) { if (proc == ProcessingState.idle) continue; expect( mapearEstadoProceso(proc, cambiandoFuente: true), mapearEstadoProceso(proc, cambiandoFuente: false), reason: '$proc debe mapear igual con y sin cambio de fuente en vuelo', ); } }); test('idle es el UNICO caso en el que las dos ramas difieren', () { final distintos = ProcessingState.values .where( (proc) => mapearEstadoProceso(proc, cambiandoFuente: true) != mapearEstadoProceso(proc, cambiandoFuente: false), ) .toList(); expect(distintos, [ProcessingState.idle]); }); }); }