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}
/// Repository to access leaderboard data in Firebase Cloud Firestore.
/// {@endtemplate}
@ -153,14 +167,28 @@ class LeaderboardRepository {
}
}
/// Checks if the given [username] is allowed. The [username] is not allowed
/// if it is a bad word.
Future<bool> isUsernameAllowed({required String username}) async {
// TODO(jonathandaniels-vgv): load this list of bad words from an endpoint
final badWords = <String>['badword'];
final filteredUsername = username.trim().toLowerCase();
final isUsernameABadWord = badWords.contains(filteredUsername);
final isUsernameAllowed = !isUsernameABadWord;
return isUsernameAllowed;
/// Determines if the given [initials] are allowed.
Future<bool> areInitialsAllowed({required String initials}) async {
// Initials can only be three uppercase A-Z letters
final initialsRegex = RegExp(r'^[A-Z]{3}$');
if (!initialsRegex.hasMatch(initials)) {
return false;
}
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
implements DocumentReference<Map<String, dynamic>> {}
class MockDocumentSnapshot extends Mock
implements DocumentSnapshot<Map<String, dynamic>> {}
void main() {
group('LeaderboardRepository', () {
late FirebaseFirestore firestore;
@ -224,17 +227,32 @@ void main() {
});
});
group('isUsernameAllowed', () {
group('areInitialsAllowed', () {
late LeaderboardRepository leaderboardRepository;
late CollectionReference<Map<String, dynamic>> collectionReference;
late DocumentReference<Map<String, dynamic>> documentReference;
late DocumentSnapshot<Map<String, dynamic>> documentSnapshot;
setUp(() async {
collectionReference = MockCollectionReference();
documentReference = MockDocumentReference();
documentSnapshot = MockDocumentSnapshot();
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 =
await leaderboardRepository.isUsernameAllowed(
username: 'goodword',
await leaderboardRepository.areInitialsAllowed(
initials: 'ABC',
);
expect(
isUsernameAllowedResponse,
@ -242,27 +260,60 @@ void main() {
);
});
test('returns false if username is a bad word', () async {
final isUsernameAllowedResponse =
await leaderboardRepository.isUsernameAllowed(
username: 'badword',
);
expect(
isUsernameAllowedResponse,
isFalse,
);
});
test(
'returns false if initials are shorter than 3 characters',
() async {
final areInitialsAllowedResponse =
await leaderboardRepository.areInitialsAllowed(initials: 'AB');
expect(areInitialsAllowedResponse, isFalse);
},
);
test('bad word detection should be case insensitive', () async {
final isUsernameAllowedResponse =
await leaderboardRepository.isUsernameAllowed(
username: ' bAdWoRd ',
);
expect(
isUsernameAllowedResponse,
isFalse,
);
test(
'returns false if initials are longer than 3 characters',
() async {
final areInitialsAllowedResponse =
await leaderboardRepository.areInitialsAllowed(initials: 'ABCD');
expect(areInitialsAllowedResponse, 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