player_test.php 16 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Test classes for handling embedded media.
 *
 * @package media_videojs
 * @copyright 2016 Marina Glancy
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

25
26
27
28
29
30
namespace media_videojs;

use core_media_manager;
use html_writer;
use media_videojs_plugin;
use moodle_url;
31
32
33
34
35
36
37
38

/**
 * Test script for media embedding.
 *
 * @package media_videojs
 * @copyright 2016 Marina Glancy
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
39
class player_test extends \advanced_testcase {
40
41
42
43

    /**
     * Pre-test setup. Preserves $CFG.
     */
44
    public function setUp(): void {
45
46
47
48
49
50
51
52
53
        parent::setUp();

        // Reset $CFG and $SERVER.
        $this->resetAfterTest();

        // Consistent initial setup: all players disabled.
        \core\plugininfo\media::set_enabled_plugins('videojs');

        // Pretend to be using Firefox browser (must support ogg for tests to work).
54
        \core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 ');
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    }

    /**
     * Test that plugin is returned as enabled media plugin.
     */
    public function test_is_installed() {
        $sortorder = \core\plugininfo\media::get_enabled_plugins();
        $this->assertEquals(['videojs' => 'videojs'], $sortorder);
    }

    /**
     * Test method get_supported_extensions()
     */
    public function test_supported_extensions() {
69
70
        $supportedextensions = array_merge(file_get_typegroup('extension', 'html_video'),
            file_get_typegroup('extension', 'html_audio'), file_get_typegroup('extension', 'media_source'));
71
72
73
74

        // Make sure that the list of extensions from the setting is filtered to HTML5 natively supported extensions.
        $player = new media_videojs_plugin();
        $this->assertTrue(in_array('.mp3', $player->get_supported_extensions()));
75
        $this->assertEmpty(array_diff($player->get_supported_extensions(), $supportedextensions));
76
77
78
79
80
81
82

        // Try to set the audioextensions to something non-native (.ra) and make sure it is not returned as supported.
        set_config('audioextensions', '.mp3,.wav,.ra', 'media_videojs');
        $player = new media_videojs_plugin();
        $this->assertNotEmpty($player->get_supported_extensions());
        $this->assertTrue(in_array('.mp3', $player->get_supported_extensions()));
        $this->assertFalse(in_array('.ra', $player->get_supported_extensions()));
83
        $this->assertEmpty(array_diff($player->get_supported_extensions(), $supportedextensions));
84

85
        // Check flash extensions are not returned as supported.
86
87
88
89
        set_config('videoextensions', '.flv,.f4v', 'media_videojs');
        $player = new media_videojs_plugin();
        $this->assertFalse(in_array('.flv', $player->get_supported_extensions()));
        $this->assertFalse(in_array('.f4v', $player->get_supported_extensions()));
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    }

    /**
     * Test embedding without media filter (for example for displaying file resorce).
     */
    public function test_embed_url() {
        global $CFG;

        $url = new moodle_url('http://example.org/1.webm');

        $manager = core_media_manager::instance();
        $embedoptions = array(
            core_media_manager::OPTION_TRUSTED => true,
            core_media_manager::OPTION_BLOCK => true,
        );

        $this->assertTrue($manager->can_embed_url($url, $embedoptions));
        $content = $manager->embed_url($url, 'Test & file', 0, 0, $embedoptions);

109
110
111
112
        $this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
        $this->assertMatchesRegularExpression('~</video>~', $content);
        $this->assertMatchesRegularExpression('~title="Test &amp; file"~', $content);
        $this->assertMatchesRegularExpression('~style="max-width:' . $CFG->media_default_width . 'px;~', $content);
113
114
115

        // Repeat sending the specific size to the manager.
        $content = $manager->embed_url($url, 'New file', 123, 50, $embedoptions);
116
        $this->assertMatchesRegularExpression('~style="max-width:123px;~', $content);
117
118
119
120
121
122

        // Repeat without sending the size and with unchecked setting to limit the video size.
        set_config('limitsize', false, 'media_videojs');

        $manager = core_media_manager::instance();
        $content = $manager->embed_url($url, 'Test & file', 0, 0, $embedoptions);
123
        $this->assertDoesNotMatchRegularExpression('~style="max-width:~', $content);
124
125
126
127
128
129
130
131
132
133
134
135
136
    }

    /**
     * Test that mediaplugin filter replaces a link to the supported file with media tag.
     *
     * filter_mediaplugin is enabled by default.
     */
    public function test_embed_link() {
        global $CFG;
        $url = new moodle_url('http://example.org/some_filename.mp4');
        $text = html_writer::link($url, 'Watch this one');
        $content = format_text($text, FORMAT_HTML);

137
138
139
140
141
        $this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
        $this->assertMatchesRegularExpression('~</video>~', $content);
        $this->assertMatchesRegularExpression('~title="Watch this one"~', $content);
        $this->assertDoesNotMatchRegularExpression('~<track\b~i', $content);
        $this->assertMatchesRegularExpression('~style="max-width:' . $CFG->media_default_width . 'px;~', $content);
142
143
    }

144
145
146
147
148
149
150
151
152
153
154
155
156
157
    /**
     * Test that only supported URLs are listed as sources but all URLs are present in links fallbacks.
     */
    public function test_fallback() {

        $urls = [
            new moodle_url('http://example.org/1.rv'), // Not supported.
            new moodle_url('http://example.org/2.webm'), // Supported.
            new moodle_url('http://example.org/3.ogv'), // Supported.
        ];

        $manager = core_media_manager::instance();
        $content = $manager->embed_alternatives($urls, '', 0, 0, []);

158
159
        $this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
        $this->assertMatchesRegularExpression('~</video>~', $content);
160
        // Title is taken from the name of the first supported file.
161
        $this->assertMatchesRegularExpression('~title="2"~', $content);
162
        // Only supported files are in <source>'s.
163
164
165
        $this->assertDoesNotMatchRegularExpression('~<source src="http://example.org/1.rv"~', $content);
        $this->assertMatchesRegularExpression('~<source src="http://example.org/2.webm"~', $content);
        $this->assertMatchesRegularExpression('~<source src="http://example.org/3.ogv"~', $content);
166
        // Links to all files are included.
167
168
169
170
171
172
        $this->assertMatchesRegularExpression(
            '~<a class="mediafallbacklink" href="http://example.org/1.rv">1.rv</a>~', $content);
        $this->assertMatchesRegularExpression(
            '~<a class="mediafallbacklink" href="http://example.org/2.webm">2.webm</a>~', $content);
        $this->assertMatchesRegularExpression(
            '~<a class="mediafallbacklink" href="http://example.org/3.ogv">3.ogv</a>~', $content);
173
174
175
176
177
178
179
180
181
182
183
    }

    /**
     * Assert other players do not apply after videojs was applied.
     */
    public function test_prevent_other_players() {
        \core\plugininfo\media::set_enabled_plugins('videojs,html5video');
        $url = new moodle_url('http://example.org/some_filename.webm');
        $text = html_writer::link($url, 'Apply one player only');
        $content = format_text($text, FORMAT_HTML);

184
        $this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
185
        $this->assertEquals(1, substr_count($content, '</video>'));
186
        $this->assertDoesNotMatchRegularExpression('~mediaplugin_html5video~', $content);
187
188
        $this->assertMatchesRegularExpression(
            '~<a class="mediafallbacklink" href="http://example.org/some_filename.webm">Apply one player only</a>~', $content);
189
190
    }

191
192
193
194
195
196
197
198
199
200
201
202
203
    /**
     * Test that mediaplugin filter adds player code on top of <video> tags.
     *
     * filter_mediaplugin is enabled by default.
     */
    public function test_embed_media() {
        global $CFG;
        $url = new moodle_url('http://example.org/some_filename.mp4');
        $trackurl = new moodle_url('http://example.org/some_filename.vtt');
        $text = '<video controls="true"><source src="'.$url.'"/><source src="somethinginvalid"/>' .
            '<track src="'.$trackurl.'">Unsupported text</video>';
        $content = format_text($text, FORMAT_HTML);

204
205
206
207
        $this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
        $this->assertMatchesRegularExpression('~</video>~', $content);
        $this->assertMatchesRegularExpression('~title="some_filename.mp4"~', $content);
        $this->assertMatchesRegularExpression('~style="max-width:' . $CFG->media_default_width . 'px;~', $content);
208
        // Unsupported text and tracks are preserved.
209
210
        $this->assertMatchesRegularExpression('~Unsupported text~', $content);
        $this->assertMatchesRegularExpression('~<track\b~i', $content);
211
        // Invalid sources are removed.
212
        $this->assertDoesNotMatchRegularExpression('~somethinginvalid~i', $content);
213
214
215
216

        // Video with dimensions and source specified as src attribute without <source> tag.
        $text = '<video controls="true" width="123" height="35" src="'.$url.'">Unsupported text</video>';
        $content = format_text($text, FORMAT_HTML);
217
218
219
220
221
222
        $this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
        $this->assertMatchesRegularExpression('~</video>~', $content);
        $this->assertMatchesRegularExpression('~<source\b~', $content);
        $this->assertMatchesRegularExpression('~style="max-width:123px;~', $content);
        $this->assertDoesNotMatchRegularExpression('~width="~', $content);
        $this->assertDoesNotMatchRegularExpression('~height="~', $content);
223
224
225
226
227
228
229
230

        // Audio tag.
        $url = new moodle_url('http://example.org/some_filename.mp3');
        $trackurl = new moodle_url('http://example.org/some_filename.vtt');
        $text = '<audio controls="true"><source src="'.$url.'"/><source src="somethinginvalid"/>' .
            '<track src="'.$trackurl.'">Unsupported text</audio>';
        $content = format_text($text, FORMAT_HTML);

231
232
233
234
235
        $this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
        $this->assertDoesNotMatchRegularExpression('~</video>~', $content);
        $this->assertMatchesRegularExpression('~</audio>~', $content);
        $this->assertMatchesRegularExpression('~title="some_filename.mp3"~', $content);
        $this->assertMatchesRegularExpression('~style="max-width:' . $CFG->media_default_width . 'px;~', $content);
236
        // Unsupported text and tracks are preserved.
237
238
        $this->assertMatchesRegularExpression('~Unsupported text~', $content);
        $this->assertMatchesRegularExpression('~<track\b~i', $content);
239
        // Invalid sources are removed.
240
        $this->assertDoesNotMatchRegularExpression('~somethinginvalid~i', $content);
241
242
    }

243
244
245
246
247
    /**
     * Helper function for testing youtube videos embedding.
     *
     * @param string $t output of core_media_manager::embed_url.
     */
248
    protected function youtube_plugin_engaged($t) {
249
250
        $this->assertStringContainsString('mediaplugin_videojs', $t);
        $this->assertStringContainsString('data-setup-lazy="{&quot;techOrder&quot;: [&quot;youtube&quot;]', $t);
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
    }

    /**
     * Test that VideoJS can embed youtube videos.
     */
    public function test_youtube() {
        set_config('youtube', 1, 'media_videojs');

        $manager = core_media_manager::instance();

        // Format: youtube.
        $url = new moodle_url('http://www.youtube.com/watch?v=vyrwMmsufJc');
        $t = $manager->embed_url($url);
        $this->youtube_plugin_engaged($t);
        $url = new moodle_url('http://www.youtube.com/v/vyrwMmsufJc');
        $t = $manager->embed_url($url);
        $this->youtube_plugin_engaged($t);

        // Format: youtube video within playlist - this will be played by video.js but without tracks selection.
        $url = new moodle_url('https://www.youtube.com/watch?v=dv2f_xfmbD8&index=4&list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0');
        $t = $manager->embed_url($url);
        $this->youtube_plugin_engaged($t);
273
        $this->assertStringContainsString('list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0', $t);
274
275
276
277

        // Format: youtube playlist - not supported.
        $url = new moodle_url('http://www.youtube.com/view_play_list?p=PL6E18E2927047B662');
        $t = $manager->embed_url($url);
278
        $this->assertStringNotContainsString('mediaplugin_videojs', $t);
279
280
        $url = new moodle_url('http://www.youtube.com/playlist?list=PL6E18E2927047B662');
        $t = $manager->embed_url($url);
281
        $this->assertStringNotContainsString('mediaplugin_videojs', $t);
282
283
        $url = new moodle_url('http://www.youtube.com/p/PL6E18E2927047B662');
        $t = $manager->embed_url($url);
284
        $this->assertStringNotContainsString('mediaplugin_videojs', $t);
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
    }

    /**
     * Data provider for {@see test_youtube_start_time}
     *
     * @return array
     */
    public function youtube_start_time_provider(): array {
        return [
            ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1h11s', 3611],
            ['https://www.youtube.com/watch?v=dv2f_xfmbD8&index=4&list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0&t=1m5s', 65],
            ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1h10m30s', 4230],
            ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=3m', 180],
            ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=43s', 43],
            ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1234', 1234],
            ['https://www.youtube.com/watch?v=JNJMF1l3udM&t=invalid', 0],
        ];
    }

    /**
     * Test Youtube video embedding with URL's containing start time interval
     *
     * @param string $url
     * @param int $expectedstart
     *
     * @dataProvider youtube_start_time_provider
     */
    public function test_youtube_start_time(string $url, int $expectedstart) {
        set_config('youtube', 1, 'media_videojs');

        $embedcode = core_media_manager::instance()->embed_url(new moodle_url($url));
316

317
        $this->youtube_plugin_engaged($embedcode);
318
        $this->assertStringContainsString("&quot;youtube&quot;: {&quot;start&quot;: &quot;{$expectedstart}&quot;}", $embedcode);
319
    }
320
321
322
323
324
325
326

    /**
     * Helper function for testing flash videos embedding.
     *
     * @param string $t output of core_media_manager::embed_url.
     */
    protected function flash_plugin_engaged($t) {
327
328
        $this->assertStringContainsString('mediaplugin_videojs', $t);
        $this->assertStringContainsString('data-setup-lazy="{&quot;techOrder&quot;: [&quot;flash&quot;, &quot;html5&quot;]', $t);
329
330
331
    }

    /**
332
     * Test that VideoJS can not embed flash videos.
333
     */
334
    public function test_flash_behaviour() {
335
336
337
338
        $manager = core_media_manager::instance();

        $url = new moodle_url('http://example.org/some_filename.flv');
        $t = $manager->embed_url($url);
339
        $this->assertStringNotContainsString('mediaplugin_videojs', $t);
340
341
        $this->assertMatchesRegularExpression(
            '~<a class="mediafallbacklink" href="http://example.org/some_filename.flv">some_filename.flv</a>~', $t);
342
343
344
    }

    /**
345
     * Test that VideoJS can not embed RTMP streams.
346
     */
347
    public function test_rtmp_behaviour() {
348
349
350
351
        $manager = core_media_manager::instance();

        $url = new moodle_url('rtmp://example.com/fms&mp4:path/to/file.mp4');
        $t = $manager->embed_url($url);
352
        $this->assertStringNotContainsString('mediaplugin_videojs', $t);
353
354
        $this->assertMatchesRegularExpression(
            '~<a class="mediafallbacklink" href="rtmp://example.com/fms&mp4:path/to/file.mp4">file.mp4</a>~', $t);
355
    }
356
}