[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/tests/ -> csslib_test.php (source)

   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   * 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   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  global $CFG;
  29  require_once($CFG->libdir . '/csslib.php');
  30  
  31  
  32  /**
  33   * CSS optimiser test class.
  34   *
  35   * @package core_css
  36   * @category phpunit
  37   * @copyright 2012 Sam Hemelryk
  38   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class core_csslib_testcase extends advanced_testcase {
  41  
  42      /**
  43       * Returns a CSS optimiser
  44       *
  45       * @return css_optimiser
  46       */
  47      protected function get_optimiser() {
  48          return new css_optimiser();
  49      }
  50  
  51      /**
  52       * Background colour tests.
  53       *
  54       * When testing background styles it is important to understand how the background shorthand works.
  55       * background shorthand allows the following styles to be specified in a single "background" declaration:
  56       *   - background-color
  57       *   - background-image
  58       *   - background-repeat
  59       *   - background-attachment
  60       *   - background-position
  61       *
  62       * If the background shorthand is used it can contain one or more of those (preferabbly in that order).
  63       * Important it does not need to contain all of them.
  64       * However even if it doesn't contain values for all styles all of the styles will be affected.
  65       * If a style is missed from the shorthand background style but has an existing value in the rule then the existing value
  66       * is cleared.
  67       *
  68       * For example:
  69       *      .test {background: url(\'test.png\');background: bottom right;background:#123456;}
  70       * will result in:
  71       *      .test {background:#123456;}
  72       *
  73       * And:
  74       *      .test {background-image: url(\'test.png\');background:#123456;}
  75       * will result in:
  76       *      .test {background:#123456;}
  77       */
  78      public function test_background() {
  79          $optimiser = new css_optimiser();
  80  
  81          $cssin = '.test {background-color: #123456;}';
  82          $cssout = '.test{background-color:#123456;}';
  83          $this->assertSame($cssout, $optimiser->process($cssin));
  84  
  85          $cssin = '.test {background: #123456;}';
  86          $cssout = '.test{background:#123456;}';
  87          $this->assertSame($cssout, $optimiser->process($cssin));
  88  
  89          $cssin = '.test {background-image: url(\'test.png\');}';
  90          $cssout = '.test{background-image:url(\'test.png\');}';
  91          $this->assertSame($cssout, $optimiser->process($cssin));
  92  
  93          $cssin = '.test {background: #123456 url(\'test.png\') no-repeat top left;}';
  94          $cssout = '.test{background:#123456 url(\'test.png\') no-repeat top left;}';
  95          $this->assertSame($cssout, $optimiser->process($cssin));
  96  
  97          // Check out this for madness, background position and background-repeat have been reversed.
  98          $cssin = '.test {background: #123456 url(\'test.png\') center no-repeat;}';
  99          $cssout = '.test{background:#123456 url(\'test.png\') no-repeat center;}';
 100          $this->assertSame($cssout, $optimiser->process($cssin));
 101  
 102          $cssin = '.test {background: url(\'test.png\') no-repeat top left;}.test{background-position: bottom right}.test {background-color:#123456;}';
 103          $cssout = '.test{background:#123456 url(\'test.png\') no-repeat bottom right;}';
 104          $this->assertSame($cssout, $optimiser->process($cssin));
 105  
 106          $cssin = '.test {background: url(   \'test.png\'    )}.test{background: bottom right}.test {background:#123456;}';
 107          $cssout = '.test{background:#123456;}';
 108          $this->assertSame($cssout, $optimiser->process($cssin));
 109  
 110          $cssin = '.test {background-image: url(\'test.png\');background:#123456;}';
 111          $cssout = '.test{background:#123456;}';
 112          $this->assertSame($cssout, $optimiser->process($cssin));
 113  
 114          $cssin = '.test {background-color: #123456;background-repeat: repeat-x; background-position: 100% 0%;}';
 115          $cssout = '.test{background-color:#123456;background-repeat:repeat-x;background-position:100% 0%;}';
 116          $this->assertSame($cssout, $optimiser->process($cssin));
 117  
 118          $cssin = '.tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
 119                    .tree_item.branch.navigation_node {background-image:none;padding-left:0;}';
 120          $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;}';
 121          $this->assertSame($cssout, $optimiser->process($cssin));
 122  
 123          $cssin = '#nextLink{background:url(data:image/gif;base64,AAAA);}';
 124          $cssout = '#nextLink{background:url(data:image/gif;base64,AAAA);}';
 125          $this->assertSame($cssout, $optimiser->process($cssin));
 126  
 127          $cssin = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
 128          $cssout = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
 129          $this->assertSame($cssout, $optimiser->process($cssin));
 130  
 131          $cssin = '.test {background: #123456 url(data:image/gif;base64,AAAA) no-repeat top left;}';
 132          $cssout = '.test{background:#123456 url(data:image/gif;base64,AAAA) no-repeat top left;}';
 133          $this->assertSame($cssout, $optimiser->process($cssin));
 134  
 135          $cssin = '#test {background-image:none;background-position:right center;background-repeat:no-repeat;}';
 136          $cssout = '#test{background-image:none;background-position:right center;background-repeat:no-repeat;}';
 137          $this->assertSame($cssout, $optimiser->process($cssin));
 138  
 139          $cssin = '.test {background: url([[pix:theme|photos]]) no-repeat 50% 50%;background-size: 40px 40px;-webkit-background-size: 40px 40px;}';
 140          $cssout = '.test{background:url([[pix:theme|photos]]) no-repeat 50% 50%;background-size:40px 40px;-webkit-background-size:40px 40px;}';
 141          $this->assertSame($cssout, $optimiser->process($cssin));
 142  
 143          $cssin = '.test{background-image: -o-linear-gradient(#3c3c3c, #111);background-image: linear-gradient(#3c3c3c, #111);}';
 144          $cssout = '.test{background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);}';
 145          $this->assertSame($cssout, $optimiser->process($cssin));
 146  
 147          $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);}';
 148          $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);}';
 149          $this->assertSame($cssout, $optimiser->process($cssin));
 150  
 151          $cssin = '.test{background:#CCC; background-image: url(test.png);}';
 152          $cssout = '.test{background:#CCC url(test.png);}';
 153          $this->assertSame($cssout, $optimiser->process($cssin));
 154  
 155          $cssin = '.test{background:#CCC; background-image: linear-gradient(#3c3c3c, #111);}';
 156          $cssout = '.test{background:#CCC;background-image:linear-gradient(#3c3c3c, #111);}';
 157          $this->assertSame($cssout, $optimiser->process($cssin));
 158  
 159          $cssin = '.test{background:#CCC; background-image: -o-linear-gradient(#3c3c3c, #111);background-image: linear-gradient(#3c3c3c, #111);}';
 160          $cssout = '.test{background:#CCC;background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);}';
 161          $this->assertSame($cssout, $optimiser->process($cssin));
 162  
 163          $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%;}';
 164          $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));}';
 165          $this->assertSame($cssout, $optimiser->process($cssin));
 166  
 167          $cssin = '.userenrolment {background-color:inherit !important;background: inherit !important;}';
 168          $cssout = '.userenrolment{background:inherit !important;}';
 169          $this->assertSame($cssout, $optimiser->process($cssin));
 170  
 171          $cssin = '.userenrolment {background-image:url(test.png) !important;background: inherit !important;}';
 172          $cssout = '.userenrolment{background:inherit !important;}';
 173          $this->assertSame($cssout, $optimiser->process($cssin));
 174  
 175          $cssin = '.userenrolment {background: inherit !important;background-image:url(test.png) !important;}';
 176          $cssout = '.userenrolment{background:inherit url(test.png) !important;}';
 177          $this->assertSame($cssout, $optimiser->process($cssin));
 178  
 179          $cssin = '.userenrolment {background: inherit !important;background-image:url(test.png);}';
 180          $cssout = '.userenrolment{background:inherit !important;}';
 181          $this->assertSame($cssout, $optimiser->process($cssin));
 182  
 183          $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);}';
 184          $this->assertSame($css, $optimiser->process($css));
 185  
 186          $css = '.userenrolment{background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;}';
 187          $this->assertSame($css, $optimiser->process($css));
 188  
 189          $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;}';
 190          $this->assertSame($css, $optimiser->process($css));
 191  
 192          $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;}';
 193          $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;}';
 194          $this->assertSame($cssout, $optimiser->process($cssin));
 195      }
 196  
 197      /**
 198       * Border tests.
 199       */
 200      public function test_borders() {
 201          $optimiser = new css_optimiser();
 202  
 203          $cssin = '.test {border: 1px solid #654321} .test {border-bottom-color: #123456}';
 204          $cssout = '.test{border:1px solid;border-color:#654321 #654321 #123456;}';
 205          $this->assertSame($cssout, $optimiser->process($cssin));
 206  
 207          $cssin = '.one {border:1px solid red;}';
 208          $cssout = '.one{border:1px solid #F00;}';
 209          $this->assertSame($cssout, $optimiser->process($cssin));
 210  
 211          $cssin = '.one {border:1px solid;} .one {border:2px dotted #DDD;}';
 212          $cssout = '.one{border:2px dotted #DDD;}';
 213          $this->assertSame($cssout, $optimiser->process($cssin));
 214  
 215          $cssin = '.one {border:2px dotted #DDD;}.one {border:1px solid;} ';
 216          $cssout = '.one{border:1px solid #DDD;}';
 217          $this->assertSame($cssout, $optimiser->process($cssin));
 218  
 219          $cssin = '.one, .two {border:1px solid red;}';
 220          $cssout = ".one, .two{border:1px solid #F00;}";
 221          $this->assertSame($cssout, $optimiser->process($cssin));
 222  
 223          $cssin = '.one, .two {border:0px;}';
 224          $cssout = ".one, .two{border-width:0;}";
 225          $this->assertSame($cssout, $optimiser->process($cssin));
 226  
 227          $cssin = '.one, .two {border: thin;}';
 228          $cssout = ".one, .two{border-width:thin;}";
 229          $this->assertSame($cssout, $optimiser->process($cssin));
 230  
 231          $cssin = '.one, .two {border: thin solid black;}';
 232          $cssout = ".one, .two{border:thin solid #000;}";
 233          $this->assertSame($cssout, $optimiser->process($cssin));
 234  
 235          $cssin = '.one, .two {border-top: 5px solid white;}';
 236          $cssout = ".one, .two{border-top:5px solid #FFF;}";
 237          $this->assertSame($cssout, $optimiser->process($cssin));
 238  
 239          $cssin = '.one {border:1px solid red;} .two {border:1px solid red;}';
 240          $cssout = ".one, .two{border:1px solid #F00;}";
 241          $this->assertSame($cssout, $optimiser->process($cssin));
 242  
 243          $cssin = '.one {border:1px solid red;width:20px;} .two {border:1px solid red;height:20px;}';
 244          $cssout = ".one{border:1px solid #F00;width:20px;} .two{border:1px solid #F00;height:20px;}";
 245          $this->assertSame($cssout, $optimiser->process($cssin));
 246  
 247          $cssin = '.test {border: 1px solid #123456;} .test {border-color: #654321}';
 248          $cssout = '.test{border:1px solid #654321;}';
 249          $this->assertSame($cssout, $optimiser->process($cssin));
 250  
 251          $cssin = '.test {border-width: 1px; border-style: solid; border-color: #123456;}';
 252          $cssout = '.test{border:1px solid #123456;}';
 253          $this->assertSame($cssout, $optimiser->process($cssin));
 254  
 255          $cssin = '.test {border:1px solid #123456;border-top:2px dotted #654321;}';
 256          $cssout = '.test{border:1px solid #123456;border-top:2px dotted #654321;}';
 257          $this->assertSame($cssout, $optimiser->process($cssin));
 258  
 259          $cssin = '.test {border:1px solid #123456;border-left:2px dotted #654321;}';
 260          $cssout = '.test{border:1px solid #123456;border-left:2px dotted #654321;}';
 261          $this->assertSame($cssout, $optimiser->process($cssin));
 262  
 263          $cssin = '.test {border-left:2px dotted #654321;border:1px solid #123456;}';
 264          $cssout = '.test{border:1px solid #123456;}';
 265          $this->assertSame($cssout, $optimiser->process($cssin));
 266  
 267          $cssin = '.test {border:1px solid;border-top-color:#123456;}';
 268          $cssout = '.test{border:1px solid;border-top-color:#123456;}';
 269          $this->assertSame($cssout, $optimiser->process($cssin));
 270  
 271          $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;}';
 272          $cssout = '.test{border:1px solid;border-top-color:#111;border-bottom-color:#222;border-left-color:#333;}';
 273          $this->assertSame($cssout, $optimiser->process($cssin));
 274  
 275          $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;border-right-color:#444;}';
 276          $cssout = '.test{border:1px solid;border-color:#111 #444 #222 #333;}';
 277          $this->assertSame($cssout, $optimiser->process($cssin));
 278  
 279          $cssin = '.generaltable .cell {border-color:#EEE;} .generaltable .cell {border-width: 1px;border-style: solid;}';
 280          $cssout = '.generaltable .cell{border:1px solid #EEE;}';
 281          $this->assertSame($cssout, $optimiser->process($cssin));
 282  
 283          $cssin = '#page-admin-roles-override .rolecap {border:none;border-bottom:1px solid #CECECE;}';
 284          $cssout = '#page-admin-roles-override .rolecap{border-top:0;border-right:0;border-bottom:1px solid #CECECE;border-left:0;}';
 285          $this->assertSame($cssout, $optimiser->process($cssin));
 286      }
 287  
 288      /**
 289       * Test colour styles.
 290       */
 291      public function test_colors() {
 292          $optimiser = new css_optimiser();
 293  
 294          $css = '.css{}';
 295          $this->assertSame($css, $optimiser->process($css));
 296  
 297          $css = '.css{color:#123456;}';
 298          $this->assertSame($css, $optimiser->process($css));
 299  
 300          $css = '#some{color:#123456;}';
 301          $this->assertSame($css, $optimiser->process($css));
 302  
 303          $css = 'div{color:#123456;}';
 304          $this->assertSame($css, $optimiser->process($css));
 305  
 306          $css = 'div.css{color:#123456;}';
 307          $this->assertSame($css, $optimiser->process($css));
 308  
 309          $css = 'div#some{color:#123456;}';
 310          $this->assertSame($css, $optimiser->process($css));
 311  
 312          $css = 'div[type=blah]{color:#123456;}';
 313          $this->assertSame($css, $optimiser->process($css));
 314  
 315          $css = 'div.css[type=blah]{color:#123456;}';
 316          $this->assertSame($css, $optimiser->process($css));
 317  
 318          $css = 'div#some[type=blah]{color:#123456;}';
 319          $this->assertSame($css, $optimiser->process($css));
 320  
 321          $css = '#some.css[type=blah]{color:#123456;}';
 322          $this->assertSame($css, $optimiser->process($css));
 323  
 324          $css = '#some .css[type=blah]{color:#123456;}';
 325          $this->assertSame($css, $optimiser->process($css));
 326  
 327          $cssin = '.one {color:red;} .two {color:#F00;}';
 328          $cssout = ".one, .two{color:#F00;}";
 329          $this->assertSame($cssout, $optimiser->process($cssin));
 330  
 331          $cssin = '.one {color:#123;color:#321;}';
 332          $cssout = '.one{color:#321;}';
 333          $this->assertSame($cssout, $optimiser->process($cssin));
 334  
 335          $cssin = '.one {color:#123; color : #321 ;}';
 336          $cssout = '.one{color:#321;}';
 337          $this->assertSame($cssout, $optimiser->process($cssin));
 338  
 339          $cssin = '.one {color:#123;} .one {color:#321;}';
 340          $cssout = '.one{color:#321;}';
 341          $this->assertSame($cssout, $optimiser->process($cssin));
 342  
 343          $cssin = '.one {color:#123 !important;color:#321;}';
 344          $cssout = '.one{color:#123 !important;}';
 345          $this->assertSame($cssout, $optimiser->process($cssin));
 346  
 347          $cssin = '.one {color:#123 !important;} .one {color:#321;}';
 348          $cssout = '.one{color:#123 !important;}';
 349          $this->assertSame($cssout, $optimiser->process($cssin));
 350  
 351          $cssin = '.one {color:#123!important;} .one {color:#321;}';
 352          $cssout = '.one{color:#123 !important;}';
 353          $this->assertSame($cssout, $optimiser->process($cssin));
 354  
 355          $cssin = '.one {color:rgb(255, 128, 1)}';
 356          $cssout = '.one{color:rgb(255, 128, 1);}';
 357          $this->assertSame($cssout, $optimiser->process($cssin));
 358  
 359          $cssin = '.one {color:rgba(255, 128, 1, 0.5)}';
 360          $cssout = '.one{color:rgba(255, 128, 1, 0.5);}';
 361          $this->assertSame($cssout, $optimiser->process($cssin));
 362  
 363          $cssin = '.one {color:hsl(120, 65%, 75%)}';
 364          $cssout = '.one{color:hsl(120, 65%, 75%);}';
 365          $this->assertSame($cssout, $optimiser->process($cssin));
 366  
 367          $cssin = '.one {color:hsla(120,65%,75%,0.5)}';
 368          $cssout = '.one{color:hsla(120,65%,75%,0.5);}';
 369          $this->assertSame($cssout, $optimiser->process($cssin));
 370  
 371          // Try some invalid colours to make sure we don't mangle them.
 372          $css = 'div#some{color:#1;}';
 373          $this->assertSame($css, $optimiser->process($css));
 374  
 375          $css = 'div#some{color:#12;}';
 376          $this->assertSame($css, $optimiser->process($css));
 377  
 378          $css = 'div#some{color:#1234;}';
 379          $this->assertSame($css, $optimiser->process($css));
 380  
 381          $css = 'div#some{color:#12345;}';
 382          $this->assertSame($css, $optimiser->process($css));
 383      }
 384  
 385      /**
 386       * Test widths.
 387       */
 388      public function test_widths() {
 389          $optimiser = new css_optimiser();
 390  
 391          $cssin  = '.css {width:0}';
 392          $cssout = '.css{width:0;}';
 393          $this->assertSame($cssout, $optimiser->process($cssin));
 394  
 395          $cssin  = '.css {width:0px}';
 396          $cssout = '.css{width:0;}';
 397          $this->assertSame($cssout, $optimiser->process($cssin));
 398  
 399          $cssin  = '.css {width:0em}';
 400          $cssout = '.css{width:0;}';
 401          $this->assertSame($cssout, $optimiser->process($cssin));
 402  
 403          $cssin  = '.css {width:0pt}';
 404          $cssout = '.css{width:0;}';
 405          $this->assertSame($cssout, $optimiser->process($cssin));
 406  
 407          $cssin  = '.css {width:0mm}';
 408          $cssout = '.css{width:0;}';
 409          $this->assertSame($cssout, $optimiser->process($cssin));
 410  
 411          $cssin  = '.css {width:100px}';
 412          $cssout = '.css{width:100px;}';
 413          $this->assertSame($cssout, $optimiser->process($cssin));
 414      }
 415  
 416      /**
 417       * Test margin styles.
 418       */
 419      public function test_margins() {
 420          $optimiser = new css_optimiser();
 421  
 422          $cssin = '.one {margin: 1px 2px 3px 4px}';
 423          $cssout = '.one{margin:1px 2px 3px 4px;}';
 424          $this->assertSame($cssout, $optimiser->process($cssin));
 425  
 426          $cssin = '.one {margin-top:1px; margin-left:4px; margin-right:2px; margin-bottom: 3px;}';
 427          $cssout = '.one{margin:1px 2px 3px 4px;}';
 428          $this->assertSame($cssout, $optimiser->process($cssin));
 429  
 430          $cssin = '.one {margin-top:1px; margin-left:4px;}';
 431          $cssout = '.one{margin-top:1px;margin-left:4px;}';
 432          $this->assertSame($cssout, $optimiser->process($cssin));
 433  
 434          $cssin = '.one {margin:1px; margin-left:4px;}';
 435          $cssout = '.one{margin:1px 1px 1px 4px;}';
 436          $this->assertSame($cssout, $optimiser->process($cssin));
 437  
 438          $cssin = '.one {margin:1px; margin-bottom:4px;}';
 439          $cssout = '.one{margin:1px 1px 4px;}';
 440          $this->assertSame($cssout, $optimiser->process($cssin));
 441  
 442          $cssin = '.one, .two, .one.two, .one .two {margin:0;} .one.two {margin:0 7px;}';
 443          $cssout = '.one, .two{margin:0;} .one.two{margin:0 7px;} .one .two{margin:0;}';
 444          $this->assertSame($cssout, $optimiser->process($cssin));
 445  
 446          $cssin = '.block {margin-top: 0px !important;margin-bottom: 0px !important;}';
 447          $cssout = '.block{margin-top:0 !important;margin-bottom:0 !important;}';
 448          $this->assertSame($cssout, $optimiser->process($cssin));
 449  
 450          $cssin = '.block {margin: 0px !important;margin-bottom: 3px;}';
 451          $cssout = '.block{margin:0 !important;}';
 452          $this->assertSame($cssout, $optimiser->process($cssin));
 453  
 454          $cssin = '.block {margin: 5px;margin-right: 0 !important;}';
 455          $cssout = '.block{margin:5px;margin-right:0 !important;}';
 456          $this->assertSame($cssout, $optimiser->process($cssin));
 457      }
 458  
 459      /**
 460       * Test padding styles.
 461       */
 462      public function test_padding() {
 463          $optimiser = new css_optimiser();
 464  
 465          $cssin = '.one {padding: 1px 2px 3px 4px}';
 466          $cssout = '.one{padding:1px 2px 3px 4px;}';
 467          $this->assertSame($cssout, $optimiser->process($cssin));
 468  
 469          $cssin = '.one {padding-top:1px; padding-left:4px; padding-right:2px; padding-bottom: 3px;}';
 470          $cssout = '.one{padding:1px 2px 3px 4px;}';
 471          $this->assertSame($cssout, $optimiser->process($cssin));
 472  
 473          $cssin = '.one {padding-top:1px; padding-left:4px;padding-bottom: 3px;}';
 474          $cssout = '.one{padding-top:1px;padding-left:4px;padding-bottom:3px;}';
 475          $this->assertSame($cssout, $optimiser->process($cssin));
 476  
 477          $cssin = '.one {padding-top:1px; padding-left:4px;}';
 478          $cssout = '.one{padding-top:1px;padding-left:4px;}';
 479          $this->assertSame($cssout, $optimiser->process($cssin));
 480  
 481          $cssin = '.one {padding:1px; padding-left:4px;}';
 482          $cssout = '.one{padding:1px 1px 1px 4px;}';
 483          $this->assertSame($cssout, $optimiser->process($cssin));
 484  
 485          $cssin = '.one {padding:1px; padding-bottom:4px;}';
 486          $cssout = '.one{padding:1px 1px 4px;}';
 487          $this->assertSame($cssout, $optimiser->process($cssin));
 488  
 489          $cssin = '.one {padding:0 !important;}';
 490          $cssout = '.one{padding:0 !important;}';
 491          $this->assertSame($cssout, $optimiser->process($cssin));
 492  
 493          $cssin = '.one {padding:0 !important;}';
 494          $cssout = '.one{padding:0 !important;}';
 495          $this->assertSame($cssout, $optimiser->process($cssin));
 496  
 497          $cssin = '.one, .two, .one.two, .one .two {padding:0;} .one.two {padding:0 7px;}';
 498          $cssout = '.one, .two{padding:0;} .one.two{padding:0 7px;} .one .two{padding:0;}';
 499          $this->assertSame($cssout, $optimiser->process($cssin));
 500  
 501          $cssin = '.block {padding-top: 0px !important;padding-bottom: 0px !important;}';
 502          $cssout = '.block{padding-top:0 !important;padding-bottom:0 !important;}';
 503          $this->assertSame($cssout, $optimiser->process($cssin));
 504  
 505          $cssin = '.block {padding: 0px !important;padding-bottom: 3px;}';
 506          $cssout = '.block{padding:0 !important;}';
 507          $this->assertSame($cssout, $optimiser->process($cssin));
 508  
 509          $cssin = '.block {padding: 5px;padding-right: 0 !important;}';
 510          $cssout = '.block{padding:5px;padding-right:0 !important;}';
 511          $this->assertSame($cssout, $optimiser->process($cssin));
 512      }
 513  
 514      /**
 515       * Test cursor optimisations
 516       */
 517      public function test_cursor() {
 518          $optimiser = new css_optimiser();
 519  
 520          // Valid cursor.
 521          $cssin = '.one {cursor: pointer;}';
 522          $cssout = '.one{cursor:pointer;}';
 523          $this->assertSame($cssout, $optimiser->process($cssin));
 524  
 525          // Invalid cursor but tolerated.
 526          $cssin = '.one {cursor: hand;}';
 527          $cssout = '.one{cursor:hand;}';
 528          $this->assertSame($cssout, $optimiser->process($cssin));
 529  
 530          // Valid cursor: url relative.
 531          $cssin = '.one {cursor: mycursor.png;}';
 532          $cssout = '.one{cursor:mycursor.png;}';
 533          $this->assertSame($cssout, $optimiser->process($cssin));
 534  
 535          // Valid cursor: url absolute.
 536          $cssin = '.one {cursor: http://local.host/mycursor.png;}';
 537          $cssout = '.one{cursor:http://local.host/mycursor.png;}';
 538          $this->assertSame($cssout, $optimiser->process($cssin));
 539      }
 540  
 541      /**
 542       * Test vertical align optimisations
 543       */
 544      public function test_vertical_align() {
 545          $optimiser = new css_optimiser();
 546  
 547          // Valid vertical aligns.
 548          $cssin = '.one {vertical-align: baseline;}';
 549          $cssout = '.one{vertical-align:baseline;}';
 550          $this->assertSame($cssout, $optimiser->process($cssin));
 551          $cssin = '.one {vertical-align: middle;}';
 552          $cssout = '.one{vertical-align:middle;}';
 553          $this->assertSame($cssout, $optimiser->process($cssin));
 554          $cssin = '.one {vertical-align: 0.75em;}';
 555          $cssout = '.one{vertical-align:0.75em;}';
 556          $this->assertSame($cssout, $optimiser->process($cssin));
 557          $cssin = '.one {vertical-align: 50%;}';
 558          $cssout = '.one{vertical-align:50%;}';
 559          $this->assertSame($cssout, $optimiser->process($cssin));
 560  
 561          // Invalid but tolerated.
 562          $cssin = '.one {vertical-align: center;}';
 563          $cssout = '.one{vertical-align:center;}';
 564          $this->assertSame($cssout, $optimiser->process($cssin));
 565      }
 566  
 567      /**
 568       * Test float optimisations
 569       */
 570      public function test_float() {
 571          $optimiser = new css_optimiser();
 572  
 573          // Valid vertical aligns.
 574          $cssin = '.one {float: inherit;}';
 575          $cssout = '.one{float:inherit;}';
 576          $this->assertSame($cssout, $optimiser->process($cssin));
 577          $cssin = '.one {float: left;}';
 578          $cssout = '.one{float:left;}';
 579          $this->assertSame($cssout, $optimiser->process($cssin));
 580          $cssin = '.one {float: right;}';
 581          $cssout = '.one{float:right;}';
 582          $this->assertSame($cssout, $optimiser->process($cssin));
 583          $cssin = '.one {float: none;}';
 584          $cssout = '.one{float:none;}';
 585          $this->assertSame($cssout, $optimiser->process($cssin));
 586  
 587          // Invalid but tolerated.
 588          $cssin = '.one {float: center;}';
 589          $cssout = '.one{float:center;}';
 590          $this->assertSame($cssout, $optimiser->process($cssin));
 591      }
 592  
 593      /**
 594       * Test some totally invalid CSS optimisation.
 595       */
 596      public function test_invalid_css_handling() {
 597          $optimiser = new css_optimiser();
 598  
 599          $cssin = array(
 600              '.one{}',
 601              '.one {:}',
 602              '.one {;}',
 603              '.one {;;;;;}',
 604              '.one {:;}',
 605              '.one {:;:;:;:::;;;}',
 606              '.one {!important}',
 607              '.one {:!important}',
 608              '.one {:!important;}',
 609              '.one {;!important}'
 610          );
 611          $cssout = '.one{}';
 612          foreach ($cssin as $css) {
 613              $this->assertSame($cssout, $optimiser->process($css));
 614          }
 615  
 616          $cssin = array(
 617              '.one{background-color:red;}',
 618              '.one {background-color:red;} .one {background-color:}',
 619              '.one {background-color:red;} .one {background-color;}',
 620              '.one {background-color:red;} .one {background-color}',
 621              '.one {background-color:red;} .one {background-color:;}',
 622              '.one {background-color:red;} .one {:blue;}',
 623              '.one {background-color:red;} .one {:#00F}',
 624          );
 625          $cssout = '.one{background-color:#F00;}';
 626          foreach ($cssin as $css) {
 627              $this->assertSame($cssout, $optimiser->process($css));
 628          }
 629  
 630          $cssin = '..one {background-color:color:red}';
 631          $cssout = '..one{background-color:color:red;}';
 632          $this->assertSame($cssout, $optimiser->process($cssin));
 633  
 634          $cssin = '#.one {background-color:color:red}';
 635          $cssout = '#.one{background-color:color:red;}';
 636          $this->assertSame($cssout, $optimiser->process($cssin));
 637  
 638          $cssin = '##one {background-color:color:red}';
 639          $cssout = '##one{background-color:color:red;}';
 640          $this->assertSame($cssout, $optimiser->process($cssin));
 641  
 642          $cssin = '.one {background-color:color:red}';
 643          $cssout = '.one{background-color:color:red;}';
 644          $this->assertSame($cssout, $optimiser->process($cssin));
 645  
 646          $cssin = '.one {background-color:red;color;border-color:blue}';
 647          $cssout = '.one{background-color:#F00;border-color:#00F;}';
 648          $this->assertSame($cssout, $optimiser->process($cssin));
 649  
 650          $cssin  = '{background-color:#123456;color:red;}{color:green;}';
 651          $cssout = "{background-color:#123456;color:#008000;}";
 652          $this->assertSame($cssout, $optimiser->process($cssin));
 653  
 654          $cssin  = '.one {color:red;} {color:green;} .one {background-color:blue;}';
 655          $cssout = ".one{color:#F00;background-color:#00F;} {color:#008000;}";
 656          $this->assertSame($cssout, $optimiser->process($cssin));
 657      }
 658  
 659      /**
 660       * Try to break some things.
 661       */
 662      public function test_break_things() {
 663          $optimiser = new css_optimiser();
 664  
 665          // Wildcard test.
 666          $cssin  = '* {color: black;}';
 667          $cssout = '*{color:#000;}';
 668          $this->assertSame($cssout, $optimiser->process($cssin));
 669  
 670          // Wildcard test.
 671          $cssin  = '.one * {color: black;}';
 672          $cssout = '.one *{color:#000;}';
 673          $this->assertSame($cssout, $optimiser->process($cssin));
 674  
 675          // Wildcard test.
 676          $cssin  = '* .one * {color: black;}';
 677          $cssout = '* .one *{color:#000;}';
 678          $this->assertSame($cssout, $optimiser->process($cssin));
 679  
 680          // Wildcard test.
 681          $cssin  = '*,* {color: black;}';
 682          $cssout = '*{color:#000;}';
 683          $this->assertSame($cssout, $optimiser->process($cssin));
 684  
 685          // Wildcard test.
 686          $cssin  = '*, * .one {color: black;}';
 687          $cssout = "*, * .one{color:#000;}";
 688          $this->assertSame($cssout, $optimiser->process($cssin));
 689  
 690          // Wildcard test.
 691          $cssin  = '*, *.one {color: black;}';
 692          $cssout = "*, *.one{color:#000;}";
 693          $this->assertSame($cssout, $optimiser->process($cssin));
 694  
 695          // Psedo test.
 696          $cssin  = '.one:before {color: black;}';
 697          $cssout = '.one:before{color:#000;}';
 698          $this->assertSame($cssout, $optimiser->process($cssin));
 699  
 700          // Psedo test.
 701          $cssin  = '.one:after {color: black;}';
 702          $cssout = '.one:after{color:#000;}';
 703          $this->assertSame($cssout, $optimiser->process($cssin));
 704  
 705          // Psedo test.
 706          $cssin  = '.one:onclick {color: black;}';
 707          $cssout = '.one:onclick{color:#000;}';
 708          $this->assertSame($cssout, $optimiser->process($cssin));
 709  
 710          // Test complex CSS rules that don't really exist but mimic other CSS rules.
 711          $cssin  = '.one {master-of-destruction: explode(\' \', "What madness");}';
 712          $cssout = '.one{master-of-destruction:explode(\' \', "What madness");}';
 713          $this->assertSame($cssout, $optimiser->process($cssin));
 714  
 715          // Test some complex IE css... I couldn't even think of a more complext solution
 716          // than the CSS they came up with.
 717          $cssin  = 'a { opacity: 0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50); }';
 718          $cssout = 'a{opacity:0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);}';
 719          $this->assertSame($cssout, $optimiser->process($cssin));
 720      }
 721  
 722      /**
 723       * A bulk processing test.
 724       */
 725      public function test_bulk_processing() {
 726          global $CFG;
 727          $cssin = <<<CSS
 728  .test .one {
 729      margin:5px;
 730      border:0;
 731  }
 732  .test .one {
 733      margin: 10px;
 734      color: red;
 735  }
 736  
 737  .test.one {
 738      margin: 15px;
 739  }
 740  
 741  #test .one {margin:  20px;}
 742  #test #one {margin:  25px;}.test #one {margin:  30px;}
 743    .test    .one      {     background-color: #123;     }
 744  .test.one{border:1px solid blue}.test.one{border-color:green;}
 745  
 746  @media print {
 747      #test .one {margin: 35px;}
 748  }
 749  
 750  @media print {
 751      #test .one {margin: 40px;color: #123456;}
 752      #test #one {margin: 45px;}
 753  }
 754  
 755  @media print,screen {
 756      #test .one {color: #654321;}
 757  }
 758  
 759  #test .one,
 760  #new.style {color:#000;}
 761  CSS;
 762  
 763          $cssout = <<<CSS
 764  .test .one{margin:10px;border-width:0;color:#F00;background-color:#123;}
 765  .test.one{margin:15px;border:1px solid #008000;}
 766  #test .one{margin:20px;color:#000;}
 767  #test #one{margin:25px;}
 768  .test #one{margin:30px;}
 769  #new.style{color:#000;}
 770  
 771  @media print {
 772    #test .one{margin:40px;color:#123456;}
 773    #test #one{margin:45px;}
 774  }
 775  @media print,screen {
 776    #test .one{color:#654321;}
 777  }
 778  CSS;
 779          $CFG->cssoptimiserpretty = true;
 780          $optimiser = new css_optimiser();
 781          $this->assertSame($optimiser->process($cssin), $cssout);
 782          unset($CFG->cssoptimiserpretty);
 783      }
 784  
 785      /**
 786       * Test CSS colour matching.
 787       */
 788      public function test_css_is_colour() {
 789          // First lets test hex colours.
 790          $this->assertTrue(css_is_colour('#123456'));
 791          $this->assertTrue(css_is_colour('#123'));
 792          $this->assertTrue(css_is_colour('#ABCDEF'));
 793          $this->assertTrue(css_is_colour('#ABC'));
 794          $this->assertTrue(css_is_colour('#abcdef'));
 795          $this->assertTrue(css_is_colour('#abc'));
 796          $this->assertTrue(css_is_colour('#aBcDeF'));
 797          $this->assertTrue(css_is_colour('#aBc'));
 798          $this->assertTrue(css_is_colour('#1a2Bc3'));
 799          $this->assertTrue(css_is_colour('#1Ac'));
 800  
 801          // Note the following two colour's aren't really colours but browsers process
 802          // them still.
 803          $this->assertTrue(css_is_colour('#A'));
 804          $this->assertTrue(css_is_colour('#12'));
 805          // Having four or five characters however are not valid colours and
 806          // browsers don't parse them. They need to fail so that broken CSS
 807          // stays broken after optimisation.
 808          $this->assertFalse(css_is_colour('#1234'));
 809          $this->assertFalse(css_is_colour('#12345'));
 810  
 811          $this->assertFalse(css_is_colour('#BCDEFG'));
 812          $this->assertFalse(css_is_colour('#'));
 813          $this->assertFalse(css_is_colour('#0000000'));
 814          $this->assertFalse(css_is_colour('#132-245'));
 815          $this->assertFalse(css_is_colour('#13 23 43'));
 816          $this->assertFalse(css_is_colour('123456'));
 817  
 818          // Next lets test real browser mapped colours.
 819          $this->assertTrue(css_is_colour('black'));
 820          $this->assertTrue(css_is_colour('blue'));
 821          $this->assertTrue(css_is_colour('BLACK'));
 822          $this->assertTrue(css_is_colour('Black'));
 823          $this->assertTrue(css_is_colour('bLACK'));
 824          $this->assertTrue(css_is_colour('mediumaquamarine'));
 825          $this->assertTrue(css_is_colour('mediumAquamarine'));
 826          $this->assertFalse(css_is_colour('monkey'));
 827          $this->assertFalse(css_is_colour(''));
 828          $this->assertFalse(css_is_colour('not a colour'));
 829  
 830          // Next lets test rgb(a) colours.
 831          $this->assertTrue(css_is_colour('rgb(255,255,255)'));
 832          $this->assertTrue(css_is_colour('rgb(0, 0, 0)'));
 833          $this->assertTrue(css_is_colour('RGB (255, 255   ,    255)'));
 834          $this->assertTrue(css_is_colour('rgba(0,0,0,0)'));
 835          $this->assertTrue(css_is_colour('RGBA(255,255,255,1)'));
 836          $this->assertTrue(css_is_colour('rgbA(255,255,255,0.5)'));
 837          $this->assertFalse(css_is_colour('rgb(-255,-255,-255)'));
 838          $this->assertFalse(css_is_colour('rgb(256,-256,256)'));
 839  
 840          // Now lets test HSL colours.
 841          $this->assertTrue(css_is_colour('hsl(0,0%,100%)'));
 842          $this->assertTrue(css_is_colour('hsl(180, 0%, 10%)'));
 843          $this->assertTrue(css_is_colour('hsl (360, 100%   ,    95%)'));
 844  
 845          // Finally test the special values.
 846          $this->assertTrue(css_is_colour('inherit'));
 847      }
 848  
 849      /**
 850       * Test the css_is_width function.
 851       */
 852      public function test_css_is_width() {
 853  
 854          $this->assertTrue(css_is_width('0'));
 855          $this->assertTrue(css_is_width('0px'));
 856          $this->assertTrue(css_is_width('0em'));
 857          $this->assertTrue(css_is_width('199px'));
 858          $this->assertTrue(css_is_width('199em'));
 859          $this->assertTrue(css_is_width('199%'));
 860          $this->assertTrue(css_is_width('-1px'));
 861          $this->assertTrue(css_is_width('auto'));
 862          $this->assertTrue(css_is_width('inherit'));
 863  
 864          // Valid widths but missing their unit specifier.
 865          $this->assertFalse(css_is_width('0.75'));
 866          $this->assertFalse(css_is_width('3'));
 867          $this->assertFalse(css_is_width('-1'));
 868  
 869          // Totally invalid widths.
 870          $this->assertFalse(css_is_width('-'));
 871          $this->assertFalse(css_is_width('bananas'));
 872          $this->assertFalse(css_is_width(''));
 873          $this->assertFalse(css_is_width('top'));
 874      }
 875  
 876      /**
 877       * This function tests some of the broken crazy CSS we have in Moodle.
 878       * For each of these things the value needs to be corrected if we can be 100%
 879       * certain what is going wrong, Or it needs to be left as is.
 880       */
 881      public function test_broken_css_found_in_moodle() {
 882          $optimiser = new css_optimiser();
 883  
 884          // Notice how things are out of order here but that they get corrected.
 885          $cssin = '.test {background:url([[pix:theme|pageheaderbgred]]) top center no-repeat}';
 886          $cssout = '.test{background:url([[pix:theme|pageheaderbgred]]) no-repeat top center;}';
 887          $this->assertSame($cssout, $optimiser->process($cssin));
 888  
 889          // Cursor hand isn't valid.
 890          $cssin  = '.test {cursor: hand;}';
 891          $cssout = '.test{cursor:hand;}';
 892          $this->assertSame($cssout, $optimiser->process($cssin));
 893  
 894          // Zoom property isn't valid.
 895          $cssin  = '.test {zoom: 1;}';
 896          $cssout = '.test{zoom:1;}';
 897          $this->assertSame($cssout, $optimiser->process($cssin));
 898  
 899          // Left isn't a valid position property.
 900          $cssin  = '.test {position: left;}';
 901          $cssout = '.test{position:left;}';
 902          $this->assertSame($cssout, $optimiser->process($cssin));
 903  
 904          // The dark red color isn't a valid HTML color but has a standardised
 905          // translation of #8B0000.
 906          $cssin  = '.test {color: darkred;}';
 907          $cssout = '.test{color:#8B0000;}';
 908          $this->assertSame($cssout, $optimiser->process($cssin));
 909  
 910          // You can't use argb colours as border colors.
 911          $cssin  = '.test {border-bottom: 1px solid rgba(0,0,0,0.25);}';
 912          $cssout = '.test{border-bottom:1px solid rgba(0,0,0,0.25);}';
 913          $this->assertSame($cssout, $optimiser->process($cssin));
 914  
 915          // Opacity with annoying IE equivalents....
 916          $cssin  = '.test {opacity: 0.5; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50);}';
 917          $cssout = '.test{opacity:0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);}';
 918          $this->assertSame($cssout, $optimiser->process($cssin));
 919      }
 920  
 921      /**
 922       * Test keyframe declarations.
 923       */
 924      public function test_keyframe_css_animation() {
 925          global $CFG;
 926          $optimiser = new css_optimiser();
 927  
 928          $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;}';
 929          $this->assertSame($css, $optimiser->process($css));
 930  
 931          $css = '@keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}';
 932          $this->assertSame($css, $optimiser->process($css));
 933  
 934          $css  = "@keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}\n";
 935          $css .= "@-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}\n";
 936          $css .= "@-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}";
 937          $this->assertSame($css, $optimiser->process($css));
 938  
 939          $cssin = <<<CSS
 940  .test {color:#FFF;}
 941  .testtwo {color:#FFF;}
 942  @media print {
 943      .test {background-color:#FFF;}
 944  }
 945  .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;}
 946  @media print {
 947      .test {background-color:#000;}
 948  }
 949  @keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
 950  @-moz-keyframes mymove{0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
 951  @-webkit-keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
 952  @media print {
 953      .test {background-color:#333;}
 954  }
 955  .test {color:#888;}
 956  .testtwo {color:#888;}
 957  CSS;
 958  
 959          $cssout = <<<CSS
 960  .test,
 961  .testtwo{color:#888;}
 962  .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;}
 963  
 964  @media print {
 965    .test{background-color:#333;}
 966  }
 967  @keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
 968  @-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
 969  @-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
 970  CSS;
 971          $CFG->cssoptimiserpretty = true;
 972          $this->assertSame($cssout, $optimiser->process($cssin));
 973          unset($CFG->cssoptimiserpretty);
 974  
 975          $cssin = <<<CSS
 976  .dndupload-target {display:none;}
 977  .dndsupported .dndupload-ready .dndupload-target {display:block;}
 978  .dndupload-uploadinprogress {display:none;text-align:center;}
 979  .dndupload-uploading .dndupload-uploadinprogress {display:block;}
 980  .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;}
 981  @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;}}
 982  
 983  /*
 984   * Select Dialogue (File Manager only)
 985   */
 986  .filemanager.fp-select .fp-select-loading {display:none;}
 987  .filemanager.fp-select.loading .fp-select-loading {display:block;}
 988  .filemanager.fp-select.loading form {display:none;}
 989  CSS;
 990  
 991          $cssout = <<<CSS
 992  .dndupload-target{display:none;}
 993  .dndsupported .dndupload-ready .dndupload-target{display:block;}
 994  .dndupload-uploadinprogress{display:none;text-align:center;}
 995  .dndupload-uploading .dndupload-uploadinprogress{display:block;}
 996  .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;}
 997  .filemanager.fp-select .fp-select-loading{display:none;}
 998  .filemanager.fp-select.loading .fp-select-loading{display:block;}
 999  .filemanager.fp-select.loading form{display:none;}
1000  
1001  @keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1002  @-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1003  @-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1004  CSS;
1005          $CFG->cssoptimiserpretty = true;
1006          $this->assertSame($cssout, $optimiser->process($cssin));
1007          unset($CFG->cssoptimiserpretty);
1008      }
1009  
1010      /**
1011       * Test media declarations.
1012       */
1013      public function test_media_rules() {
1014          $optimiser = new css_optimiser();
1015  
1016          $cssin = "@media print {\n  .test{background-color:#333;}\n}";
1017          $cssout = "@media print { .test{background-color:#333;} }";
1018          $this->assertSame($cssout, $optimiser->process($cssin));
1019  
1020          $cssin = "@media screen and (min-width:30px) {\n  #region-main-box{left: 30px;float: left;}\n}";
1021          $cssout = "@media screen and (min-width:30px) { #region-main-box{left:30px;float:left;} }";
1022          $this->assertSame($cssout, $optimiser->process($cssin));
1023  
1024          $cssin = "@media all and (min-width:500px) {\n  #region-main-box{left:30px;float:left;}\n}";
1025          $cssout = "@media all and (min-width:500px) { #region-main-box{left:30px;float:left;} }";
1026          $this->assertSame($cssout, $optimiser->process($cssin));
1027  
1028          $cssin = "@media (min-width:500px) {\n  #region-main-box{left:30px;float:left;}\n}";
1029          $cssout = "@media (min-width:500px) { #region-main-box{left:30px;float:left;} }";
1030          $this->assertSame($cssout, $optimiser->process($cssin));
1031  
1032          $cssin = "@media screen and (color), projection and (color) {\n  #region-main-box{left:30px;float:left;}\n}";
1033          $cssout = "@media screen and (color),projection and (color) { #region-main-box{left:30px;float:left;} }";
1034          $this->assertSame($cssout, $optimiser->process($cssin));
1035  
1036          $cssin = "@media print {\n  .test{background-color:#000;}\n}@media print {\n  .test{background-color:#FFF;}\n}";
1037          $cssout = "@media print { .test{background-color:#FFF;} }";
1038          $this->assertSame($cssout, $optimiser->process($cssin));
1039  
1040          $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}";
1041          $cssout = "@media screen and (min-width:30px) { #region-main-box{background-color:#FFF;} }";
1042          $this->assertSame($cssout, $optimiser->process($cssin));
1043  
1044          $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}";
1045          $cssout = "@media screen and (min-width:30px) { #region-main-box{background-color:#000;} }\n@media screen and (min-width:31px) { #region-main-box{background-color:#FFF;} }";
1046          $this->assertSame($cssout, $optimiser->process($cssin));
1047  
1048          $cssin = "@media (min-width: 768px) and (max-width: 979px) {\n*{*zoom:1;}}";
1049          $cssout = "@media (min-width: 768px) and (max-width: 979px) { *{*zoom:1;} }";
1050          $this->assertSame($cssout, $optimiser->process($cssin));
1051  
1052          $cssin = "#test {min-width:1200px;}@media (min-width: 768px) {#test {min-width: 1024px;}}";
1053          $cssout = "#test{min-width:1200px;} \n@media (min-width: 768px) { #test{min-width:1024px;} }";
1054          $this->assertSame($cssout, $optimiser->process($cssin));
1055  
1056          $cssin = "@media(min-width:768px){#page-calender-view .container fluid{min-width:1024px}}.section_add_menus{text-align:right}";
1057          $cssout = ".section_add_menus{text-align:right;} \n@media (min-width:768px) { #page-calender-view .container fluid{min-width:1024px;} }";
1058          $this->assertSame($cssout, $optimiser->process($cssin));
1059  
1060          $cssin = "@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}";
1061          $cssout = "@-ms-keyframes progress-bar-stripes {from{background-position:40px 0;}to{background-position:0 0;}}";
1062          $this->assertSame($cssout, $optimiser->process($cssin));
1063      }
1064  
1065      /**
1066       * Test the ordering of CSS optimisationss
1067       */
1068      public function test_css_optimisation_ordering() {
1069          $optimiser = $this->get_optimiser();
1070  
1071          $css = '.test{display:none;} .dialogue{display:block;} .dialogue-hidden{display:none;}';
1072          $this->assertSame($css, $optimiser->process($css));
1073  
1074          $cssin = '.test{display:none;} .dialogue-hidden{display:none;} .dialogue{display:block;}';
1075          $cssout = '.test, .dialogue-hidden{display:none;} .dialogue{display:block;}';
1076          $this->assertSame($cssout, $optimiser->process($cssin));
1077      }
1078  
1079      /**
1080       * Test CSS chunking
1081       */
1082      public function test_css_chunking() {
1083          // Test with an even number of styles.
1084          $css = 'a{}b{}c{}d{}e{}f{}';
1085          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1086          $this->assertInternalType('array', $chunks);
1087          $this->assertCount(3, $chunks);
1088          $this->assertArrayHasKey(0, $chunks);
1089          $this->assertArrayHasKey(1, $chunks);
1090          $this->assertArrayHasKey(2, $chunks);
1091          $this->assertSame('a{}b{}', $chunks[0]);
1092          $this->assertSame('c{}d{}', $chunks[1]);
1093          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\ne{}f{}", $chunks[2]);
1094  
1095          // Test with an odd number of styles.
1096          $css = 'a{}b{}c{}d{}e{}';
1097          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1098          $this->assertInternalType('array', $chunks);
1099          $this->assertCount(3, $chunks);
1100          $this->assertArrayHasKey(0, $chunks);
1101          $this->assertArrayHasKey(1, $chunks);
1102          $this->assertArrayHasKey(2, $chunks);
1103          $this->assertSame('a{}b{}', $chunks[0]);
1104          $this->assertSame('c{}d{}', $chunks[1]);
1105          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\ne{}", $chunks[2]);
1106  
1107          // Test well placed commas.
1108          $css = 'a,b{}c,d{}e,f{}';
1109          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1110          $this->assertInternalType('array', $chunks);
1111          $this->assertCount(3, $chunks);
1112          $this->assertArrayHasKey(0, $chunks);
1113          $this->assertArrayHasKey(1, $chunks);
1114          $this->assertArrayHasKey(2, $chunks);
1115          $this->assertSame('a,b{}', $chunks[0]);
1116          $this->assertSame('c,d{}', $chunks[1]);
1117          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\ne,f{}", $chunks[2]);
1118  
1119          // Test unfortunately placed commas.
1120          $css = 'a{}b,c{color:red;}d{}e{}f{}';
1121          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1122          $this->assertInternalType('array', $chunks);
1123          $this->assertCount(4, $chunks);
1124          $this->assertArrayHasKey(0, $chunks);
1125          $this->assertArrayHasKey(1, $chunks);
1126          $this->assertArrayHasKey(2, $chunks);
1127          $this->assertArrayHasKey(3, $chunks);
1128          $this->assertSame('a{}', $chunks[0]);
1129          $this->assertSame('b,c{color:red;}', $chunks[1]);
1130          $this->assertSame('d{}e{}', $chunks[2]);
1131          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\n@import url(styles.php?type=test&chunk=3);\nf{}", $chunks[3]);
1132  
1133          // Test unfortunate CSS.
1134          $css = 'a,b,c,d,e,f{color:red;}';
1135          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1136          $this->assertInternalType('array', $chunks);
1137          $this->assertCount(1, $chunks);
1138          $this->assertArrayHasKey(0, $chunks);
1139          $this->assertSame('a,b,c,d,e,f{color:red;}', $chunks[0]);
1140          $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 6. Those were ignored.');
1141  
1142          // Test to make sure invalid CSS isn't totally ruined.
1143          $css = 'a{},,,e{},';
1144          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1145          // Believe it or not we want to care what comes out here as this will be parsed correctly
1146          // by a browser.
1147          $this->assertInternalType('array', $chunks);
1148          $this->assertCount(3, $chunks);
1149          $this->assertArrayHasKey(0, $chunks);
1150          $this->assertArrayHasKey(1, $chunks);
1151          $this->assertArrayHasKey(2, $chunks);
1152          $this->assertSame('a{}', $chunks[0]);
1153          $this->assertSame(',,,e{}', $chunks[1]);
1154          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\n,", $chunks[2]);
1155          $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 6. Those were ignored.');
1156  
1157          // Test utter crap CSS to make sure we don't loop to our deaths.
1158          $css = 'a,b,c,d,e,f';
1159          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1160          $this->assertInternalType('array', $chunks);
1161          $this->assertCount(1, $chunks);
1162          $this->assertArrayHasKey(0, $chunks);
1163          $this->assertSame($css, $chunks[0]);
1164          $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 6. Those were ignored.');
1165  
1166          // Test another death situation to make sure we're invincible.
1167          $css = 'a,,,,,e';
1168          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1169          $this->assertInternalType('array', $chunks);
1170          $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 4. Those were ignored.');
1171          // I don't care what the outcome is, I just want to make sure it doesn't die.
1172  
1173          // Test media queries.
1174          $css = '@media (min-width: 980px) { .a,.b{} }';
1175          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1176          $this->assertCount(1, $chunks);
1177          $this->assertSame('@media (min-width: 980px) { .a,.b{} }', $chunks[0]);
1178  
1179          // Test media queries, with commas.
1180          $css = '.a{} @media (min-width: 700px), handheld and (orientation: landscape) { .b{} }';
1181          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1182          $this->assertCount(1, $chunks);
1183          $this->assertSame($css, $chunks[0]);
1184  
1185          // Test special rules.
1186          $css = 'a,b{ background-image: linear-gradient(to bottom, #ffffff, #cccccc);}d,e{}';
1187          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1188          $this->assertCount(2, $chunks);
1189          $this->assertSame('a,b{ background-image: linear-gradient(to bottom, #ffffff, #cccccc);}', $chunks[0]);
1190          $this->assertSame("@import url(styles.php?type=test&chunk=1);\nd,e{}", $chunks[1]);
1191  
1192          // Test media queries with too many selectors.
1193          $css = '@media (min-width: 980px) { a,b,c,d{} }';
1194          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1195          $this->assertCount(1, $chunks);
1196          $this->assertSame('@media (min-width: 980px) { a,b,c,d{} }', $chunks[0]);
1197          $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 34. Those were ignored.');
1198  
1199          // Complex test.
1200          $css = '@media (a) {b{}} c{} d,e{} f,g,h{} i,j{x:a,b,c} k,l{} @media(x){l,m{ y: a,b,c}} n{}';
1201          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 3);
1202          $this->assertCount(6, $chunks);
1203          $this->assertSame('@media (a) {b{}} c{}', $chunks[0]);
1204          $this->assertSame(' d,e{}', $chunks[1]);
1205          $this->assertSame(' f,g,h{}', $chunks[2]);
1206          $this->assertSame(' i,j{x:a,b,c}', $chunks[3]);
1207          $this->assertSame(' k,l{}', $chunks[4]);
1208          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\n@import url(styles.php?type=test&chunk=3);\n@import url(styles.php?type=test&chunk=4);\n@import url(styles.php?type=test&chunk=5);\n @media(x){l,m{ y: a,b,c}} n{}", $chunks[5]);
1209  
1210          // Multiple offset errors.
1211          $css = 'a,b,c{} d,e,f{}';
1212          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1213          $this->assertCount(2, $chunks);
1214          $this->assertSame('a,b,c{}', $chunks[0]);
1215          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n d,e,f{}", $chunks[1]);
1216          $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 6, 14. Those were ignored.');
1217  
1218          // Test the split according to IE.
1219          $css = str_repeat('a{}', 4100);
1220          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test');
1221          $this->assertCount(2, $chunks);
1222          $this->assertSame(str_repeat('a{}', 4095), $chunks[0]);
1223          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n" . str_repeat('a{}', 5), $chunks[1]);
1224  
1225          // Test strip out comments.
1226          $css = ".a {/** a\nb\nc */} /** a\nb\nc */ .b{} /** .c,.d{} */ e{}";
1227          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1228          $this->assertCount(2, $chunks);
1229          $this->assertSame('.a {}  .b{}', $chunks[0]);
1230          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n  e{}", $chunks[1]);
1231  
1232          // Test something with unicode characters.
1233          $css = 'a,b{} nav a:hover:after { content: "↓"; } b{ color:test;}';
1234          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1235          $this->assertCount(2, $chunks);
1236          $this->assertSame('a,b{}', $chunks[0]);
1237          $this->assertSame("@import url(styles.php?type=test&chunk=1);\n nav a:hover:after { content: \"↓\"; } b{ color:test;}", $chunks[1]);
1238  
1239          // Test that if there is broken CSS with too many close brace symbols,
1240          // media rules after that point are still kept together.
1241          $mediarule = '@media (width=480) {a{}b{}}';
1242          $css = 'c{}}' . $mediarule . 'd{}';
1243          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1244          $this->assertCount(3, $chunks);
1245          $this->assertEquals($mediarule, $chunks[1]);
1246  
1247          // Test that this still works even with too many close brace symbols
1248          // inside a media query (note: that broken media query may be split
1249          // after the break, but any following ones should not be).
1250          $brokenmediarule = '@media (width=480) {c{}}d{}}';
1251          $css = $brokenmediarule . 'e{}' . $mediarule . 'f{}';
1252          $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
1253          $this->assertCount(4, $chunks);
1254          $this->assertEquals($mediarule, $chunks[2]);
1255      }
1256  
1257      /**
1258       * Test CSS3.
1259       */
1260      public function test_css3() {
1261          $optimiser = $this->get_optimiser();
1262  
1263          $css = '.test > .test{display:inline-block;}';
1264          $this->assertSame($css, $optimiser->process($css));
1265  
1266          $css = '*{display:inline-block;}';
1267          $this->assertSame($css, $optimiser->process($css));
1268  
1269          $css = 'div > *{display:inline-block;}';
1270          $this->assertSame($css, $optimiser->process($css));
1271  
1272          $css = 'div:nth-child(3){display:inline-block;}';
1273          $this->assertSame($css, $optimiser->process($css));
1274  
1275          $css = '.test:nth-child(3){display:inline-block;}';
1276          $this->assertSame($css, $optimiser->process($css));
1277  
1278          $css = '*:nth-child(3){display:inline-block;}';
1279          $this->assertSame($css, $optimiser->process($css));
1280  
1281          $css = '*[id]{display:inline-block;}';
1282          $this->assertSame($css, $optimiser->process($css));
1283  
1284          $css = '*[id=blah]{display:inline-block;}';
1285          $this->assertSame($css, $optimiser->process($css));
1286  
1287          $css = '*[*id=blah]{display:inline-block;}';
1288          $this->assertSame($css, $optimiser->process($css));
1289  
1290          $css = '*[*id=blah_]{display:inline-block;}';
1291          $this->assertSame($css, $optimiser->process($css));
1292  
1293          $css = '*[id^=blah*d]{display:inline-block;}';
1294          $this->assertSame($css, $optimiser->process($css));
1295  
1296          $css = '.test{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}';
1297          $this->assertSame($css, $optimiser->process($css));
1298  
1299          $css = '#test{box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);}';
1300          $this->assertSame($css, $optimiser->process($css));
1301      }
1302  
1303      /**
1304       * Test browser hacks here.
1305       */
1306      public function test_browser_hacks() {
1307          $optimiser = $this->get_optimiser();
1308  
1309          $css = '#test{*zoom:1;}';
1310          $this->assertSame($css, $optimiser->process($css));
1311  
1312          $css = '.test{width:75%;*width:76%;}';
1313          $this->assertSame($css, $optimiser->process($css));
1314  
1315          $css = '#test{*zoom:1;*display:inline;}';
1316          $this->assertSame($css, $optimiser->process($css));
1317  
1318          $css = '.test{width:75%;*width:76%;width:76%}';
1319          $this->assertSame('.test{width:76%;*width:76%;}', $optimiser->process($css));
1320  
1321          $css = '.test{width:75%;*width:76%;*width:75%}';
1322          $this->assertSame('.test{width:75%;*width:75%;}', $optimiser->process($css));
1323      }
1324  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1