public function test_test3_complex_scenario()
 {
     // Here are the sequence of responses we are going to test. When
     // a particular PRT generates a grades, that is shown in brackets as
     // raw fraction - penalty.
     //
     //     odd         even        oddeven       unique     Mark so far
     //  1. x^3         -           x             -          -
     //  2. x^3 (1)     -           x   (0.5)     -          1.5
     //  3. (x          (x          x+1           F (0)      1.5
     //  4. x)          x^2         x+1 (0-0.1)   -          1.5
     //  5. x^2         x           x^5           -          1.5
     //  6. x^2 (0-0)   x^2         x^5 (0.5-0.2) T (1-0.1)  2.4
     //  7. x           x^2 (1)     x+3           T (1-0.1)  3.4
     //  8. x   (1-0.1) -           x+3 (0-0.3)   T (1-0.1)  3.4
     //  9. x^3         x^2         0             T (1-0.1)  3.4
     // 10. x^3 (1-0.1) x^2 (1-0.0) 0   (1-0.4)   T (1-0.1)  3.5
     //
     // Best mark
     //     1.0         1.0         0.6           0.9        3.5
     //
     // Hopefully this summary makes the following easier to understand.
     // Create a stack question.
     $q = test_question_maker::make_question('stack', 'test3_penalty0_1');
     $this->start_attempt_at_question($q, 'adaptive', 4);
     // Check the initial state.
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1');
     $this->check_output_contains_text_input('ans2');
     $this->check_output_contains_text_input('ans3');
     $this->check_output_does_not_contain_input_validation();
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertNull($this->quba->get_response_summary($this->slot));
     // Step 1.
     $this->process_submission(array('ans1' => 'x^3', 'ans2' => '', 'ans3' => 'x', 'ans4' => '', '-submit' => 1));
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3');
     $this->check_output_contains_text_input('ans2', '');
     $this->check_output_contains_text_input('ans3', 'x');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_does_not_contain_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x^3 [valid]; ans3: x [valid]', $this->quba->get_response_summary($this->slot));
     // Step 2.
     $this->process_submission(array('ans1' => 'x^3', 'ans2' => '', 'ans3' => 'x', 'ans4' => '', 'ans1_val' => 'x^3', 'ans3_val' => 'x', '-submit' => 1));
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(1.5);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3');
     $this->check_output_contains_text_input('ans2', '');
     $this->check_output_contains_text_input('ans3', 'x');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_does_not_contain_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_contains_prt_feedback('odd');
     $this->check_output_does_not_contain_prt_feedback('even');
     $this->check_output_contains_prt_feedback('oddeven');
     $this->check_output_does_not_contain_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x^3 [score]; ans3: x [score]', $this->quba->get_response_summary($this->slot));
     // Step 3.
     $this->process_submission(array('ans1' => '(x', 'ans2' => '(x', 'ans3' => 'x+1', 'ans4' => 'false', 'ans1_val' => 'x^3', 'ans3_val' => 'x', '-submit' => 1));
     $this->check_current_state(question_state::$invalid);
     $this->check_current_mark(1.5);
     $this->render();
     $this->check_output_contains_text_input('ans1', '(x');
     $this->check_output_contains_text_input('ans2', '(x');
     $this->check_output_contains_text_input('ans3', 'x+1');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback('odd');
     $this->check_output_does_not_contain_prt_feedback('even');
     $this->check_output_does_not_contain_prt_feedback('oddeven');
     $this->check_output_contains_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'false', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: (x [invalid]; ans2: (x [invalid]; ans3: x+1 [valid]; ans4: false [score]', $this->quba->get_response_summary($this->slot));
     // Step 4.
     $this->process_submission(array('ans1' => 'x)', 'ans2' => 'x^2', 'ans3' => 'x+1', 'ans4' => '', 'ans3_val' => 'x+1', '-submit' => 1));
     $this->check_current_state(question_state::$invalid);
     $this->check_current_mark(1.5);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x)');
     $this->check_output_contains_text_input('ans2', 'x^2');
     $this->check_output_contains_text_input('ans3', 'x+1');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback('odd');
     $this->check_output_does_not_contain_prt_feedback('even');
     $this->check_output_contains_prt_feedback('oddeven');
     $this->check_output_does_not_contain_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x) [invalid]; ans2: x^2 [valid]; ans3: x+1 [score]', $this->quba->get_response_summary($this->slot));
     // Step 5.
     $this->process_submission(array('ans1' => 'x^2', 'ans2' => 'x', 'ans3' => 'x^5', 'ans4' => '', 'ans2_val' => 'x^2', 'ans3_val' => 'x+1', '-submit' => 1));
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(1.5);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^2');
     $this->check_output_contains_text_input('ans2', 'x');
     $this->check_output_contains_text_input('ans3', 'x^5');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback('odd');
     $this->check_output_does_not_contain_prt_feedback('even');
     $this->check_output_does_not_contain_prt_feedback('oddeven');
     $this->check_output_does_not_contain_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x^2 [valid]; ans2: x [valid]; ans3: x^5 [valid]', $this->quba->get_response_summary($this->slot));
     // Step 6.
     $this->process_submission(array('ans1' => 'x^2', 'ans2' => 'x^2', 'ans3' => 'x^5', 'ans4' => 'true', 'ans1_val' => 'x^2', 'ans2_val' => 'x', 'ans3_val' => 'x^5', '-submit' => 1));
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(2.4);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^2');
     $this->check_output_contains_text_input('ans2', 'x^2');
     $this->check_output_contains_text_input('ans3', 'x^5');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_contains_prt_feedback('odd');
     $this->check_output_does_not_contain_prt_feedback('even');
     $this->check_output_contains_prt_feedback('oddeven');
     $this->check_output_contains_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'true', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x^2 [score]; ans2: x^2 [valid]; ans3: x^5 [score]; ans4: true [score]', $this->quba->get_response_summary($this->slot));
     // Step 7.
     $this->process_submission(array('ans1' => 'x', 'ans2' => 'x^2', 'ans3' => 'x+3', 'ans4' => 'true', 'ans1_val' => 'x^2', 'ans2_val' => 'x^2', 'ans3_val' => 'x^5', '-submit' => 1));
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(3.4);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x');
     $this->check_output_contains_text_input('ans2', 'x^2');
     $this->check_output_contains_text_input('ans3', 'x+3');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback('odd');
     $this->check_output_contains_prt_feedback('even');
     $this->check_output_does_not_contain_prt_feedback('oddeven');
     $this->check_output_contains_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'true', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x [valid]; ans2: x^2 [score]; ans3: x+3 [valid]; ans4: true [score]', $this->quba->get_response_summary($this->slot));
     // Step 8.
     $this->process_submission(array('ans1' => 'x', 'ans2' => '', 'ans3' => 'x+3', 'ans4' => 'true', 'ans1_val' => 'x', 'ans2_val' => 'x^2', 'ans3_val' => 'x+3', '-submit' => 1));
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(3.4);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x');
     $this->check_output_contains_text_input('ans2', '');
     $this->check_output_contains_text_input('ans3', 'x+3');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_does_not_contain_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_contains_prt_feedback('odd');
     $this->check_output_does_not_contain_prt_feedback('even');
     $this->check_output_contains_prt_feedback('oddeven');
     $this->check_output_contains_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'true', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x [score]; ans3: x+3 [score]; ans4: true [score]', $this->quba->get_response_summary($this->slot));
     // Step 9.
     $this->process_submission(array('ans1' => 'x^3', 'ans2' => 'x^2', 'ans3' => '0', 'ans4' => 'true', 'ans1_val' => 'x', 'ans3_val' => 'x+3', '-submit' => 1));
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(3.4);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3');
     $this->check_output_contains_text_input('ans2', 'x^2');
     $this->check_output_contains_text_input('ans3', '0');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback('odd');
     $this->check_output_does_not_contain_prt_feedback('even');
     $this->check_output_does_not_contain_prt_feedback('oddeven');
     $this->check_output_contains_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'true', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x^3 [valid]; ans2: x^2 [valid]; ans3: 0 [valid]; ans4: true [score]', $this->quba->get_response_summary($this->slot));
     // Step 10.
     $this->process_submission(array('ans1' => 'x^3', 'ans2' => 'x^2', 'ans3' => '0', 'ans4' => 'true', 'ans1_val' => 'x^3', 'ans2_val' => 'x^2', 'ans3_val' => '0', '-submit' => 1));
     $this->check_current_state(question_state::$complete);
     $this->check_current_mark(3.5);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3');
     $this->check_output_contains_text_input('ans2', 'x^2');
     $this->check_output_contains_text_input('ans3', '0');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_contains_prt_feedback('odd');
     $this->check_output_contains_prt_feedback('even');
     $this->check_output_contains_prt_feedback('oddeven');
     $this->check_output_contains_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'true', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x^3 [score]; ans2: x^2 [score]; ans3: 0 [score]; ans4: true [score]', $this->quba->get_response_summary($this->slot));
     // Submit all and finish - should update state from complete to gradedright.
     $this->quba->finish_all_questions();
     $this->check_current_state(question_state::$gradedright);
     $this->check_current_mark(3.5);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3', false);
     $this->check_output_contains_text_input('ans2', 'x^2', false);
     $this->check_output_contains_text_input('ans3', '0', false);
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_contains_prt_feedback('odd');
     $this->check_output_contains_prt_feedback('even');
     $this->check_output_contains_prt_feedback('oddeven');
     $this->check_output_contains_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'true', false), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     $this->assertEquals('ans1: x^3 [score]; ans2: x^2 [score]; ans3: 0 [score]; ans4: true [score]', $this->quba->get_response_summary($this->slot));
 }
 public function test_test3_save_completely_blank_response_then_stubmit()
 {
     // Create a stack question.
     $q = test_question_maker::make_question('stack', 'test3');
     $this->start_attempt_at_question($q, 'deferredfeedback', 4);
     // Check the initial state.
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1');
     $this->check_output_contains_text_input('ans2');
     $this->check_output_contains_text_input('ans3');
     $this->check_output_does_not_contain_input_validation();
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     // Try to save a blank response. This should not even create a new step..
     $this->process_submission(array('ans1' => '', 'ans2' => '', 'ans3' => '', 'ans4' => ''));
     $this->assertEquals(1, $this->quba->get_question_attempt($this->slot)->get_num_steps());
     // Submit all and finish.
     $this->quba->finish_all_questions();
     $this->check_current_state(question_state::$gaveup);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1', '', false);
     $this->check_output_contains_text_input('ans2', '', false);
     $this->check_output_contains_text_input('ans3', '', false);
     $this->check_output_does_not_contain_input_validation();
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', false), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
 }
 public function test_test3_submit_and_finish_incomplete()
 {
     // Create a stack question.
     $q = test_question_maker::make_question('stack', 'test3');
     $q->hints = array(new question_hint(1, 'This is the first hint.', FORMAT_HTML), new question_hint(2, 'This is the second hint.', FORMAT_HTML));
     $this->start_attempt_at_question($q, 'interactive', 4);
     // Check the right behaviour is used.
     $this->assertEquals('interactivecountback', $this->quba->get_question_attempt($this->slot)->get_behaviour_name());
     // Check the initial state.
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1');
     $this->check_output_contains_text_input('ans2');
     $this->check_output_contains_text_input('ans3');
     $this->check_output_does_not_contain_input_validation();
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     // Save a response with three parts incorrect and one part not answered.
     $this->process_submission(array('ans1' => 'x+1', 'ans1_val' => 'x+1', 'ans2' => 'x+1', 'ans2_val' => 'x+1', 'ans3' => 'x+1', 'ans3_val' => 'x+1', 'ans4' => ''));
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x+1');
     $this->check_output_contains_text_input('ans2', 'x+1');
     $this->check_output_contains_text_input('ans3', 'x+1');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     // Resubmit after validation.
     $this->finish();
     $this->check_current_state(question_state::$gradedwrong);
     $this->check_current_mark(0);
     $this->check_prt_score('odd', 0, 0.4, 1);
     $this->check_prt_score('even', 0, 0.4, 1);
     $this->check_prt_score('oddeven', 0, 0.4, 1);
     $this->check_prt_score('unique', null, null, 1);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x+1', false);
     $this->check_output_contains_text_input('ans2', 'x+1', false);
     $this->check_output_contains_text_input('ans3', 'x+1', false);
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_contains_prt_feedback('odd');
     $this->check_output_contains_prt_feedback('even');
     $this->check_output_contains_prt_feedback('oddeven');
     $this->check_output_does_not_contain_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', false), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
 }
 public function test_test3_save_invalid_response_correct_then_stubmit()
 {
     // Create a stack question.
     $q = test_question_maker::make_question('stack', 'test3');
     $this->start_attempt_at_question($q, 'immediatefeedback', 4);
     // Check the initial state.
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1');
     $this->check_output_contains_text_input('ans2');
     $this->check_output_contains_text_input('ans3');
     $this->check_output_does_not_contain_input_validation();
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), '', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     // Submit a partially correct response.
     $this->process_submission(array('ans1' => 'x^3', 'ans2' => '(x +', 'ans3' => '0', 'ans4' => 'true', '-submit' => 1));
     $this->check_current_state(question_state::$invalid);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3');
     $this->check_output_contains_text_input('ans2', '(x +');
     $this->check_output_contains_text_input('ans3', '0');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'false', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     // Try to submit again without editing. Shoud not be accepted.
     $this->process_submission(array('ans1' => 'x^3', 'ans2' => '(x +', 'ans3' => '0', 'ans4' => 'true', 'ans1_val' => 'x^3', 'ans3_val' => '0', '-submit' => 1));
     $this->check_current_state(question_state::$invalid);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3');
     $this->check_output_contains_text_input('ans2', '(x +');
     $this->check_output_contains_text_input('ans3', '0');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'false', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     // Now fix the resonse and submit. Should only be validated.
     $this->process_submission(array('ans1' => 'x^3', 'ans2' => 'x^2', 'ans3' => '0', 'ans4' => 'true', 'ans1_val' => 'x^3', 'ans3_val' => '0', '-submit' => 1));
     $this->check_current_state(question_state::$invalid);
     $this->check_current_mark(null);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3');
     $this->check_output_contains_text_input('ans2', 'x^2');
     $this->check_output_contains_text_input('ans3', '0');
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_does_not_contain_prt_feedback();
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'false', true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
     // Submit again. Should now be graded.
     $this->process_submission(array('ans1' => 'x^3', 'ans2' => 'x^2', 'ans3' => '0', 'ans4' => 'true', 'ans1_val' => 'x^3', 'ans2_val' => 'x^2', 'ans3_val' => '0', '-submit' => 1));
     $this->check_current_state(question_state::$gradedright);
     $this->check_current_mark(4);
     $this->render();
     $this->check_output_contains_text_input('ans1', 'x^3', false);
     $this->check_output_contains_text_input('ans2', 'x^2', false);
     $this->check_output_contains_text_input('ans3', '0', false);
     $this->check_output_contains_input_validation('ans1');
     $this->check_output_contains_input_validation('ans2');
     $this->check_output_contains_input_validation('ans3');
     $this->check_output_does_not_contain_input_validation('ans4');
     $this->check_output_contains_prt_feedback('odd');
     $this->check_output_contains_prt_feedback('even');
     $this->check_output_contains_prt_feedback('oddeven');
     $this->check_output_contains_prt_feedback('unique');
     $this->check_output_does_not_contain_stray_placeholders();
     $this->check_current_output($this->get_contains_select_expectation('ans4', stack_boolean_input::get_choices(), 'false', false), $this->get_does_not_contain_num_parts_correct(), $this->get_no_hint_visible_expectation());
 }