Merge branch 'MDL-42592_master' of https://github.com/markn86/moodle
[moodle.git] / lib / tests / medialib_test.php
blobeea80f40183e785f270114a93cffb0cd3a255d90
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.
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/>.
17 /**
18 * Test classes for handling embedded media (audio/video).
20 * @package core_media
21 * @category phpunit
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();
28 global $CFG;
29 require_once($CFG->libdir . '/medialib.php');
31 /**
32 * Test script for media embedding.
34 class core_medialib_testcase extends advanced_testcase {
36 /** @var array Files covered by test */
37 public static $includecoverage = array('lib/medialib.php', 'lib/outputrenderers.php');
39 /**
40 * Pre-test setup. Preserves $CFG.
42 public function setUp() {
43 global $CFG;
44 parent::setUp();
46 // Reset $CFG and $SERVER.
47 $this->resetAfterTest();
49 // Consistent initial setup: all players disabled.
50 $CFG->core_media_enable_html5video = false;
51 $CFG->core_media_enable_html5audio = false;
52 $CFG->core_media_enable_mp3 = false;
53 $CFG->core_media_enable_flv = false;
54 $CFG->core_media_enable_wmp = false;
55 $CFG->core_media_enable_qt = false;
56 $CFG->core_media_enable_rm = false;
57 $CFG->core_media_enable_youtube = false;
58 $CFG->core_media_enable_vimeo = false;
59 $CFG->core_media_enable_swf = false;
61 $_SERVER = array('HTTP_USER_AGENT' => '');
62 $this->pretend_to_be_safari();
65 /**
66 * Sets user agent to Safari.
68 private function pretend_to_be_safari() {
69 // Pretend to be using Safari browser (must support mp4 for tests to work).
70 core_useragent::instance(true, 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) ' .
71 'AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1');
74 /**
75 * Sets user agent to Firefox.
77 private function pretend_to_be_firefox() {
78 // Pretend to be using Firefox browser (must support ogg for tests to work).
79 core_useragent::instance(true, 'Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0');
82 /**
83 * Test for the core_media_player is_enabled.
85 public function test_is_enabled() {
86 global $CFG;
88 // Test enabled: unset, 0, 1.
89 $test = new core_media_player_test;
90 $this->assertFalse($test->is_enabled());
91 $CFG->core_media_enable_test = 0;
92 $this->assertFalse($test->is_enabled());
93 $CFG->core_media_enable_test = 1;
94 $this->assertTrue($test->is_enabled());
97 /**
98 * Test for core_media::get_filename.
100 public function test_get_filename() {
101 $this->assertSame('frog.mp4', core_media::get_filename(new moodle_url(
102 '/pluginfile.php/312/mod_page/content/7/frog.mp4')));
103 // This should work even though slasharguments is true, because we want
104 // it to support 'legacy' links if somebody toggles the option later.
105 $this->assertSame('frog.mp4', core_media::get_filename(new moodle_url(
106 '/pluginfile.php?file=/312/mod_page/content/7/frog.mp4')));
110 * Test for core_media::get_extension.
112 public function test_get_extension() {
113 $this->assertSame('mp4', core_media::get_extension(new moodle_url(
114 '/pluginfile.php/312/mod_page/content/7/frog.mp4')));
115 $this->assertSame('', core_media::get_extension(new moodle_url(
116 '/pluginfile.php/312/mod_page/content/7/frog')));
117 $this->assertSame('mp4', core_media::get_extension(new moodle_url(
118 '/pluginfile.php?file=/312/mod_page/content/7/frog.mp4')));
119 $this->assertSame('', core_media::get_extension(new moodle_url(
120 '/pluginfile.php?file=/312/mod_page/content/7/frog')));
124 * Test for the core_media_player list_supported_urls.
126 public function test_list_supported_urls() {
127 global $CFG;
128 $test = new core_media_player_test;
130 // Some example URLs.
131 $supported1 = new moodle_url('http://example.org/1.test');
132 $supported2 = new moodle_url('http://example.org/2.TST');
133 $unsupported = new moodle_url('http://example.org/2.jpg');
135 // No URLs => none.
136 $result = $test->list_supported_urls(array());
137 $this->assertEquals(array(), $result);
139 // One supported URL => same.
140 $result = $test->list_supported_urls(array($supported1));
141 $this->assertEquals(array($supported1), $result);
143 // Two supported URLS => same.
144 $result = $test->list_supported_urls(array($supported1, $supported2));
145 $this->assertEquals(array($supported1, $supported2), $result);
147 // One unsupported => none.
148 $result = $test->list_supported_urls(array($unsupported));
149 $this->assertEquals(array(), $result);
151 // Two supported and one unsupported => same.
152 $result = $test->list_supported_urls(array($supported2, $unsupported, $supported1));
153 $this->assertEquals(array($supported2, $supported1), $result);
157 * Test for core_media_renderer get_players
159 public function test_get_players() {
160 global $CFG, $PAGE;
162 // All players are initially disabled (except link, which you can't).
163 $renderer = new core_media_renderer_test($PAGE, '');
164 $this->assertSame('link', $renderer->get_players_test());
166 // A couple enabled, check the order.
167 $CFG->core_media_enable_html5audio = true;
168 $CFG->core_media_enable_mp3 = true;
169 $renderer = new core_media_renderer_test($PAGE, '');
170 $this->assertSame('mp3, html5audio, link', $renderer->get_players_test());
174 * Test for core_media_renderer can_embed_url
176 public function test_can_embed_url() {
177 global $CFG, $PAGE;
179 // All players are initially disabled, so mp4 cannot be rendered.
180 $url = new moodle_url('http://example.org/test.mp4');
181 $renderer = new core_media_renderer_test($PAGE, '');
182 $this->assertFalse($renderer->can_embed_url($url));
184 // Enable QT player.
185 $CFG->core_media_enable_qt = true;
186 $renderer = new core_media_renderer_test($PAGE, '');
187 $this->assertTrue($renderer->can_embed_url($url));
189 // QT + html5.
190 $CFG->core_media_enable_html5video = true;
191 $renderer = new core_media_renderer_test($PAGE, '');
192 $this->assertTrue($renderer->can_embed_url($url));
194 // Only html5.
195 $CFG->core_media_enable_qt = false;
196 $renderer = new core_media_renderer_test($PAGE, '');
197 $this->assertTrue($renderer->can_embed_url($url));
199 // Only WMP.
200 $CFG->core_media_enable_html5video = false;
201 $CFG->core_media_enable_wmp = true;
202 $renderer = new core_media_renderer_test($PAGE, '');
203 $this->assertFalse($renderer->can_embed_url($url));
207 * Test for core_media_renderer embed_url.
208 * Checks multiple format/fallback support.
210 public function test_embed_url_fallbacks() {
211 global $CFG, $PAGE;
213 $url = new moodle_url('http://example.org/test.mp4');
215 // All plugins disabled, NOLINK option.
216 $renderer = new core_media_renderer_test($PAGE, '');
217 $t = $renderer->embed_url($url, 0, 0, '',
218 array(core_media::OPTION_NO_LINK => true));
219 // Completely empty.
220 $this->assertSame('', $t);
222 // All plugins disabled but not NOLINK.
223 $renderer = new core_media_renderer_test($PAGE, '');
224 $t = $renderer->embed_url($url);
225 $this->assert_contents(false, false, true, $t);
227 // HTML5 plugin enabled.
228 $CFG->core_media_enable_html5video = true;
229 $renderer = new core_media_renderer_test($PAGE, '');
230 $t = $renderer->embed_url($url);
231 $this->assert_contents(false, true, true, $t);
233 // QT plugin enabled as well.
234 $CFG->core_media_enable_qt = true;
235 $renderer = new core_media_renderer_test($PAGE, '');
236 $t = $renderer->embed_url($url);
237 $this->assert_contents(true, true, true, $t);
239 // Nolink turned off, plugins still enabled.
240 $t = $renderer->embed_url($url, 0, 0, '',
241 array(core_media::OPTION_NO_LINK => true));
242 $this->assert_contents(true, true, false, $t);
246 * Checks the contents of the resulting HTML code to ensure it used the
247 * correct embed method(s).
249 * @param bool $hasqt True if it should have QT embed code
250 * @param bool $hashtml5 True if it should have HTML5 embed code
251 * @param bool $haslink True if it should have a fallback link
252 * @param string $text HTML content
254 private function assert_contents($hasqt, $hashtml5, $haslink, $text) {
255 // I tried to avoid making it specific to the exact details of the html
256 // code, picking out only single key strings that would let it check
257 // whether final code contains the right things.
258 $qt = 'qtplugin.cab';
259 $html5 = '</video>';
260 $link = 'mediafallbacklink';
262 if ($hasqt) {
263 $this->assertContains($qt, $text);
264 } else {
265 $this->assertNotContains($qt, $text);
268 if ($hashtml5) {
269 $this->assertContains($html5, $text);
270 } else {
271 $this->assertNotContains($html5, $text);
274 if ($haslink) {
275 $this->assertContains($link, $text);
276 } else {
277 $this->assertNotContains($link, $text);
282 * Test for core_media_renderer embed_url.
283 * Check SWF works including the special option required to enable it
285 public function test_embed_url_swf() {
286 global $CFG, $PAGE;
287 $CFG->core_media_enable_swf = true;
288 $renderer = new core_media_renderer_test($PAGE, '');
290 // Without any options...
291 $url = new moodle_url('http://example.org/test.swf');
292 $t = $renderer->embed_url($url);
293 $this->assertNotContains('</object>', $t);
295 // ...and with the 'no it's safe, I checked it' option.
296 $url = new moodle_url('http://example.org/test.swf');
297 $t = $renderer->embed_url($url, '', 0, 0, array(core_media::OPTION_TRUSTED => true));
298 $this->assertContains('</object>', $t);
302 * Test for core_media_renderer embed_url.
303 * Exercises all the basic formats not covered elsewhere.
305 public function test_embed_url_other_formats() {
306 global $CFG, $PAGE;
308 // Enable all players and get renderer.
309 $CFG->core_media_enable_html5audio = true;
310 $CFG->core_media_enable_mp3 = true;
311 $CFG->core_media_enable_flv = true;
312 $CFG->core_media_enable_wmp = true;
313 $CFG->core_media_enable_rm = true;
314 $CFG->core_media_enable_youtube = true;
315 $CFG->core_media_enable_vimeo = true;
316 $renderer = new core_media_renderer_test($PAGE, '');
318 // Check each format one at a time. This is a basic check to be sure
319 // the HTML is included for files of the right type, not a test that
320 // the HTML itself is correct.
322 // Format: mp3.
323 $url = new moodle_url('http://example.org/test.mp3');
324 $t = $renderer->embed_url($url);
325 $this->assertContains('core_media_mp3_', $t);
327 // Format: flv.
328 $url = new moodle_url('http://example.org/test.flv');
329 $t = $renderer->embed_url($url);
330 $this->assertContains('core_media_flv_', $t);
332 // Format: wmp.
333 $url = new moodle_url('http://example.org/test.avi');
334 $t = $renderer->embed_url($url);
335 $this->assertContains('6BF52A52-394A-11d3-B153-00C04F79FAA6', $t);
337 // Format: rm.
338 $url = new moodle_url('http://example.org/test.rm');
339 $t = $renderer->embed_url($url);
340 $this->assertContains('CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA', $t);
342 // Format: youtube.
343 $url = new moodle_url('http://www.youtube.com/watch?v=vyrwMmsufJc');
344 $t = $renderer->embed_url($url);
345 $this->assertContains('</iframe>', $t);
346 $url = new moodle_url('http://www.youtube.com/v/vyrwMmsufJc');
347 $t = $renderer->embed_url($url);
348 $this->assertContains('</iframe>', $t);
350 // Format: youtube playlist.
351 $url = new moodle_url('http://www.youtube.com/view_play_list?p=PL6E18E2927047B662');
352 $t = $renderer->embed_url($url);
353 $this->assertContains('</iframe>', $t);
354 $url = new moodle_url('http://www.youtube.com/playlist?list=PL6E18E2927047B662');
355 $t = $renderer->embed_url($url);
356 $this->assertContains('</iframe>', $t);
357 $url = new moodle_url('http://www.youtube.com/p/PL6E18E2927047B662');
358 $t = $renderer->embed_url($url);
359 $this->assertContains('</iframe>', $t);
361 // Format: vimeo.
362 $url = new moodle_url('http://vimeo.com/1176321');
363 $t = $renderer->embed_url($url);
364 $this->assertContains('</iframe>', $t);
366 // Format: html5audio.
367 $this->pretend_to_be_firefox();
368 $url = new moodle_url('http://example.org/test.ogg');
369 $t = $renderer->embed_url($url);
370 $this->assertContains('</audio>', $t);
374 * Same as test_embed_url MP3 test, but for slash arguments.
376 public function test_slash_arguments() {
377 global $CFG, $PAGE;
379 // Again we do not turn slasharguments actually on, because it has to
380 // work regardless of the setting of that variable in case of handling
381 // links created using previous setting.
383 // Enable MP3 and get renderer.
384 $CFG->core_media_enable_mp3 = true;
385 $renderer = new core_media_renderer_test($PAGE, '');
387 // Format: mp3.
388 $url = new moodle_url('http://example.org/pluginfile.php?file=x/y/z/test.mp3');
389 $t = $renderer->embed_url($url);
390 $this->assertContains('core_media_mp3_', $t);
394 * Test for core_media_renderer embed_url.
395 * Checks the EMBED_OR_BLANK option.
397 public function test_embed_or_blank() {
398 global $CFG, $PAGE;
399 $CFG->core_media_enable_html5audio = true;
400 $this->pretend_to_be_firefox();
402 $renderer = new core_media_renderer_test($PAGE, '');
404 $options = array(core_media::OPTION_FALLBACK_TO_BLANK => true);
406 // Embed that does match something should still include the link too.
407 $url = new moodle_url('http://example.org/test.ogg');
408 $t = $renderer->embed_url($url, '', 0, 0, $options);
409 $this->assertContains('</audio>', $t);
410 $this->assertContains('mediafallbacklink', $t);
412 // Embed that doesn't match something should be totally blank.
413 $url = new moodle_url('http://example.org/test.mp4');
414 $t = $renderer->embed_url($url, '', 0, 0, $options);
415 $this->assertSame('', $t);
419 * Test for core_media_renderer embed_url.
420 * Checks that size is passed through correctly to player objects and tests
421 * size support in html5video output.
423 public function test_embed_url_size() {
424 global $CFG, $PAGE;
426 // Technically this could break in every format and they handle size
427 // in several different ways, but I'm too lazy to test it in every
428 // format, so let's just pick one to check the values get passed
429 // through.
430 $CFG->core_media_enable_html5video = true;
431 $renderer = new core_media_renderer_test($PAGE, '');
432 $url = new moodle_url('http://example.org/test.mp4');
434 // HTML5 default size - specifies core width and does not specify height.
435 $t = $renderer->embed_url($url);
436 $this->assertContains('width="' . CORE_MEDIA_VIDEO_WIDTH . '"', $t);
437 $this->assertNotContains('height', $t);
439 // HTML5 specified size - specifies both.
440 $t = $renderer->embed_url($url, '', '666', '101');
441 $this->assertContains('width="666"', $t);
442 $this->assertContains('height="101"', $t);
444 // HTML5 size specified in url, overrides call.
445 $url = new moodle_url('http://example.org/test.mp4?d=123x456');
446 $t = $renderer->embed_url($url, '', '666', '101');
447 $this->assertContains('width="123"', $t);
448 $this->assertContains('height="456"', $t);
452 * Test for core_media_renderer embed_url.
453 * Checks that name is passed through correctly to player objects and tests
454 * name support in html5video output.
456 public function test_embed_url_name() {
457 global $CFG, $PAGE;
459 // As for size this could break in every format but I'm only testing
460 // html5video.
461 $CFG->core_media_enable_html5video = true;
462 $renderer = new core_media_renderer_test($PAGE, '');
463 $url = new moodle_url('http://example.org/test.mp4');
465 // HTML5 default name - use filename.
466 $t = $renderer->embed_url($url);
467 $this->assertContains('title="test.mp4"', $t);
469 // HTML5 specified name - check escaping.
470 $t = $renderer->embed_url($url, 'frog & toad');
471 $this->assertContains('title="frog &amp; toad"', $t);
475 * Test for core_media_renderer split_alternatives.
477 public function test_split_alternatives() {
478 // Single URL - identical moodle_url.
479 $mp4 = 'http://example.org/test.mp4';
480 $result = core_media::split_alternatives($mp4, $w, $h);
481 $this->assertEquals($mp4, $result[0]->out(false));
483 // Width and height weren't specified.
484 $this->assertEquals(0, $w);
485 $this->assertEquals(0, $h);
487 // Two URLs - identical moodle_urls.
488 $webm = 'http://example.org/test.webm';
489 $result = core_media::split_alternatives("$mp4#$webm", $w, $h);
490 $this->assertEquals($mp4, $result[0]->out(false));
491 $this->assertEquals($webm, $result[1]->out(false));
493 // Two URLs plus dimensions.
494 $size = 'd=400x280';
495 $result = core_media::split_alternatives("$mp4#$webm#$size", $w, $h);
496 $this->assertEquals($mp4, $result[0]->out(false));
497 $this->assertEquals($webm, $result[1]->out(false));
498 $this->assertEquals(400, $w);
499 $this->assertEquals(280, $h);
501 // Two URLs plus legacy dimensions (use last one).
502 $result = core_media::split_alternatives("$mp4?d=1x1#$webm?$size", $w, $h);
503 $this->assertEquals($mp4, $result[0]->out(false));
504 $this->assertEquals($webm, $result[1]->out(false));
505 $this->assertEquals(400, $w);
506 $this->assertEquals(280, $h);
510 * Test for core_media_renderer embed_alternatives (with multiple urls)
512 public function test_embed_alternatives() {
513 global $PAGE, $CFG;
515 // Most aspects of this are same as single player so let's just try
516 // a single typical / complicated scenario.
518 // MP3, WebM and FLV.
519 $urls = array(
520 new moodle_url('http://example.org/test.mp4'),
521 new moodle_url('http://example.org/test.webm'),
522 new moodle_url('http://example.org/test.flv'),
525 // Enable html5 and flv.
526 $CFG->core_media_enable_html5video = true;
527 $CFG->core_media_enable_flv = true;
528 $renderer = new core_media_renderer_test($PAGE, '');
530 // Result should contain HTML5 with two sources + FLV.
531 $t = $renderer->embed_alternatives($urls);
533 // HTML5 sources - mp4, not flv or webm (not supported in Safari).
534 $this->assertContains('<source src="http://example.org/test.mp4"', $t);
535 $this->assertNotContains('<source src="http://example.org/test.webm"', $t);
536 $this->assertNotContains('<source src="http://example.org/test.flv"', $t);
538 // FLV is before the video tag (indicating html5 is used as fallback to flv
539 // and not vice versa).
540 $this->assertTrue((bool)preg_match('~core_media_flv_.*<video~s', $t));
542 // Do same test with firefox and check we get the webm and not mp4.
543 $this->pretend_to_be_firefox();
544 $t = $renderer->embed_alternatives($urls);
546 // HTML5 sources - webm, not not flv or mp4 (not supported in Firefox).
547 $this->assertNotContains('<source src="http://example.org/test.mp4"', $t);
548 $this->assertContains('<source src="http://example.org/test.webm"', $t);
549 $this->assertNotContains('<source src="http://example.org/test.flv"', $t);
553 * Converts moodle_url array into a single comma-separated string for
554 * easier testing.
556 * @param array $urls Array of moodle_urls
557 * @return string String containing those URLs, comma-separated
559 public static function string_urls($urls) {
560 $out = array();
561 foreach ($urls as $url) {
562 $out[] = $url->out(false);
564 return implode(',', $out);
568 * Converts associative array into a semicolon-separated string for easier
569 * testing.
571 * @param array $options Associative array
572 * @return string String of form 'a=b;c=d'
574 public static function string_options($options) {
575 $out = '';
576 foreach ($options as $key => $value) {
577 if ($out) {
578 $out .= ';';
580 $out .= "$key=$value";
582 return $out;
587 * Media player stub for testing purposes.
589 class core_media_player_test extends core_media_player {
590 /** @var array Array of supported extensions */
591 public $ext;
592 /** @var int Player rank */
593 public $rank;
594 /** @var int Arbitrary number */
595 public $num;
598 * @param int $num Number (used in output)
599 * @param int $rank Player rank
600 * @param array $ext Array of supported extensions
602 public function __construct($num = 1, $rank = 13, $ext = array('tst', 'test')) {
603 $this->ext = $ext;
604 $this->rank = $rank;
605 $this->num = $num;
608 public function embed($urls, $name, $width, $height, $options) {
609 return $this->num . ':' . medialib_test::string_urls($urls) .
610 ",$name,$width,$height,<!--FALLBACK-->," . medialib_test::string_options($options);
613 public function get_supported_extensions() {
614 return $this->ext;
617 public function get_rank() {
618 return $this->rank;
623 * Media renderer override for testing purposes.
625 class core_media_renderer_test extends core_media_renderer {
627 * Access list of players as string, shortening it by getting rid of
628 * repeated text.
629 * @return string Comma-separated list of players
631 public function get_players_test() {
632 $players = $this->get_players();
633 $out = '';
634 foreach ($players as $player) {
635 if ($out) {
636 $out .= ', ';
638 $out .= str_replace('core_media_player_', '', get_class($player));
640 return $out;