Merge branch 'wip-MDL-33825-m23' of git://github.com/samhemelryk/moodle
[moodle.git] / lib / tests / csslib_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     protected $optimiser;
44     public function get_optimiser() {
45         if (!$this->optimiser instanceof css_optimiser) {
46             $this->optimiser = new css_optimiser;
47         }
48         return $this->optimiser;
49     }
51     /**
52      * Sets up the test class
53      */
54     protected function setUp() {
55         global $CFG;
56         parent::setUp();
57         // We need to disable these if they are enabled to that we can predict
58         // the output.
59         $CFG->cssoptimiserstats = false;
60         $CFG->cssoptimiserpretty = false;
62         $this->resetAfterTest(true);
63     }
65     /**
66      * Test the process method
67      */
68     public function test_process() {
69         $optimiser = new css_optimiser;
71         $this->try_broken_css_found_in_moodle();
72         $this->try_invalid_css_handling();
73         $this->try_bulk_processing();
74         $this->try_break_things();
75         $this->try_media_rules();
76         $this->try_keyframe_css_animation();
77     }
79     /**
80      * Background colour tests
81      *
82      * When testing background styles it is important to understand how the background shorthand works.
83      * background shorthand allows the following styles to be specified in a single "background" declaration:
84      *   - background-color
85      *   - background-image
86      *   - background-repeat
87      *   - background-attachment
88      *   - background-position
89      *
90      * If the background shorthand is used it can contain one or more of those (preferabbly in that order).
91      * Important it does not need to contain all of them.
92      * However even if it doesn't contain values for all styles all of the styles will be affected.
93      * If a style is missed from the shorthand background style but has an existing value in the rule then the existing value
94      * is cleared.
95      *
96      * For example:
97      *      .test {background: url(\'test.png\');background: bottom right;background:#123456;}
98      * will result in:
99      *      .test {background:#123456;}
100      *
101      * And:
102      *      .test {background-image: url(\'test.png\');background:#123456;}
103      * will result in:
104      *      .test {background:#123456;}
105      *
106      * @param css_optimiser $optimiser
107      */
108     public function test_background() {
109         $optimiser = $this->get_optimiser();
111         $cssin = '.test {background-color: #123456;}';
112         $cssout = '.test{background-color:#123456;}';
113         $this->assertEquals($cssout, $optimiser->process($cssin));
115         $cssin = '.test {background: #123456;}';
116         $cssout = '.test{background:#123456;}';
117         $this->assertEquals($cssout, $optimiser->process($cssin));
119         $cssin = '.test {background-image: url(\'test.png\');}';
120         $cssout = '.test{background-image:url(\'test.png\');}';
121         $this->assertEquals($cssout, $optimiser->process($cssin));
123         $cssin = '.test {background: #123456 url(\'test.png\') no-repeat top left;}';
124         $cssout = '.test{background:#123456 url(\'test.png\') no-repeat top left;}';
125         $this->assertEquals($cssout, $optimiser->process($cssin));
127         // Check out this for madness, background position and background-repeat have been reversed
128         $cssin = '.test {background: #123456 url(\'test.png\') center no-repeat;}';
129         $cssout = '.test{background:#123456 url(\'test.png\') no-repeat center;}';
130         $this->assertEquals($cssout, $optimiser->process($cssin));
132         $cssin = '.test {background: url(\'test.png\') no-repeat top left;}.test{background-position: bottom right}.test {background-color:#123456;}';
133         $cssout = '.test{background:#123456 url(\'test.png\') no-repeat bottom right;}';
134         $this->assertEquals($cssout, $optimiser->process($cssin));
136         $cssin = '.test {background: url(   \'test.png\'    )}.test{background: bottom right}.test {background:#123456;}';
137         $cssout = '.test{background:#123456;}';
138         $this->assertEquals($cssout, $optimiser->process($cssin));
140         $cssin = '.test {background-image: url(\'test.png\');background:#123456;}';
141         $cssout = '.test{background:#123456;}';
142         $this->assertEquals($cssout, $optimiser->process($cssin));
144         $cssin = '.test {background-color: #123456;background-repeat: repeat-x; background-position: 100% 0%;}';
145         $cssout = '.test{background-color:#123456;background-repeat:repeat-x;background-position:100% 0%;}';
146         $this->assertEquals($cssout, $optimiser->process($cssin));
148         $cssin = '.tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
149                   .tree_item.branch.navigation_node {background-image:none;padding-left:0;}';
150         $cssout = '.tree_item.branch{background-image:url([[pix:t/expanded]]);background-position:0 10%;background-repeat:no-repeat;} .tree_item.branch.navigation_node{background-image:none;padding-left:0;}';
151         $this->assertEquals($cssout, $optimiser->process($cssin));
153         $cssin = '#nextLink{background:url(data:image/gif;base64,AAAA);}';
154         $cssout = '#nextLink{background:url(data:image/gif;base64,AAAA);}';
155         $this->assertEquals($cssout, $optimiser->process($cssin));
157         $cssin = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
158         $cssout = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
159         $this->assertEquals($cssout, $optimiser->process($cssin));
161         $cssin = '.test {background: #123456 url(data:image/gif;base64,AAAA) no-repeat top left;}';
162         $cssout = '.test{background:#123456 url(data:image/gif;base64,AAAA) no-repeat top left;}';
163         $this->assertEquals($cssout, $optimiser->process($cssin));
165         $cssin = '#test {background-image:none;background-position:right center;background-repeat:no-repeat;}';
166         $cssout = '#test{background-image:none;background-position:right center;background-repeat:no-repeat;}';
167         $this->assertEquals($cssout, $optimiser->process($cssin));
169         $cssin = '.test {background: url([[pix:theme|photos]]) no-repeat 50% 50%;background-size: 40px 40px;-webkit-background-size: 40px 40px;}';
170         $cssout = '.test{background:url([[pix:theme|photos]]) no-repeat 50% 50%;background-size:40px 40px;-webkit-background-size:40px 40px;}';
171         $this->assertEquals($cssout, $optimiser->process($cssin));
173         $cssin = '.test{background-image: -o-linear-gradient(#3c3c3c, #111);background-image: linear-gradient(#3c3c3c, #111);}';
174         $cssout = '.test{background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);}';
175         $this->assertEquals($cssout, $optimiser->process($cssin));
177         $cssin = '.test{background-image: -moz-linear-gradient(#3c3c3c, #111);background-image: -webkit-linear-gradient(#3c3c3c, #111);background-image: -o-linear-gradient(#3c3c3c, #111);background-image: linear-gradient(#3c3c3c, #111);background-image: url(/test.png);}';
178         $cssout = '.test{background-image:-moz-linear-gradient(#3c3c3c, #111);background-image:-webkit-linear-gradient(#3c3c3c, #111);background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);background-image:url(/test.png);}';
179         $cssout = '.test{background-image:url(/test.png);background-image:-moz-linear-gradient(#3c3c3c, #111);background-image:-webkit-linear-gradient(#3c3c3c, #111);background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);}';
180         $this->assertEquals($cssout, $optimiser->process($cssin));
182         $cssin = '.test{background:#CCC; background-image: url(test.png);}';
183         $cssout = '.test{background:#CCC url(test.png);}';
184         $this->assertEquals($cssout, $optimiser->process($cssin));
186         $cssin = '.test{background:#CCC; background-image: linear-gradient(#3c3c3c, #111);}';
187         $cssout = '.test{background:#CCC;background-image:linear-gradient(#3c3c3c, #111);}';
188         $this->assertEquals($cssout, $optimiser->process($cssin));
190         $cssin = '.test{background:#CCC; background-image: -o-linear-gradient(#3c3c3c, #111);background-image: linear-gradient(#3c3c3c, #111);}';
191         $cssout = '.test{background:#CCC;background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);}';
192         $this->assertEquals($cssout, $optimiser->process($cssin));
194         $cssin = '#newmessageoverlay{font-weight: normal; border: 1px solid #222; background: #444; color: #ddd; text-shadow: 0 -1px 0px #000; background-image: -moz-linear-gradient(top, #333 0%, #333 5%, #444 15%, #444 60%, #222 100%); background-image: -webkit-gradient(linear, center top, center bottom, color-stop(0, #333), color-stop(5%, #333), color-stop(15%, #444), color-stop(60%, #444), color-stop(1, #222)); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr=\'#333333\', EndColorStr=\'#222222\')"; padding:20px; padding-left: 0px; padding-right: 10px; position: inherit; z-index: 9999; width: 90%; margin-left: auto; margin-right: auto; height: 100%;}';
195         $cssout = '#newmessageoverlay{font-weight:normal;border:1px solid #222;background:#444;color:#DDD;text-shadow:0 -1px 0px #000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=\'#333333\', EndColorStr=\'#222222\')";padding:20px 10px 20px 0;position:inherit;z-index:9999;width:90%;margin-left:auto;margin-right:auto;height:100%;background-image:-moz-linear-gradient(top, #333 0%, #333 5%, #444 15%, #444 60%, #222 100%);background-image:-webkit-gradient(linear, center top, center bottom, color-stop(0, #333), color-stop(5%, #333), color-stop(15%, #444), color-stop(60%, #444), color-stop(1, #222));}';
196         $this->assertEquals($cssout, $optimiser->process($cssin));
198         $cssin = '.userenrolment {background-color:inherit !important;background: inherit !important;}';
199         $cssout = '.userenrolment{background:inherit !important;}';
200         $this->assertEquals($cssout, $optimiser->process($cssin));
202         $cssin = '.userenrolment {background-image:url(test.png) !important;background: inherit !important;}';
203         $cssout = '.userenrolment{background:inherit !important;}';
204         $this->assertEquals($cssout, $optimiser->process($cssin));
206         $cssin = '.userenrolment {background: inherit !important;background-image:url(test.png) !important;}';
207         $cssout = '.userenrolment{background:inherit url(test.png) !important;}';
208         $this->assertEquals($cssout, $optimiser->process($cssin));
210         $cssin = '.userenrolment {background: inherit !important;background-image:url(test.png);}';
211         $cssout = '.userenrolment{background:inherit !important;}';
212         $this->assertEquals($cssout, $optimiser->process($cssin));
214         $css = '#filesskin .yui3-widget-hd{background:#CCC;background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC));background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC);}';
215         $this->assertEquals($css, $optimiser->process($css));
217         $css = '.userenrolment{background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;}';
218         $this->assertEquals($css, $optimiser->process($css));
220         $css = '.userenrolment{background:#CCC !important;background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC)) !important;background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;}';
221         $this->assertEquals($css, $optimiser->process($css));
223         $cssin = '.userenrolment{background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;}.userenrolment {background: #CCCCCC!important;background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC))!important;}';
224         $cssout = '.userenrolment{background:#CCC !important;background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC)) !important;}';
225         $this->assertEquals($cssout, $optimiser->process($cssin));
226     }
228     /**
229      * Border tests
230      * @param css_optimiser $optimiser
231      */
232     public function test_borders() {
233         $optimiser = $this->get_optimiser();
235         $cssin = '.test {border: 1px solid #654321} .test {border-bottom-color: #123456}';
236         $cssout = '.test{border:1px solid;border-color:#654321 #654321 #123456;}';
237         $this->assertEquals($cssout, $optimiser->process($cssin));
239         $cssin = '.one {border:1px solid red;}';
240         $cssout = '.one{border:1px solid #F00;}';
241         $this->assertEquals($cssout, $optimiser->process($cssin));
243         $cssin = '.one {border:1px solid;} .one {border:2px dotted #DDD;}';
244         $cssout = '.one{border:2px dotted #DDD;}';
245         $this->assertEquals($cssout, $optimiser->process($cssin));
247         $cssin = '.one {border:2px dotted #DDD;}.one {border:1px solid;} ';
248         $cssout = '.one{border:1px solid #DDD;}';
249         $this->assertEquals($cssout, $optimiser->process($cssin));
251         $cssin = '.one, .two {border:1px solid red;}';
252         $cssout = ".one, .two{border:1px solid #F00;}";
253         $this->assertEquals($cssout, $optimiser->process($cssin));
255         $cssin = '.one, .two {border:0px;}';
256         $cssout = ".one, .two{border-width:0;}";
257         $this->assertEquals($cssout, $optimiser->process($cssin));
259         $cssin = '.one, .two {border: thin;}';
260         $cssout = ".one, .two{border-width:thin;}";
261         $this->assertEquals($cssout, $optimiser->process($cssin));
263         $cssin = '.one, .two {border: thin solid black;}';
264         $cssout = ".one, .two{border:thin solid #000;}";
265         $this->assertEquals($cssout, $optimiser->process($cssin));
267         $cssin = '.one, .two {border-top: 5px solid white;}';
268         $cssout = ".one, .two{border-top:5px solid #FFF;}";
269         $this->assertEquals($cssout, $optimiser->process($cssin));
271         $cssin = '.one {border:1px solid red;} .two {border:1px solid red;}';
272         $cssout = ".one, .two{border:1px solid #F00;}";
273         $this->assertEquals($cssout, $optimiser->process($cssin));
275         $cssin = '.one {border:1px solid red;width:20px;} .two {border:1px solid red;height:20px;}';
276         $cssout = ".one{border:1px solid #F00;width:20px;} .two{border:1px solid #F00;height:20px;}";
277         $this->assertEquals($cssout, $optimiser->process($cssin));
279         $cssin = '.test {border: 1px solid #123456;} .test {border-color: #654321}';
280         $cssout = '.test{border:1px solid #654321;}';
281         $this->assertEquals($cssout, $optimiser->process($cssin));
283         $cssin = '.test {border-width: 1px; border-style: solid; border-color: #123456;}';
284         $cssout = '.test{border:1px solid #123456;}';
285         $this->assertEquals($cssout, $optimiser->process($cssin));
287         $cssin = '.test {border:1px solid #123456;border-top:2px dotted #654321;}';
288         $cssout = '.test{border:1px solid #123456;border-top:2px dotted #654321;}';
289         $this->assertEquals($cssout, $optimiser->process($cssin));
291         $cssin = '.test {border:1px solid #123456;border-left:2px dotted #654321;}';
292         $cssout = '.test{border:1px solid #123456;border-left:2px dotted #654321;}';
293         $this->assertEquals($cssout, $optimiser->process($cssin));
295         $cssin = '.test {border-left:2px dotted #654321;border:1px solid #123456;}';
296         $cssout = '.test{border:1px solid #123456;}';
297         $this->assertEquals($cssout, $optimiser->process($cssin));
299         $cssin = '.test {border:1px solid;border-top-color:#123456;}';
300         $cssout = '.test{border:1px solid;border-top-color:#123456;}';
301         $this->assertEquals($cssout, $optimiser->process($cssin));
303         $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;}';
304         $cssout = '.test{border:1px solid;border-top-color:#111;border-bottom-color:#222;border-left-color:#333;}';
305         $this->assertEquals($cssout, $optimiser->process($cssin));
307         $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;border-right-color:#444;}';
308         $cssout = '.test{border:1px solid;border-color:#111 #444 #222 #333;}';
309         $this->assertEquals($cssout, $optimiser->process($cssin));
311         $cssin = '.generaltable .cell {border-color:#EEE;} .generaltable .cell {border-width: 1px;border-style: solid;}';
312         $cssout = '.generaltable .cell{border:1px solid #EEE;}';
313         $this->assertEquals($cssout, $optimiser->process($cssin));
315         $cssin = '#page-admin-roles-override .rolecap {border:none;border-bottom:1px solid #CECECE;}';
316         $cssout = '#page-admin-roles-override .rolecap{border-top:0;border-right:0;border-bottom:1px solid #CECECE;border-left:0;}';
317         $this->assertEquals($cssout, $optimiser->process($cssin));
318     }
320     /**
321      * Test colour styles
322      * @param css_optimiser $optimiser
323      */
324     public function test_colors() {
325         $optimiser = $this->get_optimiser();
327         $css = '.css{}';
328         $this->assertEquals($css, $optimiser->process($css));
330         $css = '.css{color:#123456;}';
331         $this->assertEquals($css, $optimiser->process($css));
333         $css = '#some{color:#123456;}';
334         $this->assertEquals($css, $optimiser->process($css));
336         $css = 'div{color:#123456;}';
337         $this->assertEquals($css, $optimiser->process($css));
339         $css = 'div.css{color:#123456;}';
340         $this->assertEquals($css, $optimiser->process($css));
342         $css = 'div#some{color:#123456;}';
343         $this->assertEquals($css, $optimiser->process($css));
345         $css = 'div[type=blah]{color:#123456;}';
346         $this->assertEquals($css, $optimiser->process($css));
348         $css = 'div.css[type=blah]{color:#123456;}';
349         $this->assertEquals($css, $optimiser->process($css));
351         $css = 'div#some[type=blah]{color:#123456;}';
352         $this->assertEquals($css, $optimiser->process($css));
354         $css = '#some.css[type=blah]{color:#123456;}';
355         $this->assertEquals($css, $optimiser->process($css));
357         $css = '#some .css[type=blah]{color:#123456;}';
358         $this->assertEquals($css, $optimiser->process($css));
360         $cssin = '.one {color:red;} .two {color:#F00;}';
361         $cssout = ".one, .two{color:#F00;}";
362         $this->assertEquals($cssout, $optimiser->process($cssin));
364         $cssin = '.one {color:#123;color:#321;}';
365         $cssout = '.one{color:#321;}';
366         $this->assertEquals($cssout, $optimiser->process($cssin));
368         $cssin = '.one {color:#123; color : #321 ;}';
369         $cssout = '.one{color:#321;}';
370         $this->assertEquals($cssout, $optimiser->process($cssin));
372         $cssin = '.one {color:#123;} .one {color:#321;}';
373         $cssout = '.one{color:#321;}';
374         $this->assertEquals($cssout, $optimiser->process($cssin));
376         $cssin = '.one {color:#123 !important;color:#321;}';
377         $cssout = '.one{color:#123 !important;}';
378         $this->assertEquals($cssout, $optimiser->process($cssin));
380         $cssin = '.one {color:#123 !important;} .one {color:#321;}';
381         $cssout = '.one{color:#123 !important;}';
382         $this->assertEquals($cssout, $optimiser->process($cssin));
384         $cssin = '.one {color:#123!important;} .one {color:#321;}';
385         $cssout = '.one{color:#123 !important;}';
386         $this->assertEquals($cssout, $optimiser->process($cssin));
388         $cssin = '.one {color:rgb(255, 128, 1)}';
389         $cssout = '.one{color:rgb(255, 128, 1);}';
390         $this->assertEquals($cssout, $optimiser->process($cssin));
392         $cssin = '.one {color:rgba(255, 128, 1, 0.5)}';
393         $cssout = '.one{color:rgba(255, 128, 1, 0.5);}';
394         $this->assertEquals($cssout, $optimiser->process($cssin));
396         $cssin = '.one {color:hsl(120, 65%, 75%)}';
397         $cssout = '.one{color:hsl(120, 65%, 75%);}';
398         $this->assertEquals($cssout, $optimiser->process($cssin));
400         $cssin = '.one {color:hsla(120,65%,75%,0.5)}';
401         $cssout = '.one{color:hsla(120,65%,75%,0.5);}';
402         $this->assertEquals($cssout, $optimiser->process($cssin));
404         // Try some invalid colours to make sure we don't mangle them.
405         $css = 'div#some{color:#1;}';
406         $this->assertEquals($css, $optimiser->process($css));
408         $css = 'div#some{color:#12;}';
409         $this->assertEquals($css, $optimiser->process($css));
411         $css = 'div#some{color:#1234;}';
412         $this->assertEquals($css, $optimiser->process($css));
414         $css = 'div#some{color:#12345;}';
415         $this->assertEquals($css, $optimiser->process($css));
416     }
418     public function test_widths() {
419         $optimiser = $this->get_optimiser();
421         $cssin  = '.css {width:0}';
422         $cssout = '.css{width:0;}';
423         $this->assertEquals($cssout, $optimiser->process($cssin));
425         $cssin  = '.css {width:0px}';
426         $cssout = '.css{width:0;}';
427         $this->assertEquals($cssout, $optimiser->process($cssin));
429         $cssin  = '.css {width:0em}';
430         $cssout = '.css{width:0;}';
431         $this->assertEquals($cssout, $optimiser->process($cssin));
433         $cssin  = '.css {width:0pt}';
434         $cssout = '.css{width:0;}';
435         $this->assertEquals($cssout, $optimiser->process($cssin));
437         $cssin  = '.css {width:0mm}';
438         $cssout = '.css{width:0;}';
439         $this->assertEquals($cssout, $optimiser->process($cssin));
441         $cssin  = '.css {width:100px}';
442         $cssout = '.css{width:100px;}';
443         $this->assertEquals($cssout, $optimiser->process($cssin));
444     }
446     /**
447      * Test margin styles
448      * @param css_optimiser $optimiser
449      */
450     public function test_margins() {
451         $optimiser = $this->get_optimiser();
453         $cssin = '.one {margin: 1px 2px 3px 4px}';
454         $cssout = '.one{margin:1px 2px 3px 4px;}';
455         $this->assertEquals($cssout, $optimiser->process($cssin));
457         $cssin = '.one {margin-top:1px; margin-left:4px; margin-right:2px; margin-bottom: 3px;}';
458         $cssout = '.one{margin:1px 2px 3px 4px;}';
459         $this->assertEquals($cssout, $optimiser->process($cssin));
461         $cssin = '.one {margin-top:1px; margin-left:4px;}';
462         $cssout = '.one{margin-top:1px;margin-left:4px;}';
463         $this->assertEquals($cssout, $optimiser->process($cssin));
465         $cssin = '.one {margin:1px; margin-left:4px;}';
466         $cssout = '.one{margin:1px 1px 1px 4px;}';
467         $this->assertEquals($cssout, $optimiser->process($cssin));
469         $cssin = '.one {margin:1px; margin-bottom:4px;}';
470         $cssout = '.one{margin:1px 1px 4px;}';
471         $this->assertEquals($cssout, $optimiser->process($cssin));
473         $cssin = '.one, .two, .one.two, .one .two {margin:0;} .one.two {margin:0 7px;}';
474         $cssout = '.one, .two{margin:0;} .one.two{margin:0 7px;} .one .two{margin:0;}';
475         $this->assertEquals($cssout, $optimiser->process($cssin));
477         $cssin = '.block {margin-top: 0px !important;margin-bottom: 0px !important;}';
478         $cssout = '.block{margin-top:0 !important;margin-bottom:0 !important;}';
479         $this->assertEquals($cssout, $optimiser->process($cssin));
481         $cssin = '.block {margin: 0px !important;margin-bottom: 3px;}';
482         $cssout = '.block{margin:0 !important;}';
483         $this->assertEquals($cssout, $optimiser->process($cssin));
485         $cssin = '.block {margin: 5px;margin-right: 0 !important;}';
486         $cssout = '.block{margin:5px;margin-right:0 !important;}';
487         $this->assertEquals($cssout, $optimiser->process($cssin));
488     }
490     /**
491      * Test padding styles
492      *
493      * @param css_optimiser $optimiser
494      */
495     public function test_padding() {
496         $optimiser = $this->get_optimiser();
498         $cssin = '.one {padding: 1px 2px 3px 4px}';
499         $cssout = '.one{padding:1px 2px 3px 4px;}';
500         $this->assertEquals($cssout, $optimiser->process($cssin));
502         $cssin = '.one {padding-top:1px; padding-left:4px; padding-right:2px; padding-bottom: 3px;}';
503         $cssout = '.one{padding:1px 2px 3px 4px;}';
504         $this->assertEquals($cssout, $optimiser->process($cssin));
506         $cssin = '.one {padding-top:1px; padding-left:4px;padding-bottom: 3px;}';
507         $cssout = '.one{padding-top:1px;padding-left:4px;padding-bottom:3px;}';
508         $this->assertEquals($cssout, $optimiser->process($cssin));
510         $cssin = '.one {padding-top:1px; padding-left:4px;}';
511         $cssout = '.one{padding-top:1px;padding-left:4px;}';
512         $this->assertEquals($cssout, $optimiser->process($cssin));
514         $cssin = '.one {padding:1px; padding-left:4px;}';
515         $cssout = '.one{padding:1px 1px 1px 4px;}';
516         $this->assertEquals($cssout, $optimiser->process($cssin));
518         $cssin = '.one {padding:1px; padding-bottom:4px;}';
519         $cssout = '.one{padding:1px 1px 4px;}';
520         $this->assertEquals($cssout, $optimiser->process($cssin));
522         $cssin = '.one {padding:0 !important;}';
523         $cssout = '.one{padding:0 !important;}';
524         $this->assertEquals($cssout, $optimiser->process($cssin));
526         $cssin = '.one {padding:0 !important;}';
527         $cssout = '.one{padding:0 !important;}';
528         $this->assertEquals($cssout, $optimiser->process($cssin));
530         $cssin = '.one, .two, .one.two, .one .two {padding:0;} .one.two {padding:0 7px;}';
531         $cssout = '.one, .two{padding:0;} .one.two{padding:0 7px;} .one .two{padding:0;}';
532         $this->assertEquals($cssout, $optimiser->process($cssin));
534         $cssin = '.block {padding-top: 0px !important;padding-bottom: 0px !important;}';
535         $cssout = '.block{padding-top:0 !important;padding-bottom:0 !important;}';
536         $this->assertEquals($cssout, $optimiser->process($cssin));
538         $cssin = '.block {padding: 0px !important;padding-bottom: 3px;}';
539         $cssout = '.block{padding:0 !important;}';
540         $this->assertEquals($cssout, $optimiser->process($cssin));
542         $cssin = '.block {padding: 5px;padding-right: 0 !important;}';
543         $cssout = '.block{padding:5px;padding-right:0 !important;}';
544         $this->assertEquals($cssout, $optimiser->process($cssin));
545     }
547     public function test_cursor() {
548         $optimiser = $this->get_optimiser();
550         // Valid cursor
551         $cssin = '.one {cursor: pointer;}';
552         $cssout = '.one{cursor:pointer;}';
553         $this->assertEquals($cssout, $optimiser->process($cssin));
555         // Invalid cursor but tollerated
556         $cssin = '.one {cursor: hand;}';
557         $cssout = '.one{cursor:hand;}';
558         $this->assertEquals($cssout, $optimiser->process($cssin));
560         // Valid cursor: url relative
561         $cssin = '.one {cursor: mycursor.png;}';
562         $cssout = '.one{cursor:mycursor.png;}';
563         $this->assertEquals($cssout, $optimiser->process($cssin));
565         // Valid cursor: url absolute
566         $cssin = '.one {cursor: http://local.host/mycursor.png;}';
567         $cssout = '.one{cursor:http://local.host/mycursor.png;}';
568         $this->assertEquals($cssout, $optimiser->process($cssin));
569     }
571     public function test_vertical_align() {
572         $optimiser = $this->get_optimiser();
574         // Valid vertical aligns
575         $cssin = '.one {vertical-align: baseline;}';
576         $cssout = '.one{vertical-align:baseline;}';
577         $this->assertEquals($cssout, $optimiser->process($cssin));
578         $cssin = '.one {vertical-align: middle;}';
579         $cssout = '.one{vertical-align:middle;}';
580         $this->assertEquals($cssout, $optimiser->process($cssin));
581         $cssin = '.one {vertical-align: 0.75em;}';
582         $cssout = '.one{vertical-align:0.75em;}';
583         $this->assertEquals($cssout, $optimiser->process($cssin));
584         $cssin = '.one {vertical-align: 50%;}';
585         $cssout = '.one{vertical-align:50%;}';
586         $this->assertEquals($cssout, $optimiser->process($cssin));
588         // Invalid but tollerated
589         $cssin = '.one {vertical-align: center;}';
590         $cssout = '.one{vertical-align:center;}';
591         $this->assertEquals($cssout, $optimiser->process($cssin));
592     }
594     public function test_float() {
595         $optimiser = $this->get_optimiser();
597         // Valid vertical aligns
598         $cssin = '.one {float: inherit;}';
599         $cssout = '.one{float:inherit;}';
600         $this->assertEquals($cssout, $optimiser->process($cssin));
601         $cssin = '.one {float: left;}';
602         $cssout = '.one{float:left;}';
603         $this->assertEquals($cssout, $optimiser->process($cssin));
604         $cssin = '.one {float: right;}';
605         $cssout = '.one{float:right;}';
606         $this->assertEquals($cssout, $optimiser->process($cssin));
607         $cssin = '.one {float: none;}';
608         $cssout = '.one{float:none;}';
609         $this->assertEquals($cssout, $optimiser->process($cssin));
611         // Invalid but tollerated
612         $cssin = '.one {float: center;}';
613         $cssout = '.one{float:center;}';
614         $this->assertEquals($cssout, $optimiser->process($cssin));
615     }
617     /**
618      * Test some totally invalid CSS optimisation
619      *
620      * @param css_optimiser $optimiser
621      */
622     protected function try_invalid_css_handling() {
623         $optimiser = $this->get_optimiser();
625         $cssin = array(
626             '.one{}',
627             '.one {:}',
628             '.one {;}',
629             '.one {;;;;;}',
630             '.one {:;}',
631             '.one {:;:;:;:::;;;}',
632             '.one {!important}',
633             '.one {:!important}',
634             '.one {:!important;}',
635             '.one {;!important}'
636         );
637         $cssout = '.one{}';
638         foreach ($cssin as $css) {
639             $this->assertEquals($cssout, $optimiser->process($css));
640         }
642         $cssin = array(
643             '.one{background-color:red;}',
644             '.one {background-color:red;} .one {background-color:}',
645             '.one {background-color:red;} .one {background-color;}',
646             '.one {background-color:red;} .one {background-color}',
647             '.one {background-color:red;} .one {background-color:;}',
648             '.one {background-color:red;} .one {:blue;}',
649             '.one {background-color:red;} .one {:#00F}',
650         );
651         $cssout = '.one{background-color:#F00;}';
652         foreach ($cssin as $css) {
653             $this->assertEquals($cssout, $optimiser->process($css));
654         }
656         $cssin = '..one {background-color:color:red}';
657         $cssout = '..one{background-color:color:red;}';
658         $this->assertEquals($cssout, $optimiser->process($cssin));
660         $cssin = '#.one {background-color:color:red}';
661         $cssout = '#.one{background-color:color:red;}';
662         $this->assertEquals($cssout, $optimiser->process($cssin));
664         $cssin = '##one {background-color:color:red}';
665         $cssout = '##one{background-color:color:red;}';
666         $this->assertEquals($cssout, $optimiser->process($cssin));
668         $cssin = '.one {background-color:color:red}';
669         $cssout = '.one{background-color:color:red;}';
670         $this->assertEquals($cssout, $optimiser->process($cssin));
672         $cssin = '.one {background-color:red;color;border-color:blue}';
673         $cssout = '.one{background-color:#F00;border-color:#00F;}';
674         $this->assertEquals($cssout, $optimiser->process($cssin));
676         $cssin  = '{background-color:#123456;color:red;}{color:green;}';
677         $cssout = "{background-color:#123456;color:#008000;}";
678         $this->assertEquals($cssout, $optimiser->process($cssin));
680         $cssin  = '.one {color:red;} {color:green;} .one {background-color:blue;}';
681         $cssout = ".one{color:#F00;background-color:#00F;} {color:#008000;}";
682         $this->assertEquals($cssout, $optimiser->process($cssin));
683     }
685     /**
686      * Try to break some things
687      * @param css_optimiser $optimiser
688      */
689     protected function try_break_things() {
690         $optimiser = $this->get_optimiser();
692         // Wildcard test
693         $cssin  = '* {color: black;}';
694         $cssout = '*{color:#000;}';
695         $this->assertEquals($cssout, $optimiser->process($cssin));
697         // Wildcard test
698         $cssin  = '.one * {color: black;}';
699         $cssout = '.one *{color:#000;}';
700         $this->assertEquals($cssout, $optimiser->process($cssin));
702         // Wildcard test
703         $cssin  = '* .one * {color: black;}';
704         $cssout = '* .one *{color:#000;}';
705         $this->assertEquals($cssout, $optimiser->process($cssin));
707         // Wildcard test
708         $cssin  = '*,* {color: black;}';
709         $cssout = '*{color:#000;}';
710         $this->assertEquals($cssout, $optimiser->process($cssin));
712         // Wildcard test
713         $cssin  = '*, * .one {color: black;}';
714         $cssout = "*,\n* .one{color:#000;}";
715         $this->assertEquals($cssout, $optimiser->process($cssin));
717         // Wildcard test
718         $cssin  = '*, *.one {color: black;}';
719         $cssout = "*,\n*.one{color:#000;}";
720         $this->assertEquals($cssout, $optimiser->process($cssin));
722         // Psedo test
723         $cssin  = '.one:before {color: black;}';
724         $cssout = '.one:before{color:#000;}';
725         $this->assertEquals($cssout, $optimiser->process($cssin));
727         // Psedo test
728         $cssin  = '.one:after {color: black;}';
729         $cssout = '.one:after{color:#000;}';
730         $this->assertEquals($cssout, $optimiser->process($cssin));
732         // Psedo test
733         $cssin  = '.one:onclick {color: black;}';
734         $cssout = '.one:onclick{color:#000;}';
735         $this->assertEquals($cssout, $optimiser->process($cssin));
737         // Test complex CSS rules that don't really exist but mimic other CSS rules
738         $cssin  = '.one {master-of-destruction: explode(\' \', "What madness");}';
739         $cssout = '.one{master-of-destruction:explode(\' \', "What madness");}';
740         $this->assertEquals($cssout, $optimiser->process($cssin));
742         // Test some complex IE css... I couldn't even think of a more complext solution
743         // than the CSS they came up with.
744         $cssin  = 'a { opacity: 0.5; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50); }';
745         $cssout = 'a{opacity:0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);}';
746         $this->assertEquals($cssout, $optimiser->process($cssin));
747     }
749     /**
750      * A bulk processing test
751      * @param css_optimiser $optimiser
752      */
753     protected function try_bulk_processing() {
754         global $CFG;
755         $cssin = <<<CSS
756 .test .one {
757     margin:5px;
758     border:0;
760 .test .one {
761     margin: 10px;
762     color: red;
765 .test.one {
766     margin: 15px;
769 #test .one {margin:  20px;}
770 #test #one {margin:  25px;}.test #one {margin:  30px;}
771   .test    .one      {     background-color: #123;     }
772 .test.one{border:1px solid blue}.test.one{border-color:green;}
774 @media print {
775     #test .one {margin: 35px;}
778 @media print {
779     #test .one {margin: 40px;color: #123456;}
780     #test #one {margin: 45px;}
783 @media print,screen {
784     #test .one {color: #654321;}
787 #test .one,
788 #new.style {color:#000;}
789 CSS;
791         $cssout = <<<CSS
792 .test .one{margin:10px;border-width:0;color:#F00;background-color:#123;}
793 .test.one{margin:15px;border:1px solid #008000;}
794 #test .one{margin:20px;color:#000;}
795 #test #one{margin:25px;}
796 .test #one{margin:30px;}
797 #new.style{color:#000;}
799 @media print {
800   #test .one{margin:40px;color:#123456;}
801   #test #one{margin:45px;}
803 @media print,screen {
804   #test .one{color:#654321;}
806 CSS;
807         $CFG->cssoptimiserpretty = 1;
808         $this->assertEquals($this->get_optimiser()->process($cssin), $cssout);
809     }
811     /**
812      * Test CSS colour matching
813      */
814     public function test_css_is_colour() {
815         // First lets test hex colours
816         $this->assertTrue(css_is_colour('#123456'));
817         $this->assertTrue(css_is_colour('#123'));
818         $this->assertTrue(css_is_colour('#ABCDEF'));
819         $this->assertTrue(css_is_colour('#ABC'));
820         $this->assertTrue(css_is_colour('#abcdef'));
821         $this->assertTrue(css_is_colour('#abc'));
822         $this->assertTrue(css_is_colour('#aBcDeF'));
823         $this->assertTrue(css_is_colour('#aBc'));
824         $this->assertTrue(css_is_colour('#1a2Bc3'));
825         $this->assertTrue(css_is_colour('#1Ac'));
827         // Note the following two colour's arn't really colours but browsers process
828         // them still.
829         $this->assertTrue(css_is_colour('#A'));
830         $this->assertTrue(css_is_colour('#12'));
831         // Having four or five characters however are not valid colours and
832         // browsers don't parse them. They need to fail so that broken CSS
833         // stays broken after optimisation.
834         $this->assertFalse(css_is_colour('#1234'));
835         $this->assertFalse(css_is_colour('#12345'));
837         $this->assertFalse(css_is_colour('#BCDEFG'));
838         $this->assertFalse(css_is_colour('#'));
839         $this->assertFalse(css_is_colour('#0000000'));
840         $this->assertFalse(css_is_colour('#132-245'));
841         $this->assertFalse(css_is_colour('#13 23 43'));
842         $this->assertFalse(css_is_colour('123456'));
844         // Next lets test real browser mapped colours
845         $this->assertTrue(css_is_colour('black'));
846         $this->assertTrue(css_is_colour('blue'));
847         $this->assertTrue(css_is_colour('BLACK'));
848         $this->assertTrue(css_is_colour('Black'));
849         $this->assertTrue(css_is_colour('bLACK'));
850         $this->assertTrue(css_is_colour('mediumaquamarine'));
851         $this->assertTrue(css_is_colour('mediumAquamarine'));
852         $this->assertFalse(css_is_colour('monkey'));
853         $this->assertFalse(css_is_colour(''));
854         $this->assertFalse(css_is_colour('not a colour'));
856         // Next lets test rgb(a) colours
857         $this->assertTrue(css_is_colour('rgb(255,255,255)'));
858         $this->assertTrue(css_is_colour('rgb(0, 0, 0)'));
859         $this->assertTrue(css_is_colour('RGB (255, 255   ,    255)'));
860         $this->assertTrue(css_is_colour('rgba(0,0,0,0)'));
861         $this->assertTrue(css_is_colour('RGBA(255,255,255,1)'));
862         $this->assertTrue(css_is_colour('rgbA(255,255,255,0.5)'));
863         $this->assertFalse(css_is_colour('rgb(-255,-255,-255)'));
864         $this->assertFalse(css_is_colour('rgb(256,-256,256)'));
866         // Now lets test HSL colours
867         $this->assertTrue(css_is_colour('hsl(0,0%,100%)'));
868         $this->assertTrue(css_is_colour('hsl(180, 0%, 10%)'));
869         $this->assertTrue(css_is_colour('hsl (360, 100%   ,    95%)'));
871         // Finally test the special values
872         $this->assertTrue(css_is_colour('inherit'));
873     }
875     /**
876      * Test the css_is_width function
877      */
878     public function test_css_is_width() {
880         $this->assertTrue(css_is_width('0'));
881         $this->assertTrue(css_is_width('0px'));
882         $this->assertTrue(css_is_width('0em'));
883         $this->assertTrue(css_is_width('199px'));
884         $this->assertTrue(css_is_width('199em'));
885         $this->assertTrue(css_is_width('199%'));
886         $this->assertTrue(css_is_width('-1px'));
887         $this->assertTrue(css_is_width('auto'));
888         $this->assertTrue(css_is_width('inherit'));
890         // Valid widths but missing their unit specifier
891         $this->assertFalse(css_is_width('0.75'));
892         $this->assertFalse(css_is_width('3'));
893         $this->assertFalse(css_is_width('-1'));
894         // Totally invalid widths
895         $this->assertFalse(css_is_width('-'));
896         $this->assertFalse(css_is_width('bananas'));
897         $this->assertFalse(css_is_width(''));
898         $this->assertFalse(css_is_width('top'));
899     }
901     /**
902      * This function tests some of the broken crazy CSS we have in Moodle.
903      * For each of these things the value needs to be corrected if we can be 100%
904      * certain what is going wrong, Or it needs to be left as is.
905      *
906      * @param css_optimiser $optimiser
907      */
908     public function try_broken_css_found_in_moodle() {
909         $optimiser = $this->get_optimiser();
911         // Notice how things are out of order here but that they get corrected
912         $cssin = '.test {background:url([[pix:theme|pageheaderbgred]]) top center no-repeat}';
913         $cssout = '.test{background:url([[pix:theme|pageheaderbgred]]) no-repeat top center;}';
914         $this->assertEquals($cssout, $optimiser->process($cssin));
916         // Cursor hand isn't valid
917         $cssin  = '.test {cursor: hand;}';
918         $cssout = '.test{cursor:hand;}';
919         $this->assertEquals($cssout, $optimiser->process($cssin));
921         // Zoom property isn't valid
922         $cssin  = '.test {zoom: 1;}';
923         $cssout = '.test{zoom:1;}';
924         $this->assertEquals($cssout, $optimiser->process($cssin));
926         // Left isn't a valid position property
927         $cssin  = '.test {position: left;}';
928         $cssout = '.test{position:left;}';
929         $this->assertEquals($cssout, $optimiser->process($cssin));
931         // The dark red color isn't a valid HTML color but has a standardised
932         // translation of #8B0000
933         $cssin  = '.test {color: darkred;}';
934         $cssout = '.test{color:#8B0000;}';
935         $this->assertEquals($cssout, $optimiser->process($cssin));
937         // You can't use argb colours as border colors
938         $cssin  = '.test {border-bottom: 1px solid rgba(0,0,0,0.25);}';
939         $cssout = '.test{border-bottom:1px solid rgba(0,0,0,0.25);}';
940         $this->assertEquals($cssout, $optimiser->process($cssin));
942         // Opacity with annoying IE equivilants....
943         $cssin  = '.test {opacity: 0.5; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50);}';
944         $cssout = '.test{opacity:0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);}';
945         $this->assertEquals($cssout, $optimiser->process($cssin));
946     }
948     /**
949      * Test keyframe declarations
950      * @param css_optimiser $optimiser
951      */
952     public function try_keyframe_css_animation() {
953         $optimiser = $this->get_optimiser();
955         $css = '.dndupload-arrow{width:56px;height:47px;position:absolute;animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;background:url(\'[[pix:theme|fp/dnd_arrow]]\') no-repeat center;margin-left:-28px;}';
956         $this->assertEquals($css, $optimiser->process($css));
958         $css = '@keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}';
959         $this->assertEquals($css, $optimiser->process($css));
961         $css  = "@keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}\n";
962         $css .= "@-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}\n";
963         $css .= "@-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}";
964         $this->assertEquals($css, $optimiser->process($css));
967         $cssin = <<<CSS
968 .test {color:#FFF;}
969 .testtwo {color:#FFF;}
970 @media print {
971     .test {background-color:#FFF;}
973 .dndupload-arrow{width:56px;height:47px;position:absolute;animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;background:url('[[pix:theme|fp/dnd_arrow]]') no-repeat center;margin-left:-28px;}
974 @media print {
975     .test {background-color:#000;}
977 @keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
978 @-moz-keyframes mymove{0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
979 @-webkit-keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
980 @media print {
981     .test {background-color:#333;}
983 .test {color:#888;}
984 .testtwo {color:#888;}
985 CSS;
987         $cssout = <<<CSS
988 .test,
989 .testtwo{color:#888;}
990 .dndupload-arrow{width:56px;height:47px;position:absolute;animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;background:url('[[pix:theme|fp/dnd_arrow]]') no-repeat center;margin-left:-28px;}
992 @media print {
993   .test{background-color:#333;}
995 @keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
996 @-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
997 @-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
998 CSS;
999         $this->assertEquals($cssout, $optimiser->process($cssin));
1003         $cssin = <<<CSS
1004 .dndupload-target {display:none;}
1005 .dndsupported .dndupload-ready .dndupload-target {display:block;}
1006 .dndupload-uploadinprogress {display:none;text-align:center;}
1007 .dndupload-uploading .dndupload-uploadinprogress {display:block;}
1008 .dndupload-arrow {background:url('[[pix:theme|fp/dnd_arrow]]') center no-repeat;width:56px;height:47px;position:absolute;margin-left: -28px;/*right:46%;left:46%;*/animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;}
1009 @keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}@-moz-keyframes mymove{0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}@-webkit-keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
1011 /*
1012  * Select Dialogue (File Manager only)
1013  */
1014 .filemanager.fp-select .fp-select-loading {display:none;}
1015 .filemanager.fp-select.loading .fp-select-loading {display:block;}
1016 .filemanager.fp-select.loading form {display:none;}
1017 CSS;
1019         $cssout = <<<CSS
1020 .dndupload-target{display:none;}
1021 .dndsupported .dndupload-ready .dndupload-target{display:block;}
1022 .dndupload-uploadinprogress{display:none;text-align:center;}
1023 .dndupload-uploading .dndupload-uploadinprogress{display:block;}
1024 .dndupload-arrow{background:url('[[pix:theme|fp/dnd_arrow]]') no-repeat center;width:56px;height:47px;position:absolute;margin-left:-28px;animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;}
1025 .filemanager.fp-select .fp-select-loading{display:none;}
1026 .filemanager.fp-select.loading .fp-select-loading{display:block;}
1027 .filemanager.fp-select.loading form{display:none;}
1029 @keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1030 @-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1031 @-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1032 CSS;
1033         $this->assertEquals($cssout, $optimiser->process($cssin));
1034     }
1036     /**
1037      * Test media declarations
1038      * @param css_optimiser $optimiser
1039      */
1040     public function try_media_rules() {
1041         $optimiser = $this->get_optimiser();
1043         $cssin = "@media print {\n  .test{background-color:#333;}\n}";
1044         $cssout = "@media print {\n  .test{background-color:#333;}\n}";
1045         $this->assertEquals($cssout, $optimiser->process($cssin));
1047         $cssin = "@media screen and (min-width:30px) {\n  #region-main-box{left: 30px;float: left;}\n}";
1048         $cssout = "@media screen and (min-width:30px) {\n  #region-main-box{left:30px;float:left;}\n}";
1049         $this->assertEquals($cssout, $optimiser->process($cssin));
1051         $cssin = "@media all and (min-width:500px) {\n  #region-main-box{left:30px;float:left;}\n}";
1052         $cssout = "@media all and (min-width:500px) {\n  #region-main-box{left:30px;float:left;}\n}";
1053         $this->assertEquals($cssout, $optimiser->process($cssin));
1055         $cssin = "@media (min-width:500px) {\n  #region-main-box{left:30px;float:left;}\n}";
1056         $cssout = "@media (min-width:500px) {\n  #region-main-box{left:30px;float:left;}\n}";
1057         $this->assertEquals($cssout, $optimiser->process($cssin));
1059         $cssin = "@media screen and (color), projection and (color) {\n  #region-main-box{left:30px;float:left;}\n}";
1060         $cssout = "@media screen and (color),projection and (color) {\n  #region-main-box{left:30px;float:left;}\n}";
1061         $this->assertEquals($cssout, $optimiser->process($cssin));
1063         $cssin = "@media print {\n  .test{background-color:#000;}\n}@media print {\n  .test{background-color:#FFF;}\n}";
1064         $cssout = "@media print {\n  .test{background-color:#FFF;}\n}";
1065         $this->assertEquals($cssout, $optimiser->process($cssin));
1067         $cssin = "@media screen and (min-width:30px) {\n  #region-main-box{background-color:#000;}\n}\n@media screen and (min-width:30px) {\n  #region-main-box{background-color:#FFF;}\n}";
1068         $cssout = "@media screen and (min-width:30px) {\n  #region-main-box{background-color:#FFF;}\n}";
1069         $this->assertEquals($cssout, $optimiser->process($cssin));
1071         $cssin = "@media screen and (min-width:30px) {\n  #region-main-box{background-color:#000;}\n}\n@media screen and (min-width:31px) {\n  #region-main-box{background-color:#FFF;}\n}";
1072         $cssout = "@media screen and (min-width:30px) {\n  #region-main-box{background-color:#000;}\n}\n@media screen and (min-width:31px) {\n  #region-main-box{background-color:#FFF;}\n}";
1073         $this->assertEquals($cssout, $optimiser->process($cssin));
1074     }
1077     public function test_css_optimisation_ordering() {
1078         $optimiser = $this->get_optimiser();
1080         $css = '.test{display:none;} .dialogue{display:block;} .dialogue-hidden{display:none;}';
1081         $this->assertEquals($css, $optimiser->process($css));
1083         $cssin = '.test{display:none;} .dialogue-hidden{display:none;} .dialogue{display:block;}';
1084         $cssout = '.test, .dialogue-hidden{display:none;} .dialogue{display:block;}';
1085         $this->assertEquals($cssout, $optimiser->process($cssin));
1086     }