Files
pluriwave/test/servicios/servicio_audio_fallback_art_test.dart
T
FreeTLab 1b0bea5492 fix(auto): fall back to on-brand artwork when a station or track has none
Stations and tracks with no artwork showed empty tiles in the car. The
browse tree's itemEmisora/_itemLocal already fell back to the rotating
station_art_* drawable via artUriPara/artUriLocal, but the "now playing"
MediaItem built when actually playing something (car tap, phone-initiated
play, folder-queue advance, direct local-track tap) did not, so the car's
now-playing screen still went blank.

Reuse the SAME artUriPara/artUriLocal fallback (already the project's one
selection scheme, mirroring PluriStationArtFallback) at every "now playing"
construction site: reproducirPorMediaId, ServicioAudio.reproducir (now via
the extracted, unit-tested mediaItemParaEmisora), construirMediaItemColaLocal
and reproducirPistaLocal.

Guard the reverse direction too: emisoraDesdeMediaItem (extracted from the
handler's private method, now unit-tested) only reflects artUri back into
Emisora.favicon when it passes faviconUsable, so the phone UI's
CachedNetworkImage widgets never attempt a doomed fetch of the car's
android.resource:// fallback URI -- they keep falling back to
PluriStationArtFallback exactly as before.
2026-07-31 00:47:26 +02:00

140 lines
4.4 KiB
Dart

import 'dart:ui' show Locale;
import 'package:audio_service/audio_service.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pluriwave/l10n/gen/app_localizations.dart';
import 'package:pluriwave/modelos/emisora.dart';
import 'package:pluriwave/servicios/navegacion_auto.dart';
import 'package:pluriwave/servicios/servicio_audio.dart';
/// Item 3 (Android Auto fallback artwork) — the pure, handler-independent
/// half of the fix. `PluriWaveAudioHandler` cannot be instantiated in unit
/// tests (a real `just_audio.AudioPlayer` requires platform MethodChannels,
/// confirmed by `servicio_audio_source_switch_test.dart`), so the actual
/// "now playing" MediaItem construction and the reverse Emisora
/// reconstruction are extracted as pure top-level functions here, exactly
/// like `debeReaplicarEcualizador` was extracted for the EQ re-apply fix.
void main() {
final l10n = lookupAppLocalizations(const Locale('es'));
group('mediaItemParaEmisora (item 3)', () {
test(
'estación SIN favicon usable: el MediaItem usa el fallback de marca '
'(artUriPara), no queda con artUri null',
() {
const emisora = Emisora(
uuid: 'uuid-sin-arte',
nombre: 'Radio sin logo',
url: 'https://stream.demo/sin-logo',
);
final item = mediaItemParaEmisora(emisora, l10n: l10n);
expect(item.artUri, isNotNull);
expect(item.artUri.toString(), artUriPara(emisora));
},
);
test(
'estación CON favicon http(s) usable: el MediaItem sigue usando ese '
'favicon real, no el fallback',
() {
const emisora = Emisora(
uuid: 'uuid-con-arte',
nombre: 'Radio con logo',
url: 'https://stream.demo/con-logo',
favicon: 'https://cdn.example.com/logo.png',
);
final item = mediaItemParaEmisora(emisora, l10n: l10n);
expect(item.artUri.toString(), emisora.favicon);
},
);
test('preserva id, artist y extras.uuid como antes', () {
const emisora = Emisora(
uuid: 'uuid-forma',
nombre: 'Radio Forma',
url: 'https://stream.demo/forma',
pais: 'Argentina',
);
final item = mediaItemParaEmisora(emisora, l10n: l10n);
expect(item.id, emisora.url);
expect(item.artist, 'Argentina');
expect(item.album, 'PluriWave');
expect(item.extras?['uuid'], emisora.uuid);
});
});
group('emisoraDesdeMediaItem (item 3 — no phone-UI regression)', () {
test(
'artUri de marca (android.resource://…, no http) NUNCA se refleja '
'como favicon -- evitaría un intento de red inválido en '
'CachedNetworkImage del lado telefono',
() {
final mediaItem = MediaItem(
id: 'https://stream.demo/sin-logo',
title: 'Radio sin logo',
artUri: Uri.parse(
'android.resource://es.freetimelab.pluriwave/drawable/'
'station_art_aurora',
),
extras: const {'uuid': 'uuid-sin-arte'},
);
final emisora = emisoraDesdeMediaItem(mediaItem);
expect(emisora.favicon, isNull);
},
);
test(
'artUri http(s) real SÍ se refleja como favicon (comportamiento '
'previo preservado)',
() {
final mediaItem = MediaItem(
id: 'https://stream.demo/con-logo',
title: 'Radio con logo',
artUri: Uri.parse('https://cdn.example.com/logo.png'),
extras: const {'uuid': 'uuid-con-arte'},
);
final emisora = emisoraDesdeMediaItem(mediaItem);
expect(emisora.favicon, 'https://cdn.example.com/logo.png');
},
);
test('sin artUri: favicon queda null, sin lanzar', () {
final mediaItem = MediaItem(
id: 'https://stream.demo/sin-arturi',
title: 'Radio',
extras: const {'uuid': 'uuid-x'},
);
final emisora = emisoraDesdeMediaItem(mediaItem);
expect(emisora.favicon, isNull);
});
test('preserva uuid, nombre, url y pais como antes', () {
final mediaItem = MediaItem(
id: 'https://stream.demo/forma',
title: 'Radio Forma',
artist: 'Argentina',
extras: const {'uuid': 'uuid-forma'},
);
final emisora = emisoraDesdeMediaItem(mediaItem);
expect(emisora.uuid, 'uuid-forma');
expect(emisora.nombre, 'Radio Forma');
expect(emisora.url, mediaItem.id);
expect(emisora.pais, 'Argentina');
});
});
}