d92ba7a464f25b8d46514623023d6cc8fbaacf3d
[moodle.git] / lib / tests / medialib_test.php
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/>.
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  */
26 defined('MOODLE_INTERNAL') || die();
27 require_once(__DIR__ . '/fixtures/testable_core_media_player.php');
29 /**
30  * Test script for media embedding.
31  */
32 class core_medialib_testcase extends advanced_testcase {
34     /**
35      * Pre-test setup. Preserves $CFG.
36      */
37     public function setUp(): void {
38         parent::setUp();
40         // Reset $CFG and $SERVER.
41         $this->resetAfterTest();
43         // "Install" a fake plugin for testing.
44         set_config('version', '2016101400', 'media_test');
46         // Consistent initial setup: all players disabled.
47         \core\plugininfo\media::set_enabled_plugins('');
49         $_SERVER = array('HTTP_USER_AGENT' => '');
50         $this->pretend_to_be_safari();
51     }
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     }
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     }
70     /**
71      * Test for core_media::get_filename.
72      */
73     public function test_get_filename() {
74         $manager = core_media_manager::instance();
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     }
84     /**
85      * Test for core_media::get_extension.
86      */
87     public function test_get_extension() {
88         $manager = core_media_manager::instance();
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     }
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']);
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');
111         // No URLs => none.
112         $result = $test->list_supported_urls(array());
113         $this->assertEquals(array(), $result);
115         // One supported URL => same.
116         $result = $test->list_supported_urls(array($supported1));
117         $this->assertEquals(array($supported1), $result);
119         // Two supported URLS => same.
120         $result = $test->list_supported_urls(array($supported1, $supported2));
121         $this->assertEquals(array($supported1, $supported2), $result);
123         // One unsupported => none.
124         $result = $test->list_supported_urls(array($unsupported));
125         $this->assertEquals(array(), $result);
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     }
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));
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));
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));
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));
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     }
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));
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));
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));
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));
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     }
191     /**
192      * Test for embed_url.
193      * Checks multiple format/fallback support.
194      */
195     public function test_embed_url_fallbacks() {
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';
204         $url = new moodle_url('http://example.org/test.mp4');
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);
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->assertContains($link, $t);
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();
224         // Test media formats that can be played by 2 or more players.
225         $mediaformats = array('mp3', 'mp4');
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));
232             switch ($format) {
233                 case 'mp3':
234                     $this->assertContains($test, $textwithlink);
235                     $this->assertNotContains($html5video, $textwithlink);
236                     $this->assertContains($html5audio, $textwithlink);
237                     $this->assertNotContains($swf, $textwithlink);
238                     $this->assertContains($link, $textwithlink);
240                     $this->assertContains($test, $textwithoutlink);
241                     $this->assertNotContains($html5video, $textwithoutlink);
242                     $this->assertContains($html5audio, $textwithoutlink);
243                     $this->assertNotContains($swf, $textwithoutlink);
244                     $this->assertNotContains($link, $textwithoutlink);
245                     break;
247                 case 'mp4':
248                     $this->assertContains($test, $textwithlink);
249                     $this->assertContains($html5video, $textwithlink);
250                     $this->assertNotContains($html5audio, $textwithlink);
251                     $this->assertNotContains($swf, $textwithlink);
252                     $this->assertContains($link, $textwithlink);
254                     $this->assertContains($test, $textwithoutlink);
255                     $this->assertContains($html5video, $textwithoutlink);
256                     $this->assertNotContains($html5audio, $textwithoutlink);
257                     $this->assertNotContains($swf, $textwithoutlink);
258                     $this->assertNotContains($link, $textwithoutlink);
259                     break;
261                 default:
262                     break;
263             }
264         }
265     }
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();
275         // Without any options...
276         $url = new moodle_url('http://example.org/test.swf');
277         $t = $manager->embed_url($url);
278         $this->assertNotContains('</object>', $t);
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->assertContains('</object>', $t);
284     }
286     /**
287      * Same as test_embed_url MP3 test, but for slash arguments.
288      */
289     public function test_slash_arguments() {
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.
295         // Enable player.
296         \core\plugininfo\media::set_enabled_plugins('html5audio');
297         $manager = core_media_manager::instance();
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->assertContains('</audio>', $t);
303     }
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();
314         $options = array(core_media_manager::OPTION_FALLBACK_TO_BLANK => true);
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->assertContains('</audio>', $t);
320         $this->assertContains('mediafallbacklink', $t);
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     }
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;
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');
344         // HTML5 default size - specifies core width and does not specify height.
345         $t = $manager->embed_url($url);
346         $this->assertContains('width="' . $CFG->media_default_width . '"', $t);
347         $this->assertNotContains('height', $t);
349         // HTML5 specified size - specifies both.
350         $t = $manager->embed_url($url, '', '666', '101');
351         $this->assertContains('width="666"', $t);
352         $this->assertContains('height="101"', $t);
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->assertContains('width="123"', $t);
358         $this->assertContains('height="456"', $t);
359     }
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');
373         // HTML5 default name - use filename.
374         $t = $manager->embed_url($url);
375         $this->assertContains('title="test.mp4"', $t);
377         // HTML5 specified name - check escaping.
378         $t = $manager->embed_url($url, 'frog & toad');
379         $this->assertContains('title="frog &amp; toad"', $t);
380     }
382     /**
383      * Test for split_alternatives.
384      */
385     public function test_split_alternatives() {
386         $mediamanager = core_media_manager::instance();
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));
393         // Width and height weren't specified.
394         $this->assertEquals(0, $w);
395         $this->assertEquals(0, $h);
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));
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);
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     }
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.
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         );
434         // Enable html5 and "test" ("test" first).
435         \core\plugininfo\media::set_enabled_plugins('test,html5video');
436         $manager = core_media_manager::instance();
438         // Result should contain HTML5 with two sources + FLV.
439         $t = $manager->embed_alternatives($urls);
441         // HTML5 sources - mp4, but not ogv, flv or webm (not supported in Safari).
442         $this->assertContains('<source src="http://example.org/test.mp4"', $t);
443         $this->assertNotContains('<source src="http://example.org/test.ogv"', $t);
444         $this->assertNotContains('<source src="http://example.org/test.webm"', $t);
445         $this->assertNotContains('<source src="http://example.org/test.flv"', $t);
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));
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);
455         // HTML5 sources - mp4, ogv and webm, but not flv.
456         $this->assertContains('<source src="http://example.org/test.mp4"', $t);
457         $this->assertContains('<source src="http://example.org/test.ogv"', $t);
458         $this->assertContains('<source src="http://example.org/test.webm"', $t);
459         $this->assertNotContains('<source src="http://example.org/test.flv"', $t);
460     }
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();
468         $mediamanager1 = core_media_manager::instance($moodlepage1);
469         $mediamanager2 = core_media_manager::instance($moodlepage1);
471         $this->assertSame($mediamanager1, $mediamanager2);
473         $moodlepage3 = new moodle_page();
474         $mediamanager3 = core_media_manager::instance($moodlepage3);
476         $this->assertNotSame($mediamanager1, $mediamanager3);
477     }
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     }