import 'package:drift/drift.dart' show Value; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mews/application/controllers/bookmarks_controller.dart'; import 'package:mews/application/controllers/reader_settings_controller.dart'; import 'package:mews/application/controllers/subscriptions_controller.dart'; import 'package:mews/database/database.dart'; import 'package:mews/mews/document.dart'; void main() { late MewsDatabase db; setUp(() { db = MewsDatabase.test(NativeDatabase.memory()); }); tearDown(() async { await db.close(); }); test('settings round-trip through the database', () async { final settings = ReaderSettingsController(db); await settings.setFont('Atkinson Hyperlegible'); await settings.increaseSize(); await settings.setThemeMode('dark'); await settings.setVariant('warm'); final reloaded = ReaderSettingsController(db); await reloaded.load(); expect(reloaded.font.value, 'Atkinson Hyperlegible'); expect(reloaded.fontScale.value, 1.125); expect(reloaded.themeMode.value, 'dark'); expect(reloaded.variant.value, 'warm'); }); test('text size stays within its limits', () async { final settings = ReaderSettingsController(db); for (var i = 0; i < 30; i++) { await settings.increaseSize(); } expect(settings.fontScale.value, ReaderSettingsController.maxScale); for (var i = 0; i < 40; i++) { await settings.decreaseSize(); } expect(settings.fontScale.value, ReaderSettingsController.minScale); }); test('bookmarks toggle and persist', () async { final bookmarks = BookmarksController(db); await bookmarks.load(); await bookmarks.toggle('https://example.com/', 'Example'); expect(bookmarks.isBookmarked('https://example.com/'), isTrue); final reloaded = BookmarksController(db); await reloaded.load(); expect(reloaded.isBookmarked('https://example.com/'), isTrue); await reloaded.toggle('https://example.com/', 'Example'); expect(reloaded.isBookmarked('https://example.com/'), isFalse); }); test('subscribing takes on the back catalogue without flagging it', () async { final subscriptions = SubscriptionsController(db); await subscriptions.load(); final firstPost = MewsEntry( url: 'https://example.com/a.html', date: DateTime(2026, 9, 21), title: 'First post'); await subscriptions.toggle(_page('https://example.com/', [firstPost])); expect(subscriptions.isSubscribed('https://example.com/'), isTrue); // The post was stored, but read, so nothing is waiting for the reader. expect(await db.unreadCount(), 0); // Opening the page again finds nothing new. expect(await subscriptions.refreshSite(_page('https://example.com/', [firstPost])), isEmpty); // A later post is new, and stays unread until the reader opens it. final newPost = MewsEntry( url: 'https://example.com/b.html', date: DateTime(2026, 10, 8), title: 'Second post'); final fresh = await subscriptions .refreshSite(_page('https://example.com/', [newPost, firstPost])); expect(fresh.map((e) => e.url), ['https://example.com/b.html']); expect(await db.unreadCount(siteUrl: 'https://example.com/'), 1); // Finding it a second time does not report it again. expect( await subscriptions .refreshSite(_page('https://example.com/', [newPost, firstPost])), isEmpty); expect(await db.unreadCount(), 1); }); test('unread posts survive a restart', () async { final subscriptions = SubscriptionsController(db); await subscriptions.load(); await subscriptions.toggle(_page('https://example.com/', const [])); await subscriptions.refreshSite(_page('https://example.com/', [ MewsEntry( url: 'https://example.com/a.html', date: DateTime(2026, 9, 21), title: 'First post'), ])); // A fresh controller over the same database sees the same unread post, // which the old in-memory count could not do. final restarted = SubscriptionsController(db); await restarted.load(); expect(restarted.isSubscribed('https://example.com/'), isTrue); expect(await db.unreadCount(), 1); }); test('leaving a site takes its posts with it', () async { final subscriptions = SubscriptionsController(db); await subscriptions.load(); await subscriptions.toggle(_page('https://example.com/', const [])); await subscriptions.refreshSite(_page('https://example.com/', [ MewsEntry( url: 'https://example.com/a.html', date: DateTime(2026, 9, 21), title: 'First post'), ])); expect(await db.unreadCount(), 1); await subscriptions.remove('https://example.com/'); expect(subscriptions.isSubscribed('https://example.com/'), isFalse); expect(await db.unreadCount(), 0); }); test('caches pages for offline reopening', () async { await db.saveCachedPage(CachedPagesCompanion.insert( url: 'https://example.com/page.html', source: 'html', title: const Value('Page'), etag: const Value('"v1"'), )); final cached = await db.cachedPage('https://example.com/page.html'); expect(cached!.source, 'html'); expect(cached.etag, '"v1"'); expect(cached.title, 'Page'); }); test('records history and returns the last visited page', () async { await db.recordVisit('https://a.example/', 'A'); await db.recordVisit('https://b.example/', 'B'); expect(await db.lastVisitedUrl(), 'https://b.example/'); }); } MewsPage _page(String url, List entries) => MewsPage( url: url, body: const [], lang: 'en', direction: TextDirection.ltr, variant: MewsVariant.plain, entries: entries, specVersion: '0.1', );