# pylint: disable=missing-docstring # EVERY PROBLEM TYPE MUST HAVE THE FOLLOWING: # -Section in Dictionary containing: # -factory # -kwargs # -(optional metadata) # -Correct, Incorrect and Unanswered CSS selectors # -A way to answer the problem correctly and incorrectly # -A way to check the problem was answered correctly, incorrectly and blank from lettuce import world import random import textwrap from common import section_location from capa.tests.response_xml_factory import ( ChoiceResponseXMLFactory, ChoiceTextResponseXMLFactory, CodeResponseXMLFactory, CustomResponseXMLFactory, FormulaResponseXMLFactory, ImageResponseXMLFactory, MultipleChoiceResponseXMLFactory, NumericalResponseXMLFactory, OptionResponseXMLFactory, StringResponseXMLFactory, ) # Factories from capa.tests.response_xml_factory that we will use # to generate the problem XML, with the keyword args used to configure # the output. # 'correct', 'incorrect', and 'unanswered' keys are lists of CSS selectors # the presence of any in the list is sufficient PROBLEM_DICT = { 'drop down': { 'factory': OptionResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Option 2', 'options': ['Option 1', 'Option 2', 'Option 3', 'Option 4'], 'correct_option': 'Option 2'}, 'correct': ['span.correct'], 'incorrect': ['span.incorrect'], 'unanswered': ['span.unanswered']}, 'multiple choice': { 'factory': MultipleChoiceResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Choice 3', 'choices': [False, False, True, False], 'choice_names': ['choice_0', 'choice_1', 'choice_2', 'choice_3']}, 'correct': ['label.choicegroup_correct', 'span.correct'], 'incorrect': ['label.choicegroup_incorrect', 'span.incorrect'], 'unanswered': ['span.unanswered']}, 'checkbox': { 'factory': ChoiceResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Choices 1 and 3', 'choice_type': 'checkbox', 'choices': [True, False, True, False, False], 'choice_names': ['Choice 1', 'Choice 2', 'Choice 3', 'Choice 4']}, 'correct': ['span.correct'], 'incorrect': ['span.incorrect'], 'unanswered': ['span.unanswered']}, 'radio': { 'factory': ChoiceResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Choice 3', 'choice_type': 'radio', 'choices': [False, False, True, False], 'choice_names': ['Choice 1', 'Choice 2', 'Choice 3', 'Choice 4']}, 'correct': ['label.choicegroup_correct', 'span.correct'], 'incorrect': ['label.choicegroup_incorrect', 'span.incorrect'], 'unanswered': ['span.unanswered']}, 'string': { 'factory': StringResponseXMLFactory(), 'kwargs': { 'question_text': 'The answer is "correct string"', 'case_sensitive': False, 'answer': 'correct string'}, 'correct': ['div.correct'], 'incorrect': ['div.incorrect'], 'unanswered': ['div.unanswered', 'div.unsubmitted']}, 'numerical': { 'factory': NumericalResponseXMLFactory(), 'kwargs': { 'question_text': 'The answer is pi + 1', 'answer': '4.14159', 'tolerance': '0.00001', 'math_display': True}, 'correct': ['div.correct'], 'incorrect': ['div.incorrect'], 'unanswered': ['div.unanswered', 'div.unsubmitted']}, 'formula': { 'factory': FormulaResponseXMLFactory(), 'kwargs': { 'question_text': 'The solution is [mathjax]x^2+2x+y[/mathjax]', 'sample_dict': {'x': (-100, 100), 'y': (-100, 100)}, 'num_samples': 10, 'tolerance': 0.00001, 'math_display': True, 'answer': 'x^2+2*x+y'}, 'correct': ['div.correct'], 'incorrect': ['div.incorrect'], 'unanswered': ['div.unanswered', 'div.unsubmitted']}, 'script': { 'factory': CustomResponseXMLFactory(), 'kwargs': { 'question_text': 'Enter two integers that sum to 10.', 'cfn': 'test_add_to_ten', 'expect': '10', 'num_inputs': 2, 'script': textwrap.dedent(""" def test_add_to_ten(expect,ans): try: a1=int(ans[0]) a2=int(ans[1]) except ValueError: a1=0 a2=0 return (a1+a2)==int(expect) """)}, 'correct': ['div.correct'], 'incorrect': ['div.incorrect'], 'unanswered': ['div.unanswered', 'div.unsubmitted']}, 'code': { 'factory': CodeResponseXMLFactory(), 'kwargs': { 'question_text': 'Submit code to an external grader', 'initial_display': 'print "Hello world!"', 'grader_payload': '{"grader": "ps1/Spring2013/test_grader.py"}', }, 'correct': ['span.correct'], 'incorrect': ['span.incorrect'], 'unanswered': ['span.unanswered']}, 'radio_text': { 'factory': ChoiceTextResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Choice 0 and input 8', 'type': 'radiotextgroup', 'choices': [("true", {"answer": "8", "tolerance": "1"}), ("false", {"answer": "8", "tolerance": "1"}) ] }, 'correct': ['section.choicetextgroup_correct'], 'incorrect': ['section.choicetextgroup_incorrect', 'span.incorrect'], 'unanswered': ['span.unanswered']}, 'checkbox_text': { 'factory': ChoiceTextResponseXMLFactory(), 'kwargs': { 'question_text': 'The correct answer is Choice 0 and input 8', 'type': 'checkboxtextgroup', 'choices': [("true", {"answer": "8", "tolerance": "1"}), ("false", {"answer": "8", "tolerance": "1"}) ] }, 'correct': ['span.correct'], 'incorrect': ['span.incorrect'], 'unanswered': ['span.unanswered']}, 'image': { 'factory': ImageResponseXMLFactory(), 'kwargs': { 'src': '/static/images/placeholder-image.png', 'rectangle': '(50,50)-(100,100)' }, 'correct': ['span.correct'], 'incorrect': ['span.incorrect'], 'unanswered': ['span.unanswered']} } def answer_problem(course, problem_type, correctness): # Make sure that the problem has been completely rendered before # starting to input an answer. world.wait_for_ajax_complete() section_loc = section_location(course) if problem_type == "drop down": select_name = "input_{}_2_1".format( section_loc.course_key.make_usage_key('problem', 'drop_down').html_id() ) option_text = 'Option 2' if correctness == 'correct' else 'Option 3' world.select_option(select_name, option_text) elif problem_type == "multiple choice": if correctness == 'correct': world.css_check(inputfield(course, 'multiple choice', choice='choice_2')) else: world.css_check(inputfield(course, 'multiple choice', choice='choice_1')) elif problem_type == "checkbox": if correctness == 'correct': world.css_check(inputfield(course, 'checkbox', choice='choice_0')) world.css_check(inputfield(course, 'checkbox', choice='choice_2')) else: world.css_check(inputfield(course, 'checkbox', choice='choice_3')) elif problem_type == 'radio': if correctness == 'correct': world.css_check(inputfield(course, 'radio', choice='choice_2')) else: world.css_check(inputfield(course, 'radio', choice='choice_1')) elif problem_type == 'string': textvalue = 'correct string' if correctness == 'correct' else 'incorrect' world.css_fill(inputfield(course, 'string'), textvalue) elif problem_type == 'numerical': textvalue = "pi + 1" if correctness == 'correct' else str(random.randint(-2, 2)) world.css_fill(inputfield(course, 'numerical'), textvalue) elif problem_type == 'formula': textvalue = "x^2+2*x+y" if correctness == 'correct' else 'x^2' world.css_fill(inputfield(course, 'formula'), textvalue) elif problem_type == 'script': # Correct answer is any two integers that sum to 10 first_addend = random.randint(-100, 100) second_addend = 10 - first_addend # If we want an incorrect answer, then change # the second addend so they no longer sum to 10 if correctness == 'incorrect': second_addend += random.randint(1, 10) world.css_fill(inputfield(course, 'script', input_num=1), str(first_addend)) world.css_fill(inputfield(course, 'script', input_num=2), str(second_addend)) elif problem_type == 'code': # The fake xqueue server is configured to respond # correct / incorrect no matter what we submit. # Furthermore, since the inline code response uses # JavaScript to make the code display nicely, it's difficult # to programatically input text # (there's not