MDL-33699: Allow grades of 0 in assignment quickgrading
[moodle.git] / lib / tests / cssslib_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  * This file contains the unittests for the css optimiser in csslib.php
19  *
20  * @package   core_css
21  * @category  phpunit
22  * @copyright 2012 Sam Hemelryk
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->libdir . '/csslib.php');
32 /**
33  * CSS optimiser test class
34  *
35  * @package core_css
36  * @category css
37  * @copyright 2012 Sam Hemelryk
38  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  */
40 class css_optimiser_testcase extends advanced_testcase {
42     /**
43      * Sets up the test class
44      */
45     protected function setUp() {
46         global $CFG;
47         parent::setUp();
48         // We need to disable these if they are enabled to that we can predict
49         // the output.
50         $CFG->cssoptimiserstats = false;
51         $CFG->cssoptimiserpretty = false;
53         $this->resetAfterTest(true);
54     }
56     /**
57      * Test the process method
58      */
59     public function test_process() {
60         $optimiser = new css_optimiser;
62         $this->check_background($optimiser);
63         $this->check_borders($optimiser);
64         $this->check_colors($optimiser);
65         $this->check_margins($optimiser);
66         $this->check_padding($optimiser);
67         $this->check_widths($optimiser);
69         $this->try_broken_css_found_in_moodle($optimiser);
70         $this->try_invalid_css_handling($optimiser);
71         $this->try_bulk_processing($optimiser);
72         $this->try_break_things($optimiser);
73     }
75     /**
76      * Background colour tests
77      * @param css_optimiser $optimiser
78      */
79     protected function check_background(css_optimiser $optimiser) {
81         $cssin = '.test {background-color: #123456;}';
82         $cssout = '.test{background:#123456;}';
83         $this->assertEquals($cssout, $optimiser->process($cssin));
85         $cssin = '.test {background-image: url(\'test.png\');}';
86         $cssout = '.test{background-image:url(\'test.png\');}';
87         $this->assertEquals($cssout, $optimiser->process($cssin));
89         $cssin = '.test {background: #123456 url(\'test.png\') no-repeat top left;}';
90         $cssout = '.test{background:#123456 url(\'test.png\') no-repeat top left;}';
91         $this->assertEquals($cssout, $optimiser->process($cssin));
93         $cssin = '.test {background: url(\'test.png\') no-repeat top left;}.test{background-position: bottom right}.test {background-color:#123456;}';
94         $cssout = '.test{background:#123456 url(\'test.png\') no-repeat bottom right;}';
95         $this->assertEquals($cssout, $optimiser->process($cssin));
97         $cssin = '.test {background: url(   \'test.png\'    )}.test{background: bottom right}.test {background:#123456;}';
98         $cssout = '.test{background-image:url(\'test.png\');background-position:bottom right;background-color:#123456;}';
99         $this->assertEquals($cssout, $optimiser->process($cssin));
101         $cssin = '.test {background-color: #123456;background-repeat: repeat-x; background-position: 100% 0%;}';
102         $cssout = '.test{background-color:#123456;background-repeat:repeat-x;background-position:100% 0%;}';
103         $this->assertEquals($cssout, $optimiser->process($cssin));
105         $cssin = '.tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
106                   .tree_item.branch.navigation_node {background-image:none;padding-left:0;}';
107         $cssout = '.tree_item.branch{background:url([[pix:t/expanded]]) no-repeat 0 10%;} .tree_item.branch.navigation_node{background-image:none;padding-left:0;}';
108         $this->assertEquals($cssout, $optimiser->process($cssin));
110         $cssin = '.block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: 0% 5%;background-repeat: no-repeat;}
111                   .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed]]);}';
112         $cssout = '.block_tree .tree_item.emptybranch{background:url([[pix:t/collapsed_empty]]) no-repeat 0% 5%;} .block_tree .collapsed .tree_item.branch{background-image:url([[pix:t/collapsed]]);}';
113         $this->assertEquals($cssout, $optimiser->process($cssin));
116         $cssin = '#nextLink{background:url(data:image/gif;base64,AAAA);}';
117         $cssout = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
118         $this->assertEquals($cssout, $optimiser->process($cssin));
120         $cssin = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
121         $cssout = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
122         $this->assertEquals($cssout, $optimiser->process($cssin));
124         $cssin = '.test {background: #123456 url(data:image/gif;base64,AAAA) no-repeat top left;}';
125         $cssout = '.test{background:#123456 url(data:image/gif;base64,AAAA) no-repeat top left;}';
126         $this->assertEquals($cssout, $optimiser->process($cssin));
127     }
129     /**
130      * Border tests
131      * @param css_optimiser $optimiser
132      */
133     protected function check_borders(css_optimiser $optimiser) {
134         $cssin = '.test {border: 1px solid #654321} .test {border-bottom-color: #123456}';
135         $cssout = '.test{border:1px solid;border-color:#654321 #654321 #123456;}';
136         $this->assertEquals($cssout, $optimiser->process($cssin));
138         $cssin = '.one {border:1px solid red;}';
139         $cssout = '.one{border:1px solid #FF0000;}';
140         $this->assertEquals($cssout, $optimiser->process($cssin));
142         $cssin = '.one {border:1px solid;} .one {border:2px dotted #DDD;}';
143         $cssout = '.one{border:2px dotted #DDDDDD;}';
144         $this->assertEquals($cssout, $optimiser->process($cssin));
146         $cssin = '.one {border:2px dotted #DDD;}.one {border:1px solid;} ';
147         $cssout = '.one{border:1px solid #DDDDDD;}';
148         $this->assertEquals($cssout, $optimiser->process($cssin));
150         $cssin = '.one, .two {border:1px solid red;}';
151         $cssout = ".one, .two{border:1px solid #FF0000;}";
152         $this->assertEquals($cssout, $optimiser->process($cssin));
154         $cssin = '.one, .two {border:0px;}';
155         $cssout = ".one, .two{border-width:0;}";
156         $this->assertEquals($cssout, $optimiser->process($cssin));
158         $cssin = '.one, .two {border-top: 5px solid white;}';
159         $cssout = ".one, .two{border-top:5px solid #FFFFFF;}";
160         $this->assertEquals($cssout, $optimiser->process($cssin));
162         $cssin = '.one {border:1px solid red;} .two {border:1px solid red;}';
163         $cssout = ".one, .two{border:1px solid #FF0000;}";
164         $this->assertEquals($cssout, $optimiser->process($cssin));
166         $cssin = '.one {border:1px solid red;width:20px;} .two {border:1px solid red;height:20px;}';
167         $cssout = ".one{width:20px;border:1px solid #FF0000;} .two{height:20px;border:1px solid #FF0000;}";
168         $this->assertEquals($cssout, $optimiser->process($cssin));
170         $cssin = '.test {border: 1px solid #123456;} .test {border-color: #654321}';
171         $cssout = '.test{border:1px solid #654321;}';
172         $this->assertEquals($cssout, $optimiser->process($cssin));
174         $cssin = '.test {border-width: 1px; border-style: solid; border-color: #123456;}';
175         $cssout = '.test{border:1px solid #123456;}';
176         $this->assertEquals($cssout, $optimiser->process($cssin));
178         $cssin = '.test {border:1px solid #123456;border-top:2px dotted #654321;}';
179         $cssout = '.test{border:1px solid #123456;border-top:2px dotted #654321;}';
180         $this->assertEquals($cssout, $optimiser->process($cssin));
182         $cssin = '.test {border:1px solid #123456;border-left:2px dotted #654321;}';
183         $cssout = '.test{border:1px solid #123456;border-left:2px dotted #654321;}';
184         $this->assertEquals($cssout, $optimiser->process($cssin));
186         $cssin = '.test {border-left:2px dotted #654321;border:1px solid #123456;}';
187         $cssout = '.test{border:1px solid #123456;}';
188         $this->assertEquals($cssout, $optimiser->process($cssin));
190         $cssin = '.test {border:1px solid;border-top-color:#123456;}';
191         $cssout = '.test{border:1px solid;border-top-color:#123456;}';
192         $this->assertEquals($cssout, $optimiser->process($cssin));
194         $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;}';
195         $cssout = '.test{border:1px solid;border-top-color:#111;border-bottom-color:#222;border-left-color:#333;}';
196         $this->assertEquals($cssout, $optimiser->process($cssin));
198         $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;border-right-color:#444;}';
199         $cssout = '.test{border:1px solid;border-color:#111 #444 #222 #333;}';
200         $this->assertEquals($cssout, $optimiser->process($cssin));
202         $cssin = '.generaltable .cell {border-color:#EEEEEE;} .generaltable .cell {border-width: 1px;border-style: solid;}';
203         $cssout = '.generaltable .cell{border:1px solid #EEEEEE;}';
204         $this->assertEquals($cssout, $optimiser->process($cssin));
206         $cssin = '#page-admin-roles-override .rolecap {border:none;border-bottom:1px solid #CECECE;}';
207         $cssout = '#page-admin-roles-override .rolecap{border-top:0;border-right:0;border-bottom:1px solid #CECECE;border-left:0;}';
208         $this->assertEquals($cssout, $optimiser->process($cssin));
209     }
211     /**
212      * Test colour styles
213      * @param css_optimiser $optimiser
214      */
215     protected function check_colors(css_optimiser $optimiser) {
216         $css = '.css{}';
217         $this->assertEquals($css, $optimiser->process($css));
219         $css = '.css{color:#123456;}';
220         $this->assertEquals($css, $optimiser->process($css));
222         $css = '#some{color:#123456;}';
223         $this->assertEquals($css, $optimiser->process($css));
225         $css = 'div{color:#123456;}';
226         $this->assertEquals($css, $optimiser->process($css));
228         $css = 'div.css{color:#123456;}';
229         $this->assertEquals($css, $optimiser->process($css));
231         $css = 'div#some{color:#123456;}';
232         $this->assertEquals($css, $optimiser->process($css));
234         $css = 'div[type=blah]{color:#123456;}';
235         $this->assertEquals($css, $optimiser->process($css));
237         $css = 'div.css[type=blah]{color:#123456;}';
238         $this->assertEquals($css, $optimiser->process($css));
240         $css = 'div#some[type=blah]{color:#123456;}';
241         $this->assertEquals($css, $optimiser->process($css));
243         $css = '#some.css[type=blah]{color:#123456;}';
244         $this->assertEquals($css, $optimiser->process($css));
246         $css = '#some .css[type=blah]{color:#123456;}';
247         $this->assertEquals($css, $optimiser->process($css));
249         $cssin = '.one {color:red;} .two {color:#F00;}';
250         $cssout = ".one, .two{color:#F00;}";
251         $this->assertEquals($cssout, $optimiser->process($cssin));
253         $cssin = '.one {color:#123;color:#321;}';
254         $cssout = '.one{color:#321;}';
255         $this->assertEquals($cssout, $optimiser->process($cssin));
257         $cssin = '.one {color:#123; color : #321 ;}';
258         $cssout = '.one{color:#321;}';
259         $this->assertEquals($cssout, $optimiser->process($cssin));
261         $cssin = '.one {color:#123;} .one {color:#321;}';
262         $cssout = '.one{color:#321;}';
263         $this->assertEquals($cssout, $optimiser->process($cssin));
265         $cssin = '.one {color:#123 !important;color:#321;}';
266         $cssout = '.one{color:#123 !important;}';
267         $this->assertEquals($cssout, $optimiser->process($cssin));
269         $cssin = '.one {color:#123 !important;} .one {color:#321;}';
270         $cssout = '.one{color:#123 !important;}';
271         $this->assertEquals($cssout, $optimiser->process($cssin));
273         $cssin = '.one {color:rgb(255, 128, 1)}';
274         $cssout = '.one{color:rgb(255, 128, 1);}';
275         $this->assertEquals($cssout, $optimiser->process($cssin));
277         $cssin = '.one {color:rgba(255, 128, 1, 0.5)}';
278         $cssout = '.one{color:rgba(255, 128, 1, 0.5);}';
279         $this->assertEquals($cssout, $optimiser->process($cssin));
281         $cssin = '.one {color:hsl(120, 65%, 75%)}';
282         $cssout = '.one{color:hsl(120, 65%, 75%);}';
283         $this->assertEquals($cssout, $optimiser->process($cssin));
285         $cssin = '.one {color:hsla(120,65%,75%,0.5)}';
286         $cssout = '.one{color:hsla(120,65%,75%,0.5);}';
287         $this->assertEquals($cssout, $optimiser->process($cssin));
289         // Try some invalid colours to make sure we don't mangle them.
290         $css = 'div#some{color:#1;}';
291         $this->assertEquals($css, $optimiser->process($css));
293         $css = 'div#some{color:#12;}';
294         $this->assertEquals($css, $optimiser->process($css));
296         $css = 'div#some{color:#1234;}';
297         $this->assertEquals($css, $optimiser->process($css));
299         $css = 'div#some{color:#12345;}';
300         $this->assertEquals($css, $optimiser->process($css));
301     }
303     protected function check_widths(css_optimiser $optimiser) {
304         $cssin  = '.css {width:0}';
305         $cssout = '.css{width:0;}';
306         $this->assertEquals($cssout, $optimiser->process($cssin));
308         $cssin  = '.css {width:0px}';
309         $cssout = '.css{width:0;}';
310         $this->assertEquals($cssout, $optimiser->process($cssin));
312         $cssin  = '.css {width:0em}';
313         $cssout = '.css{width:0;}';
314         $this->assertEquals($cssout, $optimiser->process($cssin));
316         $cssin  = '.css {width:0pt}';
317         $cssout = '.css{width:0;}';
318         $this->assertEquals($cssout, $optimiser->process($cssin));
320         $cssin  = '.css {width:0mm}';
321         $cssout = '.css{width:0;}';
322         $this->assertEquals($cssout, $optimiser->process($cssin));
324         $cssin  = '.css {width:100px}';
325         $cssout = '.css{width:100px;}';
326         $this->assertEquals($cssout, $optimiser->process($cssin));
327     }
329     /**
330      * Test margin styles
331      * @param css_optimiser $optimiser
332      */
333     protected function check_margins(css_optimiser $optimiser) {
334         $cssin = '.one {margin: 1px 2px 3px 4px}';
335         $cssout = '.one{margin:1px 2px 3px 4px;}';
336         $this->assertEquals($cssout, $optimiser->process($cssin));
338         $cssin = '.one {margin-top:1px; margin-left:4px; margin-right:2px; margin-bottom: 3px;}';
339         $cssout = '.one{margin:1px 2px 3px 4px;}';
340         $this->assertEquals($cssout, $optimiser->process($cssin));
342         $cssin = '.one {margin-top:1px; margin-left:4px;}';
343         $cssout = '.one{margin-top:1px;margin-left:4px;}';
344         $this->assertEquals($cssout, $optimiser->process($cssin));
346         $cssin = '.one {margin:1px; margin-left:4px;}';
347         $cssout = '.one{margin:1px 1px 1px 4px;}';
348         $this->assertEquals($cssout, $optimiser->process($cssin));
350         $cssin = '.one {margin:1px; margin-bottom:4px;}';
351         $cssout = '.one{margin:1px 1px 4px;}';
352         $this->assertEquals($cssout, $optimiser->process($cssin));
354         $cssin = '.one, .two, .one.two, .one .two {margin:0;} .one.two {margin:0 7px;}';
355         $cssout = '.one, .two, .one .two{margin:0;} .one.two{margin:0 7px;}';
356         $this->assertEquals($cssout, $optimiser->process($cssin));
357     }
359     /**
360      * Test padding styles
361      *
362      * @param css_optimiser $optimiser
363      */
364     protected function check_padding(css_optimiser $optimiser) {
365         $cssin = '.one {margin: 1px 2px 3px 4px}';
366         $cssout = '.one{margin:1px 2px 3px 4px;}';
367         $this->assertEquals($cssout, $optimiser->process($cssin));
369         $cssin = '.one {margin-top:1px; margin-left:4px; margin-right:2px; margin-bottom: 3px;}';
370         $cssout = '.one{margin:1px 2px 3px 4px;}';
371         $this->assertEquals($cssout, $optimiser->process($cssin));
373         $cssin = '.one {margin-top:1px; margin-left:4px;}';
374         $cssout = '.one{margin-top:1px;margin-left:4px;}';
375         $this->assertEquals($cssout, $optimiser->process($cssin));
377         $cssin = '.one {margin:1px; margin-left:4px;}';
378         $cssout = '.one{margin:1px 1px 1px 4px;}';
379         $this->assertEquals($cssout, $optimiser->process($cssin));
381         $cssin = '.one {margin:1px; margin-bottom:4px;}';
382         $cssout = '.one{margin:1px 1px 4px;}';
383         $this->assertEquals($cssout, $optimiser->process($cssin));
385         $cssin = '.one {margin:0 !important;}';
386         $cssout = '.one{margin:0 !important;}';
387         $this->assertEquals($cssout, $optimiser->process($cssin));
389         $cssin = '.one {padding:0 !important;}';
390         $cssout = '.one{padding:0 !important;}';
391         $this->assertEquals($cssout, $optimiser->process($cssin));
393         $cssin = '.one, .two, .one.two, .one .two {margin:0;} .one.two {margin:0 7px;}';
394         $cssout = '.one, .two, .one .two{margin:0;} .one.two{margin:0 7px;}';
395         $this->assertEquals($cssout, $optimiser->process($cssin));
396     }
398     /**
399      * Test some totally invalid CSS optimisation
400      *
401      * @param css_optimiser $optimiser
402      */
403     protected function try_invalid_css_handling(css_optimiser $optimiser) {
405         $cssin = array(
406             '.one{}',
407             '.one {:}',
408             '.one {;}',
409             '.one {;;;;;}',
410             '.one {:;}',
411             '.one {:;:;:;:::;;;}',
412             '.one {!important}',
413             '.one {:!important}',
414             '.one {:!important;}',
415             '.one {;!important}'
416         );
417         $cssout = '.one{}';
418         foreach ($cssin as $css) {
419             $this->assertEquals($cssout, $optimiser->process($css));
420         }
422         $cssin = array(
423             '.one{background-color:red;}',
424             '.one {background-color:red;} .one {background-color:}',
425             '.one {background-color:red;} .one {background-color;}',
426             '.one {background-color:red;} .one {background-color}',
427             '.one {background-color:red;} .one {background-color:;}',
428             '.one {background-color:red;} .one {:blue;}',
429             '.one {background-color:red;} .one {:#00F}',
430         );
431         $cssout = '.one{background:#F00;}';
432         foreach ($cssin as $css) {
433             $this->assertEquals($cssout, $optimiser->process($css));
434         }
436         $cssin = '..one {background-color:color:red}';
437         $cssout = '..one{background-color:color:red;}';
438         $this->assertEquals($cssout, $optimiser->process($cssin));
440         $cssin = '#.one {background-color:color:red}';
441         $cssout = '#.one{background-color:color:red;}';
442         $this->assertEquals($cssout, $optimiser->process($cssin));
444         $cssin = '##one {background-color:color:red}';
445         $cssout = '##one{background-color:color:red;}';
446         $this->assertEquals($cssout, $optimiser->process($cssin));
448         $cssin = '.one {background-color:color:red}';
449         $cssout = '.one{background-color:color:red;}';
450         $this->assertEquals($cssout, $optimiser->process($cssin));
452         $cssin = '.one {background-color:red;color;border-color:blue}';
453         $cssout = '.one{background:#F00;border-color:#00F;}';
454         $this->assertEquals($cssout, $optimiser->process($cssin));
456         $cssin  = '{background-color:#123456;color:red;}{color:green;}';
457         $cssout = "{color:#008000;background:#123456;}";
458         $this->assertEquals($cssout, $optimiser->process($cssin));
460         $cssin  = '.one {color:red;} {color:green;} .one {background-color:blue;}';
461         $cssout = ".one{color:#F00;background:#00F;} {color:#008000;}";
462         $this->assertEquals($cssout, $optimiser->process($cssin));
463     }
465     /**
466      * Try to break some things
467      * @param css_optimiser $optimiser
468      */
469     protected function try_break_things(css_optimiser $optimiser) {
470         // Wildcard test
471         $cssin  = '* {color: black;}';
472         $cssout = '*{color:#000;}';
473         $this->assertEquals($cssout, $optimiser->process($cssin));
475         // Wildcard test
476         $cssin  = '.one * {color: black;}';
477         $cssout = '.one *{color:#000;}';
478         $this->assertEquals($cssout, $optimiser->process($cssin));
480         // Wildcard test
481         $cssin  = '* .one * {color: black;}';
482         $cssout = '* .one *{color:#000;}';
483         $this->assertEquals($cssout, $optimiser->process($cssin));
485         // Wildcard test
486         $cssin  = '*,* {color: black;}';
487         $cssout = '*{color:#000;}';
488         $this->assertEquals($cssout, $optimiser->process($cssin));
490         // Wildcard test
491         $cssin  = '*, * .one {color: black;}';
492         $cssout = "*,\n* .one{color:#000;}";
493         $this->assertEquals($cssout, $optimiser->process($cssin));
495         // Wildcard test
496         $cssin  = '*, *.one {color: black;}';
497         $cssout = "*,\n*.one{color:#000;}";
498         $this->assertEquals($cssout, $optimiser->process($cssin));
500         // Psedo test
501         $cssin  = '.one:before {color: black;}';
502         $cssout = '.one:before{color:#000;}';
503         $this->assertEquals($cssout, $optimiser->process($cssin));
505         // Psedo test
506         $cssin  = '.one:after {color: black;}';
507         $cssout = '.one:after{color:#000;}';
508         $this->assertEquals($cssout, $optimiser->process($cssin));
510         // Psedo test
511         $cssin  = '.one:onclick {color: black;}';
512         $cssout = '.one:onclick{color:#000;}';
513         $this->assertEquals($cssout, $optimiser->process($cssin));
515         // Test complex CSS rules that don't really exist but mimic other CSS rules
516         $cssin  = '.one {master-of-destruction: explode(\' \', "What madness");}';
517         $cssout = '.one{master-of-destruction:explode(\' \', "What madness");}';
518         $this->assertEquals($cssout, $optimiser->process($cssin));
520         // Test some complex IE css... I couldn't even think of a more complext solution
521         // than the CSS they came up with.
522         $cssin  = 'a { opacity: 0.5; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50); }';
523         $cssout = 'a{opacity:0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);}';
524         $this->assertEquals($cssout, $optimiser->process($cssin));
525     }
527     /**
528      * A bulk processing test
529      * @param css_optimiser $optimiser
530      */
531     protected function try_bulk_processing(css_optimiser $optimiser) {
532         global $CFG;
533         $cssin = <<<CSS
534 .test .one {
535     margin:5px;
536     border:0;
538 .test .one {
539     margin: 10px;
540     color: red;
543 .test.one {
544     margin: 15px;
547 #test .one {margin:  20px;}
548 #test #one {margin:  25px;}.test #one {margin:  30px;}
549   .test    .one      {     background-color: #123;     }
550 .test.one{border:1px solid blue}.test.one{border-color:green;}
552 @media print {
553     #test .one {margin: 35px;}
556 @media print {
557     #test .one {margin: 40px;color: #123456;}
558     #test #one {margin: 45px;}
561 @media print,screen {
562     #test .one {color: #654321;}
565 #test .one,
566 #new.style {color:#000;}
567 CSS;
569         $cssout = <<<CSS
570 .test .one{color:#F00;margin:10px;border-width:0;background:#123;}
571 .test.one{margin:15px;border:1px solid #008000;}
572 #test .one{color:#000;margin:20px;}
573 #test #one{margin:25px;}
574 .test #one{margin:30px;}
575 #new.style{color:#000;}
578 @media print {
579   #test .one{color:#123456;margin:40px;}
580   #test #one{margin:45px;}
583 @media print,screen {
584   #test .one{color:#654321;}
586 CSS;
587         $CFG->cssoptimiserpretty = 1;
588         $this->assertEquals($optimiser->process($cssin), $cssout);
589     }
591     /**
592      * Test CSS colour matching
593      */
594     public function test_css_is_colour() {
595         // First lets test hex colours
596         $this->assertTrue(css_is_colour('#123456'));
597         $this->assertTrue(css_is_colour('#123'));
598         $this->assertTrue(css_is_colour('#ABCDEF'));
599         $this->assertTrue(css_is_colour('#ABC'));
600         $this->assertTrue(css_is_colour('#abcdef'));
601         $this->assertTrue(css_is_colour('#abc'));
602         $this->assertTrue(css_is_colour('#aBcDeF'));
603         $this->assertTrue(css_is_colour('#aBc'));
604         $this->assertTrue(css_is_colour('#1a2Bc3'));
605         $this->assertTrue(css_is_colour('#1Ac'));
607         // Note the following two colour's arn't really colours but browsers process
608         // them still.
609         $this->assertTrue(css_is_colour('#A'));
610         $this->assertTrue(css_is_colour('#12'));
611         // Having four or five characters however are not valid colours and
612         // browsers don't parse them. They need to fail so that broken CSS
613         // stays broken after optimisation.
614         $this->assertFalse(css_is_colour('#1234'));
615         $this->assertFalse(css_is_colour('#12345'));
617         $this->assertFalse(css_is_colour('#BCDEFG'));
618         $this->assertFalse(css_is_colour('#'));
619         $this->assertFalse(css_is_colour('#0000000'));
620         $this->assertFalse(css_is_colour('#132-245'));
621         $this->assertFalse(css_is_colour('#13 23 43'));
622         $this->assertFalse(css_is_colour('123456'));
624         // Next lets test real browser mapped colours
625         $this->assertTrue(css_is_colour('black'));
626         $this->assertTrue(css_is_colour('blue'));
627         $this->assertTrue(css_is_colour('BLACK'));
628         $this->assertTrue(css_is_colour('Black'));
629         $this->assertTrue(css_is_colour('bLACK'));
630         $this->assertTrue(css_is_colour('mediumaquamarine'));
631         $this->assertTrue(css_is_colour('mediumAquamarine'));
632         $this->assertFalse(css_is_colour('monkey'));
633         $this->assertFalse(css_is_colour(''));
634         $this->assertFalse(css_is_colour('not a colour'));
636         // Next lets test rgb(a) colours
637         $this->assertTrue(css_is_colour('rgb(255,255,255)'));
638         $this->assertTrue(css_is_colour('rgb(0, 0, 0)'));
639         $this->assertTrue(css_is_colour('RGB (255, 255   ,    255)'));
640         $this->assertTrue(css_is_colour('rgba(0,0,0,0)'));
641         $this->assertTrue(css_is_colour('RGBA(255,255,255,1)'));
642         $this->assertTrue(css_is_colour('rgbA(255,255,255,0.5)'));
643         $this->assertFalse(css_is_colour('rgb(-255,-255,-255)'));
644         $this->assertFalse(css_is_colour('rgb(256,-256,256)'));
646         // Now lets test HSL colours
647         $this->assertTrue(css_is_colour('hsl(0,0%,100%)'));
648         $this->assertTrue(css_is_colour('hsl(180, 0%, 10%)'));
649         $this->assertTrue(css_is_colour('hsl (360, 100%   ,    95%)'));
651         // Finally test the special values
652         $this->assertTrue(css_is_colour('inherit'));
653     }
655     /**
656      * Test the css_is_width function
657      */
658     public function test_css_is_width() {
660         $this->assertTrue(css_is_width('0'));
661         $this->assertTrue(css_is_width('0px'));
662         $this->assertTrue(css_is_width('0em'));
663         $this->assertTrue(css_is_width('199px'));
664         $this->assertTrue(css_is_width('199em'));
665         $this->assertTrue(css_is_width('199%'));
666         $this->assertTrue(css_is_width('-1'));
667         $this->assertTrue(css_is_width('-1px'));
668         $this->assertTrue(css_is_width('auto'));
669         $this->assertTrue(css_is_width('inherit'));
671         $this->assertFalse(css_is_width('-'));
672         $this->assertFalse(css_is_width('bananas'));
673         $this->assertFalse(css_is_width(''));
674         $this->assertFalse(css_is_width('top'));
675     }
677     /**
678      * This function tests some of the broken crazy CSS we have in Moodle.
679      * For each of these things the value needs to be corrected if we can be 100%
680      * certain what is going wrong, Or it needs to be left as is.
681      *
682      * @param css_optimiser $optimiser
683      */
684     public function try_broken_css_found_in_moodle(css_optimiser $optimiser) {
685         // Notice how things are out of order here but that they get corrected
686         $cssin = '.test {background:url([[pix:theme|pageheaderbgred]]) top center no-repeat}';
687         $cssout = '.test{background:url([[pix:theme|pageheaderbgred]]) no-repeat top center;}';
688         $this->assertEquals($cssout, $optimiser->process($cssin));
690         // Cursor hand isn't valid
691         $cssin  = '.test {cursor: hand;}';
692         $cssout = '.test{cursor:hand;}';
693         $this->assertEquals($cssout, $optimiser->process($cssin));
695         // Zoom property isn't valid
696         $cssin  = '.test {zoom: 1;}';
697         $cssout = '.test{zoom:1;}';
698         $this->assertEquals($cssout, $optimiser->process($cssin));
700         // Left isn't a valid position property
701         $cssin  = '.test {position: left;}';
702         $cssout = '.test{position:left;}';
703         $this->assertEquals($cssout, $optimiser->process($cssin));
705         // The dark red color isn't a valid HTML color but has a standardised
706         // translation of #8B0000
707         $cssin  = '.test {color: darkred;}';
708         $cssout = '.test{color:#8B0000;}';
709         $this->assertEquals($cssout, $optimiser->process($cssin));
711         // You can't use argb colours as border colors
712         $cssin  = '.test {border-bottom: 1px solid rgba(0,0,0,0.25);}';
713         $cssout = '.test{border-bottom:1px solid rgba(0,0,0,0.25);}';
714         $this->assertEquals($cssout, $optimiser->process($cssin));
716         // Opacity with annoying IE equivilants....
717         $cssin  = '.test {opacity: 0.5; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50);}';
718         $cssout = '.test{opacity:0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);}';
719         $this->assertEquals($cssout, $optimiser->process($cssin));
720     }