2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Test classes for handling embedded media (audio/video).
22 * @copyright 2012 The Open University
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') ||
die();
29 * Test script for media embedding.
31 class core_medialib_testcase
extends advanced_testcase
{
34 * Pre-test setup. Preserves $CFG.
36 public function setUp() {
39 // Reset $CFG and $SERVER.
40 $this->resetAfterTest();
42 // "Install" a fake plugin for testing.
43 set_config('version', '2016101400', 'media_test');
45 // Consistent initial setup: all players disabled.
46 \core\plugininfo\media
::set_enabled_plugins('');
48 $_SERVER = array('HTTP_USER_AGENT' => '');
49 $this->pretend_to_be_safari();
53 * Sets user agent to Safari.
55 private function pretend_to_be_safari() {
56 // Pretend to be using Safari browser (must support mp4 for tests to work).
57 core_useragent
::instance(true, 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) ' .
58 'AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1');
62 * Sets user agent to Firefox.
64 private function pretend_to_be_firefox() {
65 // Pretend to be using Firefox browser (must support ogg for tests to work).
66 core_useragent
::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 ');
70 * Test for core_media::get_filename.
72 public function test_get_filename() {
73 $manager = core_media_manager
::instance();
75 $this->assertSame('frog.mp4', $manager->get_filename(new moodle_url(
76 '/pluginfile.php/312/mod_page/content/7/frog.mp4')));
77 // This should work even though slasharguments is true, because we want
78 // it to support 'legacy' links if somebody toggles the option later.
79 $this->assertSame('frog.mp4', $manager->get_filename(new moodle_url(
80 '/pluginfile.php?file=/312/mod_page/content/7/frog.mp4')));
84 * Test for core_media::get_extension.
86 public function test_get_extension() {
87 $manager = core_media_manager
::instance();
89 $this->assertSame('mp4', $manager->get_extension(new moodle_url(
90 '/pluginfile.php/312/mod_page/content/7/frog.mp4')));
91 $this->assertSame('', $manager->get_extension(new moodle_url(
92 '/pluginfile.php/312/mod_page/content/7/frog')));
93 $this->assertSame('mp4', $manager->get_extension(new moodle_url(
94 '/pluginfile.php?file=/312/mod_page/content/7/frog.mp4')));
95 $this->assertSame('', $manager->get_extension(new moodle_url(
96 '/pluginfile.php?file=/312/mod_page/content/7/frog')));
100 * Test for the core_media_player list_supported_urls.
102 public function test_list_supported_urls() {
103 $test = new media_test_plugin(1, 13, ['tst', 'test']);
105 // Some example URLs.
106 $supported1 = new moodle_url('http://example.org/1.test');
107 $supported2 = new moodle_url('http://example.org/2.TST');
108 $unsupported = new moodle_url('http://example.org/2.jpg');
111 $result = $test->list_supported_urls(array());
112 $this->assertEquals(array(), $result);
114 // One supported URL => same.
115 $result = $test->list_supported_urls(array($supported1));
116 $this->assertEquals(array($supported1), $result);
118 // Two supported URLS => same.
119 $result = $test->list_supported_urls(array($supported1, $supported2));
120 $this->assertEquals(array($supported1, $supported2), $result);
122 // One unsupported => none.
123 $result = $test->list_supported_urls(array($unsupported));
124 $this->assertEquals(array(), $result);
126 // Two supported and one unsupported => same.
127 $result = $test->list_supported_urls(array($supported2, $unsupported, $supported1));
128 $this->assertEquals(array($supported2, $supported1), $result);
132 * Test for get_players
134 public function test_get_players() {
135 // All players are initially disabled (except link, which you can't).
136 $manager = core_media_manager
::instance();
137 $this->assertEmpty($this->get_players_test($manager));
139 // A couple enabled, check the order.
140 \core\plugininfo\media
::set_enabled_plugins('youtube,html5audio');
141 $manager = core_media_manager
::instance();
142 $this->assertSame('youtube, html5audio', $this->get_players_test($manager));
144 // Test SWF and HTML5 media order.
145 \core\plugininfo\media
::set_enabled_plugins('html5video,html5audio,swf');
146 $manager = core_media_manager
::instance();
147 $this->assertSame('html5video, html5audio, swf', $this->get_players_test($manager));
149 // Make sure that our test plugin is considered installed.
150 \core\plugininfo\media
::set_enabled_plugins('test,html5video');
151 $manager = core_media_manager
::instance();
152 $this->assertSame('test, html5video', $this->get_players_test($manager));
154 // Make sure that non-existing plugin is NOT considered installed.
155 \core\plugininfo\media
::set_enabled_plugins('nonexistingplugin,html5video');
156 $manager = core_media_manager
::instance();
157 $this->assertSame('html5video', $this->get_players_test($manager));
161 * Test for can_embed_url
163 public function test_can_embed_url() {
164 // All players are initially disabled, so mp4 cannot be rendered.
165 $url = new moodle_url('http://example.org/test.mp4');
166 $manager = core_media_manager
::instance();
167 $this->assertFalse($manager->can_embed_url($url));
169 // Enable VideoJS player.
170 \core\plugininfo\media
::set_enabled_plugins('videojs');
171 $manager = core_media_manager
::instance();
172 $this->assertTrue($manager->can_embed_url($url));
175 \core\plugininfo\media
::set_enabled_plugins('videojs,html5video');
176 $manager = core_media_manager
::instance();
177 $this->assertTrue($manager->can_embed_url($url));
180 \core\plugininfo\media
::set_enabled_plugins('html5video');
181 $manager = core_media_manager
::instance();
182 $this->assertTrue($manager->can_embed_url($url));
185 \core\plugininfo\media
::set_enabled_plugins('swf');
186 $manager = core_media_manager
::instance();
187 $this->assertFalse($manager->can_embed_url($url));
191 * Test for embed_url.
192 * Checks multiple format/fallback support.
194 public function test_embed_url_fallbacks() {
196 // Key strings in the embed code that identify with the media formats being tested.
198 $html5video = '</video>';
199 $html5audio = '</audio>';
200 $link = 'mediafallbacklink';
201 $test = 'mediaplugin_test';
203 $url = new moodle_url('http://example.org/test.mp4');
205 // All plugins disabled, NOLINK option.
206 \core\plugininfo\media
::set_enabled_plugins('');
207 $manager = core_media_manager
::instance();
208 $t = $manager->embed_url($url, 0, 0, '',
209 array(core_media_manager
::OPTION_NO_LINK
=> true));
211 $this->assertSame('', $t);
213 // All plugins disabled but not NOLINK.
214 \core\plugininfo\media
::set_enabled_plugins('');
215 $manager = core_media_manager
::instance();
216 $t = $manager->embed_url($url);
217 $this->assertContains($link, $t);
219 // Enable media players that can play the same media formats. (ie. test & html5audio for mp3 files, etc.)
220 \core\plugininfo\media
::set_enabled_plugins('test,html5video,html5audio,swf');
221 $manager = core_media_manager
::instance();
223 // Test media formats that can be played by 2 or more players.
224 $mediaformats = array('mp3', 'mp4');
226 foreach ($mediaformats as $format) {
227 $url = new moodle_url('http://example.org/test.' . $format);
228 $textwithlink = $manager->embed_url($url);
229 $textwithoutlink = $manager->embed_url($url, 0, 0, '', array(core_media_manager
::OPTION_NO_LINK
=> true));
233 $this->assertContains($test, $textwithlink);
234 $this->assertNotContains($html5video, $textwithlink);
235 $this->assertContains($html5audio, $textwithlink);
236 $this->assertNotContains($swf, $textwithlink);
237 $this->assertContains($link, $textwithlink);
239 $this->assertContains($test, $textwithoutlink);
240 $this->assertNotContains($html5video, $textwithoutlink);
241 $this->assertContains($html5audio, $textwithoutlink);
242 $this->assertNotContains($swf, $textwithoutlink);
243 $this->assertNotContains($link, $textwithoutlink);
247 $this->assertContains($test, $textwithlink);
248 $this->assertContains($html5video, $textwithlink);
249 $this->assertNotContains($html5audio, $textwithlink);
250 $this->assertNotContains($swf, $textwithlink);
251 $this->assertContains($link, $textwithlink);
253 $this->assertContains($test, $textwithoutlink);
254 $this->assertContains($html5video, $textwithoutlink);
255 $this->assertNotContains($html5audio, $textwithoutlink);
256 $this->assertNotContains($swf, $textwithoutlink);
257 $this->assertNotContains($link, $textwithoutlink);
267 * Test for embed_url.
268 * Check SWF works including the special option required to enable it
270 public function test_embed_url_swf() {
271 \core\plugininfo\media
::set_enabled_plugins('swf');
272 $manager = core_media_manager
::instance();
274 // Without any options...
275 $url = new moodle_url('http://example.org/test.swf');
276 $t = $manager->embed_url($url);
277 $this->assertNotContains('</object>', $t);
279 // ...and with the 'no it's safe, I checked it' option.
280 $url = new moodle_url('http://example.org/test.swf');
281 $t = $manager->embed_url($url, '', 0, 0, array(core_media_manager
::OPTION_TRUSTED
=> true));
282 $this->assertContains('</object>', $t);
286 * Same as test_embed_url MP3 test, but for slash arguments.
288 public function test_slash_arguments() {
290 // Again we do not turn slasharguments actually on, because it has to
291 // work regardless of the setting of that variable in case of handling
292 // links created using previous setting.
295 \core\plugininfo\media
::set_enabled_plugins('html5audio');
296 $manager = core_media_manager
::instance();
299 $url = new moodle_url('http://example.org/pluginfile.php?file=x/y/z/test.mp3');
300 $t = $manager->embed_url($url);
301 $this->assertContains('</audio>', $t);
305 * Test for embed_url.
306 * Checks the EMBED_OR_BLANK option.
308 public function test_embed_or_blank() {
309 \core\plugininfo\media
::set_enabled_plugins('html5audio');
310 $manager = core_media_manager
::instance();
311 $this->pretend_to_be_firefox();
313 $options = array(core_media_manager
::OPTION_FALLBACK_TO_BLANK
=> true);
315 // Embed that does match something should still include the link too.
316 $url = new moodle_url('http://example.org/test.ogg');
317 $t = $manager->embed_url($url, '', 0, 0, $options);
318 $this->assertContains('</audio>', $t);
319 $this->assertContains('mediafallbacklink', $t);
321 // Embed that doesn't match something should be totally blank.
322 $url = new moodle_url('http://example.org/test.mp4');
323 $t = $manager->embed_url($url, '', 0, 0, $options);
324 $this->assertSame('', $t);
328 * Test for embed_url.
329 * Checks that size is passed through correctly to player objects and tests
330 * size support in html5video output.
332 public function test_embed_url_size() {
335 // Technically this could break in every format and they handle size
336 // in several different ways, but I'm too lazy to test it in every
337 // format, so let's just pick one to check the values get passed
339 \core\plugininfo\media
::set_enabled_plugins('html5video');
340 $manager = core_media_manager
::instance();
341 $url = new moodle_url('http://example.org/test.mp4');
343 // HTML5 default size - specifies core width and does not specify height.
344 $t = $manager->embed_url($url);
345 $this->assertContains('width="' . $CFG->media_default_width
. '"', $t);
346 $this->assertNotContains('height', $t);
348 // HTML5 specified size - specifies both.
349 $t = $manager->embed_url($url, '', '666', '101');
350 $this->assertContains('width="666"', $t);
351 $this->assertContains('height="101"', $t);
353 // HTML5 size specified in url, overrides call.
354 $url = new moodle_url('http://example.org/test.mp4?d=123x456');
355 $t = $manager->embed_url($url, '', '666', '101');
356 $this->assertContains('width="123"', $t);
357 $this->assertContains('height="456"', $t);
361 * Test for embed_url.
362 * Checks that name is passed through correctly to player objects and tests
363 * name support in html5video output.
365 public function test_embed_url_name() {
366 // As for size this could break in every format but I'm only testing
368 \core\plugininfo\media
::set_enabled_plugins('html5video');
369 $manager = core_media_manager
::instance();
370 $url = new moodle_url('http://example.org/test.mp4');
372 // HTML5 default name - use filename.
373 $t = $manager->embed_url($url);
374 $this->assertContains('title="test.mp4"', $t);
376 // HTML5 specified name - check escaping.
377 $t = $manager->embed_url($url, 'frog & toad');
378 $this->assertContains('title="frog & toad"', $t);
382 * Test for split_alternatives.
384 public function test_split_alternatives() {
385 $mediamanager = core_media_manager
::instance();
387 // Single URL - identical moodle_url.
388 $mp4 = 'http://example.org/test.mp4';
389 $result = $mediamanager->split_alternatives($mp4, $w, $h);
390 $this->assertEquals($mp4, $result[0]->out(false));
392 // Width and height weren't specified.
393 $this->assertEquals(0, $w);
394 $this->assertEquals(0, $h);
396 // Two URLs - identical moodle_urls.
397 $webm = 'http://example.org/test.webm';
398 $result = $mediamanager->split_alternatives("$mp4#$webm", $w, $h);
399 $this->assertEquals($mp4, $result[0]->out(false));
400 $this->assertEquals($webm, $result[1]->out(false));
402 // Two URLs plus dimensions.
404 $result = $mediamanager->split_alternatives("$mp4#$webm#$size", $w, $h);
405 $this->assertEquals($mp4, $result[0]->out(false));
406 $this->assertEquals($webm, $result[1]->out(false));
407 $this->assertEquals(400, $w);
408 $this->assertEquals(280, $h);
410 // Two URLs plus legacy dimensions (use last one).
411 $result = $mediamanager->split_alternatives("$mp4?d=1x1#$webm?$size", $w, $h);
412 $this->assertEquals($mp4, $result[0]->out(false));
413 $this->assertEquals($webm, $result[1]->out(false));
414 $this->assertEquals(400, $w);
415 $this->assertEquals(280, $h);
419 * Test for embed_alternatives (with multiple urls)
421 public function test_embed_alternatives() {
422 // Most aspects of this are same as single player so let's just try
423 // a single typical / complicated scenario.
425 // MP4, OGV, WebM and FLV.
427 new moodle_url('http://example.org/test.mp4'),
428 new moodle_url('http://example.org/test.ogv'),
429 new moodle_url('http://example.org/test.webm'),
430 new moodle_url('http://example.org/test.flv'),
433 // Enable html5 and "test" ("test" first).
434 \core\plugininfo\media
::set_enabled_plugins('test,html5video');
435 $manager = core_media_manager
::instance();
437 // Result should contain HTML5 with two sources + FLV.
438 $t = $manager->embed_alternatives($urls);
440 // HTML5 sources - mp4, but not ogv, flv or webm (not supported in Safari).
441 $this->assertContains('<source src="http://example.org/test.mp4"', $t);
442 $this->assertNotContains('<source src="http://example.org/test.ogv"', $t);
443 $this->assertNotContains('<source src="http://example.org/test.webm"', $t);
444 $this->assertNotContains('<source src="http://example.org/test.flv"', $t);
446 // FLV is before the video tag (indicating html5 is used as fallback to flv
447 // and not vice versa).
448 $this->assertTrue((bool)preg_match('~mediaplugin_test.*<video~s', $t));
450 // Do same test with firefox and check we get the webm and not mp4.
451 $this->pretend_to_be_firefox();
452 $t = $manager->embed_alternatives($urls);
454 // HTML5 sources - mp4, ogv and webm, but not flv.
455 $this->assertContains('<source src="http://example.org/test.mp4"', $t);
456 $this->assertContains('<source src="http://example.org/test.ogv"', $t);
457 $this->assertContains('<source src="http://example.org/test.webm"', $t);
458 $this->assertNotContains('<source src="http://example.org/test.flv"', $t);
462 * Make sure the instance() method returns singleton for the same page and different object for another page
464 public function test_initialise() {
465 $moodlepage1 = new moodle_page();
467 $mediamanager1 = core_media_manager
::instance($moodlepage1);
468 $mediamanager2 = core_media_manager
::instance($moodlepage1);
470 $this->assertSame($mediamanager1, $mediamanager2);
472 $moodlepage3 = new moodle_page();
473 $mediamanager3 = core_media_manager
::instance($moodlepage3);
475 $this->assertNotSame($mediamanager1, $mediamanager3);
480 * Access list of players as string, shortening it by getting rid of
482 * @param core_media_manager $manager The core_media_manager instance
483 * @return string Comma-separated list of players
485 public function get_players_test($manager) {
486 $method = new ReflectionMethod("core_media_manager", "get_players");
487 $method->setAccessible(true);
488 $players = $method->invoke($manager);
490 foreach ($players as $player) {
494 $out .= str_replace('core_media_player_', '', preg_replace('/^media_(.*)_plugin$/', '$1', get_class($player)));
501 * Media player stub for testing purposes.
503 class media_test_plugin
extends core_media_player
{
504 /** @var array Array of supported extensions */
506 /** @var int Player rank */
508 /** @var int Arbitrary number */
512 * @param int $num Number (used in output)
513 * @param int $rank Player rank
514 * @param array $ext Array of supported extensions
516 public function __construct($num = 1, $rank = 13, $ext = array('mp3', 'flv', 'f4v', 'mp4')) {
522 public function embed($urls, $name, $width, $height, $options) {
523 self
::pick_video_size($width, $height);
524 $contents = "\ntestsource=". join("\ntestsource=", $urls) .
525 "\ntestname=$name\ntestwidth=$width\ntestheight=$height\n<!--FALLBACK-->\n";
526 return html_writer
::span($contents, 'mediaplugin mediaplugin_test');
529 public function get_supported_extensions() {
533 public function get_rank() {