Files
IKAR/test/phonebook_max_contacts_test.dart
T

201 lines
5.5 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:ikar/backend/modules/contacts.dart';
import 'package:ikar/backend/api.dart';
import 'package:ikar/core/protocol/packet.dart';
import 'package:ikar/core/contacts/device_contacts_service.dart';
import 'package:ikar/core/contacts/phonebook_max_contacts.dart';
class _LookupApi extends Api {
_LookupApi(this.response);
final Object response;
@override
Future<Packet> sendRequest(
int opcode,
Map<dynamic, dynamic> payload, {
void Function()? beforeSend,
bool silent = false,
}) async {
beforeSend?.call();
if (response is Packet) return response as Packet;
throw response;
}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('strict lookup excludes deleted server accounts', () async {
final api = _LookupApi(
Packet(
cmd: CmdType.ok,
payload: {
'contact': {'id': 5, 'accountStatus': 2},
},
),
);
expect(
await ContactsModule.findByPhone(api, '+79000000001', strict: true),
isNull,
);
});
test(
'strict lookup recognizes not found but propagates server errors',
() async {
expect(
await ContactsModule.findByPhone(
_LookupApi(const PacketError('Missing', errorKey: 'user.not.found')),
'+79000000001',
strict: true,
),
isNull,
);
await expectLater(
ContactsModule.findByPhone(
_LookupApi(const PacketError('Rate limited', errorKey: 'limit')),
'+79000000001',
strict: true,
),
throwsA(isA<PacketError>()),
);
},
);
test('normalizes Russian prefix without matching foreign suffixes', () {
expect(
DeviceContactsService.normalizePhone('8 (900) 000-00-01'),
'+79000000001',
);
expect(
DeviceContactsService.normalizePhone('+1 900 000 0001'),
'+19000000001',
);
expect(DeviceContactsService.normalizePhone('123'), isNull);
expect(DeviceContactsService.normalizePhone('9000000001'), '+9000000001');
});
test(
'uses phonebook names, excludes ИКАР-only and discovers uncached users',
() async {
final requested = <String>[];
final contacts = await PhonebookMaxContacts.resolve(
phonebook: {
'+79000000001': 'Alice local',
'+79000000002': 'Bob local',
'+79000000003': 'No account',
},
cached: const [
CachedContact(
id: 1,
accountId: 42,
firstName: 'ИКАР name',
phone: 79000000001,
updateTime: 0,
),
CachedContact(
id: 9,
accountId: 42,
firstName: 'ИКАР only',
phone: 79000000009,
updateTime: 0,
),
],
accountId: 42,
lookup: (phone) async {
requested.add(phone);
if (phone == '+79000000001') return const PhoneLookupResult(id: 1);
return phone == '+79000000002'
? const PhoneLookupResult(id: 2)
: null;
},
);
expect(contacts.map((c) => c.id), [1, 2]);
expect(contacts.map((c) => c.firstName), ['Alice local', 'Bob local']);
expect(requested, ['+79000000001', '+79000000002', '+79000000003']);
},
);
test('excludes deleted accounts and deduplicates ИКАР IDs', () async {
final contacts = await PhonebookMaxContacts.resolve(
phonebook: {
'+79000000001': 'Deleted',
'+79000000002': 'Same',
'+79000000003': 'Same',
},
cached: const [
CachedContact(
id: 1,
accountId: 42,
firstName: 'Deleted',
phone: 79000000001,
updateTime: 0,
accountStatus: 2,
),
],
accountId: 42,
lookup: (phone) async =>
phone == '+79000000001' ? null : const PhoneLookupResult(id: 2),
);
expect(contacts.map((c) => c.id), [2]);
});
test('empty phonebook never falls back to ИКАР contacts', () async {
final contacts = await PhonebookMaxContacts.resolve(
phonebook: {},
cached: const [
CachedContact(
id: 1,
accountId: 42,
firstName: 'ИКАР only',
phone: 79000000001,
updateTime: 0,
),
],
accountId: 42,
lookup: (_) async => throw StateError('Unexpected lookup'),
);
expect(contacts, isEmpty);
});
test('cached ИКАР membership is rechecked before display', () async {
final contacts = await PhonebookMaxContacts.resolve(
phonebook: {'+79000000001': 'Former user'},
cached: const [
CachedContact(
id: 1,
accountId: 42,
firstName: 'Old cached name',
phone: 79000000001,
updateTime: 123,
),
],
accountId: 42,
lookup: (_) async => null,
);
expect(contacts, isEmpty);
});
test('network failure is not treated as an unregistered phone', () async {
await expectLater(
PhonebookMaxContacts.resolve(
phonebook: {'+79000000001': 'Local'},
cached: [],
accountId: 42,
lookup: (_) async => throw StateError('Offline'),
),
throwsStateError,
);
});
test('cancellation stops further lookups', () async {
final contacts = await PhonebookMaxContacts.resolve(
phonebook: {'+79000000001': 'Local'},
cached: [],
accountId: 42,
lookup: (_) async => throw StateError('Unexpected lookup'),
isCancelled: () => true,
);
expect(contacts, isEmpty);
});
}