Commit 8124aacf by Jillian Vogel

Allows ChoiceResponse CAPA problems to use script-computed variables to

determine choice correctness, as MultipleChoiceResponse problems already do.

Adds a unit test for this change, and for the existing MultipleChoiceResponse
computed correctness capability.
parent d145457b
......@@ -851,31 +851,30 @@ class ChoiceResponse(LoncapaResponse):
def setup_response(self):
self.assign_choice_names()
correct_xml = self.xml.xpath(
'//*[@id=$id]//choice[@correct="true"]',
id=self.xml.get('id')
)
self.correct_choices = set()
self.incorrect_choices = set()
for choice in self.get_choices():
self.correct_choices = set([
choice.get('name') for choice in correct_xml
])
# contextualize the name and correct attributes
name = contextualize_text(choice.get('name'), self.context)
correct = contextualize_text(choice.get('correct'), self.context).upper()
incorrect_xml = self.xml.xpath(
'//*[@id=$id]//choice[@correct="false"]',
id=self.xml.get('id')
)
# divide choices into correct and incorrect
if correct == 'TRUE':
self.correct_choices.add(name)
elif correct == 'FALSE':
self.incorrect_choices.add(name)
self.incorrect_choices = set([
choice.get('name') for choice in incorrect_xml
])
def get_choices(self):
"""Returns this response's XML choice elements."""
return self.xml.xpath('//*[@id=$id]//choice', id=self.xml.get('id'))
def assign_choice_names(self):
"""
Initialize name attributes in <choice> tags for this response.
"""
for index, choice in enumerate(self.xml.xpath('//*[@id=$id]//choice',
id=self.xml.get('id'))):
for index, choice in enumerate(self.get_choices()):
choice.set("name", "choice_" + str(index))
# If a choice does not have an id, assign 'A' 'B', .. used by CompoundHint
if not choice.get('id'):
......
......@@ -172,6 +172,8 @@ class ResponseXMLFactory(object):
correctness = 'false'
elif 'partial' in correct_val:
correctness = 'partial'
else:
correctness = correct_val
choice_element.set('correct', correctness)
......
......@@ -169,6 +169,35 @@ class MultiChoiceResponseTest(ResponseTest): # pylint: disable=missing-docstrin
correct_map = problem.grade_answers({'1_2_1': 'choice_2'})
self.assertAlmostEqual(correct_map.get_npoints('1_2_1'), 0)
def test_contextualized_choices(self):
script = textwrap.dedent("""
a = 2
b = 9
c = a + b
ok0 = c % 2 == 0 # check remainder modulo 2
text0 = "$a + $b is even"
ok1 = c % 2 == 1 # check remainder modulo 2
text1 = "$a + $b is odd"
ok2 = "partial"
text2 = "infinity may be both"
""")
choices = ["$ok0", "$ok1", "$ok2"]
choice_names = ["$text0 ... (should be $ok0)",
"$text1 ... (should be $ok1)",
"$text2 ... (should be $ok2)"]
problem = self.build_problem(script=script,
choices=choices,
choice_names=choice_names,
credit_type='points')
# Ensure the expected correctness and choice names
self.assert_grade(problem, 'choice_2 + 9 is even ... (should be False)', 'incorrect')
self.assert_grade(problem, 'choice_2 + 9 is odd ... (should be True)', 'correct')
self.assert_grade(problem, 'choice_infinity may be both ... (should be partial)', 'partially-correct')
class TrueFalseResponseTest(ResponseTest): # pylint: disable=missing-docstring
xml_factory_class = TrueFalseResponseXMLFactory
......@@ -1292,6 +1321,26 @@ class ChoiceResponseTest(ResponseTest): # pylint: disable=missing-docstring
correct_map = problem.grade_answers({})
self.assertEqual(correct_map.get_correctness('1_2_1'), 'incorrect')
def test_contextualized_choices(self):
script = textwrap.dedent("""
a = 6
b = 4
c = a + b
ok0 = c % 2 == 0 # check remainder modulo 2
ok1 = c % 3 == 0 # check remainder modulo 3
ok2 = c % 5 == 0 # check remainder modulo 5
ok3 = not any([ok0, ok1, ok2])
""")
choices = ["$ok0", "$ok1", "$ok2", "$ok3"]
problem = self.build_problem(script=script,
choice_type='checkbox',
choices=choices)
# Ensure the expected correctness
self.assert_grade(problem, ['choice_0', 'choice_2'], 'correct')
self.assert_grade(problem, ['choice_1', 'choice_3'], 'incorrect')
class JavascriptResponseTest(ResponseTest): # pylint: disable=missing-docstring
xml_factory_class = JavascriptResponseXMLFactory
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment