import 'package:commons_core/commons_core.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:tane/services/message_store.dart'; import 'package:tane/services/unread_service.dart'; import '../support/test_support.dart'; /// Unread counting is derived from stored history plus a per-peer "last read" /// mark; these tests drive it through a real [MessageStore] over an in-memory /// keystore, so no relay or network is involved. void main() { const me = 'me-pubkey'; late MessageStore store; late UnreadService unread; setUp(() { store = MessageStore(newTestChatDatabase()); unread = UnreadService(store, InMemorySecretStore()); }); tearDown(() => unread.dispose()); PrivateMessage msg(String from, String text, int atMs) => PrivateMessage( fromPubkey: from, text: text, at: DateTime.fromMillisecondsSinceEpoch(atMs)); // Persist then notify, the way InboxService.ingest does. Future receive(String peer, PrivateMessage m) async { await store.append(peer, m); await unread.onMessageReceived(peer, m); } test('an unknown peer has no unread', () async { expect(await unread.unreadCount('alice'), 0); }); test('inbound messages increment the unread count', () async { await receive('alice', msg('alice', 'hi', 1000)); await receive('alice', msg('alice', 'you there?', 2000)); expect(await unread.unreadCount('alice'), 2); }); test('markRead clears older messages but keeps newer ones', () async { await receive('alice', msg('alice', 'a', 1000)); await unread.markRead('alice'); // reads up to the latest (1000) expect(await unread.unreadCount('alice'), 0); await receive('alice', msg('alice', 'b', 2000)); expect(await unread.unreadCount('alice'), 1); }); test('own outgoing messages never count as unread', () async { await receive('alice', msg(me, 'my reply', 1000)); expect(await unread.unreadCount('alice'), 0); }); test('a message for the open chat is auto-read (no unread)', () async { unread.activePeer = 'alice'; await receive('alice', msg('alice', 'while open', 1000)); expect(await unread.unreadCount('alice'), 0); }); test('totalUnreadCount sums across conversations', () async { await receive('alice', msg('alice', 'a', 1000)); await receive('bob', msg('bob', 'b1', 1000)); await receive('bob', msg('bob', 'b2', 2000)); expect(await unread.totalUnreadCount(), 3); }); test('changes fires on a new inbound message', () async { final events = []; final sub = unread.changes.listen(events.add); await receive('alice', msg('alice', 'hi', 1000)); await Future.delayed(Duration.zero); expect(events, hasLength(1)); await sub.cancel(); }); test('changes fires on markRead', () async { await receive('alice', msg('alice', 'hi', 1000)); final events = []; final sub = unread.changes.listen(events.add); await unread.markRead('alice'); await Future.delayed(Duration.zero); expect(events, hasLength(1)); await sub.cancel(); }); }