import 'dart:convert'; import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; import 'package:path/path.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/services/news.service.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); late Directory tempDir; late NewsService newsServiceInstance; setUp(() async { tempDir = Directory.systemTemp.createTempSync('news_service_test'); AppEnvironment.initTesting( customCacheDir: join(tempDir.path, 'cache'), customSupportDir: join(tempDir.path, 'support'), ); Directory(AppEnvironment.supportDir).createSync(recursive: true); Directory(AppEnvironment.cacheDir).createSync(recursive: true); await locator.reset(); locator.registerSingleton(NewsService()); newsServiceInstance = newsService; }); tearDown(() async { if (tempDir.existsSync()) { tempDir.deleteSync(recursive: true); } }); const rssXml = ''' twonly Blog https://twonly.eu/en/blog/ Latest news, privacy insights, and development updates from twonly. en Mon, 20 Jul 2026 12:23:32 GMT <![CDATA[Finding Friends Without Phone Numbers]]> https://twonly.eu/en/blog/2026-mutual-friends.html https://twonly.eu/en/blog/2026-mutual-friends.html Sun, 03 May 2026 00:00:00 GMT '''; const rssXmlWithTwoItems = ''' twonly Blog https://twonly.eu/en/blog/ Latest news, privacy insights, and development updates from twonly. en Mon, 20 Jul 2026 12:23:32 GMT <![CDATA[Finding Friends Without Phone Numbers]]> https://twonly.eu/en/blog/2026-mutual-friends.html https://twonly.eu/en/blog/2026-mutual-friends.html Sun, 03 May 2026 00:00:00 GMT <![CDATA[New Update Available]]> https://twonly.eu/en/blog/new-update.html https://twonly.eu/en/blog/new-update.html Mon, 20 Jul 2026 12:00:00 GMT new version of twonly has been released.]]> '''; test('Initial fetch feed marks all articles as read', () async { final mockClient = MockClient((request) async { return http.Response.bytes(utf8.encode(rssXml), 200); }); await newsServiceInstance.init(); expect(newsServiceInstance.hasLoadedBefore, isFalse); expect(newsServiceInstance.unreadCountNotifier.value, 0); await newsServiceInstance.fetchFeed(client: mockClient); expect(newsServiceInstance.hasLoadedBefore, isTrue); expect(newsServiceInstance.entries.length, 1); expect(newsServiceInstance.unreadCountNotifier.value, 0); expect( newsServiceInstance.openedGuids.contains( 'https://twonly.eu/en/blog/2026-mutual-friends.html', ), isTrue, ); }); test('Subsequent fetch feed detects new articles as unread', () async { final mockClient1 = MockClient((request) async { return http.Response.bytes(utf8.encode(rssXml), 200); }); await newsServiceInstance.init(); await newsServiceInstance.fetchFeed(client: mockClient1); expect(newsServiceInstance.unreadCountNotifier.value, 0); final mockClient2 = MockClient((request) async { return http.Response.bytes(utf8.encode(rssXmlWithTwoItems), 200); }); await newsServiceInstance.fetchFeed(client: mockClient2); expect(newsServiceInstance.entries.length, 2); expect(newsServiceInstance.unreadCountNotifier.value, 1); expect( newsServiceInstance.entries[1].description, 'A brand new version of twonly has been released.', ); }); test('markAllAsRead clears unread count', () async { final mockClient1 = MockClient((request) async { return http.Response.bytes(utf8.encode(rssXml), 200); }); await newsServiceInstance.init(); await newsServiceInstance.fetchFeed(client: mockClient1); final mockClient2 = MockClient((request) async { return http.Response.bytes(utf8.encode(rssXmlWithTwoItems), 200); }); await newsServiceInstance.fetchFeed(client: mockClient2); expect(newsServiceInstance.unreadCountNotifier.value, 1); await newsServiceInstance.markAllAsRead(); expect(newsServiceInstance.unreadCountNotifier.value, 0); }); test('Cache loads correctly and restores state', () async { final mockClient = MockClient((request) async { return http.Response.bytes(utf8.encode(rssXml), 200); }); await newsServiceInstance.init(); await newsServiceInstance.fetchFeed(client: mockClient); final newServiceInstance = NewsService(); await newServiceInstance.init(); expect(newServiceInstance.hasLoadedBefore, isTrue); expect(newServiceInstance.entries.length, 1); expect(newServiceInstance.unreadCountNotifier.value, 0); expect( newServiceInstance.openedGuids.contains( 'https://twonly.eu/en/blog/2026-mutual-friends.html', ), isTrue, ); }); }