Skip to content

Commit

Permalink
fix: solved answer does not update and calls updateSolvedWordsCount o…
Browse files Browse the repository at this point in the history
…nce for each word (#462)
  • Loading branch information
AyadLaouissi authored May 9, 2024
1 parent c29b874 commit e90d62e
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ class CrosswordRepository {
}

/// Tries solving a word.
/// Returns true if succeeds and updates the word's solvedTimestamp
/// attribute.
Future<bool> answerWord(
/// The first value returns true if succeeds and updates the word's
/// solvedTimestamp attribute.
/// The second value returns true if the answer was previously answered.
Future<(bool, bool)> answerWord(
String wordId,
Mascots mascot,
String userAnswer,
Expand All @@ -94,7 +95,7 @@ class CrosswordRepository {
}

if (userAnswer.toLowerCase() != correctAnswer.answer.toLowerCase()) {
return false;
return (false, false);
}

final sectionsPoints = <Point<int>>{}
Expand Down Expand Up @@ -133,6 +134,11 @@ class CrosswordRepository {
);
}

// The word has been solved previously
if (word.solvedTimestamp != null) {
return (true, true);
}

final solvedWord = word.copyWith(
answer: correctAnswer.answer,
solvedTimestamp: clock.now().millisecondsSinceEpoch,
Expand Down Expand Up @@ -179,7 +185,7 @@ class CrosswordRepository {
await updateSection(section);
}

return true;
return (true, false);
}

String _replaceCharAt(String oldString, int index, String newChar) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,16 @@ void main() {
clue: '',
);

final word4 = Word(
id: '4',
position: const Point(1, 4),
axis: Axis.horizontal,
answer: 'solved',
clue: '',
solvedTimestamp: 12343,
mascot: Mascots.sparky,
);

setUp(() {
final record = _MockDbEntityRecord();
when(() => record.id).thenReturn('1');
Expand Down Expand Up @@ -268,13 +278,57 @@ void main() {
repository = CrosswordRepository(dbClient: dbClient);
});

test('returns true if answer is correct', () async {
test('returns (true, true) if answer is correct and pre-solved',
() async {
final record = _MockDbEntityRecord();
when(() => record.id).thenReturn('4');
when(() => record.data).thenReturn(
{
'position': {'x': 1, 'y': 4},
'size': 300,
'words': [
{'id': '4', ...word4.toJson()},
],
'borderWords': const <dynamic>[],
},
);
when(
() => dbClient.find(
sectionsCollection,
{'position.x': 1, 'position.y': 4},
),
).thenAnswer((_) async => [record]);

final answersRecord = _MockDbEntityRecord();
when(() => answersRecord.id).thenReturn('4');
when(() => answersRecord.data).thenReturn({
'answer': 'solved',
'sections': [
{'x': 1, 'y': 4},
],
'collidedWords': <Map<String, dynamic>>[],
});
when(
() => dbClient.getById(answersCollection, '4'),
).thenAnswer((_) async => answersRecord);

final time = DateTime.now();
final clock = Clock.fixed(time);
await withClock(clock, () async {
final valid =
await repository.answerWord('4', Mascots.dino, 'solved');
expect(valid, (true, true));
});
});

test('returns (true, false) if answer is correct and not preSolved',
() async {
final time = DateTime.now();
final clock = Clock.fixed(time);
await withClock(clock, () async {
final valid =
await repository.answerWord('1', Mascots.dino, 'flutter');
expect(valid, isTrue);
expect(valid, (true, false));

verify(
() => dbClient.update(
Expand Down Expand Up @@ -322,9 +376,9 @@ void main() {
});
});

test('returns false if answer is incorrect', () async {
test('returns (false, false) if answer is incorrect', () async {
final valid = await repository.answerWord('1', Mascots.dino, 'android');
expect(valid, isFalse);
expect(valid, (false, false));
});

test(
Expand Down
7 changes: 5 additions & 2 deletions api/routes/game/answer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,19 @@ Future<Response> _onPost(RequestContext context) async {
}

try {
final valid = await crosswordRepository.answerWord(
final (valid, preSolved) = await crosswordRepository.answerWord(
wordId,
player.mascot,
answer,
);

var points = 0;
if (valid) {
await crosswordRepository.updateSolvedWordsCount();
points = await leaderboardRepository.updateScore(user.id);

if (!preSolved) {
await crosswordRepository.updateSolvedWordsCount();
}
}

return Response.json(body: {'points': points});
Expand Down
74 changes: 69 additions & 5 deletions api/test/routes/game/answer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,73 @@ void main() {
});

test(
'returns Response with valid to true and updates score '
'returns Response with valid to (true, true) and updates score '
'if answer is correct',
() async {
when(() => leaderboardRepository.getPlayer('userId')).thenAnswer(
(_) async => Player(
id: 'userId',
mascot: Mascots.dash,
initials: 'ABC',
),
);

when(
() => crosswordRepository.answerWord('id', Mascots.dash, 'sun'),
).thenAnswer((_) async => (true, true));
when(
() => leaderboardRepository.updateScore(user.id),
).thenAnswer((_) async => 10);
when(() => request.json()).thenAnswer(
(_) async => {
'wordId': 'id',
'answer': 'sun',
},
);

final response = await route.onRequest(requestContext);

expect(response.statusCode, HttpStatus.ok);
expect(await response.json(), equals({'points': 10}));
verify(() => leaderboardRepository.updateScore(user.id)).called(1);
},
);

test(
'returns Response with valid to (true, true) does not call '
'updateSolvedWordsCount',
() async {
when(() => leaderboardRepository.getPlayer('userId')).thenAnswer(
(_) async => Player(
id: 'userId',
mascot: Mascots.dash,
initials: 'ABC',
),
);

when(
() => crosswordRepository.answerWord('id', Mascots.dash, 'sun'),
).thenAnswer((_) async => (true, true));
when(
() => leaderboardRepository.updateScore(user.id),
).thenAnswer((_) async => 10);
when(() => request.json()).thenAnswer(
(_) async => {
'wordId': 'id',
'answer': 'sun',
},
);

final response = await route.onRequest(requestContext);

expect(response.statusCode, HttpStatus.ok);
verifyNever(() => crosswordRepository.updateSolvedWordsCount());
},
);

test(
'returns Response with valid to (true, false) '
'calls updateSolvedWordsCount',
() async {
when(() => leaderboardRepository.getPlayer('userId')).thenAnswer(
(_) async => Player(
Expand All @@ -82,7 +147,7 @@ void main() {
).thenAnswer((_) async {});
when(
() => crosswordRepository.answerWord('id', Mascots.dash, 'sun'),
).thenAnswer((_) async => true);
).thenAnswer((_) async => (true, false));
when(
() => leaderboardRepository.updateScore(user.id),
).thenAnswer((_) async => 10);
Expand All @@ -96,8 +161,7 @@ void main() {
final response = await route.onRequest(requestContext);

expect(response.statusCode, HttpStatus.ok);
expect(await response.json(), equals({'points': 10}));
verify(() => leaderboardRepository.updateScore(user.id)).called(1);
verify(() => crosswordRepository.updateSolvedWordsCount()).called(1);
},
);

Expand All @@ -114,7 +178,7 @@ void main() {
);
when(
() => crosswordRepository.answerWord('id', Mascots.dash, 'sun'),
).thenAnswer((_) async => false);
).thenAnswer((_) async => (false, false));
when(() => request.json()).thenAnswer(
(_) async => {
'wordId': 'id',
Expand Down

0 comments on commit e90d62e

Please sign in to comment.