def test_command_strips(self, mock_stdout, *_): # Also tests: get_commands question = Question("What?", commands=[Help]) question.ask() mock_stdout.assert_called_with("Command not found: hello") self.assertEqual([Help], question.get_commands())
def test_quit(self, *_): question = Question("What", commands=[Quit]) with self.assertRaises(SystemExit) as cm: question.ask() self.assertEqual(0, cm.exception.code)
def test_has_answer(self, *_): question = Question("What?") question.ask() self.assertTrue(question.has_answer) optional_question = Question("What?", required=False) optional_question.ask() self.assertFalse(optional_question.has_answer)
def test_help_base(self, mock_stdout, *_): question = Question("What?", commands=[Help], required=False) question.ask() mock_stdout.assert_called_with( "\nAvailable commands are:\n!help: Shows the help message.\n" ) self.assertEqual("Answer", question.answer)
def test_command_no_context(self, mock_stdout, *_): question = Question("What?", required=False) question.ask() mock_stdout.assert_called_with( "Commands are disabled for this question." ) self.assertEqual("Answer", question.answer)
def test_help_no_command_list(self, mock_stdout, *_): question = Question( "What?", commands=[Help(message="Howdy?", with_command_list=False)] ) question.ask() mock_stdout.assert_called_with("Howdy?") self.assertEqual("Answer", question.answer)
def test_prefix(self, mock_stdin): question_with_prefix = Question("What?", prefix="test2") self.assertEqual("test2", question_with_prefix.get_prefix()) self.assertEqual("test2What?", question_with_prefix.get_prompt()) question_with_prefix.ask() mock_stdin.assert_called_with("test2What?")
def test_skip(self, mock_stdout, *_): question = Question("Hello?", commands=[Skip], required=False) question.answer = "World" question.ask() mock_stdout.assert_called_with("You decided to skip this question.") self.assertIsNone(question.answer) self.assertEqual(1, question.attempt)
def test_required_retries(self, mock_stdout, *_): question = Question("What?") self.assertTrue(question.get_required()) question.ask() mock_stdout.assert_called_with("This question is required.") self.assertEqual("OK", question.answer) self.assertEqual(2, question.attempt)
def test_has_correct_answer_option(self, *_): options = [ Option(value="A", expression="Something"), Option(value="B", expression="Other Something"), ] question = Question("What?", options=options, correct_answers=["A"]) question.ask() self.assertFalse(question.has_correct_answer) question.ask() self.assertTrue(question.has_correct_answer)
def test_command_not_found(self, mock_stdout, *_): # Also tests: command delimiter & first word counts as expression question = Question("What?", command_delimiter="/", commands=[Help]) question.ask() mock_stdout.assert_has_calls( [ call("Command not found: hello"), call("Command not found: search"), ] ) self.assertEqual("Answer", question.answer)
def test_strip(self, *_): question = Question("What?") self.assertTrue(question.get_strip()) question_no_strip = Question("What? 2", strip=False) self.assertFalse(question_no_strip.get_strip()) question.ask() question_no_strip.ask() self.assertEqual("spaced", question.answer) self.assertEqual(" spaced ", question_no_strip.answer)
def test_skip_inoperative_for_required(self, mock_stdout, *_): question = Question("Hello?", commands=[Skip]) question.ask() mock_stdout.assert_has_calls( [ call("You decided to skip this question."), call("This question is required."), ] ) self.assertEqual("Answer", question.answer) self.assertEqual(2, question.attempt)
def test_command_opcode_break(self, *_): # Required question is break-able class Break(Command): expression = "break" def execute(self, question, *args): return opcodes.BREAK question_ = Question("What?", commands=[Break]) question_.ask() self.assertIsNone(question_.answer) self.assertEqual(1, question_.attempt)
def test_prefix_suffix(self, mock_stdin): question_with_prefix_suffix = Question( "What?", prefix="Pre", suffix="Suf" ) self.assertEqual("Pre", question_with_prefix_suffix.get_prefix()) self.assertEqual("Suf", question_with_prefix_suffix.get_suffix()) self.assertEqual( "PreWhat?Suf", question_with_prefix_suffix.get_prompt() ) question_with_prefix_suffix.ask() mock_stdin.assert_called_with("PreWhat?Suf")
def test_unimplemented_command(self, *_): class MyCommand(Command): # noqa expression = "test" pass self.assertEqual("No description provided.", MyCommand.description) question = Question("What?", commands=[MyCommand]) with self.assertRaisesRegex( NotImplementedError, "Define a behaviour for this command using execute method.", ): question.ask()
def test_command_with_args(self, *_): class SetExtra(Command): expression = "set_extra" def execute(self, question, *args): question.extra[args[0]] = args[1] return opcodes.CONTINUE question_ = Question("What?", commands=[SetExtra]) question_.ask() self.assertEqual("meow", question_.extra["cat"]) self.assertEqual("Answer", question_.answer) self.assertEqual(2, question_.attempt)
def test_suffix(self, mock_stdin): question = Question("What?") question_with_suffix = Question("What?", suffix="test") self.assertEqual("", question.get_suffix()) self.assertEqual("test", question_with_suffix.get_suffix()) self.assertEqual("What?", question.get_prompt()) self.assertEqual("What?test", question_with_suffix.get_prompt()) question.ask() mock_stdin.assert_called_with("What?") question_with_suffix.ask() mock_stdin.assert_called_with("What?test")
def test_command_opcode_continue(self, *_): class Meow(Command): expression = "meow" def execute(self, question, *args): question.extra["meow_count"] += 1 return opcodes.CONTINUE meowing_question = Question( "What?", commands=[Meow], extra={"meow_count": 0}, required=False ) meowing_question.ask() self.assertEqual("Cat!", meowing_question.answer) self.assertEqual(2, meowing_question.extra["meow_count"]) self.assertEqual(3, meowing_question.attempt)
def test_help_custom_message(self, mock_stdout, *_): question = Question( "What?", commands=[Help(message="How ya doing?."), Quit, Skip], command_delimiter="/", required=False, ) question.ask() mock_stdout.assert_called_with( "How ya doing?.\nAvailable commands are:\n/help: Shows the help" " message.\n/quit: Quits the program.\n/skip: Skips this question" " without answering.\n" ) self.assertEqual("Answer", question.answer)
def test_option_validation(self, mock_stdout, *_): question = Question( "What?", options=[ Option(value="A", expression="Something"), Option(value="B", expression="Other Something"), ], ) question.ask() mock_stdout.assert_called_with( "\nThe selected option is not valid. Available options are: " "\nA) Something\nB) Other Something\n" ) self.assertEqual(2, question.attempt)
def test_validation(self, mock_stdout, *_): question = Question( "What", validators=[ AlphaValidator(message="This answer is not alpha."), MaxLengthValidator(13, message="This answer is too long."), ], ) question.ask() mock_stdout.assert_has_calls( [ call("This answer is not alpha."), call("This answer is too long."), ] ) self.assertEqual(3, question.attempt)
def test_command_opcode_none(self, *_): # Returning None in opcode does not re-ask the question. # It will re-ask the question if it is required though. class Meow(Command): expression = "meow" def execute(self, question, *args): question.extra["meow_count"] += 1 meowing_question = Question( "What?", commands=[Meow], extra={"meow_count": 0}, required=False ) meowing_question.ask() self.assertIsNone(meowing_question.answer) self.assertEqual(1, meowing_question.extra["meow_count"]) self.assertEqual(1, meowing_question.attempt)
def test_signals(self, *_): question = Question("What?", extra={"number": 10}) def increment_number(q): q.extra["number"] *= 8 q.extra["ans"] = q.answer def decrement_number(q): q.extra["number"] -= 5 q.extra["ans"] = q.answer question.pre_ask = increment_number question.post_answer = decrement_number question.ask() self.assertEqual(75, question.extra["number"]) self.assertEqual(question.answer, question.extra["ans"])
def test_command_opcode_none_required(self, mock_stdout, *_): # Re-ask the question if it is required even if opcode # is None. use BREAK to bypass required as well. class Meow(Command): expression = "meow" def execute(self, question, *args): question.extra["meow_count"] += 1 meowing_question = Question( "What?", commands=[Meow], extra={"meow_count": 0} ) meowing_question.ask() mock_stdout.assert_has_calls( [ call("This question is required."), call("This question is required."), ] ) self.assertEqual("Cat!", meowing_question.answer) self.assertEqual(2, meowing_question.extra["meow_count"]) self.assertEqual(3, meowing_question.attempt)
def test_has_correct_answer(self, *_): question = Question("What?", correct_answers=["Correct"]) incorrect_question = Question( "What?", correct_answers=["Hello", "Girl"] ) unanswered_question = Question("What", required=False) self.assertIn("Correct", question.get_correct_answers()) self.assertIn("Girl", incorrect_question.get_correct_answers()) self.assertIn("Hello", incorrect_question.get_correct_answers()) question.ask() incorrect_question.ask() unanswered_question.ask() self.assertTrue(question.has_correct_answer) self.assertFalse(incorrect_question.has_correct_answer) self.assertFalse(unanswered_question.has_correct_answer)
def test_answer_is_set_as_option(self, *_): option = Option(value="A", expression="Hello") question = Question("What?", options=[option]) question.ask() self.assertEqual(option, question.answer)
def test_answer_persists_on_empty_input(self, *_): question = Question("What?", required=False) question.answer = "Previous Answer" question.ask() self.assertEqual("Previous Answer", question.answer)
def test_answer_is_set(self, *_): question = Question("What?") question.ask() self.assertEqual("Answer", question.answer)
def test_attempt_increments_on_ask(self, *_): question = Question("What?") question.ask() self.assertEqual(1, question.attempt) question.ask() self.assertEqual(2, question.attempt)