Skip to content

Commit

Permalink
TW-1153 Write unit test for removeDuplicatedPhoneNumbers function
Browse files Browse the repository at this point in the history
  • Loading branch information
hieutbui authored and hoangdat committed Feb 27, 2024
1 parent 712d7c8 commit ef4f361
Show file tree
Hide file tree
Showing 4 changed files with 297 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:fluffychat/data/datasource/phonebook_datasouce.dart';
import 'package:fluffychat/domain/model/contact/contact.dart';
import 'package:fluffychat/utils/string_extension.dart';
import 'package:flutter_contacts/flutter_contacts.dart' hide Contact;

class PhonebookContactDatasourceImpl implements PhonebookContactDatasource {
Expand All @@ -8,63 +9,75 @@ class PhonebookContactDatasourceImpl implements PhonebookContactDatasource {
final phonebookContacts =
await FlutterContacts.getContacts(withProperties: true);

final listAllContacts = phonebookContacts
final listPhoneContacts = phonebookContacts
.expand(
(contact) => [
...contact.emails.map(
(email) => Contact(
email: email.address,
displayName: contact.displayName,
),
(contact) => contact.phones.map(
(phone) => Contact(
phoneNumber: phone.number,
displayName: contact.displayName,
),
...contact.phones.map(
(phone) => Contact(
phoneNumber: phone.number,
displayName: contact.displayName,
),
),
)
.toList();

final listEmailContacts = phonebookContacts
.expand(
(contact) => contact.emails.map(
(email) => Contact(
email: email.address,
displayName: contact.displayName,
),
],
),
)
.toList();

return removeDuplicatedPhoneNumbers(listAllContacts);
final listAllContacts = [
..._removeDuplicatedPhoneNumbers(listPhoneContacts),
...listEmailContacts,
];

return listAllContacts;
}

List<Contact> removeDuplicatedPhoneNumbers(List<Contact> listContacts) {
List<Contact> _removeDuplicatedPhoneNumbers(List<Contact> listContacts) {
final listVisitedPhoneNumbers = <String>[];
final listFilteredContacts = <Contact>[];

for (final contact in listContacts) {
final listContactHasPhoneNumber =
listContacts.where((contact) => contact.phoneNumber != null).toList();

for (final contact in listContactHasPhoneNumber) {
final phoneNumber = contact.phoneNumber;
if (phoneNumber != null) {
final normalizedPhoneNumber = normalizePhoneNumber(phoneNumber);
if (listVisitedPhoneNumbers.contains(normalizedPhoneNumber)) {
final contactsWithSamePhoneNumber =
listFilteredContacts.where((filteredContact) {
final filteredPhoneNumber = filteredContact.phoneNumber;
if (filteredPhoneNumber != null) {
return filteredContact.displayName == contact.displayName &&
normalizePhoneNumber(filteredPhoneNumber) ==
normalizedPhoneNumber;
}
return false;
});
if (contactsWithSamePhoneNumber.isEmpty) {
listFilteredContacts.add(contact);
} else {
continue;
}
} else {
listVisitedPhoneNumbers.add(normalizedPhoneNumber);
final normalizedPhoneNumber = phoneNumber!.normalizePhoneNumber();

if (listVisitedPhoneNumbers.contains(normalizedPhoneNumber)) {
final hasSameFilteredContact = _hasSameFilteredContact(
listFilteredContacts,
contact.displayName ?? '',
normalizedPhoneNumber,
);
if (!hasSameFilteredContact) {
listFilteredContacts.add(contact);
}
} else {
listVisitedPhoneNumbers.add(normalizedPhoneNumber);
listFilteredContacts.add(contact);
}
}

return listFilteredContacts;
}

String normalizePhoneNumber(String phoneNumber) {
return phoneNumber.replaceAll(RegExp(r'\D'), '');
bool _hasSameFilteredContact(
List<Contact> listFilteredContacts,
String contactName,
String phoneNumberNormalized,
) {
return listFilteredContacts.any(
(filteredContact) =>
filteredContact.displayName == contactName &&
filteredContact.phoneNumber?.normalizePhoneNumber() ==
phoneNumberNormalized,
);
}
}
4 changes: 4 additions & 0 deletions lib/utils/string_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -337,4 +337,8 @@ extension StringCasingExtension on String {
String get sha256Hash {
return sha256.convert(utf8.encode(this)).toString();
}

String normalizePhoneNumber() {
return replaceAll(RegExp(r'\D'), '');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import 'package:fluffychat/data/datasource_impl/contact/phonebook_contact_datasource_impl.dart';
import 'package:fluffychat/domain/model/contact/contact.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get_it/get_it.dart';

void main() {
TestWidgetsFlutterBinding.ensureInitialized();

late PhonebookContactDatasourceImpl dataSource;
const MethodChannel channel =
MethodChannel('github.com/QuisApp/flutter_contacts');

group('[PhonebookContactDatasourceImpl]', () {
final listAllContacts = [
{
'displayName': 'Alice',
'phones': [
{'number': '(212)555-6789'},
{'number': '2125556789'},
],
},
{
'displayName': 'Bob',
'phones': [
{'number': '2124678190'},
{'number': '(212)467-8190'},
],
},
{
'displayName': 'Charlie',
'phones': [
{'number': '212 555-6789'},
{'number': '2125556789'},
],
},
{
'displayName': 'David',
'phones': [
{'number': '2124678190'},
{'number': '212 467-8190'},
],
},
{
'displayName': 'Eve',
'phones': [
{'number': '+1.123.456.7890'},
{'number': '11234567890'},
],
},
{
'displayName': 'Frank',
'phones': [
{'number': '81234977890'},
{'number': '+8.123.497.7890'},
],
},
{
'displayName': 'Grace',
'phones': [
{'number': '+1 (800)-555-1234 ext. 123'},
{'number': '18005551234123'},
],
},
{
'displayName': 'Hank',
'phones': [
{'number': '18005879106234'},
{'number': '+1 (800)-587-9106 ext. 234'},
],
},
{
'displayName': 'Ivy',
'phones': [
{'number': '+1 (800)-555.1234'},
{'number': '18005551234'},
],
},
{
'displayName': 'Karl',
'phones': [
{'number': '18005873456'},
{'number': '+1 (800)-587.3456'},
],
},
{
'displayName': 'Liam',
'phones': [
{'number': '(212) 555-6789'},
{'number': '2125556789'},
],
},
{
'displayName': 'Mia',
'phones': [
{'number': '2125556789'},
{'number': '(212) 555-6789'},
],
},
{
'displayName': 'Nina',
'emails': [
{
'address': '[email protected]',
}
],
}
];

setUp(() {
final getIt = GetIt.instance;
getIt.registerFactory(
() => PhonebookContactDatasourceImpl(),
);
dataSource = getIt.get<PhonebookContactDatasourceImpl>();

TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
if (methodCall.method == 'select') {
return listAllContacts;
}
return null;
});
});

test(
'fetchContacts should return a list of contacts without duplicated phone number',
() async {
final List<Contact> expectedListContact = [
const Contact(
displayName: 'Alice',
phoneNumber: '(212)555-6789',
),
const Contact(
displayName: 'Bob',
phoneNumber: '2124678190',
),
const Contact(
displayName: 'Charlie',
phoneNumber: '212 555-6789',
),
const Contact(
displayName: 'David',
phoneNumber: '2124678190',
),
const Contact(
displayName: 'Eve',
phoneNumber: '+1.123.456.7890',
),
const Contact(
displayName: 'Frank',
phoneNumber: '81234977890',
),
const Contact(
displayName: 'Grace',
phoneNumber: '+1 (800)-555-1234 ext. 123',
),
const Contact(
displayName: 'Hank',
phoneNumber: '18005879106234',
),
const Contact(
displayName: 'Ivy',
phoneNumber: '+1 (800)-555.1234',
),
const Contact(
displayName: 'Karl',
phoneNumber: '18005873456',
),
const Contact(
displayName: 'Liam',
phoneNumber: '(212) 555-6789',
),
const Contact(
displayName: 'Mia',
phoneNumber: '2125556789',
),
const Contact(
displayName: 'Nina',
email: '[email protected]',
),
];

final result = await dataSource.fetchContacts();

expect(result, isA<List<Contact>>());
expect(result, equals(expectedListContact));
});
});
}
52 changes: 52 additions & 0 deletions test/utils/string_extension_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'package:fluffychat/utils/string_extension.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
group('[normalizePhoneNumber]', () {
test('should return phone number without any Hyphens or Parentheses', () {
const phoneNumber = '(212)555-6789';
const expectedPhoneNumber = '2125556789';

final result = phoneNumber.normalizePhoneNumber();

expect(result, equals(expectedPhoneNumber));
});

test('should return phone number without any Spaces or Dashes', () {
const phoneNumber = '212 555-6789';
const expectedPhoneNumber = '2125556789';

final result = phoneNumber.normalizePhoneNumber();

expect(result, equals(expectedPhoneNumber));
});

test('should return phone number without any Plus Sign or Dots', () {
const phoneNumber = '+1.123.456.7890';
const expectedPhoneNumber = '11234567890';

final result = phoneNumber.normalizePhoneNumber();

expect(result, equals(expectedPhoneNumber));
});

test('should return phone number without any Country Code or Extension',
() {
const phoneNumber = '+1 (800)-555-1234 ext. 123';
const expectedPhoneNumber = '18005551234123';

final result = phoneNumber.normalizePhoneNumber();

expect(result, equals(expectedPhoneNumber));
});

test('should return phone number without any special characters', () {
const phoneNumber = '+1 (800)-555.1234 ext. 325';
const expectedPhoneNumber = '18005551234325';

final result = phoneNumber.normalizePhoneNumber();

expect(result, equals(expectedPhoneNumber));
});
});
}

0 comments on commit ef4f361

Please sign in to comment.