bots: Improve response at 3 wrong answers in trivia bot.
This commit is contained in:
		
							parent
							
								
									f25772d1dc
								
							
						
					
					
						commit
						b28cfcac3d
					
				
					 2 changed files with 103 additions and 11 deletions
				
			
		|  | @ -2,12 +2,13 @@ import json | ||||||
| import html | import html | ||||||
| 
 | 
 | ||||||
| from unittest.mock import patch | from unittest.mock import patch | ||||||
| from typing import Optional | from typing import Optional, Tuple, Any, Dict | ||||||
| 
 | 
 | ||||||
| from zulip_bots.test_lib import ( | from zulip_bots.test_lib import ( | ||||||
|     BotTestCase, |     BotTestCase, | ||||||
|     DefaultTests, |     DefaultTests, | ||||||
|     read_bot_fixture_data, |     read_bot_fixture_data, | ||||||
|  |     StubBotHandler, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| from zulip_bots.request_test_lib import ( | from zulip_bots.request_test_lib import ( | ||||||
|  | @ -17,6 +18,9 @@ from zulip_bots.request_test_lib import ( | ||||||
| from zulip_bots.bots.trivia_quiz.trivia_quiz import ( | from zulip_bots.bots.trivia_quiz.trivia_quiz import ( | ||||||
|     get_quiz_from_payload, |     get_quiz_from_payload, | ||||||
|     fix_quotes, |     fix_quotes, | ||||||
|  |     get_quiz_from_id, | ||||||
|  |     update_quiz, | ||||||
|  |     handle_answer, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| class TestTriviaQuizBot(BotTestCase, DefaultTests): | class TestTriviaQuizBot(BotTestCase, DefaultTests): | ||||||
|  | @ -29,6 +33,13 @@ class TestTriviaQuizBot(BotTestCase, DefaultTests): | ||||||
|         '* **D** Mammals\n' + \ |         '* **D** Mammals\n' + \ | ||||||
|         '**reply**: answer Q001 <letter>' |         '**reply**: answer Q001 <letter>' | ||||||
| 
 | 
 | ||||||
|  |     def get_test_quiz(self) -> Tuple[Dict[str, Any], Any]: | ||||||
|  |         bot_handler = StubBotHandler() | ||||||
|  |         quiz_payload = read_bot_fixture_data('trivia_quiz', 'test_new_question')['response'] | ||||||
|  |         with patch('random.shuffle'): | ||||||
|  |             quiz = get_quiz_from_payload(quiz_payload) | ||||||
|  |         return quiz, bot_handler | ||||||
|  | 
 | ||||||
|     def _test(self, message: str, response: str, fixture: Optional[str]=None) -> None: |     def _test(self, message: str, response: str, fixture: Optional[str]=None) -> None: | ||||||
|         if fixture: |         if fixture: | ||||||
|             with self.mock_http_conversation(fixture): |             with self.mock_http_conversation(fixture): | ||||||
|  | @ -74,9 +85,12 @@ class TestTriviaQuizBot(BotTestCase, DefaultTests): | ||||||
|         with patch('random.shuffle'): |         with patch('random.shuffle'): | ||||||
|             quiz = get_quiz_from_payload(quiz_payload) |             quiz = get_quiz_from_payload(quiz_payload) | ||||||
| 
 | 
 | ||||||
|  |         # Test initial storage | ||||||
|         self.assertEqual(quiz['question'], 'Which class of animals are newts members of?') |         self.assertEqual(quiz['question'], 'Which class of animals are newts members of?') | ||||||
|         self.assertEqual(quiz['correct_letter'], 'A') |         self.assertEqual(quiz['correct_letter'], 'A') | ||||||
|         self.assertEqual(quiz['answers']['D'], 'Mammals') |         self.assertEqual(quiz['answers']['D'], 'Mammals') | ||||||
|  |         self.assertEqual(quiz['answered_options'], []) | ||||||
|  |         self.assertEqual(quiz['pending'], True) | ||||||
| 
 | 
 | ||||||
|         # test incorrect answer |         # test incorrect answer | ||||||
|         with patch('zulip_bots.bots.trivia_quiz.trivia_quiz.get_quiz_from_id', |         with patch('zulip_bots.bots.trivia_quiz.trivia_quiz.get_quiz_from_id', | ||||||
|  | @ -88,3 +102,56 @@ class TestTriviaQuizBot(BotTestCase, DefaultTests): | ||||||
|                    return_value=json.dumps(quiz)): |                    return_value=json.dumps(quiz)): | ||||||
|             with patch('zulip_bots.bots.trivia_quiz.trivia_quiz.start_new_quiz') as mock_new_quiz: |             with patch('zulip_bots.bots.trivia_quiz.trivia_quiz.start_new_quiz') as mock_new_quiz: | ||||||
|                 self._test('answer Q001 A', '**CORRECT!** Amphibian :tada:') |                 self._test('answer Q001 A', '**CORRECT!** Amphibian :tada:') | ||||||
|  | 
 | ||||||
|  |     def test_update_quiz(self) -> None: | ||||||
|  |         quiz, bot_handler = self.get_test_quiz() | ||||||
|  |         update_quiz(quiz, 'Q001', bot_handler) | ||||||
|  |         test_quiz = json.loads(bot_handler.storage.get('Q001')) | ||||||
|  |         self.assertEqual(test_quiz, quiz) | ||||||
|  | 
 | ||||||
|  |     def test_get_quiz_from_id(self) -> None: | ||||||
|  |         quiz, bot_handler = self.get_test_quiz() | ||||||
|  |         bot_handler.storage.put('Q001', quiz) | ||||||
|  |         self.assertEqual(get_quiz_from_id('Q001', bot_handler), quiz) | ||||||
|  | 
 | ||||||
|  |     def test_handle_answer(self) -> None: | ||||||
|  |         quiz, bot_handler = self.get_test_quiz() | ||||||
|  |         # create test initial storage | ||||||
|  |         update_quiz(quiz, 'Q001', bot_handler) | ||||||
|  | 
 | ||||||
|  |         # test for a correct answer | ||||||
|  |         start_new_question, response = handle_answer(quiz, 'A', 'Q001', bot_handler) | ||||||
|  |         self.assertTrue(start_new_question) | ||||||
|  |         self.assertEqual(response, '**CORRECT!** Amphibian :tada:') | ||||||
|  | 
 | ||||||
|  |         # test for an incorrect answer | ||||||
|  |         start_new_question, response = handle_answer(quiz, 'D', 'Q001', bot_handler) | ||||||
|  |         self.assertFalse(start_new_question) | ||||||
|  |         self.assertEqual(response, '**WRONG!** D is not correct :disappointed:') | ||||||
|  | 
 | ||||||
|  |     def test_handle_answer_three_failed_attempts(self) -> None: | ||||||
|  |         quiz, bot_handler = self.get_test_quiz() | ||||||
|  |         # create test storage for a question which has been incorrectly answered twice | ||||||
|  |         quiz['answered_options'] = ['C', 'B'] | ||||||
|  |         update_quiz(quiz, 'Q001', bot_handler) | ||||||
|  | 
 | ||||||
|  |         # test response  and storage after three failed attempts | ||||||
|  |         start_new_question, response = handle_answer(quiz, 'D', 'Q001', bot_handler) | ||||||
|  |         self.assertEqual(response, '**WRONG!** :disappointed: The correct answer is Amphibian.') | ||||||
|  |         self.assertTrue(start_new_question) | ||||||
|  |         quiz_reset = json.loads(bot_handler.storage.get('Q001')) | ||||||
|  |         self.assertEqual(quiz_reset['pending'], False) | ||||||
|  | 
 | ||||||
|  |         # test response after question has ended | ||||||
|  |         incorrect_answers = ['B', 'C', 'D'] | ||||||
|  |         for ans in incorrect_answers: | ||||||
|  |             start_new_question, response = handle_answer(quiz, ans, 'Q001', bot_handler) | ||||||
|  |             self.assertEqual(response, '**WRONG!** :disappointed: The correct answer is Amphibian.') | ||||||
|  |             self.assertFalse(start_new_question) | ||||||
|  |         start_new_question, response = handle_answer(quiz, 'A', 'Q001', bot_handler) | ||||||
|  |         self.assertEqual(response, '**CORRECT!** Amphibian :tada:') | ||||||
|  |         self.assertFalse(start_new_question) | ||||||
|  | 
 | ||||||
|  |         # test storage after question has ended | ||||||
|  |         quiz_reset = json.loads(bot_handler.storage.get('Q001')) | ||||||
|  |         self.assertEqual(quiz_reset['pending'], False) | ||||||
|  |  | ||||||
|  | @ -43,9 +43,9 @@ class TriviaQuizHandler: | ||||||
|                 bot_handler.send_reply(message, bot_response) |                 bot_handler.send_reply(message, bot_response) | ||||||
|                 return |                 return | ||||||
|             quiz = json.loads(quiz_payload) |             quiz = json.loads(quiz_payload) | ||||||
|             correct, bot_response = grade_question(quiz, answer) |             start_new_question, bot_response = handle_answer(quiz, answer, quiz_id, bot_handler) | ||||||
|             bot_handler.send_reply(message, bot_response) |             bot_handler.send_reply(message, bot_response) | ||||||
|             if correct: |             if start_new_question: | ||||||
|                 start_new_quiz(message, bot_handler) |                 start_new_quiz(message, bot_handler) | ||||||
|             return |             return | ||||||
|         else: |         else: | ||||||
|  | @ -125,6 +125,8 @@ def get_quiz_from_payload(payload: Dict[str, Any]) -> Dict[str, Any]: | ||||||
|     quiz = dict( |     quiz = dict( | ||||||
|         question=fix_quotes(question), |         question=fix_quotes(question), | ||||||
|         answers=answers, |         answers=answers, | ||||||
|  |         answered_options=[], | ||||||
|  |         pending=True, | ||||||
|         correct_letter=correct_letter, |         correct_letter=correct_letter, | ||||||
|     ) |     ) | ||||||
|     return quiz |     return quiz | ||||||
|  | @ -196,16 +198,39 @@ Q: {question} | ||||||
|     ) |     ) | ||||||
|     return content |     return content | ||||||
| 
 | 
 | ||||||
| def grade_question(quiz: Dict[str, Any], answer: str) -> Tuple[bool, str]: | def update_quiz(quiz: Dict[str, Any], quiz_id: str, bot_handler: Any) -> None: | ||||||
|     correct = (answer == quiz['correct_letter']) |     bot_handler.storage.put(quiz_id, json.dumps(quiz)) | ||||||
| 
 | 
 | ||||||
|     if correct: | def build_response(is_correct: bool, num_answers: int) -> str: | ||||||
|         long_answer = quiz['answers'][answer] |     if is_correct: | ||||||
|         response = '**CORRECT!** {long_answer} :tada:'.format(long_answer=long_answer) |         response = '**CORRECT!** {answer} :tada:' | ||||||
|         return correct, response |     else: | ||||||
|  |         if num_answers >= 3: | ||||||
|  |             response = '**WRONG!** :disappointed: The correct answer is {answer}.' | ||||||
|  |         else: | ||||||
|  |             response = '**WRONG!** {option} is not correct :disappointed:' | ||||||
|  |     return response | ||||||
| 
 | 
 | ||||||
|     response = '**WRONG!** {answer} is not correct :disappointed:'.format(answer=answer) | def handle_answer(quiz: Dict[str, Any], option: str, quiz_id: str, | ||||||
|     return correct, response |                   bot_handler: Any) -> Tuple[bool, str]: | ||||||
|  |     answer = quiz['answers'][quiz['correct_letter']] | ||||||
|  |     is_new_answer = (option not in quiz['answered_options']) | ||||||
|  |     if is_new_answer: | ||||||
|  |         quiz['answered_options'].append(option) | ||||||
|  | 
 | ||||||
|  |     num_answers = len(quiz['answered_options']) | ||||||
|  |     is_correct = (option == quiz['correct_letter']) | ||||||
|  | 
 | ||||||
|  |     start_new_question = quiz['pending'] and (is_correct or num_answers >= 3) | ||||||
|  |     if start_new_question or is_correct: | ||||||
|  |         quiz['pending'] = False | ||||||
|  | 
 | ||||||
|  |     if is_new_answer or start_new_question: | ||||||
|  |         update_quiz(quiz, quiz_id, bot_handler) | ||||||
|  | 
 | ||||||
|  |     response = build_response(is_correct, num_answers).format( | ||||||
|  |         option=option, answer=answer, id=quiz_id) | ||||||
|  |     return start_new_question, response | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| handler_class = TriviaQuizHandler | handler_class = TriviaQuizHandler | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Rhea Parekh
						Rhea Parekh