Commit 1990a412 by zubiar-arbi

escape single quotes in optioninput (optionresponse) tags

STUD-893
parent 54eaabce
...@@ -309,6 +309,9 @@ class OptionInput(InputTypeBase): ...@@ -309,6 +309,9 @@ class OptionInput(InputTypeBase):
Given options string, convert it into an ordered list of (option_id, option_description) tuples, where Given options string, convert it into an ordered list of (option_id, option_description) tuples, where
id==description for now. TODO: make it possible to specify different id and descriptions. id==description for now. TODO: make it possible to specify different id and descriptions.
""" """
# convert single quotes inside option values to html encoded string
options = re.sub(r"([a-zA-Z])('|\\')([a-zA-Z])", r"\1'\3", options)
options = re.sub(r"\\'", r"'", options) # replace already escaped single quotes
# parse the set of possible options # parse the set of possible options
lexer = shlex.shlex(options[1:-1].encode('utf8')) lexer = shlex.shlex(options[1:-1].encode('utf8'))
lexer.quotes = "'" lexer.quotes = "'"
...@@ -316,7 +319,8 @@ class OptionInput(InputTypeBase): ...@@ -316,7 +319,8 @@ class OptionInput(InputTypeBase):
lexer.whitespace = ", " lexer.whitespace = ", "
# remove quotes # remove quotes
tokens = [x[1:-1].decode('utf8') for x in lexer] # convert escaped single quotes (html encoded string) back to single quotes
tokens = [x[1:-1].decode('utf8').replace("'", "'") for x in lexer]
# make list of (option_id, option_description), with description=id # make list of (option_id, option_description), with description=id
return [(t, t) for t in tokens] return [(t, t) for t in tokens]
......
...@@ -41,7 +41,7 @@ class OptionInputTest(unittest.TestCase): ...@@ -41,7 +41,7 @@ class OptionInputTest(unittest.TestCase):
''' '''
def test_rendering(self): def test_rendering(self):
xml_str = """<optioninput options="('Up','Down')" id="sky_input" correct="Up"/>""" xml_str = """<optioninput options="('Up','Down','Don't know')" id="sky_input" correct="Up"/>"""
element = etree.fromstring(xml_str) element = etree.fromstring(xml_str)
state = {'value': 'Down', state = {'value': 'Down',
...@@ -54,7 +54,7 @@ class OptionInputTest(unittest.TestCase): ...@@ -54,7 +54,7 @@ class OptionInputTest(unittest.TestCase):
expected = { expected = {
'STATIC_URL': '/dummy-static/', 'STATIC_URL': '/dummy-static/',
'value': 'Down', 'value': 'Down',
'options': [('Up', 'Up'), ('Down', 'Down')], 'options': [('Up', 'Up'), ('Down', 'Down'), ('Don\'t know', 'Don\'t know')],
'status': 'answered', 'status': 'answered',
'msg': '', 'msg': '',
'inline': False, 'inline': False,
...@@ -80,6 +80,10 @@ class OptionInputTest(unittest.TestCase): ...@@ -80,6 +80,10 @@ class OptionInputTest(unittest.TestCase):
check(u"('б в','в')", [u'б в', u'в']) check(u"('б в','в')", [u'б в', u'в'])
check(u"('Мой \"кавыки\"место','в')", [u'Мой \"кавыки\"место', u'в']) check(u"('Мой \"кавыки\"место','в')", [u'Мой \"кавыки\"место', u'в'])
# check that escaping single quotes with leading backslash (\') properly works
# note: actual input by user will be hasn\'t but json parses it as hasn\\'t
check(u"('hasnt','hasn't')", [u'hasnt', u'hasn\'t'])
class ChoiceGroupTest(unittest.TestCase): class ChoiceGroupTest(unittest.TestCase):
''' '''
......
...@@ -345,6 +345,17 @@ class OptionResponseTest(ResponseTest): ...@@ -345,6 +345,17 @@ class OptionResponseTest(ResponseTest):
# Options not in the list should be marked incorrect # Options not in the list should be marked incorrect
self.assert_grade(problem, "invalid_option", "incorrect") self.assert_grade(problem, "invalid_option", "incorrect")
def test_quote_option(self):
# Test that option response properly escapes quotes inside options strings
problem = self.build_problem(options=["hasnot", "hasn't", "has'nt"],
correct_option="hasn't")
# Assert that correct option with a quote inside is marked correctly
self.assert_grade(problem, "hasnot", "incorrect")
self.assert_grade(problem, "hasn't", "correct")
self.assert_grade(problem, "hasn\'t", "correct")
self.assert_grade(problem, "has'nt", "incorrect")
class FormulaResponseTest(ResponseTest): class FormulaResponseTest(ResponseTest):
""" """
......
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