class TextInputExtendedHintsCaseSensitive(HintTest): """Sometimes the semantics can be encoded in the class name.""" xml = load_fixture('extended_hints_text_input.xml') problem = new_loncapa_problem(xml) @data( {'problem_id': u'1_6_1', 'choice': 'abc', 'expected_string': ''}, {'problem_id': u'1_6_1', 'choice': 'A', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint1</div></div>'}, {'problem_id': u'1_6_1', 'choice': 'a', 'expected_string': u''}, {'problem_id': u'1_6_1', 'choice': 'B', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint2</div></div>'}, {'problem_id': u'1_6_1', 'choice': 'b', 'expected_string': u''}, {'problem_id': u'1_6_1', 'choice': 'C', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">hint4</div></div>'}, {'problem_id': u'1_6_1', 'choice': 'c', 'expected_string': u''}, # regexp cases {'problem_id': u'1_6_1', 'choice': 'FGG', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">hint6</div></div>'}, {'problem_id': u'1_6_1', 'choice': 'fgG', 'expected_string': u''}, ) @unpack def test_text_input_hints(self, problem_id, choice, expected_string): message_text = self.get_hint(problem_id, choice) assert message_text == expected_string
class TextInputExtendedHintsCaseInsensitive(HintTest): """Test Text Input Extended hints Case Insensitive""" xml = load_fixture('extended_hints_text_input.xml') problem = new_loncapa_problem(xml) @data( {'problem_id': u'1_5_1', 'choice': 'abc', 'expected_string': ''}, # wrong answer yielding no hint {'problem_id': u'1_5_1', 'choice': 'A', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Woo Hoo </span><div class="hint-text">hint1</div></div>'}, {'problem_id': u'1_5_1', 'choice': 'a', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Woo Hoo </span><div class="hint-text">hint1</div></div>'}, {'problem_id': u'1_5_1', 'choice': 'B', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><div class="hint-text">hint2</div></div>'}, {'problem_id': u'1_5_1', 'choice': 'b', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><div class="hint-text">hint2</div></div>'}, {'problem_id': u'1_5_1', 'choice': 'C', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><div class="hint-text">hint4</div></div>'}, {'problem_id': u'1_5_1', 'choice': 'c', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><div class="hint-text">hint4</div></div>'}, # regexp cases {'problem_id': u'1_5_1', 'choice': 'FGGG', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><div class="hint-text">hint6</div></div>'}, {'problem_id': u'1_5_1', 'choice': 'fgG', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><div class="hint-text">hint6</div></div>'}, ) @unpack def test_text_input_hints(self, problem_id, choice, expected_string): hint = self.get_hint(problem_id, choice) assert hint == expected_string
class TextInputExtendedHintsRegex(HintTest): """ Extended hints where the answer is regex mode. """ xml = load_fixture('extended_hints_text_input.xml') problem = new_loncapa_problem(xml) @data( {'problem_id': u'1_8_1', 'choice': 'ABwrong', 'correct': 'incorrect', 'expected_string': ''}, {'problem_id': u'1_8_1', 'choice': 'ABC', 'correct': 'correct', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint1</div></div>'}, {'problem_id': u'1_8_1', 'choice': 'ABBBBC', 'correct': 'correct', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint1</div></div>'}, {'problem_id': u'1_8_1', 'choice': 'aBc', 'correct': 'correct', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint1</div></div>'}, {'problem_id': u'1_8_1', 'choice': 'BBBB', 'correct': 'correct', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint2</div></div>'}, {'problem_id': u'1_8_1', 'choice': 'bbb', 'correct': 'correct', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint2</div></div>'}, {'problem_id': u'1_8_1', 'choice': 'C', 'correct': 'incorrect', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">hint4</div></div>'}, {'problem_id': u'1_8_1', 'choice': 'c', 'correct': 'incorrect', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">hint4</div></div>'}, {'problem_id': u'1_8_1', 'choice': 'D', 'correct': 'incorrect', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">hint6</div></div>'}, {'problem_id': u'1_8_1', 'choice': 'd', 'correct': 'incorrect', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">hint6</div></div>'}, ) @unpack def test_text_input_hints(self, problem_id, choice, correct, expected_string): message_text = self.get_hint(problem_id, choice) assert message_text == expected_string assert self.correctness(problem_id, choice) == correct
class MultpleChoiceHintsWithHtmlTest(HintTest): """ This class consists of a suite of test cases to be run on the multiple choice problem represented by the XML below. """ xml = load_fixture('extended_hints_multiple_choice_with_html.xml') problem = new_loncapa_problem(xml) def test_tracking_log(self): """Test that the tracking log comes out right.""" self.problem.capa_module.reset_mock() self.get_hint(u'1_2_1', u'choice_0') self.problem.capa_module.runtime.track_function.assert_called_with( 'edx.problem.hint.feedback_displayed', { 'module_id': u'i4x://Foo/bar/mock/abc', 'problem_part_id': '1_1', 'trigger_type': 'single', 'student_answer': [u'choice_0'], 'correctness': False, 'question_type': 'multiplechoiceresponse', 'hint_label': 'Incorrect:', 'hints': [{ 'text': 'Mushroom <img src="#" ale="#"/>is a fungus, not a fruit.' }] }) @data( { 'problem_id': u'1_2_1', 'choice': u'choice_0', 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">Mushroom <img src="#" ale="#"/>is a fungus, not a fruit.</div></div>' }, { 'problem_id': u'1_2_1', 'choice': u'choice_1', 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">Potato is <img src="#" ale="#"/> not a fruit.</div></div>' }, { 'problem_id': u'1_2_1', 'choice': u'choice_2', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text"><a href="#">Apple</a> is a fruit.</div></div>' }) @unpack def test_multiplechoice_hints(self, problem_id, choice, expected_string): hint = self.get_hint(problem_id, choice) self.assertEqual(hint, expected_string)
def test_targeted_feedback_not_finished(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") self.assertRegexpMatches(without_new_lines, r"<div>.*'wrong-1'.*'wrong-2'.*'correct-1'.*'wrong-3'.*</div>") self.assertNotRegexpMatches(without_new_lines, r"feedback1|feedback2|feedback3|feedbackC") self.assertEquals(the_html, problem.get_html(), "Should be able to call get_html() twice")
def test_targeted_feedback_not_finished(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") self.assertRegex(without_new_lines, r"<div>.*'wrong-1'.*'wrong-2'.*'correct-1'.*'wrong-3'.*</div>") self.assertNotRegexpMatches(without_new_lines, r"feedback1|feedback2|feedback3|feedbackC") self.assertEqual(the_html, problem.get_html(), "Should be able to call get_html() twice")
def test_targeted_feedback_multiple_not_answered(self): # Not answered -> empty targeted feedback problem = new_loncapa_problem( load_fixture('targeted_feedback_multiple.xml')) the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") # Q1 and Q2 have no feedback self.assertRegexpMatches( without_new_lines, r'<targetedfeedbackset.*?/>.*<targetedfeedbackset.*?/>')
def test_targeted_feedback_multiple_not_answered(self): # Not answered -> empty targeted feedback problem = new_loncapa_problem(load_fixture('targeted_feedback_multiple.xml')) the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") # Q1 and Q2 have no feedback self.assertRegexpMatches( without_new_lines, r'<targetedfeedbackset.*?/>.*<targetedfeedbackset.*?/>' )
def test_targeted_feedback_student_answer2(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_0'} the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") # pylint: disable=line-too-long self.assertRegexpMatches(without_new_lines, r"<targetedfeedback explanation-id=\"feedback1\" role=\"group\" aria-describedby=\"1_2_1-legend\">\s*<span class=\"sr\">Incorrect</span>.*1st WRONG solution") self.assertRegexpMatches(without_new_lines, r"<div>\{.*'1_solution_1'.*\}</div>") self.assertNotRegexpMatches(without_new_lines, r"feedback2|feedback3|feedbackC")
class TextInputExtendedHintsCompatible(HintTest): """ Compatibility test with mixed old and new style additional_answer tags. """ xml = load_fixture('extended_hints_text_input.xml') problem = new_loncapa_problem(xml) @data( { 'problem_id': u'1_7_1', 'choice': 'A', 'correct': 'correct', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint1</div></div>' }, { 'problem_id': u'1_7_1', 'choice': 'B', 'correct': 'correct', 'expected_string': '' }, { 'problem_id': u'1_7_1', 'choice': 'C', 'correct': 'correct', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">hint2</div></div>' }, { 'problem_id': u'1_7_1', 'choice': 'D', 'correct': 'incorrect', 'expected_string': '' }, # check going through conversion with difficult chars { 'problem_id': u'1_7_1', 'choice': """<&"'>""", 'correct': 'correct', 'expected_string': '' }, ) @unpack def test_text_input_hints(self, problem_id, choice, correct, expected_string): message_text = self.get_hint(problem_id, choice) self.assertEqual(message_text, expected_string) self.assertEqual(self.correctness(problem_id, choice), correct)
def test_targeted_feedback_student_answer2(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_0'} the_html = problem.get_html() without_new_lines = the_html.replace("\\n", "").replace("\n", "") # pylint: disable=line-too-long self.assertRegex(without_new_lines, r"<targetedfeedback explanation-id=\"feedback1\" role=\"group\" aria-describedby=\"1_2_1-legend\">\s*<span class=\"sr\">Incorrect</span>.*1st WRONG solution") self.assertRegex(without_new_lines, r"<div>\{.*'1_solution_1'.*\}</div>") self.assertNotRegexpMatches(without_new_lines, r"feedback2|feedback3|feedbackC")
def test_targeted_feedback_student_answer2(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_0'} the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") self.assertRegexpMatches(without_new_lines, r"<targetedfeedback explanation-id=\"feedback1\">.*1st WRONG solution") self.assertRegexpMatches(without_new_lines, r"<div>\{.*'1_solution_1'.*\}</div>") self.assertNotRegexpMatches(without_new_lines, r"feedback2|feedback3|feedbackC")
def test_targeted_feedback_correct_answer(self): """ Test the case of targeted feedback for a correct answer. """ problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_2'} the_html = problem.get_html() without_new_lines = the_html.replace("\\n", "").replace("\n", "") # pylint: disable=line-too-long self.assertRegex(without_new_lines, r"<targetedfeedback explanation-id=\"feedbackC\" role=\"group\" aria-describedby=\"1_2_1-legend\">\s*<span class=\"sr\">Correct</span>.*Feedback on your correct solution...") self.assertNotRegexpMatches(without_new_lines, r"feedback1|feedback2|feedback3")
def test_targeted_feedback_multiple_answer_1(self): problem = new_loncapa_problem( load_fixture('targeted_feedback_multiple.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_0'} # feedback1 the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") # Q1 has feedback1 and Q2 has nothing self.assertRegex( without_new_lines, r'<targetedfeedbackset.*?>.*?explanation-id="feedback1".*?</targetedfeedbackset>.*' + r'<targetedfeedbackset>\s*</targetedfeedbackset>')
def test_targeted_feedback_multiple_answer_2(self): problem = new_loncapa_problem(load_fixture('targeted_feedback_multiple.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_0', '1_3_1': 'choice_2'} # Q1 wrong, Q2 correct the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") # Q1 has feedback1 and Q2 has feedbackC self.assertRegexpMatches( without_new_lines, r'<targetedfeedbackset.*?>.*?explanation-id="feedback1".*?</targetedfeedbackset>.*' + r'<targetedfeedbackset.*?>.*explanation-id="feedbackC".*?</targetedfeedbackset>' )
def test_targeted_feedback_correct_answer(self): """ Test the case of targeted feedback for a correct answer. """ problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_2'} the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") # pylint: disable=line-too-long self.assertRegexpMatches(without_new_lines, r"<targetedfeedback explanation-id=\"feedbackC\" role=\"group\" aria-describedby=\"1_2_1-legend\">\s*<span class=\"sr\">Correct</span>.*Feedback on your correct solution...") self.assertNotRegexpMatches(without_new_lines, r"feedback1|feedback2|feedback3")
def test_targeted_feedback_student_answer1(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_3'} the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") self.assertRegexpMatches(without_new_lines, r"<targetedfeedback explanation-id=\"feedback3\">.*3rd WRONG solution") self.assertNotRegexpMatches(without_new_lines, r"feedback1|feedback2|feedbackC") # Check that calling it multiple times yields the same thing the_html2 = problem.get_html() self.assertEquals(the_html, the_html2)
def test_targeted_feedback_student_answer1(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_3'} the_html = problem.get_html() without_new_lines = the_html.replace("\\n", "").replace("\n", "") # pylint: disable=line-too-long self.assertRegex(without_new_lines, r"<targetedfeedback explanation-id=\"feedback3\" role=\"group\" aria-describedby=\"1_2_1-legend\">\s*<span class=\"sr\">Incorrect</span>.*3rd WRONG solution") self.assertNotRegexpMatches(without_new_lines, r"feedback1|feedback2|feedbackC") # Check that calling it multiple times yields the same thing the_html2 = problem.get_html() self.assertEqual(the_html, the_html2)
def test_targeted_feedback_student_answer1(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_3'} the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") # pylint: disable=line-too-long self.assertRegexpMatches(without_new_lines, r"<targetedfeedback explanation-id=\"feedback3\" role=\"group\" aria-describedby=\"1_2_1-legend\">\s*<span class=\"sr\">Incorrect</span>.*3rd WRONG solution") self.assertNotRegexpMatches(without_new_lines, r"feedback1|feedback2|feedbackC") # Check that calling it multiple times yields the same thing the_html2 = problem.get_html() self.assertEquals(the_html, the_html2)
class TextInputHintsTest(HintTest): """ Test Text Input Hints Test """ xml = load_fixture('extended_hints_text_input.xml') problem = new_loncapa_problem(xml) def test_tracking_log(self): """Test that the tracking log comes out right.""" self.problem.capa_module.reset_mock() self.get_hint(u'1_3_1', u'Blue') self.problem.capa_module.runtime.track_function.assert_called_with( 'edx.problem.hint.feedback_displayed', {'module_id': u'i4x://Foo/bar/mock/abc', 'problem_part_id': '1_2', 'trigger_type': 'single', 'hint_label': u'Correct:', 'correctness': True, 'student_answer': [u'Blue'], 'question_type': 'stringresponse', 'hints': [{'text': 'The red light is scattered by water molecules leaving only blue light.'}]} ) @data( {'problem_id': u'1_2_1', u'choice': u'GermanyΩ', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">I do not think so.Ω</div></div>'}, {'problem_id': u'1_2_1', u'choice': u'franceΩ', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">Viva la France!Ω</div></div>'}, {'problem_id': u'1_2_1', u'choice': u'FranceΩ', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">Viva la France!Ω</div></div>'}, {'problem_id': u'1_2_1', u'choice': u'Mexico', 'expected_string': ''}, {'problem_id': u'1_2_1', u'choice': u'USAΩ', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">Less well known, but yes, there is a Paris, Texas.Ω</div></div>'}, {'problem_id': u'1_2_1', u'choice': u'usaΩ', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">Less well known, but yes, there is a Paris, Texas.Ω</div></div>'}, {'problem_id': u'1_2_1', u'choice': u'uSAxΩ', 'expected_string': u''}, {'problem_id': u'1_2_1', u'choice': u'NICKLANDΩ', 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">The country name does not end in LANDΩ</div></div>'}, {'problem_id': u'1_3_1', u'choice': u'Blue', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">The red light is scattered by water molecules leaving only blue light.</div></div>'}, {'problem_id': u'1_3_1', u'choice': u'blue', 'expected_string': u''}, {'problem_id': u'1_3_1', u'choice': u'b', 'expected_string': u''}, ) @unpack def test_text_input_hints(self, problem_id, choice, expected_string): hint = self.get_hint(problem_id, choice) assert hint == expected_string
def test_targeted_feedback_student_answer2(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_0'} the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") self.assertRegexpMatches( without_new_lines, r"<targetedfeedback explanation-id=\"feedback1\">.*1st WRONG solution" ) self.assertRegexpMatches(without_new_lines, r"<div>\{.*'1_solution_1'.*\}</div>") self.assertNotRegexpMatches(without_new_lines, r"feedback2|feedback3|feedbackC")
def test_targeted_feedback_student_answer1(self): problem = new_loncapa_problem(load_fixture('targeted_feedback.xml')) problem.done = True problem.student_answers = {'1_2_1': 'choice_3'} the_html = problem.get_html() without_new_lines = the_html.replace("\n", "") self.assertRegexpMatches( without_new_lines, r"<targetedfeedback explanation-id=\"feedback3\">.*3rd WRONG solution" ) self.assertNotRegexpMatches(without_new_lines, r"feedback1|feedback2|feedbackC") # Check that calling it multiple times yields the same thing the_html2 = problem.get_html() self.assertEquals(the_html, the_html2)
class DropdownHintsTest(HintTest): """ This class consists of a suite of test cases to be run on the drop down problem represented by the XML below. """ xml = load_fixture('extended_hints_dropdown.xml') problem = new_loncapa_problem(xml) def test_tracking_log(self): """Test that the tracking log comes out right.""" self.problem.capa_module.reset_mock() self.get_hint(u'1_3_1', u'FACES') self.problem.capa_module.runtime.track_function.assert_called_with( 'edx.problem.hint.feedback_displayed', {'module_id': u'i4x://Foo/bar/mock/abc', 'problem_part_id': '1_2', 'trigger_type': 'single', 'student_answer': [u'FACES'], 'correctness': True, 'question_type': 'optionresponse', 'hint_label': 'Correct:', 'hints': [{'text': 'With lots of makeup, doncha know?'}]} ) @data( {'problem_id': u'1_2_1', 'choice': 'Multiple Choice', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Good Job </span><div class="hint-text">Yes, multiple choice is the right answer.</div></div>'}, {'problem_id': u'1_2_1', 'choice': 'Text Input', 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">No, text input problems do not present options.</div></div>'}, {'problem_id': u'1_2_1', 'choice': 'Numerical Input', 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">No, numerical input problems do not present options.</div></div>'}, {'problem_id': u'1_3_1', 'choice': 'FACES', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">With lots of makeup, doncha know?</div></div>'}, {'problem_id': u'1_3_1', 'choice': 'dogs', 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">NOPE </span><div class="hint-text">Not dogs, not cats, not toads</div></div>'}, {'problem_id': u'1_3_1', 'choice': 'wrongo', 'expected_string': ''}, # Regression case where feedback includes answer substring {'problem_id': u'1_4_1', 'choice': 'AAA', 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">AAABBB1</div></div>'}, {'problem_id': u'1_4_1', 'choice': 'BBB', 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">AAABBB2</div></div>'}, {'problem_id': u'1_4_1', 'choice': 'not going to match', 'expected_string': ''}, ) @unpack def test_dropdown_hints(self, problem_id, choice, expected_string): hint = self.get_hint(problem_id, choice) assert hint == expected_string
class NumericInputHintsTest(HintTest): """ This class consists of a suite of test cases to be run on the numeric input problem represented by the XML below. """ xml = load_fixture('extended_hints_numeric_input.xml') problem = new_loncapa_problem(xml) # this problem is properly constructed def test_tracking_log(self): self.get_hint(u'1_2_1', u'1.141') self.problem.capa_module.runtime.track_function.assert_called_with( 'edx.problem.hint.feedback_displayed', {'module_id': u'i4x://Foo/bar/mock/abc', 'problem_part_id': '1_1', 'trigger_type': 'single', 'hint_label': u'Nice', 'correctness': True, 'student_answer': [u'1.141'], 'question_type': 'numericalresponse', 'hints': [{'text': 'The square root of two turns up in the strangest places.'}]} ) @data( {'problem_id': u'1_2_1', 'choice': '1.141', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Nice </span><div class="hint-text">The square root of two turns up in the strangest places.</div></div>'}, # additional answer {'problem_id': u'1_2_1', 'choice': '10', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">This is an additional hint.</div></div>'}, {'problem_id': u'1_3_1', 'choice': '4', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">Pretty easy, uh?.</div></div>'}, # should get hint, when correct via numeric-tolerance {'problem_id': u'1_2_1', 'choice': '1.15', 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Nice </span><div class="hint-text">The square root of two turns up in the strangest places.</div></div>'}, # when they answer wrong, nothing {'problem_id': u'1_2_1', 'choice': '2', 'expected_string': ''}, ) @unpack def test_numeric_input_hints(self, problem_id, choice, expected_string): hint = self.get_hint(problem_id, choice) assert hint == expected_string
class CheckboxHintsTest(HintTest): """ This class consists of a suite of test cases to be run on the checkbox problem represented by the XML below. """ xml = load_fixture('extended_hints_checkbox.xml') problem = new_loncapa_problem(xml) # this problem is properly constructed @data( { 'problem_id': u'1_2_1', 'choice': [u'choice_0'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">You are right that apple is a fruit.</div><div class="hint-text">You are right that mushrooms are not fruit</div><div class="hint-text">Remember that grape is also a fruit.</div><div class="hint-text">What is a camero anyway?</div></div></div>' }, { 'problem_id': u'1_2_1', 'choice': [u'choice_1'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">Remember that apple is also a fruit.</div><div class="hint-text">Mushroom is a fungus, not a fruit.</div><div class="hint-text">Remember that grape is also a fruit.</div><div class="hint-text">What is a camero anyway?</div></div></div>' }, { 'problem_id': u'1_2_1', 'choice': [u'choice_2'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">Remember that apple is also a fruit.</div><div class="hint-text">You are right that mushrooms are not fruit</div><div class="hint-text">You are right that grape is a fruit</div><div class="hint-text">What is a camero anyway?</div></div></div>' }, { 'problem_id': u'1_2_1', 'choice': [u'choice_3'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">Remember that apple is also a fruit.</div><div class="hint-text">You are right that mushrooms are not fruit</div><div class="hint-text">Remember that grape is also a fruit.</div><div class="hint-text">What is a camero anyway?</div></div></div>' }, { 'problem_id': u'1_2_1', 'choice': [u'choice_4'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">Remember that apple is also a fruit.</div><div class="hint-text">You are right that mushrooms are not fruit</div><div class="hint-text">Remember that grape is also a fruit.</div><div class="hint-text">I do not know what a Camero is but it is not a fruit.</div></div></div>' }, { 'problem_id': u'1_2_1', 'choice': [u'choice_0', u'choice_1'], # compound 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Almost right </span><div class="hint-text">You are right that apple is a fruit, but there is one you are missing. Also, mushroom is not a fruit.</div></div>' }, { 'problem_id': u'1_2_1', 'choice': [u'choice_1', u'choice_2'], # compound 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">You are right that grape is a fruit, but there is one you are missing. Also, mushroom is not a fruit.</div></div>' }, { 'problem_id': u'1_2_1', 'choice': [u'choice_0', u'choice_2'], 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="feedback-hint-multi"><div class="hint-text">You are right that apple is a fruit.</div><div class="hint-text">You are right that mushrooms are not fruit</div><div class="hint-text">You are right that grape is a fruit</div><div class="hint-text">What is a camero anyway?</div></div></div>' }, { 'problem_id': u'1_3_1', 'choice': [u'choice_0'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">No, sorry, a banana is a fruit.</div><div class="hint-text">You are right that mushrooms are not vegatbles</div><div class="hint-text">Brussel sprout is the only vegetable in this list.</div></div></div>' }, { 'problem_id': u'1_3_1', 'choice': [u'choice_1'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">poor banana.</div><div class="hint-text">You are right that mushrooms are not vegatbles</div><div class="hint-text">Brussel sprout is the only vegetable in this list.</div></div></div>' }, { 'problem_id': u'1_3_1', 'choice': [u'choice_2'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">poor banana.</div><div class="hint-text">Mushroom is a fungus, not a vegetable.</div><div class="hint-text">Brussel sprout is the only vegetable in this list.</div></div></div>' }, { 'problem_id': u'1_3_1', 'choice': [u'choice_3'], 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="feedback-hint-multi"><div class="hint-text">poor banana.</div><div class="hint-text">You are right that mushrooms are not vegatbles</div><div class="hint-text">Brussel sprouts are vegetables.</div></div></div>' }, { 'problem_id': u'1_3_1', 'choice': [u'choice_0', u'choice_1'], # compound 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Very funny </span><div class="hint-text">Making a banana split?</div></div>' }, { 'problem_id': u'1_3_1', 'choice': [u'choice_1', u'choice_2'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">poor banana.</div><div class="hint-text">Mushroom is a fungus, not a vegetable.</div><div class="hint-text">Brussel sprout is the only vegetable in this list.</div></div></div>' }, { 'problem_id': u'1_3_1', 'choice': [u'choice_0', u'choice_2'], 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">No, sorry, a banana is a fruit.</div><div class="hint-text">Mushroom is a fungus, not a vegetable.</div><div class="hint-text">Brussel sprout is the only vegetable in this list.</div></div></div>' }, # check for interaction between compoundhint and correct/incorrect { 'problem_id': u'1_4_1', 'choice': [u'choice_0', u'choice_1'], # compound 'expected_string': u'<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="hint-text">AB</div></div>' }, { 'problem_id': u'1_4_1', 'choice': [u'choice_0', u'choice_2'], # compound 'expected_string': u'<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="hint-text">AC</div></div>' }, # check for labeling where multiple child hints have labels # These are some tricky cases { 'problem_id': '1_5_1', 'choice': ['choice_0', 'choice_1'], 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">AA </span><div class="feedback-hint-multi"><div class="hint-text">aa</div></div></div>' }, { 'problem_id': '1_5_1', 'choice': ['choice_0'], 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">aa</div><div class="hint-text">bb</div></div></div>' }, { 'problem_id': '1_5_1', 'choice': ['choice_1'], 'expected_string': '' }, { 'problem_id': '1_5_1', 'choice': [], 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">BB </span><div class="feedback-hint-multi"><div class="hint-text">bb</div></div></div>' }, { 'problem_id': '1_6_1', 'choice': ['choice_0'], 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><div class="feedback-hint-multi"><div class="hint-text">aa</div></div></div>' }, { 'problem_id': '1_6_1', 'choice': ['choice_0', 'choice_1'], 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><div class="hint-text">compoundo</div></div>' }, # The user selects *nothing*, but can still get "unselected" feedback { 'problem_id': '1_7_1', 'choice': [], 'expected_string': '<div class="feedback-hint-incorrect"><div class="explanation-title">Answer</div><span class="hint-label">Incorrect: </span><div class="feedback-hint-multi"><div class="hint-text">bb</div></div></div>' }, # 100% not match of sel/unsel feedback { 'problem_id': '1_7_1', 'choice': ['choice_1'], 'expected_string': '' }, # Here we have the correct combination, and that makes feedback too { 'problem_id': '1_7_1', 'choice': ['choice_0'], 'expected_string': '<div class="feedback-hint-correct"><div class="explanation-title">Answer</div><span class="hint-label">Correct: </span><div class="feedback-hint-multi"><div class="hint-text">aa</div><div class="hint-text">bb</div></div></div>' }, ) @unpack def test_checkbox_hints(self, problem_id, choice, expected_string): self.maxDiff = None # pylint: disable=invalid-name hint = self.get_hint(problem_id, choice) self.assertEqual(hint, expected_string)
def test_error_conditions_illegal_element(self): xml_with_errors = load_fixture('extended_hints_with_errors.xml') with self.assertRaises(Exception): new_loncapa_problem( xml_with_errors) # this problem is improperly constructed
class MultpleChoiceHintsTest(HintTest): """ This class consists of a suite of test cases to be run on the multiple choice problem represented by the XML below. """ xml = load_fixture('extended_hints_multiple_choice.xml') problem = new_loncapa_problem(xml) def test_tracking_log(self): """Test that the tracking log comes out right.""" self.problem.capa_module.reset_mock() self.get_hint(u'1_3_1', u'choice_2') self.problem.capa_module.runtime.track_function.assert_called_with( 'edx.problem.hint.feedback_displayed', { 'module_id': 'i4x://Foo/bar/mock/abc', 'problem_part_id': '1_2', 'trigger_type': 'single', 'student_answer': [u'choice_2'], 'correctness': False, 'question_type': 'multiplechoiceresponse', 'hint_label': 'OOPS', 'hints': [{ 'text': 'Apple is a fruit.' }] }) @data( { 'problem_id': u'1_2_1', 'choice': u'choice_0', 'expected_string': '<div class="feedback-hint-incorrect"><div class="hint-text">Mushroom is a fungus, not a fruit.</div></div>' }, { 'problem_id': u'1_2_1', 'choice': u'choice_1', 'expected_string': '' }, { 'problem_id': u'1_3_1', 'choice': u'choice_1', 'expected_string': '<div class="feedback-hint-correct"><div class="hint-label">Correct: </div><div class="hint-text">Potato is a root vegetable.</div></div>' }, { 'problem_id': u'1_2_1', 'choice': u'choice_2', 'expected_string': '<div class="feedback-hint-correct"><div class="hint-label">OUTSTANDING: </div><div class="hint-text">Apple is indeed a fruit.</div></div>' }, { 'problem_id': u'1_3_1', 'choice': u'choice_2', 'expected_string': '<div class="feedback-hint-incorrect"><div class="hint-label">OOPS: </div><div class="hint-text">Apple is a fruit.</div></div>' }, { 'problem_id': u'1_3_1', 'choice': u'choice_9', 'expected_string': '' }, ) @unpack def test_multiplechoice_hints(self, problem_id, choice, expected_string): hint = self.get_hint(problem_id, choice) self.assertEqual(hint, expected_string)
def test_error_conditions_illegal_element(self): xml_with_errors = load_fixture('extended_hints_with_errors.xml') with self.assertRaises(Exception): new_loncapa_problem(xml_with_errors) # this problem is improperly constructed