import 'package:flutter_test/flutter_test.dart'; import 'package:worldhopper/models/entry.dart'; import 'package:worldhopper/models/stream_link.dart'; import 'package:worldhopper/services/server_software/server_software.dart'; // Test the fetchEntryProgress logic directly since it's a pure data extraction // from StreamLink.lastRead — no HTTP or platform channels needed. Map _extractProgress(List entries) { final result = {}; for (final entry in entries) { if (entry.hasStreamLink && entry.streamLink!.lastRead != null && entry.streamLink!.lastRead! > 0) { result[entry.id] = EntryProgress( entryId: entry.id, currentPage: entry.streamLink!.lastRead!, totalPages: entry.streamLink!.pageCount, ); } } return result; } StreamLink _streamLink({int pageCount = 50, int? lastRead}) => StreamLink( href: 'https://example.com/page/{pageNumber}', type: 'image/jpeg', pageCount: pageCount, lastRead: lastRead, ); Entry _entry(String id, {StreamLink? streamLink}) => Entry( id: id, title: 'Entry $id', streamLink: streamLink, ); void main() { group('OPDS fetchEntryProgress logic', () { test('extracts progress from StreamLink.lastRead', () { final entries = [ _entry('e1', streamLink: _streamLink(pageCount: 100, lastRead: 49)), _entry('e2', streamLink: _streamLink(pageCount: 50, lastRead: 24)), ]; final result = _extractProgress(entries); expect(result, hasLength(2)); expect(result['e1']!.currentPage, 49); expect(result['e1']!.totalPages, 100); expect(result['e1']!.percentage, 0.5); expect(result['e2']!.currentPage, 24); expect(result['e2']!.totalPages, 50); expect(result['e2']!.percentage, 0.5); }); test('skips entries without StreamLink', () { final entries = [ _entry('e1'), _entry('e2', streamLink: _streamLink(pageCount: 10, lastRead: 5)), ]; final result = _extractProgress(entries); expect(result, hasLength(1)); expect(result.containsKey('e1'), isFalse); expect(result.containsKey('e2'), isTrue); }); test('skips entries with lastRead = null', () { final entries = [ _entry('e1', streamLink: _streamLink(pageCount: 10, lastRead: null)), ]; final result = _extractProgress(entries); expect(result, isEmpty); }); test('skips entries with lastRead = 0', () { final entries = [ _entry('e1', streamLink: _streamLink(pageCount: 10, lastRead: 0)), ]; final result = _extractProgress(entries); expect(result, isEmpty); }); test('returns empty map for empty entry list', () { final result = _extractProgress([]); expect(result, isEmpty); }); test('marks completed entry correctly', () { final entries = [ _entry('e1', streamLink: _streamLink(pageCount: 10, lastRead: 9)), ]; final result = _extractProgress(entries); expect(result['e1']!.isCompleted, isTrue); expect(result['e1']!.percentage, 1.0); }); test('handles mixed entries with and without progress', () { final entries = [ _entry('e1', streamLink: _streamLink(pageCount: 20, lastRead: 10)), _entry('e2'), _entry('e3', streamLink: _streamLink(pageCount: 30, lastRead: null)), _entry('e4', streamLink: _streamLink(pageCount: 40, lastRead: 0)), _entry('e5', streamLink: _streamLink(pageCount: 50, lastRead: 25)), ]; final result = _extractProgress(entries); expect(result, hasLength(2)); expect(result.containsKey('e1'), isTrue); expect(result.containsKey('e5'), isTrue); expect(result['e1']!.percentage, closeTo(0.55, 0.01)); expect(result['e5']!.percentage, closeTo(0.52, 0.01)); }); }); }