Commit a7fcb7d6 by Will Daly

Added tests for <schematicresponse>

parent f2bb9a2d
...@@ -35,15 +35,15 @@ class ResponseXMLFactory(object): ...@@ -35,15 +35,15 @@ class ResponseXMLFactory(object):
For all response types, **kwargs can contain: For all response types, **kwargs can contain:
'question_text': The text of the question to display, *question_text*: The text of the question to display,
wrapped in <p> tags. wrapped in <p> tags.
'explanation_text': The detailed explanation that will *explanation_text*: The detailed explanation that will
be shown if the user answers incorrectly. be shown if the user answers incorrectly.
'script': The embedded Python script (a string) *script*: The embedded Python script (a string)
'num_inputs': The number of input elements *num_inputs*: The number of input elements
to create [DEFAULT: 1] to create [DEFAULT: 1]
Returns a string representation of the XML tree. Returns a string representation of the XML tree.
...@@ -51,7 +51,7 @@ class ResponseXMLFactory(object): ...@@ -51,7 +51,7 @@ class ResponseXMLFactory(object):
# Retrieve keyward arguments # Retrieve keyward arguments
question_text = kwargs.get('question_text', '') question_text = kwargs.get('question_text', '')
explanation_text = kwargs.get('explanation_text') explanation_text = kwargs.get('explanation_text', '')
script = kwargs.get('script', None) script = kwargs.get('script', None)
num_inputs = kwargs.get('num_inputs', 1) num_inputs = kwargs.get('num_inputs', 1)
...@@ -91,9 +91,9 @@ class ResponseXMLFactory(object): ...@@ -91,9 +91,9 @@ class ResponseXMLFactory(object):
Uses **kwargs: Uses **kwargs:
'math_display': If True, then includes a MathJax display of user input *math_display*: If True, then includes a MathJax display of user input
'size': An integer representing the width of the text line *size*: An integer representing the width of the text line
""" """
math_display = kwargs.get('math_display', False) math_display = kwargs.get('math_display', False)
size = kwargs.get('size', None) size = kwargs.get('size', None)
...@@ -108,6 +108,7 @@ class ResponseXMLFactory(object): ...@@ -108,6 +108,7 @@ class ResponseXMLFactory(object):
return input_element return input_element
class NumericalResponseXMLFactory(ResponseXMLFactory): class NumericalResponseXMLFactory(ResponseXMLFactory):
""" Factory for producing <numericalresponse> XML trees """ """ Factory for producing <numericalresponse> XML trees """
...@@ -115,9 +116,9 @@ class NumericalResponseXMLFactory(ResponseXMLFactory): ...@@ -115,9 +116,9 @@ class NumericalResponseXMLFactory(ResponseXMLFactory):
""" Create a <numericalresponse> XML element. """ Create a <numericalresponse> XML element.
Uses **kwarg keys: Uses **kwarg keys:
'answer': The correct answer (e.g. "5") *answer*: The correct answer (e.g. "5")
'tolerance': The tolerance within which a response *tolerance*: The tolerance within which a response
is considered correct. Can be a decimal (e.g. "0.01") is considered correct. Can be a decimal (e.g. "0.01")
or percentage (e.g. "2%") or percentage (e.g. "2%")
""" """
...@@ -140,24 +141,27 @@ class NumericalResponseXMLFactory(ResponseXMLFactory): ...@@ -140,24 +141,27 @@ class NumericalResponseXMLFactory(ResponseXMLFactory):
def create_input_element(self, **kwargs): def create_input_element(self, **kwargs):
return ResponseXMLFactory.textline_input_xml(**kwargs) return ResponseXMLFactory.textline_input_xml(**kwargs)
class CustomResponseXMLFactory(ResponseXMLFactory): class CustomResponseXMLFactory(ResponseXMLFactory):
""" Factory for producing <customresponse> XML trees """ """ Factory for producing <customresponse> XML trees """
def create_response_element(self, **kwargs): def create_response_element(self, **kwargs):
""" Create a <customresponse> XML element. """ Create a <customresponse> XML element.
Use **kwargs: Uses **kwargs:
'cfn': the Python code to run. Can be inline code, *cfn*: the Python code to run. Can be inline code,
or the name of a function defined in earlier <script> tags. or the name of a function defined in earlier <script> tags.
Should have the form: cfn(expect, ans) Should have the form: cfn(expect, answer_given, student_answers)
where expect is a value (see below) where expect is a value (see below),
and ans is a list of values. answer_given is a single value (for 1 input)
or a list of values (for multiple inputs),
and student_answers is a dict of answers by input ID.
'expect': The value passed as the first argument to the function cfn *expect*: The value passed to the function cfn
'answer': Inline script that calculates the answer *answer*: Inline script that calculates the answer
""" """
# Retrieve **kwargs # Retrieve **kwargs
...@@ -182,3 +186,47 @@ class CustomResponseXMLFactory(ResponseXMLFactory): ...@@ -182,3 +186,47 @@ class CustomResponseXMLFactory(ResponseXMLFactory):
def create_input_element(self, **kwargs): def create_input_element(self, **kwargs):
return ResponseXMLFactory.textline_input_xml(**kwargs) return ResponseXMLFactory.textline_input_xml(**kwargs)
class CodeResponseXMLFactory(ResponseXMLFactory):
""" Factory for creating <coderesponse> XML trees """
def create_response_element(self, **kwargs):
""" Create a <coderesponse> XML element """
raise NotImplemented
def create_input_element(self, **kwargs):
raise NotImplemented
class SchematicResponseXMLFactory(ResponseXMLFactory):
""" Factory for creating <schematicresponse> XML trees """
def create_response_element(self, **kwargs):
""" Create the <schematicresponse> XML element.
Uses *kwargs*:
*answer*: The Python script used to evaluate the answer.
"""
answer_script = kwargs.get('answer', None)
# Create the <schematicresponse> element
response_element = etree.Element("schematicresponse")
# Insert the <answer> script if one is provided
if answer_script:
answer_element = etree.SubElement(response_element, "answer")
answer_element.set("type", "loncapa/python")
answer_element.text = str(answer_script)
return response_element
def create_input_element(self, **kwargs):
""" Create the <schematic> XML element.
Although <schematic> can have several attributes,
(*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 <schematic>."""
return etree.Element("schematic")
...@@ -609,3 +609,36 @@ class CustomResponseTest(unittest.TestCase): ...@@ -609,3 +609,36 @@ class CustomResponseTest(unittest.TestCase):
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct') self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
self.assertEqual(correct_map.get_correctness('1_2_2'), 'correct') self.assertEqual(correct_map.get_correctness('1_2_2'), 'correct')
self.assertEqual(correct_map.get_correctness('1_2_3'), 'correct') self.assertEqual(correct_map.get_correctness('1_2_3'), 'correct')
from response_xml_factory import SchematicResponseXMLFactory
class SchematicResponseTest(unittest.TestCase):
def setUp(self):
self.xml_factory = SchematicResponseXMLFactory()
def test_grade(self):
# Most of the schematic-specific work is handled elsewhere
# (in client-side JavaScript)
# The <schematicresponse> is responsible only for executing the
# Python code in <answer> with *submission* (list)
# in the global context.
# To test that the context is set up correctly,
# we create a script that sets *correct* to true
# if and only if we find the *submission* (list)
script="correct = ['correct' if 'test' in submission[0] else 'incorrect']"
xml = self.xml_factory.build_xml(answer=script)
problem = lcp.LoncapaProblem(xml, '1', system=test_system)
# The actual dictionary would contain schematic information
# sent from the JavaScript simulation
submission_dict = {'test': 'test'}
input_dict = { '1_2_1': json.dumps(submission_dict) }
correct_map = problem.grade_answers(input_dict)
# Expect that the problem is graded as true
# (That is, our script verifies that the context
# is what we expect)
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
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