fix(compras): revocar el PRO tras un reembolso sin penalizar a quien pago
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.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
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);
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user