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 310]

   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   * Data provider tests.
  19   *
  20   * @package    mod_survey
  21   * @category   test
  22   * @copyright  2018 Frédéric Massart
  23   * @author     Frédéric Massart <fred@branchup.tech>
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  global $CFG;
  29  
  30  use core_privacy\tests\provider_testcase;
  31  use core_privacy\local\request\approved_contextlist;
  32  use core_privacy\local\request\approved_userlist;
  33  use core_privacy\local\request\transform;
  34  use core_privacy\local\request\writer;
  35  use mod_survey\privacy\provider;
  36  
  37  require_once($CFG->dirroot . '/mod/survey/lib.php');
  38  
  39  /**
  40   * Data provider testcase class.
  41   *
  42   * @package    mod_survey
  43   * @category   test
  44   * @copyright  2018 Frédéric Massart
  45   * @author     Frédéric Massart <fred@branchup.tech>
  46   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  47   */
  48  class mod_survey_privacy_testcase extends provider_testcase {
  49  
  50      public function setUp() {
  51          global $PAGE;
  52          $this->resetAfterTest();
  53          $PAGE->get_renderer('core');
  54      }
  55  
  56      public function test_get_contexts_for_userid() {
  57          $dg = $this->getDataGenerator();
  58  
  59          $c1 = $dg->create_course();
  60          $c2 = $dg->create_course();
  61          $cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
  62          $cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
  63          $cm1c = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
  64          $cm2a = $dg->create_module('survey', ['template' => 1, 'course' => $c2]);
  65          $cm2b = $dg->create_module('survey', ['template' => 1, 'course' => $c2]);
  66          $u1 = $dg->create_user();
  67          $u2 = $dg->create_user();
  68  
  69          $this->create_answer($cm1a->id, 1, $u1->id);
  70          $this->create_answer($cm1a->id, 1, $u2->id);
  71          $this->create_answer($cm1b->id, 1, $u2->id);
  72          $this->create_answer($cm2a->id, 1, $u1->id);
  73          $this->create_analysis($cm2b->id, $u1->id);
  74          $this->create_analysis($cm1c->id, $u2->id);
  75  
  76          $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
  77          $this->assertCount(3, $contextids);
  78          $this->assertTrue(in_array(context_module::instance($cm1a->cmid)->id, $contextids));
  79          $this->assertTrue(in_array(context_module::instance($cm2a->cmid)->id, $contextids));
  80          $this->assertTrue(in_array(context_module::instance($cm2b->cmid)->id, $contextids));
  81  
  82          $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
  83          $this->assertCount(3, $contextids);
  84          $this->assertTrue(in_array(context_module::instance($cm1a->cmid)->id, $contextids));
  85          $this->assertTrue(in_array(context_module::instance($cm1b->cmid)->id, $contextids));
  86          $this->assertTrue(in_array(context_module::instance($cm1c->cmid)->id, $contextids));
  87      }
  88  
  89      /**
  90       * Test for provider::test_get_users_in_context().
  91       */
  92      public function test_get_users_in_context() {
  93          $dg = $this->getDataGenerator();
  94          $component = 'mod_survey';
  95  
  96          $c1 = $dg->create_course();
  97          $c2 = $dg->create_course();
  98          $cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
  99          $cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
 100          $cm2 = $dg->create_module('survey', ['template' => 1, 'course' => $c2]);
 101          $cm1acontext = context_module::instance($cm1a->cmid);
 102          $cm1bcontext = context_module::instance($cm1b->cmid);
 103          $cm2context = context_module::instance($cm2->cmid);
 104  
 105          $u1 = $dg->create_user();
 106          $u2 = $dg->create_user();
 107          $bothusers = [$u1->id, $u2->id];
 108          sort($bothusers);
 109  
 110          $this->create_answer($cm1a->id, 1, $u1->id);
 111          $this->create_answer($cm1b->id, 1, $u1->id);
 112          $this->create_answer($cm1b->id, 1, $u2->id);
 113          $this->create_answer($cm2->id, 1, $u2->id);
 114          $this->create_analysis($cm2->id, $u1->id);
 115  
 116          // Cm1a should only contain u1.
 117          $userlist = new \core_privacy\local\request\userlist($cm1acontext, $component);
 118          provider::get_users_in_context($userlist);
 119  
 120          $this->assertCount(1, $userlist);
 121          $this->assertEquals([$u1->id], $userlist->get_userids());
 122  
 123          // Cm1b should contain u1 and u2 (both have answers).
 124          $userlist = new \core_privacy\local\request\userlist($cm1bcontext, $component);
 125          provider::get_users_in_context($userlist);
 126  
 127          $this->assertCount(2, $userlist);
 128          $actual = $userlist->get_userids();
 129          sort($actual);
 130          $this->assertEquals($bothusers, $actual);
 131  
 132          // Cm2 should contain u1 (analysis) and u2 (answer).
 133          $userlist = new \core_privacy\local\request\userlist($cm2context, $component);
 134          provider::get_users_in_context($userlist);
 135  
 136          $this->assertCount(2, $userlist);
 137          $actual = $userlist->get_userids();
 138          sort($actual);
 139          $this->assertEquals($bothusers, $actual);
 140      }
 141  
 142      public function test_delete_data_for_all_users_in_context() {
 143          global $DB;
 144          $dg = $this->getDataGenerator();
 145  
 146          $c1 = $dg->create_course();
 147          $cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
 148          $cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
 149          $cm1c = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
 150          $u1 = $dg->create_user();
 151          $u2 = $dg->create_user();
 152  
 153          $this->create_answer($cm1a->id, 1, $u1->id);
 154          $this->create_answer($cm1a->id, 1, $u2->id);
 155          $this->create_answer($cm1b->id, 1, $u2->id);
 156          $this->create_answer($cm1c->id, 1, $u1->id);
 157          $this->create_analysis($cm1a->id, $u1->id);
 158          $this->create_analysis($cm1b->id, $u1->id);
 159          $this->create_analysis($cm1a->id, $u2->id);
 160          $this->create_analysis($cm1c->id, $u2->id);
 161  
 162          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 163          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
 164          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 165          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
 166          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 167          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
 168          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 169          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
 170  
 171          // Deleting the course does nothing.
 172          provider::delete_data_for_all_users_in_context(context_course::instance($c1->id));
 173          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 174          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
 175          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 176          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
 177          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 178          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
 179          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 180          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
 181  
 182          provider::delete_data_for_all_users_in_context(context_module::instance($cm1c->cmid));
 183          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 184          $this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
 185          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 186          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
 187          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 188          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
 189          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 190          $this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
 191  
 192          provider::delete_data_for_all_users_in_context(context_module::instance($cm1a->cmid));
 193          $this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 194          $this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
 195          $this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 196          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
 197          $this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 198          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
 199          $this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 200          $this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
 201      }
 202  
 203      public function test_delete_data_for_user() {
 204          global $DB;
 205          $dg = $this->getDataGenerator();
 206  
 207          $c1 = $dg->create_course();
 208          $cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
 209          $cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
 210          $cm1c = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
 211          $u1 = $dg->create_user();
 212          $u2 = $dg->create_user();
 213  
 214          $this->create_answer($cm1a->id, 1, $u1->id);
 215          $this->create_answer($cm1a->id, 1, $u2->id);
 216          $this->create_answer($cm1b->id, 1, $u2->id);
 217          $this->create_answer($cm1c->id, 1, $u1->id);
 218          $this->create_analysis($cm1a->id, $u1->id);
 219          $this->create_analysis($cm1b->id, $u1->id);
 220          $this->create_analysis($cm1a->id, $u2->id);
 221          $this->create_analysis($cm1c->id, $u2->id);
 222  
 223          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 224          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
 225          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 226          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
 227          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 228          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
 229          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 230          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
 231  
 232          provider::delete_data_for_user(new approved_contextlist($u1, 'mod_survey', [
 233              context_course::instance($c1->id)->id,
 234              context_module::instance($cm1a->cmid)->id,
 235              context_module::instance($cm1b->cmid)->id,
 236          ]));
 237          $this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 238          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
 239          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 240          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
 241          $this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 242          $this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
 243          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 244          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
 245      }
 246  
 247      /**
 248       * Test for provider::delete_data_for_users().
 249       */
 250      public function test_delete_data_for_users() {
 251          global $DB;
 252          $dg = $this->getDataGenerator();
 253          $component = 'mod_survey';
 254  
 255          $c1 = $dg->create_course();
 256          $cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
 257          $cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
 258          $cm1c = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
 259          $cm1acontext = context_module::instance($cm1a->cmid);
 260          $cm1bcontext = context_module::instance($cm1b->cmid);
 261  
 262          $u1 = $dg->create_user();
 263          $u2 = $dg->create_user();
 264  
 265          $this->create_answer($cm1a->id, 1, $u1->id);
 266          $this->create_answer($cm1a->id, 1, $u2->id);
 267          $this->create_analysis($cm1a->id, $u1->id);
 268          $this->create_analysis($cm1a->id, $u2->id);
 269          $this->create_answer($cm1b->id, 1, $u2->id);
 270          $this->create_analysis($cm1b->id, $u1->id);
 271          $this->create_answer($cm1c->id, 1, $u1->id);
 272          $this->create_analysis($cm1c->id, $u2->id);
 273  
 274          // Confirm data exists before deletion.
 275          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 276          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
 277          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 278          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
 279          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 280          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
 281          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 282          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
 283  
 284          // Ensure only approved user data is deleted.
 285          $approveduserids = [$u1->id];
 286          $approvedlist = new approved_userlist($cm1acontext, $component, $approveduserids);
 287          provider::delete_data_for_users($approvedlist);
 288  
 289          $this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 290          $this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
 291          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 292          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
 293  
 294          $approveduserids = [$u1->id, $u2->id];
 295          $approvedlist = new approved_userlist($cm1bcontext, $component, $approveduserids);
 296          provider::delete_data_for_users($approvedlist);
 297  
 298          $this->assertFalse($DB->record_exists('survey_answers', ['survey' => $cm1b->id]));
 299          $this->assertFalse($DB->record_exists('survey_analysis', ['survey' => $cm1b->id]));
 300  
 301          $this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
 302          $this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
 303      }
 304  
 305      public function test_export_data_for_user() {
 306          global $DB;
 307          $dg = $this->getDataGenerator();
 308  
 309          $templates = $DB->get_records_menu('survey', array('template' => 0), 'name', 'name, id');
 310  
 311          $c1 = $dg->create_course();
 312          $s1a = $dg->create_module('survey', ['template' => $templates['attlsname'], 'course' => $c1]);
 313          $s1b = $dg->create_module('survey', ['template' => $templates['ciqname'], 'course' => $c1]);
 314          $s1c = $dg->create_module('survey', ['template' => $templates['collesapname'], 'course' => $c1]);
 315          $u1 = $dg->create_user();
 316          $u2 = $dg->create_user();
 317  
 318          $s1actx = context_module::instance($s1a->cmid);
 319          $s1bctx = context_module::instance($s1b->cmid);
 320          $s1cctx = context_module::instance($s1c->cmid);
 321  
 322          $this->answer_survey($s1a, $u1, $c1, $s1actx);
 323          $this->answer_survey($s1b, $u1, $c1, $s1bctx);
 324          $this->create_analysis($s1a->id, $u1->id, 'Hello,');
 325  
 326          $this->answer_survey($s1a, $u2, $c1, $s1actx);
 327          $this->answer_survey($s1c, $u2, $c1, $s1cctx);
 328          $this->create_analysis($s1b->id, $u2->id, 'World!');
 329  
 330          provider::export_user_data(new approved_contextlist($u1, 'mod_survey', [$s1actx->id, $s1bctx->id, $s1cctx->id]));
 331  
 332          $data = writer::with_context($s1actx)->get_data([]);
 333          $this->assertNotEmpty($data);
 334          $this->assert_exported_answers($data->answers, $u1, $s1a);
 335          $data = writer::with_context($s1actx)->get_related_data([], 'survey_analysis');
 336          $this->assertEquals('Hello,', $data->notes);
 337  
 338          $data = writer::with_context($s1bctx)->get_data([]);
 339          $this->assertNotEmpty($data);
 340          $this->assert_exported_answers($data->answers, $u1, $s1b);
 341          $data = writer::with_context($s1bctx)->get_related_data([], 'survey_analysis');
 342          $this->assertEmpty($data);
 343  
 344          $data = writer::with_context($s1cctx)->get_data([]);
 345          $this->assertEmpty($data);
 346          $data = writer::with_context($s1cctx)->get_related_data([], 'survey_analysis');
 347          $this->assertEmpty($data);
 348  
 349          writer::reset();
 350          provider::export_user_data(new approved_contextlist($u2, 'mod_survey', [$s1actx->id, $s1bctx->id, $s1cctx->id]));
 351  
 352          $data = writer::with_context($s1actx)->get_data([]);
 353          $this->assertNotEmpty($data);
 354          $this->assert_exported_answers($data->answers, $u2, $s1a);
 355          $data = writer::with_context($s1actx)->get_related_data([], 'survey_analysis');
 356          $this->assertEmpty($data);
 357  
 358          $data = writer::with_context($s1bctx)->get_data([]);
 359          $this->assertEmpty($data);
 360          $data = writer::with_context($s1bctx)->get_related_data([], 'survey_analysis');
 361          $this->assertEquals('World!', $data->notes);
 362  
 363          $data = writer::with_context($s1cctx)->get_data([]);
 364          $this->assertNotEmpty($data);
 365          $this->assert_exported_answers($data->answers, $u2, $s1c);
 366          $data = writer::with_context($s1cctx)->get_related_data([], 'survey_analysis');
 367          $this->assertEmpty($data);
 368      }
 369  
 370      /**
 371       * Answer a survey in a predictable manner.
 372       *
 373       * @param stdClass $survey The survey.
 374       * @param stdClass $user The user.
 375       * @param stdClass $course The course.
 376       * @param context_module $context The module context.
 377       * @return void
 378       */
 379      protected function answer_survey($survey, $user, $course, context_module $context) {
 380          global $USER;
 381  
 382          $userid = $user->id;
 383          $questions = survey_get_questions($survey);
 384          $answer = function(&$answers, $q) use ($userid) {
 385              $key = 'q' . ($q->type == 2 ? 'P' : '') . $q->id;
 386  
 387              if ($q->type < 1) {
 388                  $a = "A:{$q->id}:{$userid}";
 389                  $answers[$key] = $a;
 390  
 391              } else if ($q->type < 3) {
 392                  $options = explode(',', get_string($q->options, 'mod_survey'));
 393                  $answers[$key] = ($q->id + $userid) % count($options) + 1;
 394  
 395              } else {
 396                  $options = explode(',', get_string($q->options, 'mod_survey'));
 397                  $answers["q{$q->id}"] = ($q->id + $userid) % count($options) + 1;
 398                  $answers["qP{$q->id}"] = ($q->id + $userid + 1) % count($options) + 1;
 399              }
 400  
 401          };
 402  
 403          foreach ($questions as $q) {
 404              if ($q->type < 0) {
 405                  continue;
 406              } else if ($q->type > 0 && $q->multi) {
 407                  $subquestions = survey_get_subquestions($q);
 408                  foreach ($subquestions as $sq) {
 409                      $answer($answers, $sq);
 410                  }
 411              } else {
 412                  $answer($answers, $q);
 413              }
 414          }
 415  
 416          $origuser = $USER;
 417          $this->setUser($user);
 418          survey_save_answers($survey, $answers, $course, $context);
 419          $this->setUser($origuser);
 420      }
 421  
 422      /**
 423       * Assert the answers provided to a survey.
 424       *
 425       * @param array $answers The answers.
 426       * @param object $user The user.
 427       * @param object $survey The survey.
 428       * @return void
 429       */
 430      protected function assert_exported_answers($answers, $user, $survey) {
 431          global $DB;
 432  
 433          $userid = $user->id;
 434          $questionids = explode(',', $survey->questions);
 435          $topquestions = $DB->get_records_list('survey_questions', 'id', $questionids, 'id');
 436          $questions = [];
 437  
 438          foreach ($topquestions as $q) {
 439              if ($q->type < 0) {
 440                  continue;
 441              } else if ($q->type > 0 && $q->multi) {
 442                  $questionids = explode(',', $q->multi);
 443                  $subqs = $DB->get_records_list('survey_questions', 'id', $questionids, 'id');
 444              } else {
 445                  $subqs = [$q];
 446              }
 447              foreach ($subqs as $sq) {
 448                  $questions[] = $sq;
 449              }
 450          }
 451  
 452          $this->assertCount(count($questions), $answers);
 453  
 454          $answer = reset($answers);
 455          foreach ($questions as $question) {
 456              $qtype = $question->type;
 457              $question = survey_translate_question($question);
 458              $options = $qtype > 0 ? explode(',', $question->options) : '-';
 459              $this->assertEquals($question->text, $answer['question']['text']);
 460              $this->assertEquals($question->shorttext, $answer['question']['shorttext']);
 461              $this->assertEquals($question->intro, $answer['question']['intro']);
 462              $this->assertEquals($options, $answer['question']['options']);
 463  
 464              if ($qtype < 1) {
 465                  $this->assertEquals("A:{$question->id}:{$userid}", $answer['answer']['actual']);
 466  
 467              } else if ($qtype == 1 || $qtype == 2) {
 468                  $chosen = ($question->id + $userid) % count($options);
 469                  $key = $qtype == 1 ? 'actual' : 'preferred';
 470                  $this->assertEquals($options[$chosen], $answer['answer'][$key]);
 471  
 472              } else {
 473                  $chosen = ($question->id + $userid) % count($options);
 474                  $this->assertEquals($options[$chosen], $answer['answer']['actual']);
 475                  $chosen = ($question->id + $userid + 1) % count($options);
 476                  $this->assertEquals($options[$chosen], $answer['answer']['preferred']);
 477              }
 478  
 479              // Grab next answer, if any.
 480              $answer = next($answers);
 481          }
 482  
 483      }
 484  
 485      /**
 486       * Create analysis.
 487       *
 488       * @param int $surveyid The survey ID.
 489       * @param int $userid The user ID.
 490       * @param string $notes The nodes.
 491       * @return stdClass
 492       */
 493      protected function create_analysis($surveyid, $userid, $notes = '') {
 494          global $DB;
 495          $record = (object) [
 496              'survey' => $surveyid,
 497              'userid' => $userid,
 498              'notes' => $notes
 499          ];
 500          $record->id = $DB->insert_record('survey_analysis', $record);
 501          return $record;
 502      }
 503  
 504      /**
 505       * Create answer.
 506       *
 507       * @param int $surveyid The survey ID.
 508       * @param int $questionid The question ID.
 509       * @param int $userid The user ID.
 510       * @param string $answer1 The first answer field.
 511       * @param string $answer2 The second answer field.
 512       * @return stdClass
 513       */
 514      protected function create_answer($surveyid, $questionid, $userid, $answer1 = '', $answer2 = '') {
 515          global $DB;
 516          $record = (object) [
 517              'survey' => $surveyid,
 518              'question' => $questionid,
 519              'userid' => $userid,
 520              'answer1' => $answer1,
 521              'answer2' => $answer2,
 522              'time' => time()
 523          ];
 524          $record->id = $DB->insert_record('survey_answers', $record);
 525          return $record;
 526      }
 527  
 528  }