Search moodle.org's
Developer Documentation

See Release Notes

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

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