Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  • Differences Between: [Versions 37 and 311] [Versions 38 and 311]

       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  }