Verificacion silenciosa en segundo plano con queryPastPurchases, al abrir o volver a la app y al cargar Android Auto. Solo revoca tras dos respuestas validas de Play sin la compra separadas 12h; sin red o con error no toca nada. Reactiva el PRO automaticamente si Play confirma la compra.
85 lines
2.5 KiB
Dart
85 lines
2.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:pluriwave/servicios/servicio_audio.dart';
|
|
import 'package:pluriwave/servicios/verificacion_licencia.dart';
|
|
|
|
/// Android Auto (headless) trigger of the silent license check: the
|
|
/// `registrar*` seam `main.dart` wires, exercised without a real
|
|
/// `PluriWaveAudioHandler`.
|
|
void main() {
|
|
late int invalidaciones;
|
|
|
|
setUp(() {
|
|
invalidaciones = 0;
|
|
registrarInvalidacionArbolAuto(() => invalidaciones++);
|
|
});
|
|
|
|
tearDown(() {
|
|
registrarInvalidacionArbolAuto(() {});
|
|
registrarVerificacionLicenciaAuto(null);
|
|
});
|
|
|
|
test('sin verificador registrado es un no-op que nunca lanza', () async {
|
|
registrarVerificacionLicenciaAuto(null);
|
|
|
|
await dispararVerificacionLicenciaAuto();
|
|
|
|
expect(invalidaciones, 0);
|
|
});
|
|
|
|
test('una revocacion invalida el arbol de Auto', () async {
|
|
registrarVerificacionLicenciaAuto(() async => CambioLicencia.revocada);
|
|
|
|
await dispararVerificacionLicenciaAuto();
|
|
|
|
expect(invalidaciones, 1);
|
|
});
|
|
|
|
test('un desbloqueo silencioso tambien invalida el arbol', () async {
|
|
registrarVerificacionLicenciaAuto(() async => CambioLicencia.desbloqueada);
|
|
|
|
await dispararVerificacionLicenciaAuto();
|
|
|
|
expect(invalidaciones, 1);
|
|
});
|
|
|
|
test('sin cambios no invalida nada', () async {
|
|
registrarVerificacionLicenciaAuto(() async => CambioLicencia.sinCambios);
|
|
|
|
await dispararVerificacionLicenciaAuto();
|
|
|
|
expect(invalidaciones, 0);
|
|
});
|
|
|
|
test('un fallo del verificador se traga en silencio', () async {
|
|
registrarVerificacionLicenciaAuto(() async => throw StateError('boom'));
|
|
|
|
await expectLater(dispararVerificacionLicenciaAuto(), completes);
|
|
expect(invalidaciones, 0);
|
|
});
|
|
|
|
test(
|
|
'no retiene al llamador: devuelve antes de que la consulta acabe',
|
|
() async {
|
|
final pendiente = Completer<CambioLicencia>();
|
|
registrarVerificacionLicenciaAuto(() => pendiente.future);
|
|
|
|
// The browse path calls this unawaited; the returned future being
|
|
// pending here proves the verification runs in the background.
|
|
var terminado = false;
|
|
unawaited(
|
|
dispararVerificacionLicenciaAuto().then((_) => terminado = true),
|
|
);
|
|
await Future<void>.delayed(Duration.zero);
|
|
expect(terminado, isFalse);
|
|
|
|
pendiente.complete(CambioLicencia.revocada);
|
|
await Future<void>.delayed(Duration.zero);
|
|
await Future<void>.delayed(Duration.zero);
|
|
expect(terminado, isTrue);
|
|
expect(invalidaciones, 1);
|
|
},
|
|
);
|
|
}
|