import 'dart:ui' show Locale; import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/l10n/gen/app_localizations.dart'; import 'package:pluriwave/modelos/preset_ecualizador.dart'; import 'package:pluriwave/servicios/navegacion_auto.dart'; import 'package:pluriwave/servicios/servicio_audio.dart'; /// Decision `auto/ecualizador-diseno` -- the "Ecualizador" browsable /// folder's item-building (`itemsEcualizadorAuto`), the pure, /// `AppLocalizations`-dependent half of the folder feature. Lives in a /// dedicated file, separate from `servicio_audio_eq_custom_actions_test.dart` /// (which covers the now-playing screen's on/off toggle) because this is a /// different car UI surface: a browsable folder, not a custom action. void main() { final l10n = lookupAppLocalizations(const Locale('es')); group('itemsEcualizadorAuto (decision `auto/ecualizador-diseno`)', () { test('devuelve exactamente 7 items: Desactivar primero, luego los 6 ' 'presets de fábrica, todos playable', () { final items = itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.flat, l10n: l10n, ); expect(items, hasLength(7)); expect(items.first.id, ConstructorArbolAuto.idDesactivarEq); for (final item in items) { expect(item.playable, isTrue); } }); test('los 6 presets aparecen en el mismo orden que ' 'PresetEcualizador.presets, cada uno con su id eq_preset:', () { final items = itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.flat, l10n: l10n, ); final builder = ConstructorArbolAuto(); final idsPresets = items.skip(1).map((i) => i.id).toList(); final idsEsperados = PresetEcualizador.presets .map((p) => builder.idPresetEq(p.nombre)) .toList(); expect(idsPresets, idsEsperados); }); test('los nombres de preset están localizados vía nombrePresetVisible, ' 'no crudos', () { final items = itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.flat, l10n: l10n, ); final builder = ConstructorArbolAuto(); final rock = items.firstWhere( (i) => i.id == builder.idPresetEq(PresetEcualizador.rock.nombre), ); expect(rock.title, contains(nombrePresetVisible(l10n, 'Rock'))); }); test('con el ecualizador ACTIVO, el preset actual queda marcado y ' 'Desactivar NO', () { final items = itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.jazz, l10n: l10n, ); final builder = ConstructorArbolAuto(); final desactivar = items.firstWhere( (i) => i.id == ConstructorArbolAuto.idDesactivarEq, ); final jazz = items.firstWhere( (i) => i.id == builder.idPresetEq(PresetEcualizador.jazz.nombre), ); final marcados = items.where((i) => i.title.contains('✓')).toList(); expect(desactivar.title, isNot(contains('✓'))); expect(jazz.title, contains('✓')); expect(marcados, hasLength(1)); expect(marcados.single.id, jazz.id); }); test('con el ecualizador DESACTIVADO, Desactivar queda marcado y NINGÚN ' 'preset lo está', () { final items = itemsEcualizadorAuto( activo: false, presetActual: PresetEcualizador.rock, l10n: l10n, ); final desactivar = items.firstWhere( (i) => i.id == ConstructorArbolAuto.idDesactivarEq, ); final marcados = items.where((i) => i.title.contains('✓')).toList(); expect(desactivar.title, contains('✓')); expect(marcados, hasLength(1)); expect(marcados.single.id, ConstructorArbolAuto.idDesactivarEq); }); test('el label de Desactivar usa l10n.autoEqDisableOption', () { final items = itemsEcualizadorAuto( activo: false, presetActual: PresetEcualizador.flat, l10n: l10n, ); final desactivar = items.firstWhere( (i) => i.id == ConstructorArbolAuto.idDesactivarEq, ); expect(desactivar.title, contains(l10n.autoEqDisableOption)); }); }); /// On-device feedback: the folder only ever listed the six FACTORY /// presets, so a user's own saved presets were unreachable from the car — /// the surface where a preset picker matters most, since you cannot pull /// out the phone and drag five band sliders while driving. group('presets personalizados del usuario en la carpeta', () { final mio = PresetEcualizador( nombre: 'Mi coche', bandas: [4.0, 2.0, 0.0, 1.0, 3.0], ); final otro = PresetEcualizador( nombre: 'Podcast noche', bandas: [-3.0, 0.0, 3.0, 2.0, -1.0], ); test('se listan tras los 6 de fábrica, en orden de guardado', () { final items = itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.flat, l10n: l10n, presetsPersonalizados: [mio, otro], ); expect(items, hasLength(9)); expect(items[7].title, contains('Mi coche')); expect(items[8].title, contains('Podcast noche')); }); test('su id sigue el mismo formato eq_preset: y resuelve al ' 'preset correcto con la lista combinada', () { final constructor = ConstructorArbolAuto(); final universo = presetsEcualizadorAuto(personalizados: [mio]); final items = itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.flat, l10n: l10n, presetsPersonalizados: [mio], ); final item = items.last; expect(item.id, constructor.idPresetEq('Mi coche')); expect(item.playable, isTrue); expect(constructor.resolverPresetEq(item.id, presets: universo), mio); }); test('sin la lista combinada NO resuelve: es exactamente el fallo que se ' 'reportó, un item visible que al pulsarlo no hacía nada', () { final constructor = ConstructorArbolAuto(); // Default `presets` == the factory six only. This is what the tap // dispatch used to do, and why a listed custom preset was a no-op. expect( constructor.resolverPresetEq(constructor.idPresetEq('Mi coche')), isNull, ); }); test('pulsar un preset personalizado lo aplica de verdad', () async { final aplicados = []; var encendido = false; await seleccionarPresetEqPorMediaId( ConstructorArbolAuto().idPresetEq('Mi coche'), activo: false, aplicarPreset: (p) async => aplicados.add(p), activarEcualizador: (v) async => encendido = v, presets: presetsEcualizadorAuto(personalizados: [mio]), ); expect(aplicados, [mio]); // Tapping any preset while the EQ is off must also switch it on, // exactly as it already does for a factory preset. expect(encendido, isTrue); }); test('el preset personalizado activo se marca con ✓, y solo él', () { final items = itemsEcualizadorAuto( activo: true, presetActual: mio, l10n: l10n, presetsPersonalizados: [mio, otro], ); final marcados = items.where((i) => i.title.contains('✓')).toList(); expect(marcados, hasLength(1)); expect(marcados.single.id, ConstructorArbolAuto().idPresetEq('Mi coche')); }); test('un personalizado que repite el nombre de uno de fábrica se DESCARTA ' '— su id solo podría resolver al de fábrica, así que mostrarlo ' 'aplicaría un preset distinto del que anuncia', () { final impostor = PresetEcualizador( nombre: 'Rock', bandas: [9.0, 9.0, 9.0, 9.0, 9.0], ); final universo = presetsEcualizadorAuto(personalizados: [impostor, mio]); expect(universo.where((p) => p.nombre == 'Rock'), hasLength(1)); expect( universo.firstWhere((p) => p.nombre == 'Rock'), PresetEcualizador.rock, ); expect(universo, contains(mio)); expect( itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.flat, l10n: l10n, presetsPersonalizados: [impostor, mio], ), hasLength(8), ); }); test('sin presets guardados la carpeta queda exactamente como antes', () { expect( itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.flat, l10n: l10n, ).map((i) => i.id), itemsEcualizadorAuto( activo: true, presetActual: PresetEcualizador.flat, l10n: l10n, presetsPersonalizados: const [], ).map((i) => i.id), ); }); }); }