# pylint: disable=too-many-lines # -*- coding: utf-8 -*- """ Tests of extended hints """ import unittest import pytest from ddt import data, ddt, unpack from xmodule.capa.tests.helpers import load_fixture, new_loncapa_problem # With the use of ddt, some of the data expected_string cases below are naturally long stretches # of text text without whitespace. I think it's best to leave such lines intact # in the test code. Therefore: # For out many ddt data cases, prefer a compact form of { .. } class HintTest(unittest.TestCase): """Base class for tests of extended hinting functionality.""" def correctness(self, problem_id, choice): """Grades the problem and returns the 'correctness' string from cmap.""" student_answers = {problem_id: choice} cmap = self.problem.grade_answers(answers=student_answers) # pylint: disable=no-member return cmap[problem_id]["correctness"] def get_hint(self, problem_id, choice): """Grades the problem and returns its hint from cmap or the empty string.""" student_answers = {problem_id: choice} cmap = self.problem.grade_answers(answers=student_answers) # pylint: disable=no-member adict = cmap.cmap.get(problem_id) if adict: return adict["msg"] return "" # It is a little surprising how much more complicated TextInput is than all the other cases. @ddt 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_block.reset_mock() self.get_hint("1_3_1", "Blue") self.problem.capa_block.runtime.publish.assert_called_with( self.problem.capa_block, "edx.problem.hint.feedback_displayed", { "module_id": "i4x://Foo/bar/mock/abc", "problem_part_id": "1_2", "trigger_type": "single", "hint_label": "Correct:", "correctness": True, "student_answer": ["Blue"], "question_type": "stringresponse", "hints": [{"text": "The red light is scattered by water molecules leaving only blue light."}], }, ) @data( { "problem_id": "1_2_1", "choice": "GermanyΩ", "expected_string": ( '
Answer
' 'Incorrect: ' '
I do not think so.Ω
' ), }, { "problem_id": "1_2_1", "choice": "franceΩ", "expected_string": ( '
Answer
' 'Correct: ' '
Viva la France!Ω
' ), }, { "problem_id": "1_2_1", "choice": "FranceΩ", "expected_string": ( '
Answer
' 'Correct: ' '
Viva la France!Ω
' ), }, {"problem_id": "1_2_1", "choice": "Mexico", "expected_string": ""}, { "problem_id": "1_2_1", "choice": "USAΩ", "expected_string": ( '
Answer
' 'Correct:
' "Less well known, but yes, there is a Paris, Texas.Ω
" ), }, { "problem_id": "1_2_1", "choice": "usaΩ", "expected_string": ( '
Answer
' 'Correct:
' "Less well known, but yes, there is a Paris, Texas.Ω
" ), }, {"problem_id": "1_2_1", "choice": "uSAxΩ", "expected_string": ""}, { "problem_id": "1_2_1", "choice": "NICKLANDΩ", "expected_string": ( '
Answer
' 'Incorrect: ' '
The country name does not end in LANDΩ
' ), }, { "problem_id": "1_3_1", "choice": "Blue", "expected_string": ( '
Answer
' 'Correct:
' "The red light is scattered by water molecules leaving only blue light.
" ), }, {"problem_id": "1_3_1", "choice": "blue", "expected_string": ""}, {"problem_id": "1_3_1", "choice": "b", "expected_string": ""}, ) @unpack def test_text_input_hints(self, problem_id, choice, expected_string): """Check that the correct hint HTML is returned for each text input answer.""" hint = self.get_hint(problem_id, choice) assert hint == expected_string @ddt 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": "1_5_1", "choice": "abc", "expected_string": ""}, # wrong answer yielding no hint { "problem_id": "1_5_1", "choice": "A", "expected_string": ( '
Answer
' 'Woo Hoo
hint1
' ), }, { "problem_id": "1_5_1", "choice": "a", "expected_string": ( '
Answer
' 'Woo Hoo
hint1
' ), }, { "problem_id": "1_5_1", "choice": "B", "expected_string": ( '
Answer
' '
hint2
' ), }, { "problem_id": "1_5_1", "choice": "b", "expected_string": ( '
Answer
' '
hint2
' ), }, { "problem_id": "1_5_1", "choice": "C", "expected_string": ( '
Answer
' '
hint4
' ), }, { "problem_id": "1_5_1", "choice": "c", "expected_string": ( '
Answer
' '
hint4
' ), }, # regexp cases { "problem_id": "1_5_1", "choice": "FGGG", "expected_string": ( '
Answer
' '
hint6
' ), }, { "problem_id": "1_5_1", "choice": "fgG", "expected_string": ( '
Answer
' '
hint6
' ), }, ) @unpack def test_text_input_hints(self, problem_id, choice, expected_string): """Ensure that text input hints match case-insensitively when expected.""" hint = self.get_hint(problem_id, choice) assert hint == expected_string @ddt 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": "1_6_1", "choice": "abc", "expected_string": ""}, { "problem_id": "1_6_1", "choice": "A", "expected_string": ( '
Answer
' 'Correct:
hint1
' ), }, {"problem_id": "1_6_1", "choice": "a", "expected_string": ""}, { "problem_id": "1_6_1", "choice": "B", "expected_string": ( '
Answer
' 'Correct:
hint2
' ), }, {"problem_id": "1_6_1", "choice": "b", "expected_string": ""}, { "problem_id": "1_6_1", "choice": "C", "expected_string": ( '
Answer
' 'Incorrect: ' '
hint4
' ), }, {"problem_id": "1_6_1", "choice": "c", "expected_string": ""}, # regexp cases { "problem_id": "1_6_1", "choice": "FGG", "expected_string": ( '
Answer
' 'Incorrect: ' '
hint6
' ), }, {"problem_id": "1_6_1", "choice": "fgG", "expected_string": ""}, ) @unpack def test_text_input_hints(self, problem_id, choice, expected_string): """Ensure that text input hints match case-sensitively when required.""" message_text = self.get_hint(problem_id, choice) assert message_text == expected_string @ddt 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": "1_7_1", "choice": "A", "correct": "correct", "expected_string": ( '
Answer
' 'Correct: ' '
hint1
' ), }, {"problem_id": "1_7_1", "choice": "B", "correct": "correct", "expected_string": ""}, { "problem_id": "1_7_1", "choice": "C", "correct": "correct", "expected_string": ( '
Answer
' 'Correct: ' '
hint2
' ), }, {"problem_id": "1_7_1", "choice": "D", "correct": "incorrect", "expected_string": ""}, # check going through conversion with difficult chars {"problem_id": "1_7_1", "choice": """<&"'>""", "correct": "correct", "expected_string": ""}, ) @unpack def test_text_input_hints(self, problem_id, choice, correct, expected_string): """Test compatibility between old and new style additional_answer hints.""" message_text = self.get_hint(problem_id, choice) assert message_text == expected_string assert self.correctness(problem_id, choice) == correct @ddt 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": "1_8_1", "choice": "ABwrong", "correct": "incorrect", "expected_string": ""}, { "problem_id": "1_8_1", "choice": "ABC", "correct": "correct", "expected_string": ( '
Answer
' 'Correct: ' '
hint1
' ), }, { "problem_id": "1_8_1", "choice": "ABBBBC", "correct": "correct", "expected_string": ( '
Answer
' 'Correct: ' '
hint1
' ), }, { "problem_id": "1_8_1", "choice": "aBc", "correct": "correct", "expected_string": ( '
Answer
' 'Correct: ' '
hint1
' ), }, { "problem_id": "1_8_1", "choice": "BBBB", "correct": "correct", "expected_string": ( '
Answer
' 'Correct: ' '
hint2
' ), }, { "problem_id": "1_8_1", "choice": "bbb", "correct": "correct", "expected_string": ( '
Answer
' 'Correct: ' '
hint2
' ), }, { "problem_id": "1_8_1", "choice": "C", "correct": "incorrect", "expected_string": ( '
Answer
' 'Incorrect: ' '
hint4
' ), }, { "problem_id": "1_8_1", "choice": "c", "correct": "incorrect", "expected_string": ( '
Answer
' 'Incorrect: ' '
hint4
' ), }, { "problem_id": "1_8_1", "choice": "D", "correct": "incorrect", "expected_string": ( '
Answer
' 'Incorrect: ' '
hint6
' ), }, { "problem_id": "1_8_1", "choice": "d", "correct": "incorrect", "expected_string": ( '
Answer
' 'Incorrect: ' '
hint6
' ), }, ) @unpack def test_text_input_hints(self, problem_id, choice, correct, expected_string): """Validate text input hints where answers are defined with regex matching.""" message_text = self.get_hint(problem_id, choice) assert message_text == expected_string assert self.correctness(problem_id, choice) == correct @ddt 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): """Verify that the tracking log is published correctly for numeric input hints.""" self.get_hint("1_2_1", "1.141") self.problem.capa_block.runtime.publish.assert_called_with( self.problem.capa_block, "edx.problem.hint.feedback_displayed", { "module_id": "i4x://Foo/bar/mock/abc", "problem_part_id": "1_1", "trigger_type": "single", "hint_label": "Nice", "correctness": True, "student_answer": ["1.141"], "question_type": "numericalresponse", "hints": [{"text": "The square root of two turns up in the strangest places."}], }, ) @data( { "problem_id": "1_2_1", "choice": "1.141", "expected_string": ( '
Answer
' 'Nice
' "The square root of two turns up in the strangest places.
" ), }, # additional answer { "problem_id": "1_2_1", "choice": "10", "expected_string": ( '
Answer
' 'Correct: ' '
This is an additional hint.
' ), }, { "problem_id": "1_3_1", "choice": "4", "expected_string": ( '
Answer
' 'Correct: ' '
Pretty easy, uh?.
' ), }, # should get hint, when correct via numeric-tolerance { "problem_id": "1_2_1", "choice": "1.15", "expected_string": ( '
Answer
' 'Nice
' "The square root of two turns up in the strangest places.
" ), }, # when they answer wrong, nothing {"problem_id": "1_2_1", "choice": "2", "expected_string": ""}, ) @unpack def test_numeric_input_hints(self, problem_id, choice, expected_string): """Check that the correct hint HTML is returned for numeric input answers.""" hint = self.get_hint(problem_id, choice) assert hint == expected_string @ddt 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": "1_2_1", "choice": ["choice_0"], "expected_string": ( '
Answer
' 'Incorrect:
' '
You are right that apple is a fruit.
' '
You are right that mushrooms are not fruit
' '
Remember that grape is also a fruit.
' '
What is a camero anyway?
' ), }, { "problem_id": "1_2_1", "choice": ["choice_1"], "expected_string": ( '
Answer
' 'Incorrect:
' '
Remember that apple is also a fruit.
' '
Mushroom is a fungus, not a fruit.
' '
Remember that grape is also a fruit.
' '
What is a camero anyway?
' ), }, { "problem_id": "1_2_1", "choice": ["choice_2"], "expected_string": ( '
Answer
' 'Incorrect:
' '
Remember that apple is also a fruit.
' '
You are right that mushrooms are not fruit
' '
You are right that grape is a fruit
' '
What is a camero anyway?
' ), }, { "problem_id": "1_2_1", "choice": ["choice_3"], "expected_string": ( '
Answer
' 'Incorrect:
' '
Remember that apple is also a fruit.
' '
You are right that mushrooms are not fruit
' '
Remember that grape is also a fruit.
' '
What is a camero anyway?
' ), }, { "problem_id": "1_2_1", "choice": ["choice_4"], "expected_string": ( '
Answer
' 'Incorrect:
' '
Remember that apple is also a fruit.
' '
You are right that mushrooms are not fruit
' '
Remember that grape is also a fruit.
' '
I do not know what a Camero is but it is not a fruit.' "
" ), }, { "problem_id": "1_2_1", "choice": ["choice_0", "choice_1"], # compound "expected_string": ( '
Answer
' 'Almost right
' "You are right that apple is a fruit, but there is one you are missing. " "Also, mushroom is not a fruit.
" ), }, { "problem_id": "1_2_1", "choice": ["choice_1", "choice_2"], # compound "expected_string": ( '
Answer
' 'Incorrect:
' "You are right that grape is a fruit, but there is one you are missing. " "Also, mushroom is not a fruit.
" ), }, { "problem_id": "1_2_1", "choice": ["choice_0", "choice_2"], "expected_string": ( '
Answer
' 'Correct:
' '
You are right that apple is a fruit.
' '
You are right that mushrooms are not fruit
' '
You are right that grape is a fruit
' '
What is a camero anyway?
' ), }, { "problem_id": "1_3_1", "choice": ["choice_0"], "expected_string": ( '
Answer
' 'Incorrect:
' '
No, sorry, a banana is a fruit.
' '
You are right that mushrooms are not vegatbles
' '
Brussel sprout is the only vegetable in this list.' "
" ), }, { "problem_id": "1_3_1", "choice": ["choice_1"], "expected_string": ( '
Answer
' 'Incorrect:
' '
poor banana.
' '
You are right that mushrooms are not vegatbles
' '
Brussel sprout is the only vegetable in this list.' "
" ), }, { "problem_id": "1_3_1", "choice": ["choice_2"], "expected_string": ( '
Answer
' 'Incorrect:
' '
poor banana.
' '
Mushroom is a fungus, not a vegetable.
' '
Brussel sprout is the only vegetable in this list.' "
" ), }, { "problem_id": "1_3_1", "choice": ["choice_3"], "expected_string": ( '
Answer
' 'Correct:
' '
poor banana.
' '
You are right that mushrooms are not vegatbles
' '
Brussel sprouts are vegetables.
' ), }, { "problem_id": "1_3_1", "choice": ["choice_0", "choice_1"], # compound "expected_string": ( '
Answer
' 'Very funny ' '
Making a banana split?
' ), }, { "problem_id": "1_3_1", "choice": ["choice_1", "choice_2"], "expected_string": ( '
Answer
' 'Incorrect:
' '
poor banana.
' '
Mushroom is a fungus, not a vegetable.
' '
Brussel sprout is the only vegetable in this list.' "
" ), }, { "problem_id": "1_3_1", "choice": ["choice_0", "choice_2"], "expected_string": ( '
Answer
' 'Incorrect:
' '
No, sorry, a banana is a fruit.
' '
Mushroom is a fungus, not a vegetable.
' '
Brussel sprout is the only vegetable in this list.' "
" ), }, # check for interaction between compoundhint and correct/incorrect { "problem_id": "1_4_1", "choice": ["choice_0", "choice_1"], # compound "expected_string": ( '
Answer
' 'Incorrect:
AB
' ), }, { "problem_id": "1_4_1", "choice": ["choice_0", "choice_2"], # compound "expected_string": ( '
Answer
' 'Correct:
AC
' ), }, # 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": ( '
Answer
' 'AA
' '
aa
' ), }, { "problem_id": "1_5_1", "choice": ["choice_0"], "expected_string": ( '
Answer
' 'Incorrect:
' '
aa
bb
' ), }, {"problem_id": "1_5_1", "choice": ["choice_1"], "expected_string": ""}, { "problem_id": "1_5_1", "choice": [], "expected_string": ( '
Answer
' 'BB
' '
bb
' ), }, { "problem_id": "1_6_1", "choice": ["choice_0"], "expected_string": ( '
Answer
' '
aa
' ), }, { "problem_id": "1_6_1", "choice": ["choice_0", "choice_1"], "expected_string": ( '
Answer
' '
compoundo
' ), }, # The user selects *nothing*, but can still get "unselected" feedback { "problem_id": "1_7_1", "choice": [], "expected_string": ( '
Answer
' 'Incorrect:
' '
bb
' ), }, # 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": ( '
Answer
' 'Correct:
' '
aa
bb
' ), }, ) @unpack def test_checkbox_hints(self, problem_id, choice, expected_string): """ Check that the correct hint HTML is returned for selected checkboxes, including compound and multi-child hints. """ self.maxDiff = None # pylint: disable=invalid-name hint = self.get_hint(problem_id, choice) assert hint == expected_string class CheckboxHintsTestTracking(HintTest): """ Test the rather complicated tracking log output for checkbox cases. """ xml = """

question

Apple A true A false Banana Cronut C true A C Compound
""" problem = new_loncapa_problem(xml) def test_tracking_log(self): """Test checkbox tracking log - by far the most complicated case""" # A -> 1 hint self.get_hint("1_2_1", ["choice_0"]) self.problem.capa_block.runtime.publish.assert_called_with( self.problem.capa_block, "edx.problem.hint.feedback_displayed", { "hint_label": "Incorrect:", "module_id": "i4x://Foo/bar/mock/abc", "problem_part_id": "1_1", "choice_all": ["choice_0", "choice_1", "choice_2"], "correctness": False, "trigger_type": "single", "student_answer": ["choice_0"], "hints": [{"text": "A true", "trigger": [{"choice": "choice_0", "selected": True}]}], "question_type": "choiceresponse", }, ) # B C -> 2 hints self.problem.capa_block.runtime.publish.reset_mock() self.get_hint("1_2_1", ["choice_1", "choice_2"]) self.problem.capa_block.runtime.publish.assert_called_with( self.problem.capa_block, "edx.problem.hint.feedback_displayed", { "hint_label": "Incorrect:", "module_id": "i4x://Foo/bar/mock/abc", "problem_part_id": "1_1", "choice_all": ["choice_0", "choice_1", "choice_2"], "correctness": False, "trigger_type": "single", "student_answer": ["choice_1", "choice_2"], "hints": [ {"text": "A false", "trigger": [{"choice": "choice_0", "selected": False}]}, {"text": "C true", "trigger": [{"choice": "choice_2", "selected": True}]}, ], "question_type": "choiceresponse", }, ) # A C -> 1 Compound hint self.problem.capa_block.runtime.publish.reset_mock() self.get_hint("1_2_1", ["choice_0", "choice_2"]) self.problem.capa_block.runtime.publish.assert_called_with( self.problem.capa_block, "edx.problem.hint.feedback_displayed", { "hint_label": "Correct:", "module_id": "i4x://Foo/bar/mock/abc", "problem_part_id": "1_1", "choice_all": ["choice_0", "choice_1", "choice_2"], "correctness": True, "trigger_type": "compound", "student_answer": ["choice_0", "choice_2"], "hints": [ { "text": "A C Compound", "trigger": [{"choice": "choice_0", "selected": True}, {"choice": "choice_2", "selected": True}], } ], "question_type": "choiceresponse", }, ) @ddt 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_block.reset_mock() self.get_hint("1_3_1", "choice_2") self.problem.capa_block.runtime.publish.assert_called_with( self.problem.capa_block, "edx.problem.hint.feedback_displayed", { "module_id": "i4x://Foo/bar/mock/abc", "problem_part_id": "1_2", "trigger_type": "single", "student_answer": ["choice_2"], "correctness": False, "question_type": "multiplechoiceresponse", "hint_label": "OOPS", "hints": [{"text": "Apple is a fruit."}], }, ) @data( { "problem_id": "1_2_1", "choice": "choice_0", "expected_string": ( '
Answer
' '
Mushroom is a fungus, not a fruit.
' ), }, {"problem_id": "1_2_1", "choice": "choice_1", "expected_string": ""}, { "problem_id": "1_3_1", "choice": "choice_1", "expected_string": ( '
Answer
' 'Correct: ' '
Potato is a root vegetable.
' ), }, { "problem_id": "1_2_1", "choice": "choice_2", "expected_string": ( '
Answer
' 'OUTSTANDING ' '
Apple is indeed a fruit.
' ), }, { "problem_id": "1_3_1", "choice": "choice_2", "expected_string": ( '
Answer
' 'OOPS ' '
Apple is a fruit.
' ), }, {"problem_id": "1_3_1", "choice": "choice_9", "expected_string": ""}, ) @unpack def test_multiplechoice_hints(self, problem_id, choice, expected_string): """Check that the correct hint HTML is returned for each choice in multiple choice problems.""" hint = self.get_hint(problem_id, choice) assert hint == expected_string @ddt 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_block.reset_mock() self.get_hint("1_2_1", "choice_0") self.problem.capa_block.runtime.publish.assert_called_with( self.problem.capa_block, "edx.problem.hint.feedback_displayed", { "module_id": "i4x://Foo/bar/mock/abc", "problem_part_id": "1_1", "trigger_type": "single", "student_answer": ["choice_0"], "correctness": False, "question_type": "multiplechoiceresponse", "hint_label": "Incorrect:", "hints": [{"text": 'Mushroom is a fungus, not a fruit.'}], }, ) @data( { "problem_id": "1_2_1", "choice": "choice_0", "expected_string": ( '
Answer
' 'Incorrect:
' 'Mushroom is a fungus, not a fruit.
' ), }, { "problem_id": "1_2_1", "choice": "choice_1", "expected_string": ( '
Answer
' 'Incorrect:
' 'Potato is not a fruit.
' ), }, { "problem_id": "1_2_1", "choice": "choice_2", "expected_string": ( '
Answer
' 'Correct:
' 'Apple is a fruit.
' ), }, ) @unpack def test_multiplechoice_hints(self, problem_id, choice, expected_string): """Check that the correct hint HTML, including HTML content, is returned for each choice.""" hint = self.get_hint(problem_id, choice) assert hint == expected_string @ddt 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_block.reset_mock() self.get_hint("1_3_1", "FACES") self.problem.capa_block.runtime.publish.assert_called_with( self.problem.capa_block, "edx.problem.hint.feedback_displayed", { "module_id": "i4x://Foo/bar/mock/abc", "problem_part_id": "1_2", "trigger_type": "single", "student_answer": ["FACES"], "correctness": True, "question_type": "optionresponse", "hint_label": "Correct:", "hints": [{"text": "With lots of makeup, doncha know?"}], }, ) @data( { "problem_id": "1_2_1", "choice": "Multiple Choice", "expected_string": ( '
Answer
' 'Good Job
' "Yes, multiple choice is the right answer.
" ), }, { "problem_id": "1_2_1", "choice": "Text Input", "expected_string": ( '
Answer
' 'Incorrect:
' "No, text input problems do not present options.
" ), }, { "problem_id": "1_2_1", "choice": "Numerical Input", "expected_string": ( '
Answer
' 'Incorrect:
' "No, numerical input problems do not present options.
" ), }, { "problem_id": "1_3_1", "choice": "FACES", "expected_string": ( '
Answer
' 'Correct:
' "With lots of makeup, doncha know?
" ), }, { "problem_id": "1_3_1", "choice": "dogs", "expected_string": ( '
Answer
' 'NOPE
' "Not dogs, not cats, not toads
" ), }, {"problem_id": "1_3_1", "choice": "wrongo", "expected_string": ""}, # Regression case where feedback includes answer substring { "problem_id": "1_4_1", "choice": "AAA", "expected_string": ( '
Answer
' 'Incorrect: ' '
AAABBB1
' ), }, { "problem_id": "1_4_1", "choice": "BBB", "expected_string": ( '
Answer
' 'Correct: ' '
AAABBB2
' ), }, {"problem_id": "1_4_1", "choice": "not going to match", "expected_string": ""}, ) @unpack def test_dropdown_hints(self, problem_id, choice, expected_string): """Check that the correct hint HTML is returned for each choice in dropdown problems.""" hint = self.get_hint(problem_id, choice) assert hint == expected_string class ErrorConditionsTest(HintTest): """ Erroneous xml should raise exception. """ def test_error_conditions_illegal_element(self): """Ensure that malformed XML raises an exception when creating a problem.""" xml_with_errors = load_fixture("extended_hints_with_errors.xml") with pytest.raises(Exception): new_loncapa_problem(xml_with_errors) # this problem is improperly constructed