MediaWiki
REL1_20
|
00001 <?php 00008 class CSSJanusTest extends MediaWikiTestCase { 00012 function testTransform( $cssA, $cssB = null ) { 00013 00014 if ( $cssB ) { 00015 $transformedA = CSSJanus::transform( $cssA ); 00016 $this->assertEquals( $transformedA, $cssB, 'Test A-B transformation' ); 00017 00018 $transformedB = CSSJanus::transform( $cssB ); 00019 $this->assertEquals( $transformedB, $cssA, 'Test B-A transformation' ); 00020 00021 // If no B version is provided, it means 00022 // the output should equal the input. 00023 } else { 00024 $transformedA = CSSJanus::transform( $cssA ); 00025 $this->assertEquals( $transformedA, $cssA, 'Nothing was flipped' ); 00026 } 00027 } 00028 00032 function testTransformAdvanced( $code, $expectedOutput, $options = array() ) { 00033 $swapLtrRtlInURL = isset( $options['swapLtrRtlInURL'] ) ? $options['swapLtrRtlInURL'] : false; 00034 $swapLeftRightInURL = isset( $options['swapLeftRightInURL'] ) ? $options['swapLeftRightInURL'] : false; 00035 00036 $flipped = CSSJanus::transform( $code, $swapLtrRtlInURL, $swapLeftRightInURL ); 00037 00038 $this->assertEquals( $expectedOutput, $flipped, 00039 'Test flipping, options: url-ltr-rtl=' . ($swapLtrRtlInURL ? 'true' : 'false') 00040 . ' url-left-right=' . ($swapLeftRightInURL ? 'true' : 'false') 00041 ); 00042 } 00047 function testTransformBroken( $code, $expectedOutput ) { 00048 $flipped = CSSJanus::transform( $code ); 00049 00050 $this->assertEquals( $expectedOutput, $flipped, 'Test flipping' ); 00051 } 00052 00057 function provideTransformCases() { 00058 return array( 00059 // Property keys 00060 array( 00061 '.foo { left: 0; }', 00062 '.foo { right: 0; }' 00063 ), 00064 // Guard against partial keys 00065 // (CSS currently doesn't have flippable properties 00066 // that contain the direction as part of the key without 00067 // dash separation) 00068 array( 00069 '.foo { alright: 0; }' 00070 ), 00071 array( 00072 '.foo { balleft: 0; }' 00073 ), 00074 00075 // Dashed property keys 00076 array( 00077 '.foo { padding-left: 0; }', 00078 '.foo { padding-right: 0; }' 00079 ), 00080 array( 00081 '.foo { margin-left: 0; }', 00082 '.foo { margin-right: 0; }' 00083 ), 00084 array( 00085 '.foo { border-left: 0; }', 00086 '.foo { border-right: 0; }' 00087 ), 00088 00089 // Double-dashed property keys 00090 array( 00091 '.foo { border-left-color: red; }', 00092 '.foo { border-right-color: red; }' 00093 ), 00094 array( 00095 // Includes unknown properties? 00096 '.foo { x-left-y: 0; }', 00097 '.foo { x-right-y: 0; }' 00098 ), 00099 00100 // Multi-value properties 00101 array( 00102 '.foo { padding: 0; }' 00103 ), 00104 array( 00105 '.foo { padding: 0 1px; }' 00106 ), 00107 array( 00108 '.foo { padding: 0 1px 2px; }' 00109 ), 00110 array( 00111 '.foo { padding: 0 1px 2px 3px; }', 00112 '.foo { padding: 0 3px 2px 1px; }' 00113 ), 00114 00115 // Shorthand / Four notation 00116 array( 00117 '.foo { padding: .25em 15px 0pt 0ex; }', 00118 '.foo { padding: .25em 0ex 0pt 15px; }' 00119 ), 00120 array( 00121 '.foo { margin: 1px -4px 3px 2px; }', 00122 '.foo { margin: 1px 2px 3px -4px; }' 00123 ), 00124 array( 00125 '.foo { padding: 0 15px .25em 0; }', 00126 '.foo { padding: 0 0 .25em 15px; }' 00127 ), 00128 array( 00129 '.foo { padding: 1px 4.1grad 3px 2%; }', 00130 '.foo { padding: 1px 2% 3px 4.1grad; }' 00131 ), 00132 array( 00133 '.foo { padding: 1px 2px 3px auto; }', 00134 '.foo { padding: 1px auto 3px 2px; }' 00135 ), 00136 array( 00137 '.foo { padding: 1px inherit 3px auto; }', 00138 '.foo { padding: 1px auto 3px inherit; }' 00139 ), 00140 array( 00141 '.foo { border-radius: .25em 15px 0pt 0ex; }', 00142 '.foo { border-radius: .25em 0ex 0pt 15px; }' 00143 ), 00144 array( 00145 '.foo { x-unknown: a b c d; }' 00146 ), 00147 array( 00148 '.foo barpx 0 2% { opacity: 0; }' 00149 ), 00150 array( 00151 '#settings td p strong' 00152 ), 00153 array( 00154 # Not sure how 4+ values should behave, 00155 # testing to make sure changes are detected 00156 '.foo { x-unknown: 1 2 3 4 5; }', 00157 '.foo { x-unknown: 1 4 3 2 5; }', 00158 ), 00159 array( 00160 '.foo { x-unknown: 1 2 3 4 5 6; }', 00161 '.foo { x-unknown: 1 4 3 2 5 6; }', 00162 ), 00163 00164 // Shorthand / Three notation 00165 array( 00166 '.foo { margin: 1em 0 .25em; }' 00167 ), 00168 array( 00169 '.foo { margin:-1.5em 0 -.75em; }' 00170 ), 00171 00172 // Shorthand / Two notation 00173 array( 00174 '.foo { padding: 1px 2px; }' 00175 ), 00176 00177 // Shorthand / One notation 00178 array( 00179 '.foo { padding: 1px; }' 00180 ), 00181 00182 // Direction 00183 // Note: This differs from the Python implementation, 00184 // see also CSSJanus::fixDirection for more info. 00185 array( 00186 '.foo { direction: ltr; }', 00187 '.foo { direction: rtl; }' 00188 ), 00189 array( 00190 '.foo { direction: rtl; }', 00191 '.foo { direction: ltr; }' 00192 ), 00193 array( 00194 'input { direction: ltr; }', 00195 'input { direction: rtl; }' 00196 ), 00197 array( 00198 'input { direction: rtl; }', 00199 'input { direction: ltr; }' 00200 ), 00201 array( 00202 'body { direction: ltr; }', 00203 'body { direction: rtl; }' 00204 ), 00205 array( 00206 '.foo, body, input { direction: ltr; }', 00207 '.foo, body, input { direction: rtl; }' 00208 ), 00209 array( 00210 'body { padding: 10px; direction: ltr; }', 00211 'body { padding: 10px; direction: rtl; }' 00212 ), 00213 array( 00214 'body { direction: ltr } .myClass { direction: ltr }', 00215 'body { direction: rtl } .myClass { direction: rtl }' 00216 ), 00217 00218 // Left/right values 00219 array( 00220 '.foo { float: left; }', 00221 '.foo { float: right; }' 00222 ), 00223 array( 00224 '.foo { text-align: left; }', 00225 '.foo { text-align: right; }' 00226 ), 00227 array( 00228 '.foo { -x-unknown: left; }', 00229 '.foo { -x-unknown: right; }' 00230 ), 00231 // Guard against selectors that look flippable 00232 array( 00233 '.column-left { width: 0; }' 00234 ), 00235 array( 00236 'a.left { width: 0; }' 00237 ), 00238 array( 00239 'a.leftification { width: 0; }' 00240 ), 00241 array( 00242 'a.ltr { width: 0; }' 00243 ), 00244 array( 00245 # <div class="a-ltr png"> 00246 '.a-ltr.png { width: 0; }' 00247 ), 00248 array( 00249 # <foo-ltr attr="x"> 00250 'foo-ltr[attr="x"] { width: 0; }' 00251 ), 00252 array( 00253 'div.left > span.right+span.left { width: 0; }' 00254 ), 00255 array( 00256 '.thisclass .left .myclass { width: 0; }' 00257 ), 00258 array( 00259 '.thisclass .left .myclass #myid { width: 0; }' 00260 ), 00261 00262 // Cursor values (east/west) 00263 array( 00264 '.foo { cursor: e-resize; }', 00265 '.foo { cursor: w-resize; }' 00266 ), 00267 array( 00268 '.foo { cursor: se-resize; }', 00269 '.foo { cursor: sw-resize; }' 00270 ), 00271 array( 00272 '.foo { cursor: ne-resize; }', 00273 '.foo { cursor: nw-resize; }' 00274 ), 00275 00276 // Background 00277 array( 00278 '.foo { background-position: top left; }', 00279 '.foo { background-position: top right; }' 00280 ), 00281 array( 00282 '.foo { background: url(/foo/bar.png) top left; }', 00283 '.foo { background: url(/foo/bar.png) top right; }' 00284 ), 00285 array( 00286 '.foo { background: url(/foo/bar.png) top left no-repeat; }', 00287 '.foo { background: url(/foo/bar.png) top right no-repeat; }' 00288 ), 00289 array( 00290 '.foo { background: url(/foo/bar.png) no-repeat top left; }', 00291 '.foo { background: url(/foo/bar.png) no-repeat top right; }' 00292 ), 00293 array( 00294 '.foo { background: #fff url(/foo/bar.png) no-repeat top left; }', 00295 '.foo { background: #fff url(/foo/bar.png) no-repeat top right; }' 00296 ), 00297 array( 00298 '.foo { background-position: 100% 40%; }', 00299 '.foo { background-position: 0% 40%; }' 00300 ), 00301 array( 00302 '.foo { background-position: 23% 0; }', 00303 '.foo { background-position: 77% 0; }' 00304 ), 00305 array( 00306 '.foo { background-position: 23% auto; }', 00307 '.foo { background-position: 77% auto; }' 00308 ), 00309 array( 00310 '.foo { background-position-x: 23%; }', 00311 '.foo { background-position-x: 77%; }' 00312 ), 00313 array( 00314 '.foo { background-position-y: 23%; }', 00315 '.foo { background-position-y: 23%; }' 00316 ), 00317 array( 00318 '.foo { background:url(../foo.png) no-repeat 75% 50%; }', 00319 '.foo { background:url(../foo.png) no-repeat 25% 50%; }' 00320 ), 00321 array( 00322 '.foo { background: 10% 20% } .bar { background: 40% 30% }', 00323 '.foo { background: 90% 20% } .bar { background: 60% 30% }' 00324 ), 00325 00326 // Multiple rules 00327 array( 00328 'body { direction: rtl; float: right; } .foo { direction: ltr; float: right; }', 00329 'body { direction: ltr; float: left; } .foo { direction: rtl; float: left; }', 00330 ), 00331 00332 // Duplicate properties 00333 array( 00334 '.foo { float: left; float: right; float: left; }', 00335 '.foo { float: right; float: left; float: right; }', 00336 ), 00337 00338 // Preserve comments 00339 array( 00340 '/* left /* right */left: 10px', 00341 '/* left /* right */right: 10px' 00342 ), 00343 array( 00344 '/*left*//*left*/left: 10px', 00345 '/*left*//*left*/right: 10px' 00346 ), 00347 array( 00348 '/* Going right is cool */ .foo { width: 0 }', 00349 ), 00350 array( 00351 "/* padding-right 1 2 3 4 */\n#test { width: 0}\n/*right*/" 00352 ), 00353 array( 00354 "/** Two line comment\n * left\n \*/\n#test {width: 0}" 00355 ), 00356 00357 // @noflip annotation 00358 array( 00359 // before selector (single) 00360 '/* @noflip */ div { float: left; }' 00361 ), 00362 array( 00363 // before selector (multiple) 00364 '/* @noflip */ div, .notme { float: left; }' 00365 ), 00366 array( 00367 // inside selector 00368 'div, /* @noflip */ .foo { float: left; }' 00369 ), 00370 array( 00371 // after selector 00372 'div, .notme /* @noflip */ { float: left; }' 00373 ), 00374 array( 00375 // before multiple rules 00376 '/* @noflip */ div { float: left; } .foo { float: left; }', 00377 '/* @noflip */ div { float: left; } .foo { float: right; }' 00378 ), 00379 array( 00380 // after multiple rules 00381 '.foo { float: left; } /* @noflip */ div { float: left; }', 00382 '.foo { float: right; } /* @noflip */ div { float: left; }' 00383 ), 00384 array( 00385 // before multiple properties 00386 'div { /* @noflip */ float: left; text-align: left; }', 00387 'div { /* @noflip */ float: left; text-align: right; }' 00388 ), 00389 array( 00390 // after multiple properties 00391 'div { float: left; /* @noflip */ text-align: left; }', 00392 'div { float: right; /* @noflip */ text-align: left; }' 00393 ), 00394 00395 // Guard against css3 stuff 00396 array( 00397 'background-image: -moz-linear-gradient(#326cc1, #234e8c);' 00398 ), 00399 array( 00400 'background-image: -webkit-gradient(linear, 100% 0%, 0% 0%, from(#666666), to(#ffffff));' 00401 ), 00402 00403 // CSS syntax / white-space variations 00404 // spaces, no spaces, tabs, new lines, omitting semi-colons 00405 array( 00406 ".foo { left: 0; }", 00407 ".foo { right: 0; }" 00408 ), 00409 array( 00410 ".foo{ left: 0; }", 00411 ".foo{ right: 0; }" 00412 ), 00413 array( 00414 ".foo{ left: 0 }", 00415 ".foo{ right: 0 }" 00416 ), 00417 array( 00418 ".foo{left:0 }", 00419 ".foo{right:0 }" 00420 ), 00421 array( 00422 ".foo{left:0}", 00423 ".foo{right:0}" 00424 ), 00425 array( 00426 ".foo { left : 0 ; }", 00427 ".foo { right : 0 ; }" 00428 ), 00429 array( 00430 ".foo\n { left : 0 ; }", 00431 ".foo\n { right : 0 ; }" 00432 ), 00433 array( 00434 ".foo\n { \nleft : 0 ; }", 00435 ".foo\n { \nright : 0 ; }" 00436 ), 00437 array( 00438 ".foo\n { \n left : 0 ; }", 00439 ".foo\n { \n right : 0 ; }" 00440 ), 00441 array( 00442 ".foo\n { \n left\n : 0; }", 00443 ".foo\n { \n right\n : 0; }" 00444 ), 00445 array( 00446 ".foo \n { \n left\n : 0; }", 00447 ".foo \n { \n right\n : 0; }" 00448 ), 00449 array( 00450 ".foo\n{\nleft\n:\n0;}", 00451 ".foo\n{\nright\n:\n0;}" 00452 ), 00453 array( 00454 ".foo\n.bar {\n\tleft: 0;\n}", 00455 ".foo\n.bar {\n\tright: 0;\n}" 00456 ), 00457 array( 00458 ".foo\t{\tleft\t:\t0;}", 00459 ".foo\t{\tright\t:\t0;}" 00460 ), 00461 ); 00462 } 00463 00469 function provideTransformAdvancedCases() { 00470 $bgPairs = array( 00471 # [ - _ . ] <-> [ left right ltr rtl ] 00472 'foo.jpg' => 'foo.jpg', 00473 'left.jpg' => 'right.jpg', 00474 'ltr.jpg' => 'rtl.jpg', 00475 00476 'foo-left.png' => 'foo-right.png', 00477 'foo_left.png' => 'foo_right.png', 00478 'foo.left.png' => 'foo.right.png', 00479 00480 'foo-ltr.png' => 'foo-rtl.png', 00481 'foo_ltr.png' => 'foo_rtl.png', 00482 'foo.ltr.png' => 'foo.rtl.png', 00483 00484 'left-foo.png' => 'right-foo.png', 00485 'left_foo.png' => 'right_foo.png', 00486 'left.foo.png' => 'right.foo.png', 00487 00488 'ltr-foo.png' => 'rtl-foo.png', 00489 'ltr_foo.png' => 'rtl_foo.png', 00490 'ltr.foo.png' => 'rtl.foo.png', 00491 00492 'foo-ltr-left.gif' => 'foo-rtl-right.gif', 00493 'foo_ltr_left.gif' => 'foo_rtl_right.gif', 00494 'foo.ltr.left.gif' => 'foo.rtl.right.gif', 00495 'foo-ltr_left.gif' => 'foo-rtl_right.gif', 00496 'foo_ltr.left.gif' => 'foo_rtl.right.gif', 00497 ); 00498 $provider = array(); 00499 foreach ( $bgPairs as $left => $right ) { 00500 # By default '-rtl' and '-left' etc. are not touched, 00501 # Only when the appropiate parameter is set. 00502 $provider[] = array( 00503 ".foo { background: url(images/$left); }", 00504 ".foo { background: url(images/$left); }" 00505 ); 00506 $provider[] = array( 00507 ".foo { background: url(images/$right); }", 00508 ".foo { background: url(images/$right); }" 00509 ); 00510 $provider[] = array( 00511 ".foo { background: url(images/$left); }", 00512 ".foo { background: url(images/$right); }", 00513 array( 00514 'swapLtrRtlInURL' => true, 00515 'swapLeftRightInURL' => true, 00516 ) 00517 ); 00518 $provider[] = array( 00519 ".foo { background: url(images/$right); }", 00520 ".foo { background: url(images/$left); }", 00521 array( 00522 'swapLtrRtlInURL' => true, 00523 'swapLeftRightInURL' => true, 00524 ) 00525 ); 00526 } 00527 00528 return $provider; 00529 } 00530 00535 function provideTransformBrokenCases() { 00536 return array( 00537 // Guard against partial keys 00538 array( 00539 '.foo { leftxx: 0; }', 00540 '.foo { leftxx: 0; }' 00541 ), 00542 array( 00543 '.foo { rightxx: 0; }', 00544 '.foo { rightxx: 0; }' 00545 ), 00546 00547 // Guard against selectors that look flippable 00548 array( 00549 # <foo-left-x attr="x"> 00550 'foo-left-x[attr="x"] { width: 0; }', 00551 'foo-left-x[attr="x"] { width: 0; }' 00552 ), 00553 array( 00554 # <div class="foo" data-left="x"> 00555 '.foo[data-left="x"] { width: 0; }', 00556 '.foo[data-left="x"] { width: 0; }' 00557 ), 00558 ); 00559 } 00560 }