import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:fuel_tax_tracker/services/app_state.dart'; import 'package:fuel_tax_tracker/services/database_service.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; /// Covers the "pay to remove ads for a year" entitlement outside of the /// merge SQL itself (see db_merge_test.dart for that): [DatabaseService]'s /// storage round-trip, and [AppState.adsCurrentlyDisabled]'s pure /// expiry-comparison logic. void main() { group('DatabaseService ad-free entitlement storage', () { late Directory tempDir; late DatabaseService database; setUpAll(() { sqfliteFfiInit(); databaseFactory = databaseFactoryFfi; }); setUp(() async { tempDir = await Directory.systemTemp.createTemp('ad_free_entitlement_test_'); PathProviderPlatform.instance = _FakePathProviderPlatform(tempDir.path); database = DatabaseService(); await database.init(); }); tearDown(() async { await database.rawDb.close(); await tempDir.delete(recursive: true); }); test('getAdFreeUntil is null before any purchase is recorded', () async { expect(await database.getAdFreeUntil(), isNull); }); test('setAdFreeUntil then getAdFreeUntil round-trips the value', () async { final until = DateTime.utc(2027, 8, 13); final now = DateTime.utc(2026, 8, 13); await database.setAdFreeUntil(until, now); expect(await database.getAdFreeUntil(), until); }); test('setAdFreeUntil overwrites a previous value rather than adding a row', () async { await database.setAdFreeUntil(DateTime.utc(2027, 1, 1), DateTime.utc(2026, 1, 1)); await database.setAdFreeUntil(DateTime.utc(2028, 1, 1), DateTime.utc(2027, 1, 1)); final rows = await database.rawDb.query('ad_free_entitlement'); expect(rows, hasLength(1)); expect(await database.getAdFreeUntil(), DateTime.utc(2028, 1, 1)); }); }); group('AppState.adsCurrentlyDisabled', () { test('false when no entitlement has ever been recorded', () { final appState = AppState(); expect(appState.adsCurrentlyDisabled, isFalse); }); test('true when the entitlement date is in the future', () { final appState = AppState(); appState.adFreeUntil = DateTime.now().toUtc().add(const Duration(days: 30)); expect(appState.adsCurrentlyDisabled, isTrue); }); test('false once the entitlement date is in the past (the year lapsed)', () { final appState = AppState(); appState.adFreeUntil = DateTime.now().toUtc().subtract(const Duration(days: 1)); expect(appState.adsCurrentlyDisabled, isFalse); }); }); } class _FakePathProviderPlatform extends PathProviderPlatform with MockPlatformInterfaceMixin { final String tempPath; _FakePathProviderPlatform(this.tempPath); @override Future getApplicationDocumentsPath() async => tempPath; @override Future getTemporaryPath() async => tempPath; }