Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

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

   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  namespace core_analytics;
  18  
  19  defined('MOODLE_INTERNAL') || die();
  20  
  21  require_once (__DIR__ . '/fixtures/test_indicator_max.php');
  22  require_once (__DIR__ . '/fixtures/test_target_shortname.php');
  23  
  24  /**
  25   * Unit tests for prediction actions.
  26   *
  27   * @package   core_analytics
  28   * @copyright 2017 David MonllaĆ³ {@link http://www.davidmonllao.com}
  29   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   */
  31  class prediction_actions_test extends \advanced_testcase {
  32  
  33      /** @var model Store Model. */
  34      protected $model;
  35  
  36      /** @var \stdClass Store model object. */
  37      protected $modelobj;
  38  
  39      /** @var \stdClass Course 1 record. */
  40      protected $course1;
  41  
  42      /** @var \stdClass Course 2 record. */
  43      protected $course2;
  44  
  45      /** @var \context_course Store Model. */
  46      protected $context;
  47  
  48      /** @var \stdClass Teacher 1 user record. */
  49      protected $teacher1;
  50  
  51      /** @var \stdClass Teacher 2 user record. */
  52      protected $teacher2;
  53  
  54      /** @var \stdClass Teacher 3 user record. */
  55      protected $teacher3;
  56  
  57      /**
  58       * Common startup tasks
  59       */
  60      public function setUp(): void {
  61          global $DB;
  62  
  63          $this->setAdminUser();
  64          $target = \core_analytics\manager::get_target('test_target_shortname');
  65          $indicators = array('test_indicator_max');
  66          foreach ($indicators as $key => $indicator) {
  67              $indicators[$key] = \core_analytics\manager::get_indicator($indicator);
  68          }
  69  
  70          $this->model = \core_analytics\model::create($target, $indicators);
  71          $this->modelobj = $this->model->get_model_obj();
  72          $this->model->enable('\core\analytics\time_splitting\single_range');
  73  
  74          $this->resetAfterTest(true);
  75  
  76          $this->course1 = $this->getDataGenerator()->create_course();
  77          $this->course2 = $this->getDataGenerator()->create_course();
  78          $this->context = \context_course::instance($this->course1->id);
  79  
  80          $this->teacher1 = $this->getDataGenerator()->create_user();
  81          $this->teacher2 = $this->getDataGenerator()->create_user();
  82          $this->teacher3 = $this->getDataGenerator()->create_user();
  83  
  84          $this->getDataGenerator()->enrol_user($this->teacher1->id, $this->course1->id, 'editingteacher');
  85          $this->getDataGenerator()->enrol_user($this->teacher2->id, $this->course1->id, 'editingteacher');
  86          $this->getDataGenerator()->enrol_user($this->teacher3->id, $this->course1->id, 'editingteacher');
  87  
  88          // The only relevant fields are modelid, contextid and sampleid. I'm cheating and setting
  89          // contextid as the course context so teachers can access these predictions.
  90          $pred = new \stdClass();
  91          $pred->modelid = $this->model->get_id();
  92          $pred->contextid = $this->context->id;
  93          $pred->sampleid = $this->course1->id;
  94          $pred->rangeindex = 1;
  95          $pred->prediction = 1;
  96          $pred->predictionscore = 1;
  97          $pred->calculations = json_encode(array('test_indicator_max' => 1));
  98          $pred->timecreated = time();
  99          $DB->insert_record('analytics_predictions', $pred);
 100  
 101          $pred->sampleid = $this->course2->id;
 102          $DB->insert_record('analytics_predictions', $pred);
 103      }
 104  
 105      /**
 106       * test_get_predictions
 107       */
 108      public function test_action_executed() {
 109          global $DB;
 110  
 111          $this->assertEquals(0, $DB->count_records('analytics_prediction_actions'));
 112  
 113          // Teacher 2 flags a prediction (it doesn't matter which one) as fixed.
 114          $this->setUser($this->teacher2);
 115          list($ignored, $predictions) = $this->model->get_predictions($this->context, true);
 116          $prediction = reset($predictions);
 117          $prediction->action_executed(\core_analytics\prediction::ACTION_FIXED, $this->model->get_target());
 118  
 119          $recordset = $this->model->get_prediction_actions($this->context);
 120          $this->assertCount(1, $recordset);
 121          $recordset->close();
 122          $this->assertEquals(1, $DB->count_records('analytics_prediction_actions'));
 123          $action = $DB->get_record('analytics_prediction_actions', array('userid' => $this->teacher2->id));
 124          $this->assertEquals(\core_analytics\prediction::ACTION_FIXED, $action->actionname);
 125  
 126          $prediction->action_executed(\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED, $this->model->get_target());
 127          $recordset = $this->model->get_prediction_actions($this->context);
 128          $this->assertCount(2, $recordset);
 129          $recordset->close();
 130          $this->assertEquals(2, $DB->count_records('analytics_prediction_actions'));
 131      }
 132  
 133      /**
 134       * Data provider for test_get_executed_actions.
 135       *
 136       * @return  array
 137       */
 138      public function execute_actions_provider(): array {
 139          return [
 140              'Empty actions with no filter' => [
 141                  [],
 142                  [],
 143                  0
 144              ],
 145              'Empty actions with filter' => [
 146                  [],
 147                  [\core_analytics\prediction::ACTION_FIXED],
 148                  0
 149              ],
 150              'Multiple actions with no filter' => [
 151                  [
 152                      \core_analytics\prediction::ACTION_FIXED,
 153                      \core_analytics\prediction::ACTION_FIXED,
 154                      \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
 155                  ],
 156                  [],
 157                  3
 158              ],
 159              'Multiple actions applying filter' => [
 160                  [
 161                      \core_analytics\prediction::ACTION_FIXED,
 162                      \core_analytics\prediction::ACTION_FIXED,
 163                      \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
 164                  ],
 165                  [\core_analytics\prediction::ACTION_FIXED],
 166                  2
 167              ],
 168              'Multiple actions not applying filter' => [
 169                  [
 170                      \core_analytics\prediction::ACTION_FIXED,
 171                      \core_analytics\prediction::ACTION_FIXED,
 172                      \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
 173                  ],
 174                  [\core_analytics\prediction::ACTION_NOT_APPLICABLE],
 175                  0
 176              ],
 177              'Multiple actions with multiple filter' => [
 178                  [
 179                      \core_analytics\prediction::ACTION_FIXED,
 180                      \core_analytics\prediction::ACTION_FIXED,
 181                      \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
 182                  ],
 183                  [\core_analytics\prediction::ACTION_FIXED, \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED],
 184                  3
 185              ],
 186          ];
 187      }
 188  
 189      /**
 190       * Tests for get_executed_actions() function.
 191       *
 192       * @dataProvider    execute_actions_provider
 193       * @param   array   $actionstoexecute    An array of actions to execute
 194       * @param   array   $actionnamefilter   Actions to filter
 195       * @param   int     $returned             Number of actions returned
 196       *
 197       * @covers \core_analytics\prediction::get_executed_actions
 198       */
 199      public function test_get_executed_actions(array $actionstoexecute, array $actionnamefilter, int $returned) {
 200  
 201          $this->setUser($this->teacher2);
 202          list($ignored, $predictions) = $this->model->get_predictions($this->context, true);
 203          $prediction = reset($predictions);
 204          $target = $this->model->get_target();
 205          foreach($actionstoexecute as $action) {
 206              $prediction->action_executed($action, $target);
 207          }
 208  
 209          $filteredactions = $prediction->get_executed_actions($actionnamefilter);
 210          $this->assertCount($returned, $filteredactions);
 211      }
 212  
 213      /**
 214       * test_get_predictions
 215       */
 216      public function test_get_predictions() {
 217          global $DB;
 218  
 219          // Already logged in as admin.
 220          list($ignored, $predictions) = $this->model->get_predictions($this->context, true);
 221          $this->assertCount(2, $predictions);
 222  
 223          $this->setUser($this->teacher1);
 224          list($ignored, $predictions) = $this->model->get_predictions($this->context, true);
 225          $this->assertCount(2, $predictions);
 226  
 227          $this->setUser($this->teacher2);
 228          list($ignored, $predictions) = $this->model->get_predictions($this->context, false);
 229          $this->assertCount(2, $predictions);
 230  
 231          // Teacher 2 flags a prediction (it doesn't matter which one).
 232          $prediction = reset($predictions);
 233          $prediction->action_executed(\core_analytics\prediction::ACTION_FIXED, $this->model->get_target());
 234          $prediction->action_executed(\core_analytics\prediction::ACTION_NOT_APPLICABLE, $this->model->get_target());
 235          $prediction->action_executed(\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED, $this->model->get_target());
 236  
 237          $recordset = $this->model->get_prediction_actions($this->context);
 238          $this->assertCount(3, $recordset);
 239          $recordset->close();
 240  
 241          list($ignored, $predictions) = $this->model->get_predictions($this->context, true);
 242          $this->assertCount(1, $predictions);
 243          list($ignored, $predictions) = $this->model->get_predictions($this->context, false);
 244          $this->assertCount(2, $predictions);
 245  
 246          // Teacher 1 can still see both predictions.
 247          $this->setUser($this->teacher1);
 248          list($ignored, $predictions) = $this->model->get_predictions($this->context, true);
 249          $this->assertCount(2, $predictions);
 250          list($ignored, $predictions) = $this->model->get_predictions($this->context, false);
 251          $this->assertCount(2, $predictions);
 252  
 253          $recordset = $this->model->get_prediction_actions($this->context);
 254          $this->assertCount(3, $recordset);
 255          $recordset->close();
 256  
 257          // Trying with a deleted course.
 258          $DB->delete_records('course', ['id' => $this->course2->id]);
 259          $this->setUser($this->teacher3);
 260          list($ignored, $predictions) = $this->model->get_predictions($this->context);
 261          $this->assertCount(1, $predictions);
 262          reset($predictions)->action_executed(\core_analytics\prediction::ACTION_FIXED, $this->model->get_target());
 263          $this->assertEmpty($this->model->get_predictions($this->context));
 264      }
 265  }