Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 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  namespace mod_choice;
  18  
  19  use externallib_advanced_testcase;
  20  use mod_choice_external;
  21  
  22  defined('MOODLE_INTERNAL') || die();
  23  
  24  global $CFG;
  25  
  26  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  27  require_once($CFG->dirroot . '/mod/choice/lib.php');
  28  
  29  /**
  30   * External choice functions unit tests
  31   *
  32   * @package    mod_choice
  33   * @category   external
  34   * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
  35   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class externallib_test extends externallib_advanced_testcase {
  38  
  39      /**
  40       * Test get_choice_results
  41       */
  42      public function test_get_choice_results() {
  43          global $DB;
  44  
  45          $this->resetAfterTest(true);
  46  
  47          $course = self::getDataGenerator()->create_course();
  48          $params = new \stdClass();
  49          $params->course = $course->id;
  50          $params->option = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
  51          $params->name = 'First Choice Activity';
  52          $params->showresults = CHOICE_SHOWRESULTS_AFTER_ANSWER;
  53          $params->publish = 1;
  54          $params->allowmultiple = 1;
  55          $params->showunanswered = 1;
  56          $choice = self::getDataGenerator()->create_module('choice', $params);
  57  
  58          $cm = get_coursemodule_from_id('choice', $choice->cmid);
  59          $choiceinstance = choice_get_choice($cm->instance);
  60          $options = array_keys($choiceinstance->option);
  61          $student1 = $this->getDataGenerator()->create_user();
  62          $student2 = $this->getDataGenerator()->create_user();
  63          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
  64  
  65          // Enroll Students in Course1.
  66          self::getDataGenerator()->enrol_user($student1->id,  $course->id, $studentrole->id);
  67          self::getDataGenerator()->enrol_user($student2->id,  $course->id, $studentrole->id);
  68  
  69          $this->setUser($student1);
  70          $myanswer = $options[2];
  71          choice_user_submit_response($myanswer, $choice, $student1->id, $course, $cm);
  72          $results = mod_choice_external::get_choice_results($choice->id);
  73          // We need to execute the return values cleaning process to simulate the web service server.
  74          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
  75  
  76          // Create an array with optionID as Key.
  77          $resultsarr = array();
  78          foreach ($results['options'] as $option) {
  79              $resultsarr[$option['id']] = $option['userresponses'];
  80          }
  81          // The stundent1 is the userid who choosed the myanswer(option 3).
  82          $this->assertEquals($resultsarr[$myanswer][0]['userid'], $student1->id);
  83          // The stundent2 is the userid who didn't answered yet.
  84          $this->assertEquals($resultsarr[0][0]['userid'], $student2->id);
  85  
  86          // As Stundent2 we cannot see results (until we answered).
  87          $this->setUser($student2);
  88          $results = mod_choice_external::get_choice_results($choice->id);
  89          // We need to execute the return values cleaning process to simulate the web service server.
  90          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
  91          // We do not retrieve any response!
  92          foreach ($results['options'] as $option) {
  93              $this->assertCount(0, $option['userresponses']);
  94          }
  95  
  96          $timenow = time();
  97          // We can see results only after activity close (even if we didn't answered).
  98          $choice->showresults = CHOICE_SHOWRESULTS_AFTER_CLOSE;
  99          // Set timeopen and timeclose in the past.
 100          $choice->timeopen = $timenow - (60 * 60 * 24 * 3);
 101          $choice->timeclose = $timenow + (60 * 60 * 24 * 2);
 102          $DB->update_record('choice', $choice);
 103  
 104          $results = mod_choice_external::get_choice_results($choice->id);
 105          // We need to execute the return values cleaning process to simulate the web service server.
 106          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
 107          // We do not retrieve any response (activity is still open).
 108          foreach ($results['options'] as $option) {
 109              $this->assertCount(0, $option['userresponses']);
 110          }
 111  
 112          // We close the activity (setting timeclose in the past).
 113          $choice->timeclose = $timenow - (60 * 60 * 24 * 2);
 114          $DB->update_record('choice', $choice);
 115          // Now as Stundent2 we will see results!
 116          $results = mod_choice_external::get_choice_results($choice->id);
 117          // We need to execute the return values cleaning process to simulate the web service server.
 118          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
 119          // Create an array with optionID as Key.
 120          $resultsarr = array();
 121          foreach ($results['options'] as $option) {
 122              $resultsarr[$option['id']] = $option['userresponses'];
 123          }
 124          // The stundent1 is the userid who choosed the myanswer(option 3).
 125          $this->assertEquals($resultsarr[$myanswer][0]['userid'], $student1->id);
 126          // The stundent2 is the userid who didn't answered yet.
 127          $this->assertEquals($resultsarr[0][0]['userid'], $student2->id);
 128  
 129          // Do not publish user names!
 130          $choice->publish = 0;
 131          $DB->update_record('choice', $choice);
 132          $results = mod_choice_external::get_choice_results($choice->id);
 133          // We need to execute the return values cleaning process to simulate the web service server.
 134          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
 135          // Create an array with optionID as Key.
 136          $resultsarr = array();
 137          // Does not show any user response!
 138          foreach ($results['options'] as $option) {
 139              $this->assertCount(0, $option['userresponses']);
 140              $resultsarr[$option['id']] = $option;
 141          }
 142          // But we can see totals and percentages.
 143          $this->assertEquals(1, $resultsarr[$myanswer]['numberofuser']);
 144      }
 145  
 146      /**
 147       * Test get_choice_options
 148       */
 149      public function test_get_choice_options() {
 150          global $DB;
 151  
 152          // Warningcodes.
 153          $notopenyet = 1;
 154          $previewonly = 2;
 155          $expired = 3;
 156  
 157          $this->resetAfterTest(true);
 158          $timenow = time();
 159          $timeopen = $timenow + (60 * 60 * 24 * 2);
 160          $timeclose = $timenow + (60 * 60 * 24 * 7);
 161          $course = self::getDataGenerator()->create_course();
 162          $possibleoptions = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
 163          $params = array();
 164          $params['course'] = $course->id;
 165          $params['option'] = $possibleoptions;
 166          $params['name'] = 'First Choice Activity';
 167          $params['showpreview'] = 0;
 168  
 169          $generator = $this->getDataGenerator()->get_plugin_generator('mod_choice');
 170          $choice = $generator->create_instance($params);
 171  
 172          $student1 = $this->getDataGenerator()->create_user();
 173          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 174          // Enroll Students in Course.
 175          self::getDataGenerator()->enrol_user($student1->id,  $course->id, $studentrole->id);
 176          $this->setUser($student1);
 177  
 178          $results = mod_choice_external::get_choice_options($choice->id);
 179          // We need to execute the return values cleaning process to simulate the web service server.
 180          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
 181          // We should retrieve all options.
 182          $this->assertCount(count($possibleoptions), $results['options']);
 183  
 184          // Here we force timeopen/close in the future.
 185          $choice->timeopen = $timeopen;
 186          $choice->timeclose = $timeclose;
 187          $DB->update_record('choice', $choice);
 188  
 189          $results = mod_choice_external::get_choice_options($choice->id);
 190          // We need to execute the return values cleaning process to simulate the web service server.
 191          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
 192          // We should retrieve no options.
 193          $this->assertCount(0, $results['options']);
 194          $this->assertEquals($notopenyet, $results['warnings'][0]['warningcode']);
 195  
 196          // Here we see the options because of preview!
 197          $choice->showpreview = 1;
 198          $DB->update_record('choice', $choice);
 199          $results = mod_choice_external::get_choice_options($choice->id);
 200          // We need to execute the return values cleaning process to simulate the web service server.
 201          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
 202          // We should retrieve all options.
 203          $this->assertCount(count($possibleoptions), $results['options']);
 204  
 205          foreach ($results['options'] as $option) {
 206              // Each option is disabled as this is only the preview!
 207              $this->assertEquals(1, $option['disabled']);
 208          }
 209          $warnings = array();
 210          foreach ($results['warnings'] as $warning) {
 211              $warnings[$warning['warningcode']] = $warning['message'];
 212          }
 213          $this->assertTrue(isset($warnings[$previewonly]));
 214          $this->assertTrue(isset($warnings[$notopenyet]));
 215  
 216          // Simulate activity as opened!
 217          $choice->timeopen = $timenow - (60 * 60 * 24 * 3);
 218          $choice->timeclose = $timenow + (60 * 60 * 24 * 2);
 219          $DB->update_record('choice', $choice);
 220          $cm = get_coursemodule_from_id('choice', $choice->cmid);
 221          $choiceinstance = choice_get_choice($cm->instance);
 222          $optionsids = array_keys($choiceinstance->option);
 223          $myanswerid = $optionsids[2];
 224          choice_user_submit_response($myanswerid, $choice, $student1->id, $course, $cm);
 225  
 226          $results = mod_choice_external::get_choice_options($choice->id);
 227          // We need to execute the return values cleaning process to simulate the web service server.
 228          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
 229          // We should retrieve all options.
 230          $this->assertCount(count($possibleoptions), $results['options']);
 231          foreach ($results['options'] as $option) {
 232              // When we answered and we cannot update our choice.
 233              if ($option['id'] == $myanswerid and !$choice->allowupdate) {
 234                  $this->assertEquals(1, $option['disabled']);
 235                  $this->assertEquals(1, $option['checked']);
 236              } else {
 237                  $this->assertEquals(0, $option['disabled']);
 238              }
 239          }
 240  
 241          // Set timeopen and timeclose as older than today!
 242          // We simulate what happens when the activity is closed.
 243          $choice->timeopen = $timenow - (60 * 60 * 24 * 3);
 244          $choice->timeclose = $timenow - (60 * 60 * 24 * 2);
 245          $DB->update_record('choice', $choice);
 246          $results = mod_choice_external::get_choice_options($choice->id);
 247          // We need to execute the return values cleaning process to simulate the web service server.
 248          $results = \external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
 249          // We should retrieve no options.
 250          $this->assertCount(0, $results['options']);
 251          $this->assertEquals($expired, $results['warnings'][0]['warningcode']);
 252  
 253      }
 254  
 255      /**
 256       * Test submit_choice_response
 257       */
 258      public function test_submit_choice_response() {
 259          global $DB;
 260  
 261          $this->resetAfterTest(true);
 262  
 263          $course = self::getDataGenerator()->create_course();
 264          $params = new \stdClass();
 265          $params->course = $course->id;
 266          $params->option = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
 267          $params->name = 'First Choice Activity';
 268          $params->showresults = CHOICE_SHOWRESULTS_ALWAYS;
 269          $params->allowmultiple = 1;
 270          $params->showunanswered = 1;
 271          $choice = self::getDataGenerator()->create_module('choice', $params);
 272          $cm = get_coursemodule_from_id('choice', $choice->cmid);
 273          $choiceinstance = choice_get_choice($cm->instance);
 274          $options = array_keys($choiceinstance->option);
 275          $student1 = $this->getDataGenerator()->create_user();
 276          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 277  
 278          // Enroll Students in Course1.
 279          self::getDataGenerator()->enrol_user($student1->id,  $course->id, $studentrole->id);
 280  
 281          $this->setUser($student1);
 282          $myresponse = $options[2];
 283          $results = mod_choice_external::submit_choice_response($choice->id, array($myresponse));
 284          // We need to execute the return values cleaning process to simulate the web service server.
 285          $results = \external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
 286          $myanswers = $DB->get_records('choice_answers', array('choiceid' => $choice->id, 'userid' => $student1->id));
 287          $myanswer = reset($myanswers);
 288          $this->assertEquals($results['answers'][0]['id'], $myanswer->id);
 289          $this->assertEquals($results['answers'][0]['choiceid'], $myanswer->choiceid);
 290          $this->assertEquals($results['answers'][0]['userid'], $myanswer->userid);
 291          $this->assertEquals($results['answers'][0]['timemodified'], $myanswer->timemodified);
 292      }
 293  
 294      /**
 295       * Test view_choice
 296       */
 297      public function test_view_choice() {
 298          global $DB;
 299  
 300          $this->resetAfterTest(true);
 301  
 302          // Setup test data.
 303          $course = $this->getDataGenerator()->create_course();
 304          $choice = $this->getDataGenerator()->create_module('choice', array('course' => $course->id));
 305          $context = \context_module::instance($choice->cmid);
 306          $cm = get_coursemodule_from_instance('choice', $choice->id);
 307  
 308          // Test invalid instance id.
 309          try {
 310              mod_choice_external::view_choice(0);
 311              $this->fail('Exception expected due to invalid mod_choice instance id.');
 312          } catch (\moodle_exception $e) {
 313              $this->assertEquals('invalidcoursemodule', $e->errorcode);
 314          }
 315  
 316          // Test not-enrolled user.
 317          $user = self::getDataGenerator()->create_user();
 318          $this->setUser($user);
 319          try {
 320              mod_choice_external::view_choice($choice->id);
 321              $this->fail('Exception expected due to not enrolled user.');
 322          } catch (\moodle_exception $e) {
 323              $this->assertEquals('requireloginerror', $e->errorcode);
 324          }
 325  
 326          // Test user with full capabilities.
 327          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 328          $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
 329  
 330          // Trigger and capture the event.
 331          $sink = $this->redirectEvents();
 332  
 333          $result = mod_choice_external::view_choice($choice->id);
 334          $result = \external_api::clean_returnvalue(mod_choice_external::view_choice_returns(), $result);
 335  
 336          $events = $sink->get_events();
 337          $this->assertCount(1, $events);
 338          $event = array_shift($events);
 339  
 340          // Checking that the event contains the expected values.
 341          $this->assertInstanceOf('\mod_choice\event\course_module_viewed', $event);
 342          $this->assertEquals($context, $event->get_context());
 343          $moodlechoice = new \moodle_url('/mod/choice/view.php', array('id' => $cm->id));
 344          $this->assertEquals($moodlechoice, $event->get_url());
 345          $this->assertEventContextNotUsed($event);
 346          $this->assertNotEmpty($event->get_name());
 347  
 348      }
 349  
 350      /**
 351       * Test get_choices_by_courses
 352       */
 353      public function test_get_choices_by_courses() {
 354          global $DB;
 355          $this->resetAfterTest(true);
 356          // As admin.
 357          $this->setAdminUser();
 358          $course1 = self::getDataGenerator()->create_course();
 359          $choiceoptions1 = array(
 360            'course' => $course1->id,
 361            'name' => 'First IMSCP'
 362          );
 363          $choice1 = self::getDataGenerator()->create_module('choice', $choiceoptions1);
 364          $course2 = self::getDataGenerator()->create_course();
 365  
 366          $choiceoptions2 = array(
 367            'course' => $course2->id,
 368            'name' => 'Second IMSCP'
 369          );
 370          $choice2 = self::getDataGenerator()->create_module('choice', $choiceoptions2);
 371          $student1 = $this->getDataGenerator()->create_user();
 372  
 373          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 374  
 375          // Enroll Student1 in Course1.
 376          self::getDataGenerator()->enrol_user($student1->id,  $course1->id, $studentrole->id);
 377  
 378          $this->setUser($student1);
 379          $choices = mod_choice_external::get_choices_by_courses(array());
 380          $choices = \external_api::clean_returnvalue(mod_choice_external::get_choices_by_courses_returns(), $choices);
 381          $this->assertCount(1, $choices['choices']);
 382          $this->assertEquals('First IMSCP', $choices['choices'][0]['name']);
 383          // As Student you cannot see some IMSCP properties like 'section'.
 384          $this->assertFalse(isset($choices['choices'][0]['section']));
 385  
 386          // Student1 is not enrolled in this Course.
 387          // The webservice will give a warning!
 388          $choices = mod_choice_external::get_choices_by_courses(array($course2->id));
 389          $choices = \external_api::clean_returnvalue(mod_choice_external::get_choices_by_courses_returns(), $choices);
 390          $this->assertCount(0, $choices['choices']);
 391          $this->assertEquals(1, $choices['warnings'][0]['warningcode']);
 392  
 393          // Now as admin.
 394          $this->setAdminUser();
 395          // As Admin we can see this IMSCP.
 396          $choices = mod_choice_external::get_choices_by_courses(array($course2->id));
 397          $choices = \external_api::clean_returnvalue(mod_choice_external::get_choices_by_courses_returns(), $choices);
 398          $this->assertCount(1, $choices['choices']);
 399          $this->assertEquals('Second IMSCP', $choices['choices'][0]['name']);
 400          // As an Admin you can see some IMSCP properties like 'section'.
 401          $this->assertEquals(0, $choices['choices'][0]['section']);
 402  
 403          // Now, prohibit capabilities.
 404          $this->setUser($student1);
 405          $contextcourse1 = \context_course::instance($course1->id);
 406          // Prohibit capability = mod:choice:choose on Course1 for students.
 407          assign_capability('mod/choice:choose', CAP_PROHIBIT, $studentrole->id, $contextcourse1->id);
 408          accesslib_clear_all_caches_for_unit_testing();
 409  
 410          $choices = mod_choice_external::get_choices_by_courses(array($course1->id));
 411          $choices = \external_api::clean_returnvalue(mod_choice_external::get_choices_by_courses_returns(), $choices);
 412          $this->assertFalse(isset($choices['choices'][0]['timeopen']));
 413      }
 414  
 415      /**
 416       * Test delete_choice_responses
 417       */
 418      public function test_delete_choice_responses() {
 419          global $DB;
 420  
 421          $this->resetAfterTest(true);
 422  
 423          $course = self::getDataGenerator()->create_course();
 424          $params = new \stdClass();
 425          $params->course = $course->id;
 426          $params->option = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
 427          $params->name = 'First Choice Activity';
 428          $params->showresults = CHOICE_SHOWRESULTS_ALWAYS;
 429          $params->allowmultiple = 1;
 430          $params->showunanswered = 1;
 431          $choice = self::getDataGenerator()->create_module('choice', $params);
 432          $cm = get_coursemodule_from_id('choice', $choice->cmid);
 433  
 434          $choiceinstance = choice_get_choice($cm->instance);
 435          $options = array_keys($choiceinstance->option);
 436  
 437          $student = $this->getDataGenerator()->create_user();
 438          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 439  
 440          // Enroll student in Course1.
 441          self::getDataGenerator()->enrol_user($student->id,  $course->id, $studentrole->id);
 442  
 443          $this->setUser($student);
 444          $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
 445          $results = \external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
 446  
 447          $myresponses = array_keys(choice_get_my_response($choice));
 448  
 449          // Try to delete responses when allow update is false.
 450          try {
 451              mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[0]));
 452              $this->fail('Exception expected due to missing permissions.');
 453          } catch (\required_capability_exception $e) {
 454              $this->assertEquals('nopermissions', $e->errorcode);
 455          }
 456  
 457          // Set allow update to true, and a passed time close.
 458          $DB->set_field('choice', 'allowupdate', 1, array('id' => $choice->id));
 459          $DB->set_field('choice', 'timeclose', time() - DAYSECS, array('id' => $choice->id));
 460          try {
 461              mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[1]));
 462              $this->fail('Exception expected due to expired choice.');
 463          } catch (\moodle_exception $e) {
 464              $this->assertEquals('expired', $e->errorcode);
 465          }
 466  
 467          // Reset time close. We should be able now to delete all the responses.
 468          $DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
 469          $results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[1]));
 470          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 471  
 472          $this->assertTrue($results['status']);
 473          $this->assertCount(0, $results['warnings']);
 474          // Now, in the DB 0 responses.
 475          $this->assertCount(0, choice_get_my_response($choice));
 476  
 477          // Submit again the responses.
 478          $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
 479          $results = \external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
 480  
 481          $myresponses = array_keys(choice_get_my_response($choice));
 482          // Delete only one response.
 483          $results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0]));
 484          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 485          $this->assertTrue($results['status']);
 486          $this->assertCount(0, $results['warnings']);
 487          // Now, in the DB 1 response still.
 488          $this->assertCount(1, choice_get_my_response($choice));
 489  
 490          // Delete the remaining response, passing 2 invalid responses ids.
 491          $results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[1], $myresponses[0] + 2,
 492                                                                  $myresponses[0] + 3));
 493          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 494          $this->assertTrue($results['status']);
 495          // 2 warnings, 2 invalid responses.
 496          $this->assertCount(2, $results['warnings']);
 497          // Now, in the DB 0 responses.
 498          $this->assertCount(0, choice_get_my_response($choice));
 499  
 500          // Now, as an admin we must be able to delete all the responses under any condition.
 501          $this->setUser($student);
 502          // Submit again the responses.
 503          $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
 504          $results = \external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
 505          $studentresponses = array_keys(choice_get_my_response($choice));
 506  
 507          $this->setAdminUser();
 508          $DB->set_field('choice', 'allowupdate', 0, array('id' => $choice->id));
 509          $DB->set_field('choice', 'timeclose', time() - DAYSECS, array('id' => $choice->id));
 510  
 511          $results = mod_choice_external::delete_choice_responses($choice->id, array($studentresponses[0], $studentresponses[1]));
 512          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 513  
 514          $this->assertTrue($results['status']);
 515          $this->assertCount(0, $results['warnings']);
 516  
 517          // Submit again the responses.
 518          $this->setUser($student);
 519          $DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
 520          $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
 521          $results = \external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
 522  
 523          // Test admin try to delete his own responses (he didn't respond so nothing should be deleted).
 524          $this->setAdminUser();
 525          $results = mod_choice_external::delete_choice_responses($choice->id);
 526          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 527          $this->assertFalse($results['status']);
 528          $this->assertCount(0, $results['warnings']);
 529          $allresponses = choice_get_all_responses($choice);
 530          $this->assertCount(2, $allresponses);   // No responses deleted (admin didn't submit any).
 531  
 532          // Now admin submit a couple of responses more.
 533          $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
 534          $results = \external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
 535          $allresponses = choice_get_all_responses($choice);
 536          $this->assertCount(4, $allresponses);
 537          // Admin responses are deleted when passing an empty array.
 538          $results = mod_choice_external::delete_choice_responses($choice->id);
 539          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 540          $this->assertTrue($results['status']);
 541          $this->assertCount(0, $results['warnings']);
 542          $allresponses = choice_get_all_responses($choice);
 543          $this->assertCount(2, $allresponses);
 544  
 545          // Now admin will delete all the other users responses.
 546          $results = mod_choice_external::delete_choice_responses($choice->id, array_keys($allresponses));
 547          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 548  
 549          $this->assertTrue($results['status']);
 550          $this->assertCount(0, $results['warnings']);
 551          $allresponses = choice_get_all_responses($choice);
 552          $this->assertCount(0, $allresponses);   // Now all the responses were deleted.
 553  
 554          // Admin try do delete an invalid response.
 555          $results = mod_choice_external::delete_choice_responses($choice->id, array(-1));
 556          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 557  
 558          $this->assertFalse($results['status']);
 559          $this->assertCount(1, $results['warnings']);
 560  
 561          // Now, in the DB 0 responses.
 562          $this->setUser($student);
 563  
 564          // Submit again respones.
 565          $DB->set_field('choice', 'allowupdate', 1, array('id' => $choice->id));
 566          $DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
 567          $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
 568          $results = \external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
 569  
 570          // Delete all responses.
 571          $results = mod_choice_external::delete_choice_responses($choice->id);
 572          $results = \external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
 573  
 574          $this->assertTrue($results['status']);
 575          $this->assertCount(0, $results['warnings']);
 576          $this->assertCount(0, choice_get_my_response($choice));
 577  
 578      }
 579  }