''' Steps for problem.feature lettuce tests ''' #pylint: disable=C0111 #pylint: disable=W0621 from lettuce import world, step from lettuce.django import django_url import random import textwrap from common import i_am_registered_for_the_course, \ TEST_SECTION_NAME, section_location from capa.tests.response_xml_factory import OptionResponseXMLFactory, \ ChoiceResponseXMLFactory, MultipleChoiceResponseXMLFactory, \ StringResponseXMLFactory, NumericalResponseXMLFactory, \ FormulaResponseXMLFactory, CustomResponseXMLFactory, \ CodeResponseXMLFactory # 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. PROBLEM_FACTORY_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'}}, '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']}}, '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']}}, 'string': { 'factory': StringResponseXMLFactory(), 'kwargs': { 'question_text': 'The answer is "correct string"', 'case_sensitive': False, 'answer': 'correct string'}}, 'numerical': { 'factory': NumericalResponseXMLFactory(), 'kwargs': { 'question_text': 'The answer is pi + 1', 'answer': '4.14159', 'tolerance': '0.00001', 'math_display': True}}, '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'}}, '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) """)}}, '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"}', }}, } def add_problem_to_course(course, problem_type): ''' Add a problem to the course we have created using factories. ''' assert(problem_type in PROBLEM_FACTORY_DICT) # Generate the problem XML using capa.tests.response_xml_factory factory_dict = PROBLEM_FACTORY_DICT[problem_type] problem_xml = factory_dict['factory'].build_xml(**factory_dict['kwargs']) # Create a problem item using our generated XML # We set rerandomize=always in the metadata so that the "Reset" button # will appear. template_name = "i4x://edx/templates/problem/Blank_Common_Problem" world.ItemFactory.create(parent_location=section_location(course), template=template_name, display_name=str(problem_type), data=problem_xml, metadata={'rerandomize': 'always'}) @step(u'I am viewing a "([^"]*)" problem') def view_problem(step, problem_type): i_am_registered_for_the_course(step, 'model_course') # Ensure that the course has this problem type add_problem_to_course('model_course', problem_type) # Go to the one section in the factory-created course # which should be loaded with the correct problem chapter_name = TEST_SECTION_NAME.replace(" ", "_") section_name = chapter_name url = django_url('/courses/edx/model_course/Test_Course/courseware/%s/%s' % (chapter_name, section_name)) world.browser.visit(url) @step(u'External graders respond "([^"]*)"') def set_external_grader_response(step, correctness): assert(correctness in ['correct', 'incorrect']) response_dict = {'correct': True if correctness == 'correct' else False, 'score': 1 if correctness == 'correct' else 0, 'msg': 'Your problem was graded %s' % correctness} # Set the fake xqueue server to always respond # correct/incorrect when asked to grade a problem world.xqueue_server.set_grade_response(response_dict) @step(u'I answer a "([^"]*)" problem "([^"]*)ly"') def answer_problem(step, problem_type, correctness): """ Mark a given problem type correct or incorrect, then submit it. *problem_type* is a string representing the type of problem (e.g. 'drop down') *correctness* is in ['correct', 'incorrect'] """ assert(correctness in ['correct', 'incorrect']) if problem_type == "drop down": select_name = "input_i4x-edx-model_course-problem-drop_down_2_1" option_text = 'Option 2' if correctness == 'correct' else 'Option 3' world.browser.select(select_name, option_text) elif problem_type == "multiple choice": if correctness == 'correct': inputfield('multiple choice', choice='choice_2').check() else: inputfield('multiple choice', choice='choice_1').check() elif problem_type == "checkbox": if correctness == 'correct': inputfield('checkbox', choice='choice_0').check() inputfield('checkbox', choice='choice_2').check() else: inputfield('checkbox', choice='choice_3').check() elif problem_type == 'string': textvalue = 'correct string' if correctness == 'correct' \ else 'incorrect' inputfield('string').fill(textvalue) elif problem_type == 'numerical': textvalue = "pi + 1" if correctness == 'correct' \ else str(random.randint(-2, 2)) inputfield('numerical').fill(textvalue) elif problem_type == 'formula': textvalue = "x^2+2*x+y" if correctness == 'correct' else 'x^2' inputfield('formula').fill(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) inputfield('script', input_num=1).fill(str(first_addend)) inputfield('script', input_num=2).fill(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