def test_safe_eval_error(self): test_cases = [TCData("__import__('os')", "_value_")] for test_case in test_cases: with self.assertRaises(NameError): ConditionalAnswer.safe_eval(test_case.input[0], test_case.input[1])
def test_calculate_completion(self): test_cases = [ TCData([], 0), TCData(['1', '1', '0'], 1), TCData([None, None, None], 0), TCData([None, '0', None, '1'], 0.5), TCData(['0', None, None, None], 0.25) ] for test_case in test_cases: conditional_answer = ConditionalAnswer(test_case.input, None) self.assertEqual(conditional_answer.calculate_completion(), test_case.expected_output)
def test_calculate_mark(self): test_cases = [ TCData([True, True, True], 1), TCData([False, False, False], 0), TCData([True, True, False, False], 0.5), TCData([True, False, False, False], 0.25), TCData([False, False, True, False], 0.25), TCData([False, True, True, False, True, False], 0.5) ] for test_case in test_cases: conditional_answer = ConditionalAnswer(None, test_case.input) self.assertEqual(conditional_answer.calculate_mark(), test_case.expected_output)
def build_from_data(cls, data): # NOTE: A saved submission already has its questions and options ordered (subparts are ALWAYS ordered) questions = [QuestionDM.from_data(x) for x in data['questions']] answers_data = data['answers'] assert len(questions) == len(answers_data) answers = [] # building a new list to store lists of Answer data models for i, answer_data in enumerate(answers_data): subparts_answers = [] assert len(answer_data) == len(questions[i].subparts) for j, subpart_answer_data in enumerate(answer_data): subpart_answer = None subpart_type = questions[i].subparts[j].type if subpart_type == HWCentralQuestionType.MCSA: subpart_answer = MCSAQAnswer.from_data(subpart_answer_data) elif subpart_type == HWCentralQuestionType.MCMA: subpart_answer = MCMAQAnswer.from_data(subpart_answer_data) elif subpart_type == HWCentralQuestionType.NUMERIC: subpart_answer = NumericAnswer.from_data(subpart_answer_data) elif subpart_type == HWCentralQuestionType.TEXTUAL: subpart_answer = TextualAnswer.from_data(subpart_answer_data) elif subpart_type == HWCentralQuestionType.CONDITIONAL: subpart_answer = ConditionalAnswer.from_data(subpart_answer_data, questions[i].subparts[j].answer.answer_format) else: raise InvalidHWCentralQuestionTypeError(subpart_type) subparts_answers.append(subpart_answer) answers.append(subparts_answers) return cls(questions, answers)
def test_sanitize_for_eval(self): test_cases = [ TCData('lambda', True), TCData('foo\nbar', True), TCData('__import__', True), TCData('def fun():\n\texit()', True), TCData('12*3', False), TCData('1.89', False), TCData('34/57', False), TCData('-56', False), TCData('Jawaharlal Nehru', False) ] for test_case in test_cases: if test_case.expected_output: with self.assertRaises(EvalSanitizationError): ConditionalAnswer.sanitize_for_eval(test_case.input) else: self.assertEqual( ConditionalAnswer.sanitize_for_eval(test_case.input), test_case.input)
def test_check_answer(self): test_cases = [ TCData((HWCentralConditionalAnswerFormat.NUMERIC, 1, '_value_ < 10', []), [False]), TCData((HWCentralConditionalAnswerFormat.NUMERIC, 3, '_value_ < 10', []), [False, False, False]), TCData((HWCentralConditionalAnswerFormat.NUMERIC, 3, '_value_ < 10', ['5.1', '3/10', '- 5 / 56']), [True, True, True]), TCData((HWCentralConditionalAnswerFormat.NUMERIC, 1, '_value_ < 10', ['11.1']), [False]), TCData((HWCentralConditionalAnswerFormat.NUMERIC, 3, '_value_ < 10', [None, '9', None]), [False, True, False]), TCData((HWCentralConditionalAnswerFormat.TEXTUAL, 1, '_value_.isupper()', []), [False]), TCData((HWCentralConditionalAnswerFormat.TEXTUAL, 3, '_value_.isupper()', []), [False, False, False]), TCData((HWCentralConditionalAnswerFormat.TEXTUAL, 3, '_value_.isupper()', [' FOO BAR\t ', 'BANANA', 'W A T\t\t E RMELON']), [True, True, True]), TCData((HWCentralConditionalAnswerFormat.TEXTUAL, 1, '_value_.isupper()', ['foobar']), [False]), TCData((HWCentralConditionalAnswerFormat.TEXTUAL, 3, '_value_.isupper()', [None, ' FU BAR', None]), [False, True, False]) ] for test_case in test_cases: subpart_question_mock = NonCallableMagicMock(spec_set=['answer']) subpart_question_mock.answer = NonCallableMagicMock( spec_set=['answer_format', 'num_answers', 'condition']) subpart_question_mock.answer.answer_format = test_case.input[0] subpart_question_mock.answer.num_answers = test_case.input[1] subpart_question_mock.answer.condition = test_case.input[2] conditional_answer = ConditionalAnswer(test_case.input[3], None) conditional_answer.check_answer(subpart_question_mock) self.assertEqual(conditional_answer.correct, test_case.expected_output)
def get_answers(self): """ This method should only be called after validation. """ # go through associated submission data model to find out the expected fields in the form # build 2-D answer list for every subpart answer answers = [ ] # building a new list to store lists of Answer data models for i, question in enumerate(self.submission_vm.questions): subparts_answers = [] for j, subpart in enumerate(question.subparts): if subpart.type == HWCentralQuestionType.CONDITIONAL: conditional_subpart_answers = [] for k in xrange(subpart.answer.num_answers): field_key = SubmissionForm.build_conditional_subfield_key( i, j, k) conditional_subpart_answers.append( self.cleaned_data[field_key]) subpart_answer = ConditionalAnswer.from_form_field( conditional_subpart_answers) else: field_key = SubmissionForm.build_subpart_field_key(i, j) subpart_answer_data = self.cleaned_data[field_key] if subpart.type == HWCentralQuestionType.MCSA: subpart_answer = MCSAQAnswer.from_form_field( subpart_answer_data) elif subpart.type == HWCentralQuestionType.MCMA: subpart_answer = MCMAQAnswer.from_form_field( subpart_answer_data) elif subpart.type == HWCentralQuestionType.NUMERIC: subpart_answer = NumericAnswer.from_form_field( subpart_answer_data) elif subpart.type == HWCentralQuestionType.TEXTUAL: subpart_answer = TextualAnswer.from_form_field( subpart_answer_data) else: raise InvalidHWCentralQuestionTypeError(subpart.type) subparts_answers.append(subpart_answer) answers.append(subparts_answers) return answers
def test_safe_eval(self): test_cases = [ TCData((Decimal(12), '_value_ < 15'), True), TCData((Decimal('1.05'), '_value_ - 1 == Decimal(str(0.05))'), True), TCData(('foobar', 'len(_value_) > 0'), True), TCData(('foobar', '_value_.isupper()'), False), TCData((Decimal('1.666'), '_value_ > 1.5 and _value_ < 1.6'), False), TCData(('banana', "_value_ in set(['watermelon', 'orange'])"), False) ] for test_case in test_cases: self.assertEqual( ConditionalAnswer.safe_eval(test_case.input[0], test_case.input[1]), test_case.expected_output)