import 'package:flutter_test/flutter_test.dart'; import 'package:ikar/backend/modules/contacts.dart'; import 'package:ikar/core/contacts/phonebook_contact_sync.dart'; void main() { const existing = CachedContact( id: 2, accountId: 1, firstName: 'Existing', phone: 79000000002, updateTime: 0, ); var current = true; late List lookups; late List additions; late Map accounts; setUp(() { current = true; lookups = []; additions = []; accounts = {'+79000000003': 3}; }); Future sync( Map book, { int accountId = 1, List contacts = const [existing], Future Function(String)? lookup, Future Function(String, String)? add, }) => PhonebookContactSync.importContacts( phonebook: book, contacts: contacts, accountId: accountId, lookup: lookup ?? (phone) async { lookups.add(phone); final id = accounts[phone]; return id == null ? null : PhoneLookupResult(id: id); }, add: add ?? (phone, name) async { additions.add('$phone:$name'); return const AddContactResult(AddContactStatus.added); }, isCurrent: () => current, requestDelay: Duration.zero, ); test( 'adds registered numbers once, skips existing and absent accounts', () async { expect( await sync({ '+79000000002': 'Do not rename', '8 (900) 000-00-03': 'New', '+79000000003': 'Duplicate', '+79000000004': 'No ИКАР', '123': 'Invalid', }), 1, ); expect(lookups, ['+79000000003', '+79000000004']); expect(additions, ['+79000000003:New']); }, ); test('skips own account and existing contacts with hidden numbers', () async { accounts = {'+79000000003': 2, '+79000000004': 1}; expect(await sync({'+79000000003': 'Hidden', '+79000000004': 'Self'}), 0); expect(additions, isEmpty); }); test( 'a later pass discovers new phone entries and newly registered users', () async { expect(await sync({'+79000000004': 'Later'}), 0); accounts['+79000000004'] = 4; expect(await sync({'+79000000003': 'New', '+79000000004': 'Later'}), 2); }, ); test( 'account switch during lookup prevents adding to another account', () async { expect( await sync( {'+79000000003': 'New'}, lookup: (_) async { current = false; return const PhoneLookupResult(id: 3); }, ), 0, ); expect(additions, isEmpty); }, ); test('lookup failure stops the pass and can be retried', () async { await expectLater( sync( {'+79000000003': 'New'}, lookup: (_) async { throw StateError('offline'); }, ), throwsStateError, ); expect(additions, isEmpty); expect(await sync({'+79000000003': 'New'}), 1); }); test('add failure stops further requests and remains retryable', () async { await expectLater( sync({ '+79000000003': 'New', '+79000000004': 'Next', }, add: (_, _) async => const AddContactResult(AddContactStatus.error)), throwsStateError, ); expect(lookups, ['+79000000003']); expect(await sync({'+79000000003': 'New'}), 1); }); test('registration disappearing before add is not counted', () async { expect( await sync( {'+79000000003': 'New'}, add: (_, _) async => const AddContactResult(AddContactStatus.notFound), ), 0, ); }); test('empty phonebook sends no requests', () async { expect(await sync({}), 0); expect(lookups, isEmpty); expect(additions, isEmpty); }); }