MDL-53240 filetypes: Enhance the filetypes element with a types browser
[moodle.git] / lib / form / tests / filetypes_util_test.php
CommitLineData
6c4a5fdf
DM
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 * Provides the {@link core_form\filetypes_util_testcase} class.
19 *
20 * @package core_form
21 * @category test
22 * @copyright 2017 David Mudrák <david@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26namespace core_form;
27
28use advanced_testcase;
29
30defined('MOODLE_INTERNAL') || die();
31
32global $CFG;
33
34/**
35 * Test cases for the {@link core_form\filetypes_util} class.
36 *
37 * @copyright 2017 David Mudrak <david@moodle.com>
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 */
40class filetypes_util_testcase extends advanced_testcase {
41
42 /**
43 * Test normalizing list of extensions.
44 */
45 public function test_normalize_file_types() {
46
47 $this->resetAfterTest(true);
48 $util = new filetypes_util();
49
50 $this->assertSame(['.odt'], $util->normalize_file_types('.odt'));
51 $this->assertSame(['.odt'], $util->normalize_file_types('odt'));
52 $this->assertSame(['.odt'], $util->normalize_file_types('.ODT'));
53 $this->assertSame(['.doc', '.jpg', '.mp3'], $util->normalize_file_types('doc, jpg, mp3'));
54 $this->assertSame(['.doc', '.jpg', '.mp3'], $util->normalize_file_types(['.doc', '.jpg', '.mp3']));
55 $this->assertSame(['.doc', '.jpg', '.mp3'], $util->normalize_file_types('doc, *.jpg, mp3'));
56 $this->assertSame(['.doc', '.jpg', '.mp3'], $util->normalize_file_types(['doc ', ' JPG ', '.mp3']));
57 $this->assertSame(['.rtf', '.pdf', '.docx'],
58 $util->normalize_file_types("RTF,.pdf\n...DocX,,,;\rPDF\trtf ...Rtf"));
59 $this->assertSame(['.tgz', '.tar.gz'], $util->normalize_file_types('tgz,TAR.GZ tar.gz .tar.gz tgz TGZ'));
60 $this->assertSame(['.notebook'], $util->normalize_file_types('"Notebook":notebook;NOTEBOOK;,\'NoTeBook\''));
61 $this->assertSame([], $util->normalize_file_types(''));
62 $this->assertSame([], $util->normalize_file_types([]));
63 $this->assertSame(['.0'], $util->normalize_file_types(0));
64 $this->assertSame(['.0'], $util->normalize_file_types('0'));
65 $this->assertSame(['.odt'], $util->normalize_file_types('*.odt'));
66 $this->assertSame([], $util->normalize_file_types('.'));
67 $this->assertSame(['.foo'], $util->normalize_file_types('. foo'));
68 $this->assertSame(['*'], $util->normalize_file_types('*'));
69 $this->assertSame([], $util->normalize_file_types('*~'));
70 $this->assertSame(['.pdf', '.ps'], $util->normalize_file_types('pdf *.ps foo* *bar .r??'));
71 $this->assertSame(['*'], $util->normalize_file_types('pdf *.ps foo* * *bar .r??'));
72 }
73
74 /**
75 * Test MIME type formal recognition.
76 */
77 public function test_looks_like_mimetype() {
78
79 $this->resetAfterTest(true);
80 $util = new filetypes_util();
81
82 $this->assertTrue($util->looks_like_mimetype('type/subtype'));
83 $this->assertTrue($util->looks_like_mimetype('type/x-subtype'));
84 $this->assertTrue($util->looks_like_mimetype('type/x-subtype+xml'));
85 $this->assertTrue($util->looks_like_mimetype('type/vnd.subtype.xml'));
86 $this->assertTrue($util->looks_like_mimetype('type/vnd.subtype+xml'));
87
88 $this->assertFalse($util->looks_like_mimetype('.gif'));
89 $this->assertFalse($util->looks_like_mimetype('audio'));
90 $this->assertFalse($util->looks_like_mimetype('foo/bar/baz'));
91 }
92
93 /**
94 * Test getting/checking group.
95 */
96 public function test_is_filetype_group() {
97
98 $this->resetAfterTest(true);
99 $util = new filetypes_util();
100
101 $audio = $util->is_filetype_group('audio');
102 $this->assertNotFalse($audio);
103 $this->assertInternalType('array', $audio->extensions);
104 $this->assertInternalType('array', $audio->mimetypes);
105
106 $this->assertFalse($util->is_filetype_group('.gif'));
107 $this->assertFalse($util->is_filetype_group('somethingveryunlikelytoeverexist'));
108 }
109
110
111 /**
112 * Test describing list of extensions.
113 */
114 public function test_describe_file_types() {
115
116 $this->resetAfterTest(true);
117 $util = new filetypes_util();
118
119 force_current_language('en');
120
121 // Check that it is able to describe individual file extensions.
122 $desc = $util->describe_file_types('jpg .jpeg *.jpe PNG;.gif, mudrd8mz');
123 $this->assertTrue($desc->hasdescriptions);
124
125 $desc = $desc->descriptions;
126 $this->assertEquals(4, count($desc));
127
128 $this->assertEquals('File', $desc[0]->description);
129 $this->assertEquals('.mudrd8mz', $desc[0]->extensions);
130
131 $this->assertEquals('Image (JPEG)', $desc[2]->description);
132 $this->assertContains('.jpg', $desc[2]->extensions);
133 $this->assertContains('.jpeg', $desc[2]->extensions);
134 $this->assertContains('.jpe', $desc[2]->extensions);
135
136 // Check that it can describe groups and mimetypes too.
137 $desc = $util->describe_file_types('audio text/plain');
138 $this->assertTrue($desc->hasdescriptions);
139
140 $desc = $desc->descriptions;
141 $this->assertEquals(2, count($desc));
142
143 $this->assertEquals('Audio files', $desc[0]->description);
144 $this->assertContains('.mp3', $desc[0]->extensions);
145 $this->assertContains('.wav', $desc[0]->extensions);
146 $this->assertContains('.ogg', $desc[0]->extensions);
147
148 $this->assertEquals('Text file', $desc[1]->description);
149 $this->assertContains('.txt', $desc[1]->extensions);
150
151 // Empty.
152 $desc = $util->describe_file_types('');
153 $this->assertFalse($desc->hasdescriptions);
154 $this->assertEmpty($desc->descriptions);
155
156 // Any.
157 $desc = $util->describe_file_types('*');
158 $this->assertTrue($desc->hasdescriptions);
159 $this->assertNotEmpty($desc->descriptions[0]->description);
160 $this->assertEmpty($desc->descriptions[0]->extensions);
161
162 // Unknown mimetype.
163 $desc = $util->describe_file_types('application/x-something-really-unlikely-ever-exist');
164 $this->assertTrue($desc->hasdescriptions);
165 $this->assertEquals('application/x-something-really-unlikely-ever-exist', $desc->descriptions[0]->description);
166 $this->assertEmpty($desc->descriptions[0]->extensions);
167 }
e3ad9db6
DM
168
169 /**
170 * Test expanding mime types into extensions.
171 */
172 public function test_expand() {
173
174 $this->resetAfterTest(true);
175 $util = new filetypes_util();
176
177 $this->assertSame([], $util->expand(''));
178
179 $expanded = $util->expand('document .cdr text/plain');
180 $this->assertNotContains('document', $expanded);
181 $this->assertNotContains('text/plain', $expanded);
182 $this->assertContains('.doc', $expanded);
183 $this->assertContains('.odt', $expanded);
184 $this->assertContains('.txt', $expanded);
185 $this->assertContains('.cdr', $expanded);
186
187 $expanded = $util->expand('document .cdr text/plain', true, false);
188 $this->assertContains('document', $expanded);
189 $this->assertNotContains('text/plain', $expanded);
190 $this->assertContains('.doc', $expanded);
191 $this->assertContains('.odt', $expanded);
192 $this->assertContains('.txt', $expanded);
193 $this->assertContains('.cdr', $expanded);
194
195 $expanded = $util->expand('document .cdr text/plain', false, true);
196 $this->assertNotContains('document', $expanded);
197 $this->assertContains('text/plain', $expanded);
198 $this->assertContains('.doc', $expanded);
199 $this->assertContains('.odt', $expanded);
200 $this->assertContains('.txt', $expanded);
201 $this->assertContains('.cdr', $expanded);
202
203 $this->assertSame([], $util->expand('foo/bar', true, false));
204 $this->assertSame(['foo/bar'], $util->expand('foo/bar', true, true));
205 }
206
207 /**
208 * Test checking that a type is among others.
209 */
210 public function test_is_whitelisted() {
211
212 $this->resetAfterTest(true);
213 $util = new filetypes_util();
214
215 // These should be intuitively true.
216 $this->assertTrue($util->is_whitelisted('txt', 'text/plain'));
217 $this->assertTrue($util->is_whitelisted('txt', 'doc txt rtf'));
218 $this->assertTrue($util->is_whitelisted('.txt', '.doc;.txt;.rtf'));
219 $this->assertTrue($util->is_whitelisted('audio', 'text/plain audio video'));
220 $this->assertTrue($util->is_whitelisted('text/plain', 'text/plain audio video'));
221 $this->assertTrue($util->is_whitelisted('jpg jpe jpeg', 'image/jpeg'));
222
223 // These should be intuitively false.
224 $this->assertFalse($util->is_whitelisted('.gif', 'text/plain'));
225
226 // Not all text/plain formats are in the document group.
227 $this->assertFalse($util->is_whitelisted('text/plain', 'document'));
228
229 // Not all documents (and also the group itself) is not a plain text.
230 $this->assertFalse($util->is_whitelisted('document', 'text/plain'));
231
232 // Any type is included if the filter is empty.
233 $this->assertTrue($util->is_whitelisted('txt', ''));
234 $this->assertTrue($util->is_whitelisted('txt', '*'));
235 }
236
237 /**
238 * Test populating the tree for the browser.
239 */
240 public function test_data_for_browser() {
241
242 $this->resetAfterTest(true);
243 $util = new filetypes_util();
244
245 $data = $util->data_for_browser();
246 $this->assertContainsOnly('object', $data);
247 foreach ($data as $group) {
248 $this->assertObjectHasAttribute('key', $group);
249 $this->assertObjectHasAttribute('types', $group);
250 if ($group->key !== '') {
251 $this->assertTrue($group->selectable);
252 }
253 }
254
255 // All these three files are in both "image" and also "web_image"
256 // groups. We display both groups.
257 $data = $util->data_for_browser('jpg png gif', true, '.gif');
258 $this->assertEquals(2, count($data));
259 $this->assertTrue($data[0]->key !== $data[1]->key);
260 foreach ($data as $group) {
261 $this->assertTrue(($group->key === 'image' || $group->key === 'web_image'));
262 $this->assertEquals(3, count($group->types));
263 $this->assertFalse($group->selectable);
264 foreach ($group->types as $ext) {
265 if ($ext->key === '.gif') {
266 $this->assertTrue($ext->selected);
267 } else {
268 $this->assertFalse($ext->selected);
269 }
270 }
271 }
272
273 // There is a group web_image which is a subset of the group image. The
274 // file extensions that fall into both groups will be displayed twice.
275 $data = $util->data_for_browser('web_image');
276 foreach ($data as $group) {
277 $this->assertTrue(($group->key === 'image' || $group->key === 'web_image'));
278 }
279
280 // Check that "All file types" are displayed first.
281 $data = $util->data_for_browser();
282 $group = array_shift($data);
283 $this->assertEquals('*', $group->key);
284
285 // Check that "All file types" is not displayed if should not.
286 $data = $util->data_for_browser(null, false);
287 $group = array_shift($data);
288 $this->assertNotEquals('*', $group->key);
289
290 // Groups with an extension selected start expanded. The "Other files"
291 // starts expanded. The rest start collapsed.
292 $data = $util->data_for_browser(null, false, '.png');
293 foreach ($data as $group) {
294 if ($group->key === 'document') {
295 $this->assertfalse($group->expanded);
296 } else if ($group->key === '') {
297 $this->assertTrue($group->expanded);
298 }
299 foreach ($group->types as $ext) {
300 foreach ($group->types as $ext) {
301 if ($ext->key === '.png') {
302 $this->assertTrue($ext->selected);
303 $this->assertTrue($group->expanded);
304 }
305 }
306 }
307 }
308 }
86bb4f5b
JO
309
310 /**
311 * Data provider for testing test_is_allowed_file_type.
312 *
313 * @return array
314 */
315 public function is_allowed_file_type_provider() {
316 return [
317 'Filetype not in extension whitelist' => [
318 'filename' => 'test.xml',
319 'whitelist' => '.png .jpg',
320 'expected' => false
321 ],
322 'Filetype not in mimetype whitelist' => [
323 'filename' => 'test.xml',
324 'whitelist' => 'image/png',
325 'expected' => false
326 ],
327 'Filetype not in group whitelist' => [
328 'filename' => 'test.xml',
329 'whitelist' => 'web_file',
330 'expected' => false
331 ],
332 'Filetype in whitelist as extension' => [
333 'filename' => 'test.xml',
334 'whitelist' => 'xml',
335 'expected' => true
336 ],
337 'Empty whitelist should allow all' => [
338 'filename' => 'test.xml',
339 'whitelist' => '',
340 'expected' => true
341 ],
342 'Filetype in whitelist but later on' => [
343 'filename' => 'test.xml',
344 'whitelist' => 'gif;jpeg,image/png xml xlsx',
345 'expected' => true
346 ],
347 'Filetype in whitelist as mimetype' => [
348 'filename' => 'test.xml',
349 'whitelist' => 'image/png application/xml',
350 'expected' => true
351 ],
352 'Filetype in whitelist as group' => [
353 'filename' => 'test.html',
354 'whitelist' => 'video,web_file',
355 'expected' => true
356 ],
357 ];
358 }
359
360 /**
361 * Test is_allowed_file_type().
362 * @dataProvider is_allowed_file_type_provider
363 * @param string $filename The filename to check
364 * @param string $whitelist The space , or ; separated list of types supported
365 * @param boolean $expected The expected result. True if the file is allowed, false if not.
366 */
367 public function test_is_allowed_file_type($filename, $whitelist, $expected) {
368 $util = new filetypes_util();
369 $this->assertSame($expected, $util->is_allowed_file_type($filename, $whitelist));
370 }
371
372 /**
373 * Data provider for testing test_get_unknown_file_types.
374 *
375 * @return array
376 */
377 public function get_unknown_file_types_provider() {
378 return [
379 'Unknown extension' => [
380 'filetypes' => '.rat',
381 'expected' => ['.rat']
382 ],
383 'Multiple unknown extensions' => [
384 'filetypes' => '.ricefield .rat',
385 'expected' => ['.ricefield', '.rat']
386 ],
387 'Existant extension' => [
388 'filetypes' => '.xml',
389 'expected' => []
390 ],
391 'Existant group' => [
392 'filetypes' => 'web_file',
393 'expected' => []
394 ],
395 'Nonexistant mimetypes' => [
396 'filetypes' => 'ricefield/rat',
397 'expected' => ['ricefield/rat']
398 ],
399 'Existant mimetype' => [
400 'filetypes' => 'application/xml',
401 'expected' => []
402 ],
403 'Multiple unknown mimetypes' => [
404 'filetypes' => 'ricefield/rat cam/ball',
405 'expected' => ['ricefield/rat', 'cam/ball']
406 ],
407 'Strange characters in unknown extension/group' => [
408 'filetypes' => '©ç√√ß∂å√©åß©√',
409 'expected' => ['.©ç√√ß∂å√©åß©√']
410 ],
411 'Some existant some not' => [
412 'filetypes' => '.txt application/xml web_file ©ç√√ß∂å√©åß©√ .png ricefield/rat document',
413 'expected' => ['.©ç√√ß∂å√©åß©√', 'ricefield/rat']
414 ],
415 ];
416 }
417
418 /**
419 * Test get_unknown_file_types().
420 * @dataProvider get_unknown_file_types_provider
421 * @param string $filetypes The filetypes to check
422 * @param array $expected The expected result. The list of non existant file types.
423 */
424 public function test_get_unknown_file_types($filetypes, $expected) {
425 $util = new filetypes_util();
426 $this->assertSame($expected, $util->get_unknown_file_types($filetypes));
427 }
6c4a5fdf 428}