chore: addressed review feedback

pull/226/head
Jonathan Daniels 3 years ago
parent f8e5c038a7
commit 3431477a22

@ -72,6 +72,20 @@ class FetchPlayerRankingException extends LeaderboardException {
); );
} }
/// {@template fetch_prohibited_initials_exception}
/// Exception thrown when failure occurs while fetching prohibited initials.
/// {@endtemplate}
class FetchProhibitedInitialsException extends LeaderboardException {
/// {@macro fetch_prohibited_initials_exception}
const FetchProhibitedInitialsException(
Object error,
StackTrace stackTrace,
) : super(
error,
stackTrace,
);
}
/// {@template leaderboard_repository} /// {@template leaderboard_repository}
/// Repository to access leaderboard data in Firebase Cloud Firestore. /// Repository to access leaderboard data in Firebase Cloud Firestore.
/// {@endtemplate} /// {@endtemplate}
@ -153,14 +167,28 @@ class LeaderboardRepository {
} }
} }
/// Checks if the given [username] is allowed. The [username] is not allowed /// Determines if the given [initials] are allowed.
/// if it is a bad word. Future<bool> areInitialsAllowed({required String initials}) async {
Future<bool> isUsernameAllowed({required String username}) async { // Initials can only be three uppercase A-Z letters
// TODO(jonathandaniels-vgv): load this list of bad words from an endpoint final initialsRegex = RegExp(r'^[A-Z]{3}$');
final badWords = <String>['badword']; if (!initialsRegex.hasMatch(initials)) {
final filteredUsername = username.trim().toLowerCase(); return false;
final isUsernameABadWord = badWords.contains(filteredUsername); }
final isUsernameAllowed = !isUsernameABadWord;
return isUsernameAllowed; try {
final document = await _firebaseFirestore
.collection('prohibitedInitials')
.doc('list')
.get();
final prohibitedInitials = List<String>.from(
document.get('prohibitedInitials') as List,
);
final isProhibited = prohibitedInitials.contains(
initials.trim().toLowerCase(),
);
return !isProhibited;
} on Exception catch (error, stackTrace) {
throw FetchProhibitedInitialsException(error, stackTrace);
}
} }
} }

@ -21,6 +21,9 @@ class MockQueryDocumentSnapshot extends Mock
class MockDocumentReference extends Mock class MockDocumentReference extends Mock
implements DocumentReference<Map<String, dynamic>> {} implements DocumentReference<Map<String, dynamic>> {}
class MockDocumentSnapshot extends Mock
implements DocumentSnapshot<Map<String, dynamic>> {}
void main() { void main() {
group('LeaderboardRepository', () { group('LeaderboardRepository', () {
late FirebaseFirestore firestore; late FirebaseFirestore firestore;
@ -224,17 +227,32 @@ void main() {
}); });
}); });
group('isUsernameAllowed', () { group('areInitialsAllowed', () {
late LeaderboardRepository leaderboardRepository; late LeaderboardRepository leaderboardRepository;
late CollectionReference<Map<String, dynamic>> collectionReference;
late DocumentReference<Map<String, dynamic>> documentReference;
late DocumentSnapshot<Map<String, dynamic>> documentSnapshot;
setUp(() async { setUp(() async {
collectionReference = MockCollectionReference();
documentReference = MockDocumentReference();
documentSnapshot = MockDocumentSnapshot();
leaderboardRepository = LeaderboardRepository(firestore); leaderboardRepository = LeaderboardRepository(firestore);
when(() => firestore.collection('prohibitedInitials'))
.thenReturn(collectionReference);
when(() => collectionReference.doc('list'))
.thenReturn(documentReference);
when(() => documentReference.get())
.thenAnswer((_) async => documentSnapshot);
when<dynamic>(() => documentSnapshot.get('prohibitedInitials'))
.thenReturn(['bad']);
}); });
test('returns true if username is not a bad word', () async { test('returns true if initials are three letters and allowed', () async {
final isUsernameAllowedResponse = final isUsernameAllowedResponse =
await leaderboardRepository.isUsernameAllowed( await leaderboardRepository.areInitialsAllowed(
username: 'goodword', initials: 'ABC',
); );
expect( expect(
isUsernameAllowedResponse, isUsernameAllowedResponse,
@ -242,27 +260,60 @@ void main() {
); );
}); });
test('returns false if username is a bad word', () async { test(
final isUsernameAllowedResponse = 'returns false if initials are shorter than 3 characters',
await leaderboardRepository.isUsernameAllowed( () async {
username: 'badword', final areInitialsAllowedResponse =
); await leaderboardRepository.areInitialsAllowed(initials: 'AB');
expect( expect(areInitialsAllowedResponse, isFalse);
isUsernameAllowedResponse, },
isFalse, );
);
});
test('bad word detection should be case insensitive', () async { test(
final isUsernameAllowedResponse = 'returns false if initials are longer than 3 characters',
await leaderboardRepository.isUsernameAllowed( () async {
username: ' bAdWoRd ', final areInitialsAllowedResponse =
); await leaderboardRepository.areInitialsAllowed(initials: 'ABCD');
expect( expect(areInitialsAllowedResponse, isFalse);
isUsernameAllowedResponse, },
isFalse, );
);
test(
'returns false if initials contain a lowercase letter',
() async {
final areInitialsAllowedResponse =
await leaderboardRepository.areInitialsAllowed(initials: 'AbC');
expect(areInitialsAllowedResponse, isFalse);
},
);
test(
'returns false if initials contain a special character',
() async {
final areInitialsAllowedResponse =
await leaderboardRepository.areInitialsAllowed(initials: 'A@C');
expect(areInitialsAllowedResponse, isFalse);
},
);
test('returns false if initials are forbidden', () async {
final areInitialsAllowedResponse =
await leaderboardRepository.areInitialsAllowed(initials: 'BAD');
expect(areInitialsAllowedResponse, isFalse);
}); });
test(
'throws FetchProhibitedInitialsException when Exception occurs '
'when trying to retrieve information from firestore',
() async {
when(() => firestore.collection('prohibitedInitials'))
.thenThrow(Exception('oops'));
expect(
() => leaderboardRepository.areInitialsAllowed(initials: 'ABC'),
throwsA(isA<FetchProhibitedInitialsException>()),
);
},
);
}); });
}); });
} }

Loading…
Cancel
Save