From c225af4e4dbda9a51a6669a68544b03d5d87bd5d Mon Sep 17 00:00:00 2001 From: Will Daly Date: Tue, 26 Feb 2013 14:33:46 -0500 Subject: [PATCH] Modified ChoiceResponse to use XML generated by factory. --- .../capa/capa/tests/response_xml_factory.py | 120 ++++++++++++++++-- .../lib/capa/capa/tests/test_responsetypes.py | 62 +++++---- 2 files changed, 147 insertions(+), 35 deletions(-) diff --git a/common/lib/capa/capa/tests/response_xml_factory.py b/common/lib/capa/capa/tests/response_xml_factory.py index 5b539d4901..768911d261 100644 --- a/common/lib/capa/capa/tests/response_xml_factory.py +++ b/common/lib/capa/capa/tests/response_xml_factory.py @@ -188,16 +188,6 @@ class CustomResponseXMLFactory(ResponseXMLFactory): return ResponseXMLFactory.textline_input_xml(**kwargs) -class CodeResponseXMLFactory(ResponseXMLFactory): - """ Factory for creating XML trees """ - - def create_response_element(self, **kwargs): - """ Create a XML element """ - raise NotImplemented - - def create_input_element(self, **kwargs): - raise NotImplemented - class SchematicResponseXMLFactory(ResponseXMLFactory): """ Factory for creating XML trees """ @@ -225,8 +215,114 @@ class SchematicResponseXMLFactory(ResponseXMLFactory): """ Create the XML element. Although can have several attributes, - (*height*, *width*, *parts*, *analyses*, *submit_analysis*, - and *initial_value*), + (*height*, *width*, *parts*, *analyses*, *submit_analysis*, and *initial_value*), none of them are used in the capa module. For testing, we create a bare-bones version of .""" return etree.Element("schematic") + +class CodeResponseXMLFactory(ResponseXMLFactory): + """ Factory for creating XML trees """ + + def create_response_element(self, **kwargs): + """ Create a XML element """ + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented + + +class ChoiceResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + """ Create a element """ + return etree.Element("choiceresponse") + + def create_input_element(self, **kwargs): + """ Create a element. + + Uses *kwargs*: + + *allow_multiple*: If True, use checkboxes; + otherwise, use radio buttons + DEFAULT: True + + *choices*: List of True/False values indicating whether + a particular choice is correct or not. + Users must choose *all* correct options in order + to be marked correct. + DEFAULT: [True] + """ + + # Retrieve **kwargs + allow_multiple = kwargs.get('allow_multiple', True) + choices = kwargs.get('choices', [True]) + + # Create the or element + group_element = etree.Element("checkboxgroup" if allow_multiple else "radiogroup") + + # Create the elements + for correct_val in choices: + choice_element = etree.SubElement(group_element, "choice") + choice_element.set("correct", "true" if correct_val else "false") + + # Add some text describing the choice + etree.SubElement(choice_element, "startouttext") + etree.text = "Choice description" + etree.SubElement(choice_element, "endouttext") + + return group_element + +class FormulaResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented + +class ImageResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented + +class JavascriptResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented + +class MultipleChoiceResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented + +class OptionResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented + +class StringResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented + +class SymbolicResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented + +class TrueFalseResponseXMLFactory(ResponseXMLFactory): + def create_response_element(self, **kwargs): + raise NotImplemented + + def create_input_element(self, **kwargs): + raise NotImplemented diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index c2bdf2ddce..e7cb9a7d76 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -386,32 +386,48 @@ class CodeResponseTest(unittest.TestCase): self.assertEquals(answers_converted['1_4_1'], [fp.name, fp.name]) +from response_xml_factory import ChoiceResponseXMLFactory class ChoiceResponseTest(unittest.TestCase): - def test_cr_rb_grade(self): - problem_file = os.path.dirname(__file__) + "/test_files/choiceresponse_radio.xml" - test_lcp = lcp.LoncapaProblem(open(problem_file).read(), '1', system=test_system) - correct_answers = {'1_2_1': 'choice_2', - '1_3_1': ['choice_2', 'choice_3']} - test_answers = {'1_2_1': 'choice_2', - '1_3_1': 'choice_2', - } - self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_1'), 'correct') - self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_1'), 'incorrect') + def setUp(self): + self.xml_factory = ChoiceResponseXMLFactory() - def test_cr_cb_grade(self): - problem_file = os.path.dirname(__file__) + "/test_files/choiceresponse_checkbox.xml" - test_lcp = lcp.LoncapaProblem(open(problem_file).read(), '1', system=test_system) - correct_answers = {'1_2_1': 'choice_2', - '1_3_1': ['choice_2', 'choice_3'], - '1_4_1': ['choice_2', 'choice_3']} - test_answers = {'1_2_1': 'choice_2', - '1_3_1': 'choice_2', - '1_4_1': ['choice_2', 'choice_3'], - } - self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_1'), 'correct') - self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_1'), 'incorrect') - self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_4_1'), 'correct') + def test_radio_group_grade(self): + xml = self.xml_factory.build_xml(allow_multiple=False, + choices=[False, True, False]) + + problem = lcp.LoncapaProblem(xml, '1', system=test_system) + + # Check that we get the expected results + self._assert_grade(problem, 'choice_0', 'incorrect') + self._assert_grade(problem, 'choice_1', 'correct') + self._assert_grade(problem, 'choice_2', 'incorrect') + + # No choice 3 exists --> mark incorrect + self._assert_grade(problem, 'choice_3', 'incorrect') + + + def test_checkbox_group_grade(self): + xml = self.xml_factory.build_xml(allow_multiple=True, + choices=[False, True, True]) + + problem = lcp.LoncapaProblem(xml, '1', system=test_system) + + # Check that we get the expected results + # (correct if and only if BOTH correct choices chosen) + self._assert_grade(problem, ['choice_1', 'choice_2'], 'correct') + self._assert_grade(problem, 'choice_1', 'incorrect') + self._assert_grade(problem, 'choice_2', 'incorrect') + self._assert_grade(problem, ['choice_0', 'choice_1'], 'incorrect') + self._assert_grade(problem, ['choice_0', 'choice_2'], 'incorrect') + + # No choice 3 exists --> mark incorrect + self._assert_grade(problem, 'choice_3', 'incorrect') + + def _assert_grade(self, problem, submission, expected_correctness): + input_dict = {'1_2_1': submission} + correct_map = problem.grade_answers(input_dict) + self.assertEquals(correct_map.get_correctness('1_2_1'), expected_correctness) class JavascriptResponseTest(unittest.TestCase):