Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   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 for the question_attempt class.
  19   *
  20   * Action methods like start, process_action and finish are assumed to be
  21   * tested by walkthrough tests in the various behaviours.
  22   *
  23   * @package    moodlecore
  24   * @subpackage questionengine
  25   * @copyright  2009 The Open University
  26   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   */
  28  
  29  
  30  defined('MOODLE_INTERNAL') || die();
  31  
  32  global $CFG;
  33  require_once (__DIR__ . '/../lib.php');
  34  require_once (__DIR__ . '/helpers.php');
  35  
  36  
  37  /**
  38   * Unit tests for loading data into the {@link question_attempt} class.
  39   *
  40   * @copyright  2009 The Open University
  41   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  42   */
  43  class question_attempt_db_test extends data_loading_method_test_base {
  44      public function test_load() {
  45          $records = new question_test_recordset(array(
  46              array('questionattemptid', 'contextid', 'questionusageid', 'slot',
  47                                     'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'maxfraction', 'flagged',
  48                                                                                         'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
  49                                                                                                                 'attemptstepid', 'sequencenumber', 'state', 'fraction',
  50                                                                                                                                                  'timecreated', 'userid', 'name', 'value'),
  51              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo',              null, 1256233700, 1,       null, null),
  52              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete',          null, 1256233705, 1,   'answer',  '1'),
  53              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 1, '', '', '', 1256233790, 3, 2, 'complete',          null, 1256233710, 1,   'answer',  '0'),
  54              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 4, 3, 'complete',          null, 1256233715, 1,   'answer',  '1'),
  55              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 5, 4, 'gradedright',  1.0000000, 1256233720, 1,  '-finish',  '1'),
  56              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-comment', 'Not good enough!'),
  57              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1,    '-mark',  '1'),
  58              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-maxmark',  '2'),
  59          ));
  60  
  61          $question = test_question_maker::make_question('truefalse', 'true');
  62          $question->id = -1;
  63  
  64          question_bank::start_unit_test();
  65          question_bank::load_test_question_data($question);
  66          $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
  67          question_bank::end_unit_test();
  68  
  69          $this->assertEquals($question->questiontext, $qa->get_question(false)->questiontext);
  70  
  71          $this->assertEquals(6, $qa->get_num_steps());
  72  
  73          $step = $qa->get_step(0);
  74          $this->assertEquals(question_state::$todo, $step->get_state());
  75          $this->assertNull($step->get_fraction());
  76          $this->assertEquals(1256233700, $step->get_timecreated());
  77          $this->assertEquals(1, $step->get_user_id());
  78          $this->assertEquals(array(), $step->get_all_data());
  79  
  80          $step = $qa->get_step(1);
  81          $this->assertEquals(question_state::$complete, $step->get_state());
  82          $this->assertNull($step->get_fraction());
  83          $this->assertEquals(1256233705, $step->get_timecreated());
  84          $this->assertEquals(1, $step->get_user_id());
  85          $this->assertEquals(array('answer' => '1'), $step->get_all_data());
  86  
  87          $step = $qa->get_step(2);
  88          $this->assertEquals(question_state::$complete, $step->get_state());
  89          $this->assertNull($step->get_fraction());
  90          $this->assertEquals(1256233710, $step->get_timecreated());
  91          $this->assertEquals(1, $step->get_user_id());
  92          $this->assertEquals(array('answer' => '0'), $step->get_all_data());
  93  
  94          $step = $qa->get_step(3);
  95          $this->assertEquals(question_state::$complete, $step->get_state());
  96          $this->assertNull($step->get_fraction());
  97          $this->assertEquals(1256233715, $step->get_timecreated());
  98          $this->assertEquals(1, $step->get_user_id());
  99          $this->assertEquals(array('answer' => '1'), $step->get_all_data());
 100  
 101          $step = $qa->get_step(4);
 102          $this->assertEquals(question_state::$gradedright, $step->get_state());
 103          $this->assertEquals(1, $step->get_fraction());
 104          $this->assertEquals(1256233720, $step->get_timecreated());
 105          $this->assertEquals(1, $step->get_user_id());
 106          $this->assertEquals(array('-finish' => '1'), $step->get_all_data());
 107  
 108          $step = $qa->get_step(5);
 109          $this->assertEquals(question_state::$mangrpartial, $step->get_state());
 110          $this->assertEquals(0.5, $step->get_fraction());
 111          $this->assertEquals(1256233790, $step->get_timecreated());
 112          $this->assertEquals(1, $step->get_user_id());
 113          $this->assertEquals(array('-comment' => 'Not good enough!', '-mark' => '1', '-maxmark' => '2'),
 114                  $step->get_all_data());
 115      }
 116  
 117      public function test_load_missing_question() {
 118          $records = new question_test_recordset(array(
 119              array('questionattemptid', 'contextid', 'questionusageid', 'slot',
 120                                     'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'maxfraction', 'flagged',
 121                                                                                         'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
 122                                                                                                                 'attemptstepid', 'sequencenumber', 'state', 'fraction',
 123                                                                                                                                                  'timecreated', 'userid', 'name', 'value'),
 124              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo',              null, 1256233700, 1,       null, null),
 125          ));
 126  
 127          question_bank::start_unit_test();
 128          $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
 129          question_bank::end_unit_test();
 130  
 131          $missingq = question_bank::get_qtype('missingtype')->make_deleted_instance(-1, 2);
 132          $this->assertEquals($missingq, $qa->get_question(false));
 133  
 134          $this->assertEquals(1, $qa->get_num_steps());
 135  
 136          $step = $qa->get_step(0);
 137          $this->assertEquals(question_state::$todo, $step->get_state());
 138          $this->assertNull($step->get_fraction());
 139          $this->assertEquals(1256233700, $step->get_timecreated());
 140          $this->assertEquals(1, $step->get_user_id());
 141          $this->assertEquals(array(), $step->get_all_data());
 142      }
 143  
 144      public function test_load_with_autosaved_data() {
 145          $records = new question_test_recordset(array(
 146              array('questionattemptid', 'contextid', 'questionusageid', 'slot',
 147                                     'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'maxfraction', 'flagged',
 148                                                                                         'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
 149                                                                                                               'attemptstepid', 'sequencenumber', 'state', 'fraction',
 150                                                                                                                                                  'timecreated', 'userid', 'name', 'value'),
 151              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 4, -3, 'complete',          null, 1256233715, 1,   'answer',  '1'),
 152              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 1,  0, 'todo',              null, 1256233700, 1,       null, null),
 153              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 2,  1, 'complete',          null, 1256233705, 1,   'answer',  '1'),
 154              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 1, '', '', '', 1256233790, 3,  2, 'complete',          null, 1256233710, 1,   'answer',  '0'),
 155          ));
 156  
 157          $question = test_question_maker::make_question('truefalse', 'true');
 158          $question->id = -1;
 159  
 160          question_bank::start_unit_test();
 161          question_bank::load_test_question_data($question);
 162          $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
 163          question_bank::end_unit_test();
 164  
 165          $this->assertEquals($question->questiontext, $qa->get_question(false)->questiontext);
 166  
 167          $this->assertEquals(4, $qa->get_num_steps());
 168          $this->assertTrue($qa->has_autosaved_step());
 169  
 170          $step = $qa->get_step(0);
 171          $this->assertEquals(question_state::$todo, $step->get_state());
 172          $this->assertNull($step->get_fraction());
 173          $this->assertEquals(1256233700, $step->get_timecreated());
 174          $this->assertEquals(1, $step->get_user_id());
 175          $this->assertEquals(array(), $step->get_all_data());
 176  
 177          $step = $qa->get_step(1);
 178          $this->assertEquals(question_state::$complete, $step->get_state());
 179          $this->assertNull($step->get_fraction());
 180          $this->assertEquals(1256233705, $step->get_timecreated());
 181          $this->assertEquals(1, $step->get_user_id());
 182          $this->assertEquals(array('answer' => '1'), $step->get_all_data());
 183  
 184          $step = $qa->get_step(2);
 185          $this->assertEquals(question_state::$complete, $step->get_state());
 186          $this->assertNull($step->get_fraction());
 187          $this->assertEquals(1256233710, $step->get_timecreated());
 188          $this->assertEquals(1, $step->get_user_id());
 189          $this->assertEquals(array('answer' => '0'), $step->get_all_data());
 190  
 191          $step = $qa->get_step(3);
 192          $this->assertEquals(question_state::$complete, $step->get_state());
 193          $this->assertNull($step->get_fraction());
 194          $this->assertEquals(1256233715, $step->get_timecreated());
 195          $this->assertEquals(1, $step->get_user_id());
 196          $this->assertEquals(array('answer' => '1'), $step->get_all_data());
 197      }
 198  
 199      public function test_load_with_unnecessary_autosaved_data() {
 200          // The point here is that the somehow (probably due to two things
 201          // happening concurrently, we have autosaved data in the database that
 202          // has already been superceded by real data, so it should be ignored.
 203          // There is also a second lot of redundant data to delete.
 204          $records = new question_test_recordset(array(
 205              array('questionattemptid', 'contextid', 'questionusageid', 'slot',
 206                                     'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'maxfraction', 'flagged',
 207                                                                                         'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
 208                                                                                                               'attemptstepid', 'sequencenumber', 'state', 'fraction',
 209                                                                                                                                                  'timecreated', 'userid', 'name', 'value'),
 210              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 5, -2, 'complete',          null, 1256233715, 1,   'answer',  '0'),
 211              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 4, -1, 'complete',          null, 1256233715, 1,   'answer',  '0'),
 212              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 1,  0, 'todo',              null, 1256233700, 1,       null, null),
 213              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 0, '', '', '', 1256233790, 2,  1, 'complete',          null, 1256233705, 1,   'answer',  '1'),
 214              array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1.0000000, 1, '', '', '', 1256233790, 3,  2, 'complete',          null, 1256233710, 1,   'answer',  '0'),
 215          ));
 216  
 217          $question = test_question_maker::make_question('truefalse', 'true');
 218          $question->id = -1;
 219  
 220          question_bank::start_unit_test();
 221          question_bank::load_test_question_data($question);
 222          $observer = new testable_question_engine_unit_of_work(
 223                  question_engine::make_questions_usage_by_activity('unit_test', context_system::instance()));
 224          $qa = question_attempt::load_from_records($records, 1, $observer, 'deferredfeedback');
 225          question_bank::end_unit_test();
 226  
 227          $this->assertEquals($question->questiontext, $qa->get_question(false)->questiontext);
 228  
 229          $this->assertEquals(3, $qa->get_num_steps());
 230          $this->assertFalse($qa->has_autosaved_step());
 231  
 232          $step = $qa->get_step(0);
 233          $this->assertEquals(question_state::$todo, $step->get_state());
 234          $this->assertNull($step->get_fraction());
 235          $this->assertEquals(1256233700, $step->get_timecreated());
 236          $this->assertEquals(1, $step->get_user_id());
 237          $this->assertEquals(array(), $step->get_all_data());
 238  
 239          $step = $qa->get_step(1);
 240          $this->assertEquals(question_state::$complete, $step->get_state());
 241          $this->assertNull($step->get_fraction());
 242          $this->assertEquals(1256233705, $step->get_timecreated());
 243          $this->assertEquals(1, $step->get_user_id());
 244          $this->assertEquals(array('answer' => '1'), $step->get_all_data());
 245  
 246          $step = $qa->get_step(2);
 247          $this->assertEquals(question_state::$complete, $step->get_state());
 248          $this->assertNull($step->get_fraction());
 249          $this->assertEquals(1256233710, $step->get_timecreated());
 250          $this->assertEquals(1, $step->get_user_id());
 251          $this->assertEquals(array('answer' => '0'), $step->get_all_data());
 252  
 253          $this->assertEquals(2, count($observer->get_steps_deleted()));
 254      }
 255  }