Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

MDL-37847 plain text essays were screwing up HTML special chars.

This was incorrect use of PARAM_CLEANHTML for these inputs.

This fix also adds some unit tests to try to verify that this does not
break again in future.
  • Loading branch information...
commit c0d12fc1cdd1c31087b968db0cd9d6e97145230c 1 parent 1918a24
Tim Hunt authored February 04, 2013
16  question/engine/tests/helpers.php
@@ -619,8 +619,14 @@ public function __construct($pattern, $message = '') {
619 619
     protected $displayoptions;
620 620
     /** @var question_usage_by_activity */
621 621
     protected $quba;
622  
-    /** @var unknown_type integer */
  622
+    /** @var integer */
  623
+
623 624
     protected $slot;
  625
+    /**
  626
+     * @var string after {@link render()} has been called, this contains the
  627
+     * display of the question in its current state.
  628
+     */
  629
+    protected $currentoutput = '';
624 630
 
625 631
     protected function setUp() {
626 632
         parent::setUp();
@@ -671,6 +677,14 @@ protected function check_current_mark($mark) {
671 677
     }
672 678
 
673 679
     /**
  680
+     * Generate the HTML rendering of the question in its current state in
  681
+     * $this->currentoutput so that it can be verified.
  682
+     */
  683
+    protected function render() {
  684
+        $this->currentoutput = $this->quba->render_question($this->slot, $this->displayoptions);
  685
+    }
  686
+
  687
+    /**
674 688
      * @param $condition one or more Expectations. (users varargs).
675 689
      */
676 690
     protected function check_current_output() {
4  question/type/essay/question.php
@@ -56,8 +56,10 @@ public function get_format_renderer(moodle_page $page) {
56 56
     public function get_expected_data() {
57 57
         if ($this->responseformat == 'editorfilepicker') {
58 58
             $expecteddata = array('answer' => question_attempt::PARAM_CLEANHTML_FILES);
59  
-        } else {
  59
+        } else if ($this->responseformat == 'editor') {
60 60
             $expecteddata = array('answer' => PARAM_CLEANHTML);
  61
+        } else {
  62
+            $expecteddata = array('answer' => PARAM_RAW);
61 63
         }
62 64
         $expecteddata['answerformat'] = PARAM_ALPHANUMEXT;
63 65
         if ($this->attachments != 0) {
100  question/type/essay/tests/helper.php
... ...
@@ -0,0 +1,100 @@
  1
+<?php
  2
+// This file is part of Moodle - http://moodle.org/
  3
+//
  4
+// Moodle is free software: you can redistribute it and/or modify
  5
+// it under the terms of the GNU General Public License as published by
  6
+// the Free Software Foundation, either version 3 of the License, or
  7
+// (at your option) any later version.
  8
+//
  9
+// Moodle is distributed in the hope that it will be useful,
  10
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+// GNU General Public License for more details.
  13
+//
  14
+// You should have received a copy of the GNU General Public License
  15
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16
+
  17
+/**
  18
+ * Test helpers for the essay question type.
  19
+ *
  20
+ * @package    qtype_essay
  21
+ * @copyright  2013 The Open University
  22
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23
+ */
  24
+
  25
+
  26
+defined('MOODLE_INTERNAL') || die();
  27
+
  28
+
  29
+/**
  30
+ * Test helper class for the essay question type.
  31
+ *
  32
+ * @copyright  2013 The Open University
  33
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34
+ */
  35
+class qtype_essay_test_helper extends question_test_helper {
  36
+    public function get_test_questions() {
  37
+        return array('editor', 'editorfilepicker', 'plain', 'monospaced');
  38
+    }
  39
+
  40
+    /**
  41
+     * Helper method to reduce duplication.
  42
+     * @return qtype_essay_question
  43
+     */
  44
+    protected function initialise_essay_question() {
  45
+        question_bank::load_question_definition_classes('essay');
  46
+        $q = new qtype_essay_question();
  47
+        test_question_maker::initialise_a_question($q);
  48
+        $q->name = 'Essay question (HTML editor)';
  49
+        $q->questiontext = 'Please write a story about a frog.';
  50
+        $q->generalfeedback = 'I hope your story had a beginning, a middle and an end.';
  51
+        $q->responseformat = 'editor';
  52
+        $q->responsefieldlines = 10;
  53
+        $q->attachments = 0;
  54
+        $q->graderinfo = '';
  55
+        $q->graderinfoformat = FORMAT_HTML;
  56
+        $q->qtype = question_bank::get_qtype('essay');
  57
+
  58
+        return $q;
  59
+    }
  60
+
  61
+    /**
  62
+     * Makes an essay question using the HTML editor as input.
  63
+     * @return qtype_essay_question
  64
+     */
  65
+    public function make_essay_question_editor() {
  66
+        return $this->initialise_essay_question();
  67
+    }
  68
+
  69
+    /**
  70
+     * Makes an essay question using the HTML editor allowing embedded files as
  71
+     * input, and up to three attachments.
  72
+     * @return qtype_essay_question
  73
+     */
  74
+    public function make_essay_question_editorfilepicker() {
  75
+        $q = $this->initialise_essay_question();
  76
+        $q->responseformat = 'editorfilepicker';
  77
+        $q->attachments = 3;
  78
+        return $q;
  79
+    }
  80
+
  81
+    /**
  82
+     * Makes an essay question using plain text input.
  83
+     * @return qtype_essay_question
  84
+     */
  85
+    public function make_essay_question_plain() {
  86
+        $q = $this->initialise_essay_question();
  87
+        $q->responseformat = 'plain';
  88
+        return $q;
  89
+    }
  90
+
  91
+    /**
  92
+     * Makes an essay question using monospaced input.
  93
+     * @return qtype_essay_question
  94
+     */
  95
+    public function make_essay_question_monospaced() {
  96
+        $q = $this->initialise_essay_question();
  97
+        $q->responseformat = 'monospaced';
  98
+        return $q;
  99
+    }
  100
+}
156  question/type/essay/tests/walkthrough_test.php
... ...
@@ -0,0 +1,156 @@
  1
+<?php
  2
+// This file is part of Moodle - http://moodle.org/
  3
+//
  4
+// Moodle is free software: you can redistribute it and/or modify
  5
+// it under the terms of the GNU General Public License as published by
  6
+// the Free Software Foundation, either version 3 of the License, or
  7
+// (at your option) any later version.
  8
+//
  9
+// Moodle is distributed in the hope that it will be useful,
  10
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+// GNU General Public License for more details.
  13
+//
  14
+// You should have received a copy of the GNU General Public License
  15
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16
+
  17
+/**
  18
+ * This file contains tests that walks essay questions through some attempts.
  19
+ *
  20
+ * @package   qtype_essay
  21
+ * @copyright 2013 The Open University
  22
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23
+ */
  24
+
  25
+
  26
+defined('MOODLE_INTERNAL') || die();
  27
+
  28
+global $CFG;
  29
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
  30
+
  31
+
  32
+/**
  33
+ * Unit tests for the essay question type.
  34
+ *
  35
+ * @copyright 2013 The Open University
  36
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37
+ */
  38
+class qtype_essay_walkthrough_test extends qbehaviour_walkthrough_test_base {
  39
+
  40
+    protected function check_contains_textarea($name, $content = '', $height = 10) {
  41
+        $fieldname = $this->quba->get_field_prefix($this->slot) . $name;
  42
+
  43
+        $this->assertTag(array('tag' => 'textarea',
  44
+                'attributes' => array('cols' => '60', 'rows' => $height,
  45
+                        'name' => $fieldname)),
  46
+                $this->currentoutput);
  47
+
  48
+        if ($content) {
  49
+            $this->assertRegExp('/' . preg_quote(s($content), '/') . '/', $this->currentoutput);
  50
+        }
  51
+    }
  52
+
  53
+    public function test_deferred_feedback_html_editor() {
  54
+
  55
+        // Create a matching question.
  56
+        $q = test_question_maker::make_question('essay', 'editor');
  57
+        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
  58
+
  59
+        $prefix = $this->quba->get_field_prefix($this->slot);
  60
+        $fieldname = $prefix . 'answer';
  61
+        $response = '<p>The <b>cat</b> sat on the mat. Then it ate a <b>frog</b>.</p>';
  62
+
  63
+        // Check the initial state.
  64
+        $this->check_current_state(question_state::$todo);
  65
+        $this->check_current_mark(null);
  66
+        $this->render();
  67
+        $this->check_contains_textarea('answer', '');
  68
+        $this->check_current_output(
  69
+                $this->get_contains_question_text_expectation($q),
  70
+                $this->get_does_not_contain_feedback_expectation());
  71
+        $this->check_step_count(1);
  72
+
  73
+        // Save a response.
  74
+        $this->quba->process_all_actions(null, array(
  75
+            'slots'                    => $this->slot,
  76
+            $fieldname                 => $response,
  77
+            $fieldname . 'format'      => FORMAT_HTML,
  78
+            $prefix . ':sequencecheck' => '1',
  79
+        ));
  80
+
  81
+        // Verify.
  82
+        $this->check_current_state(question_state::$complete);
  83
+        $this->check_current_mark(null);
  84
+        $this->check_step_count(2);
  85
+        $this->render();
  86
+        $this->check_contains_textarea('answer', $response);
  87
+        $this->check_current_output(
  88
+                $this->get_contains_question_text_expectation($q),
  89
+                $this->get_does_not_contain_feedback_expectation());
  90
+        $this->check_step_count(2);
  91
+
  92
+        // Finish the attempt.
  93
+        $this->quba->finish_all_questions();
  94
+
  95
+        // Verify.
  96
+        $this->check_current_state(question_state::$needsgrading);
  97
+        $this->check_current_mark(null);
  98
+        $this->render();
  99
+        $this->assertRegExp('/' . preg_quote($response, '/') . '/', $this->currentoutput);
  100
+        $this->check_current_output(
  101
+                $this->get_contains_question_text_expectation($q),
  102
+                $this->get_contains_general_feedback_expectation($q));
  103
+    }
  104
+
  105
+    public function test_deferred_feedback_plain_text() {
  106
+
  107
+        // Create a matching question.
  108
+        $q = test_question_maker::make_question('essay', 'plain');
  109
+        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
  110
+
  111
+        $prefix = $this->quba->get_field_prefix($this->slot);
  112
+        $fieldname = $prefix . 'answer';
  113
+        $response = "x < 1\nx > 0\nFrog & Toad were friends.";
  114
+
  115
+        // Check the initial state.
  116
+        $this->check_current_state(question_state::$todo);
  117
+        $this->check_current_mark(null);
  118
+        $this->render();
  119
+        $this->check_contains_textarea('answer', '');
  120
+        $this->check_current_output(
  121
+                $this->get_contains_question_text_expectation($q),
  122
+                $this->get_does_not_contain_feedback_expectation());
  123
+        $this->check_step_count(1);
  124
+
  125
+        // Save a response.
  126
+        $this->quba->process_all_actions(null, array(
  127
+            'slots'                    => $this->slot,
  128
+            $fieldname                 => $response,
  129
+            $fieldname . 'format'      => FORMAT_HTML,
  130
+            $prefix . ':sequencecheck' => '1',
  131
+        ));
  132
+
  133
+        // Verify.
  134
+        $this->check_current_state(question_state::$complete);
  135
+        $this->check_current_mark(null);
  136
+        $this->check_step_count(2);
  137
+        $this->render();
  138
+        $this->check_contains_textarea('answer', $response);
  139
+        $this->check_current_output(
  140
+                $this->get_contains_question_text_expectation($q),
  141
+                $this->get_does_not_contain_feedback_expectation());
  142
+        $this->check_step_count(2);
  143
+
  144
+        // Finish the attempt.
  145
+        $this->quba->finish_all_questions();
  146
+
  147
+        // Verify.
  148
+        $this->check_current_state(question_state::$needsgrading);
  149
+        $this->check_current_mark(null);
  150
+        $this->render();
  151
+        $this->assertRegExp('/' . preg_quote(s($response), '/') . '/', $this->currentoutput);
  152
+        $this->check_current_output(
  153
+                $this->get_contains_question_text_expectation($q),
  154
+                $this->get_contains_general_feedback_expectation($q));
  155
+    }
  156
+}

0 notes on commit c0d12fc

Please sign in to comment.
Something went wrong with that request. Please try again.