Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [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   * Test classes for handling embedded media (audio/video).
  19   *
  20   * @package   core
  21   * @category  test
  22   * @copyright 2012 The Open University
  23   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  require_once (__DIR__ . '/fixtures/testable_core_media_player.php');
  28  
  29  /**
  30   * Test script for media embedding.
  31   */
  32  class core_medialib_testcase extends advanced_testcase {
  33  
  34      /**
  35       * Pre-test setup. Preserves $CFG.
  36       */
  37      public function setUp(): void {
  38          parent::setUp();
  39  
  40          // Reset $CFG and $SERVER.
  41          $this->resetAfterTest();
  42  
  43          // "Install" a fake plugin for testing.
  44          set_config('version', '2016101400', 'media_test');
  45  
  46          // Consistent initial setup: all players disabled.
  47          \core\plugininfo\media::set_enabled_plugins('');
  48  
  49          $_SERVER = array('HTTP_USER_AGENT' => '');
  50          $this->pretend_to_be_safari();
  51      }
  52  
  53      /**
  54       * Sets user agent to Safari.
  55       */
  56      private function pretend_to_be_safari() {
  57          // Pretend to be using Safari browser (must support mp4 for tests to work).
  58          core_useragent::instance(true, 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) ' .
  59                  'AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1');
  60      }
  61  
  62      /**
  63       * Sets user agent to Firefox.
  64       */
  65      private function pretend_to_be_firefox() {
  66          // Pretend to be using Firefox browser (must support ogg for tests to work).
  67          core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 ');
  68      }
  69  
  70      /**
  71       * Test for core_media::get_filename.
  72       */
  73      public function test_get_filename() {
  74          $manager = core_media_manager::instance();
  75  
  76          $this->assertSame('frog.mp4', $manager->get_filename(new moodle_url(
  77                  '/pluginfile.php/312/mod_page/content/7/frog.mp4')));
  78          // This should work even though slasharguments is true, because we want
  79          // it to support 'legacy' links if somebody toggles the option later.
  80          $this->assertSame('frog.mp4', $manager->get_filename(new moodle_url(
  81                  '/pluginfile.php?file=/312/mod_page/content/7/frog.mp4')));
  82      }
  83  
  84      /**
  85       * Test for core_media::get_extension.
  86       */
  87      public function test_get_extension() {
  88          $manager = core_media_manager::instance();
  89  
  90          $this->assertSame('mp4', $manager->get_extension(new moodle_url(
  91                  '/pluginfile.php/312/mod_page/content/7/frog.mp4')));
  92          $this->assertSame('', $manager->get_extension(new moodle_url(
  93                  '/pluginfile.php/312/mod_page/content/7/frog')));
  94          $this->assertSame('mp4', $manager->get_extension(new moodle_url(
  95                  '/pluginfile.php?file=/312/mod_page/content/7/frog.mp4')));
  96          $this->assertSame('', $manager->get_extension(new moodle_url(
  97                  '/pluginfile.php?file=/312/mod_page/content/7/frog')));
  98      }
  99  
 100      /**
 101       * Test for the core_media_player list_supported_urls.
 102       */
 103      public function test_list_supported_urls() {
 104          $test = new media_test_plugin(1, 13, ['tst', 'test']);
 105  
 106          // Some example URLs.
 107          $supported1 = new moodle_url('http://example.org/1.test');
 108          $supported2 = new moodle_url('http://example.org/2.TST');
 109          $unsupported = new moodle_url('http://example.org/2.jpg');
 110  
 111          // No URLs => none.
 112          $result = $test->list_supported_urls(array());
 113          $this->assertEquals(array(), $result);
 114  
 115          // One supported URL => same.
 116          $result = $test->list_supported_urls(array($supported1));
 117          $this->assertEquals(array($supported1), $result);
 118  
 119          // Two supported URLS => same.
 120          $result = $test->list_supported_urls(array($supported1, $supported2));
 121          $this->assertEquals(array($supported1, $supported2), $result);
 122  
 123          // One unsupported => none.
 124          $result = $test->list_supported_urls(array($unsupported));
 125          $this->assertEquals(array(), $result);
 126  
 127          // Two supported and one unsupported => same.
 128          $result = $test->list_supported_urls(array($supported2, $unsupported, $supported1));
 129          $this->assertEquals(array($supported2, $supported1), $result);
 130      }
 131  
 132      /**
 133       * Test for get_players
 134       */
 135      public function test_get_players() {
 136          // All players are initially disabled (except link, which you can't).
 137          $manager = core_media_manager::instance();
 138          $this->assertEmpty($this->get_players_test($manager));
 139  
 140          // A couple enabled, check the order.
 141          \core\plugininfo\media::set_enabled_plugins('youtube,html5audio');
 142          $manager = core_media_manager::instance();
 143          $this->assertSame('youtube, html5audio', $this->get_players_test($manager));
 144  
 145          // Test SWF and HTML5 media order.
 146          \core\plugininfo\media::set_enabled_plugins('html5video,html5audio,swf');
 147          $manager = core_media_manager::instance();
 148          $this->assertSame('html5video, html5audio, swf', $this->get_players_test($manager));
 149  
 150          // Make sure that our test plugin is considered installed.
 151          \core\plugininfo\media::set_enabled_plugins('test,html5video');
 152          $manager = core_media_manager::instance();
 153          $this->assertSame('test, html5video', $this->get_players_test($manager));
 154  
 155          // Make sure that non-existing plugin is NOT considered installed.
 156          \core\plugininfo\media::set_enabled_plugins('nonexistingplugin,html5video');
 157          $manager = core_media_manager::instance();
 158          $this->assertSame('html5video', $this->get_players_test($manager));
 159      }
 160  
 161      /**
 162       * Test for can_embed_url
 163       */
 164      public function test_can_embed_url() {
 165          // All players are initially disabled, so mp4 cannot be rendered.
 166          $url = new moodle_url('http://example.org/test.mp4');
 167          $manager = core_media_manager::instance();
 168          $this->assertFalse($manager->can_embed_url($url));
 169  
 170          // Enable VideoJS player.
 171          \core\plugininfo\media::set_enabled_plugins('videojs');
 172          $manager = core_media_manager::instance();
 173          $this->assertTrue($manager->can_embed_url($url));
 174  
 175          // VideoJS + html5.
 176          \core\plugininfo\media::set_enabled_plugins('videojs,html5video');
 177          $manager = core_media_manager::instance();
 178          $this->assertTrue($manager->can_embed_url($url));
 179  
 180          // Only html5.
 181          \core\plugininfo\media::set_enabled_plugins('html5video');
 182          $manager = core_media_manager::instance();
 183          $this->assertTrue($manager->can_embed_url($url));
 184  
 185          // Only SWF.
 186          \core\plugininfo\media::set_enabled_plugins('swf');
 187          $manager = core_media_manager::instance();
 188          $this->assertFalse($manager->can_embed_url($url));
 189      }
 190  
 191      /**
 192       * Test for embed_url.
 193       * Checks multiple format/fallback support.
 194       */
 195      public function test_embed_url_fallbacks() {
 196  
 197          // Key strings in the embed code that identify with the media formats being tested.
 198          $swf = '</object>';
 199          $html5video = '</video>';
 200          $html5audio = '</audio>';
 201          $link = 'mediafallbacklink';
 202          $test = 'mediaplugin_test';
 203  
 204          $url = new moodle_url('http://example.org/test.mp4');
 205  
 206          // All plugins disabled, NOLINK option.
 207          \core\plugininfo\media::set_enabled_plugins('');
 208          $manager = core_media_manager::instance();
 209          $t = $manager->embed_url($url, 0, 0, '',
 210                  array(core_media_manager::OPTION_NO_LINK => true));
 211          // Completely empty.
 212          $this->assertSame('', $t);
 213  
 214          // All plugins disabled but not NOLINK.
 215          \core\plugininfo\media::set_enabled_plugins('');
 216          $manager = core_media_manager::instance();
 217          $t = $manager->embed_url($url);
 218          $this->assertStringContainsString($link, $t);
 219  
 220          // Enable media players that can play the same media formats. (ie. test & html5audio for mp3 files, etc.)
 221          \core\plugininfo\media::set_enabled_plugins('test,html5video,html5audio,swf');
 222          $manager = core_media_manager::instance();
 223  
 224          // Test media formats that can be played by 2 or more players.
 225          $mediaformats = array('mp3', 'mp4');
 226  
 227          foreach ($mediaformats as $format) {
 228              $url = new moodle_url('http://example.org/test.' . $format);
 229              $textwithlink = $manager->embed_url($url);
 230              $textwithoutlink = $manager->embed_url($url, 0, 0, '', array(core_media_manager::OPTION_NO_LINK => true));
 231  
 232              switch ($format) {
 233                  case 'mp3':
 234                      $this->assertStringContainsString($test, $textwithlink);
 235                      $this->assertStringNotContainsString($html5video, $textwithlink);
 236                      $this->assertStringContainsString($html5audio, $textwithlink);
 237                      $this->assertStringNotContainsString($swf, $textwithlink);
 238                      $this->assertStringContainsString($link, $textwithlink);
 239  
 240                      $this->assertStringContainsString($test, $textwithoutlink);
 241                      $this->assertStringNotContainsString($html5video, $textwithoutlink);
 242                      $this->assertStringContainsString($html5audio, $textwithoutlink);
 243                      $this->assertStringNotContainsString($swf, $textwithoutlink);
 244                      $this->assertStringNotContainsString($link, $textwithoutlink);
 245                      break;
 246  
 247                  case 'mp4':
 248                      $this->assertStringContainsString($test, $textwithlink);
 249                      $this->assertStringContainsString($html5video, $textwithlink);
 250                      $this->assertStringNotContainsString($html5audio, $textwithlink);
 251                      $this->assertStringNotContainsString($swf, $textwithlink);
 252                      $this->assertStringContainsString($link, $textwithlink);
 253  
 254                      $this->assertStringContainsString($test, $textwithoutlink);
 255                      $this->assertStringContainsString($html5video, $textwithoutlink);
 256                      $this->assertStringNotContainsString($html5audio, $textwithoutlink);
 257                      $this->assertStringNotContainsString($swf, $textwithoutlink);
 258                      $this->assertStringNotContainsString($link, $textwithoutlink);
 259                      break;
 260  
 261                  default:
 262                      break;
 263              }
 264          }
 265      }
 266  
 267      /**
 268       * Test for embed_url.
 269       * Check SWF works including the special option required to enable it
 270       */
 271      public function test_embed_url_swf() {
 272          \core\plugininfo\media::set_enabled_plugins('swf');
 273          $manager = core_media_manager::instance();
 274  
 275          // Without any options...
 276          $url = new moodle_url('http://example.org/test.swf');
 277          $t = $manager->embed_url($url);
 278          $this->assertStringNotContainsString('</object>', $t);
 279  
 280          // ...and with the 'no it's safe, I checked it' option.
 281          $url = new moodle_url('http://example.org/test.swf');
 282          $t = $manager->embed_url($url, '', 0, 0, array(core_media_manager::OPTION_TRUSTED => true));
 283          $this->assertStringContainsString('</object>', $t);
 284      }
 285  
 286      /**
 287       * Same as test_embed_url MP3 test, but for slash arguments.
 288       */
 289      public function test_slash_arguments() {
 290  
 291          // Again we do not turn slasharguments actually on, because it has to
 292          // work regardless of the setting of that variable in case of handling
 293          // links created using previous setting.
 294  
 295          // Enable player.
 296          \core\plugininfo\media::set_enabled_plugins('html5audio');
 297          $manager = core_media_manager::instance();
 298  
 299          // Format: mp3.
 300          $url = new moodle_url('http://example.org/pluginfile.php?file=x/y/z/test.mp3');
 301          $t = $manager->embed_url($url);
 302          $this->assertStringContainsString('</audio>', $t);
 303      }
 304  
 305      /**
 306       * Test for embed_url.
 307       * Checks the EMBED_OR_BLANK option.
 308       */
 309      public function test_embed_or_blank() {
 310          \core\plugininfo\media::set_enabled_plugins('html5audio');
 311          $manager = core_media_manager::instance();
 312          $this->pretend_to_be_firefox();
 313  
 314          $options = array(core_media_manager::OPTION_FALLBACK_TO_BLANK => true);
 315  
 316          // Embed that does match something should still include the link too.
 317          $url = new moodle_url('http://example.org/test.ogg');
 318          $t = $manager->embed_url($url, '', 0, 0, $options);
 319          $this->assertStringContainsString('</audio>', $t);
 320          $this->assertStringContainsString('mediafallbacklink', $t);
 321  
 322          // Embed that doesn't match something should be totally blank.
 323          $url = new moodle_url('http://example.org/test.mp4');
 324          $t = $manager->embed_url($url, '', 0, 0, $options);
 325          $this->assertSame('', $t);
 326      }
 327  
 328      /**
 329       * Test for embed_url.
 330       * Checks that size is passed through correctly to player objects and tests
 331       * size support in html5video output.
 332       */
 333      public function test_embed_url_size() {
 334          global $CFG;
 335  
 336          // Technically this could break in every format and they handle size
 337          // in several different ways, but I'm too lazy to test it in every
 338          // format, so let's just pick one to check the values get passed
 339          // through.
 340          \core\plugininfo\media::set_enabled_plugins('html5video');
 341          $manager = core_media_manager::instance();
 342          $url = new moodle_url('http://example.org/test.mp4');
 343  
 344          // HTML5 default size - specifies core width and does not specify height.
 345          $t = $manager->embed_url($url);
 346          $this->assertStringContainsString('width="' . $CFG->media_default_width . '"', $t);
 347          $this->assertStringNotContainsString('height', $t);
 348  
 349          // HTML5 specified size - specifies both.
 350          $t = $manager->embed_url($url, '', '666', '101');
 351          $this->assertStringContainsString('width="666"', $t);
 352          $this->assertStringContainsString('height="101"', $t);
 353  
 354          // HTML5 size specified in url, overrides call.
 355          $url = new moodle_url('http://example.org/test.mp4?d=123x456');
 356          $t = $manager->embed_url($url, '', '666', '101');
 357          $this->assertStringContainsString('width="123"', $t);
 358          $this->assertStringContainsString('height="456"', $t);
 359      }
 360  
 361      /**
 362       * Test for embed_url.
 363       * Checks that name is passed through correctly to player objects and tests
 364       * name support in html5video output.
 365       */
 366      public function test_embed_url_name() {
 367          // As for size this could break in every format but I'm only testing
 368          // html5video.
 369          \core\plugininfo\media::set_enabled_plugins('html5video');
 370          $manager = core_media_manager::instance();
 371          $url = new moodle_url('http://example.org/test.mp4');
 372  
 373          // HTML5 default name - use filename.
 374          $t = $manager->embed_url($url);
 375          $this->assertStringContainsString('title="test.mp4"', $t);
 376  
 377          // HTML5 specified name - check escaping.
 378          $t = $manager->embed_url($url, 'frog & toad');
 379          $this->assertStringContainsString('title="frog &amp; toad"', $t);
 380      }
 381  
 382      /**
 383       * Test for split_alternatives.
 384       */
 385      public function test_split_alternatives() {
 386          $mediamanager = core_media_manager::instance();
 387  
 388          // Single URL - identical moodle_url.
 389          $mp4 = 'http://example.org/test.mp4';
 390          $result = $mediamanager->split_alternatives($mp4, $w, $h);
 391          $this->assertEquals($mp4, $result[0]->out(false));
 392  
 393          // Width and height weren't specified.
 394          $this->assertEquals(0, $w);
 395          $this->assertEquals(0, $h);
 396  
 397          // Two URLs - identical moodle_urls.
 398          $webm = 'http://example.org/test.webm';
 399          $result = $mediamanager->split_alternatives("$mp4#$webm", $w, $h);
 400          $this->assertEquals($mp4, $result[0]->out(false));
 401          $this->assertEquals($webm, $result[1]->out(false));
 402  
 403          // Two URLs plus dimensions.
 404          $size = 'd=400x280';
 405          $result = $mediamanager->split_alternatives("$mp4#$webm#$size", $w, $h);
 406          $this->assertEquals($mp4, $result[0]->out(false));
 407          $this->assertEquals($webm, $result[1]->out(false));
 408          $this->assertEquals(400, $w);
 409          $this->assertEquals(280, $h);
 410  
 411          // Two URLs plus legacy dimensions (use last one).
 412          $result = $mediamanager->split_alternatives("$mp4?d=1x1#$webm?$size", $w, $h);
 413          $this->assertEquals($mp4, $result[0]->out(false));
 414          $this->assertEquals($webm, $result[1]->out(false));
 415          $this->assertEquals(400, $w);
 416          $this->assertEquals(280, $h);
 417      }
 418  
 419      /**
 420       * Test for embed_alternatives (with multiple urls)
 421       */
 422      public function test_embed_alternatives() {
 423          // Most aspects of this are same as single player so let's just try
 424          // a single typical / complicated scenario.
 425  
 426          // MP4, OGV, WebM and FLV.
 427          $urls = array(
 428              new moodle_url('http://example.org/test.mp4'),
 429              new moodle_url('http://example.org/test.ogv'),
 430              new moodle_url('http://example.org/test.webm'),
 431              new moodle_url('http://example.org/test.flv'),
 432          );
 433  
 434          // Enable html5 and "test" ("test" first).
 435          \core\plugininfo\media::set_enabled_plugins('test,html5video');
 436          $manager = core_media_manager::instance();
 437  
 438          // Result should contain HTML5 with two sources + FLV.
 439          $t = $manager->embed_alternatives($urls);
 440  
 441          // HTML5 sources - mp4, but not ogv, flv or webm (not supported in Safari).
 442          $this->assertStringContainsString('<source src="http://example.org/test.mp4"', $t);
 443          $this->assertStringNotContainsString('<source src="http://example.org/test.ogv"', $t);
 444          $this->assertStringNotContainsString('<source src="http://example.org/test.webm"', $t);
 445          $this->assertStringNotContainsString('<source src="http://example.org/test.flv"', $t);
 446  
 447          // FLV is before the video tag (indicating html5 is used as fallback to flv
 448          // and not vice versa).
 449          $this->assertTrue((bool)preg_match('~mediaplugin_test.*<video~s', $t));
 450  
 451          // Do same test with firefox and check we get the webm and not mp4.
 452          $this->pretend_to_be_firefox();
 453          $t = $manager->embed_alternatives($urls);
 454  
 455          // HTML5 sources - mp4, ogv and webm, but not flv.
 456          $this->assertStringContainsString('<source src="http://example.org/test.mp4"', $t);
 457          $this->assertStringContainsString('<source src="http://example.org/test.ogv"', $t);
 458          $this->assertStringContainsString('<source src="http://example.org/test.webm"', $t);
 459          $this->assertStringNotContainsString('<source src="http://example.org/test.flv"', $t);
 460      }
 461  
 462      /**
 463       * Make sure the instance() method returns singleton for the same page and different object for another page
 464       */
 465      public function test_initialise() {
 466          $moodlepage1 = new moodle_page();
 467  
 468          $mediamanager1 = core_media_manager::instance($moodlepage1);
 469          $mediamanager2 = core_media_manager::instance($moodlepage1);
 470  
 471          $this->assertSame($mediamanager1, $mediamanager2);
 472  
 473          $moodlepage3 = new moodle_page();
 474          $mediamanager3 = core_media_manager::instance($moodlepage3);
 475  
 476          $this->assertNotSame($mediamanager1, $mediamanager3);
 477      }
 478  
 479  
 480      /**
 481       * Access list of players as string, shortening it by getting rid of
 482       * repeated text.
 483       * @param core_media_manager $manager The core_media_manager instance
 484       * @return string Comma-separated list of players
 485       */
 486      public function get_players_test($manager) {
 487          $method = new ReflectionMethod("core_media_manager", "get_players");
 488          $method->setAccessible(true);
 489          $players = $method->invoke($manager);
 490          $out = '';
 491          foreach ($players as $player) {
 492              if ($out) {
 493                  $out .= ', ';
 494              }
 495              $out .= str_replace('core_media_player_', '', preg_replace('/^media_(.*)_plugin$/', '$1', get_class($player)));
 496          }
 497          return $out;
 498      }
 499  }