jenkins-bot has submitted this change and it was merged.

Change subject: Add unit tests for CSSParse and CSSRender
......................................................................


Add unit tests for CSSParse and CSSRender

Test the roundtrip on a collection of correct and pathological
stylesheets to ascertain whether the parse is behaving as
expected.

Bug: T483
Change-Id: I484cc856b5696c1fa6265769320f79853365e1d6
---
M TemplateStyles.hooks.php
M extension.json
A tests/CSSParseRenderTest.php
3 files changed, 245 insertions(+), 0 deletions(-)

Approvals:
  BryanDavis: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/TemplateStyles.hooks.php b/TemplateStyles.hooks.php
index 9a0c0c7..b75e356 100644
--- a/TemplateStyles.hooks.php
+++ b/TemplateStyles.hooks.php
@@ -15,6 +15,11 @@
                return true;
        }
 
+       public static function onUnitTestsList( &$paths ) {
+               $paths[] = __DIR__ . '/tests/phpunit/';
+               return true;
+       }
+
        private static function decodeFromBlob( $blob ) {
                $tree = gzdecode( $blob );
                if ( $tree ) {
diff --git a/extension.json b/extension.json
index 3e0f3e0..13f787a 100644
--- a/extension.json
+++ b/extension.json
@@ -36,6 +36,9 @@
                ],
                "OutputPageParserOutput": [
                        "TemplateStylesHooks::onOutputPageParserOutput"
+               ],
+               "UnitTestList": [
+                       "TemplateStyleHooks::onUnitTestList"
                ]
        }
 }
diff --git a/tests/CSSParseRenderTest.php b/tests/CSSParseRenderTest.php
new file mode 100644
index 0000000..3ebff59
--- /dev/null
+++ b/tests/CSSParseRenderTest.php
@@ -0,0 +1,237 @@
+<?php
+
+/**
+ * @group TemplateStyles
+ */
+class CSSParseRenderTest extends MediaWikiTestCase {
+
+       protected function setUp() {
+               parent::setUp();
+       }
+
+       public static function provideCSSParser() {
+               return [
+                       [       'test' => 'Bare declaration',
+                               'expect' => '',
+                               'css' => <<<FIN
+                                       prop: val;
+FIN
+                       ],
+                       [       'test' => 'Blacklisted property',
+                               'expect' => '.X .sel {good:123;} ',
+                               'css' => <<<FIN
+                                       .sel {
+                                         good: 123;
+                                         -evil: "boo";
+                               }
+FIN
+                       ],
+                       [       'test' => 'Case insensivity',
+                               'expect' => '@media screen { .X .sel1 
{prop:WhiteListed(foo);} } ',
+                               'css' => <<<FIN
+                                       @MEDIA screen {
+                                               .sel1 {
+                                                       prop: WhiteListed(foo);
+                                                       -EVIL: evil;
+                                               }
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Comment trickery',
+                               'expect' => '.X .sel1 {} .X .sel2 .sel3 
{prop3:val3;} ',
+                               'css' => <<<FIN
+                                       .sel1 {
+                                               -ev/* x */il: evil;
+                                       }
+                                       .sel2 /* { prop2: val2; } */
+                                       .sel3 {
+                                               prop3: val3;
+                                       } /* unfinishe
+FIN
+                       ],
+                       [       'test' => 'Complex selectors',
+                               'expect' => '.X .sel1[foo=\'ba{r\'] #id 
a.foo::hover {prop1:val1;} ',
+                               'css' => <<<FIN
+                                       .sel1[foo='ba{r'] #id a.foo::hover {
+                                               prop1: val1;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Edge cases',
+                               'expect' => '.X :sel {} ',
+                               'css' => <<<FIN
+                                       :sel {
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Function in function',
+                               'expect' => '.X .sel1 {} ',
+                               'css' => <<<FIN
+                                       .sel1 {
+                                               prop1: whitelisted(1, evil(2));
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Incomplete rule',
+                               'expect' => '.X .sel {prop:val;} ',
+                               'css' => <<<FIN
+                                       .sel {
+                                         prop: val;
+FIN
+                       ],
+                       [       'test' => 'Media block',
+                               'expect' => '.X .sel2 {prop2:val2;} @media 
print { .X .sel1 {prop1:val1;} } ',
+                               'css' => <<<FIN
+                                       @media print {
+                                         .sel1 {
+                                               prop1: val1;
+                                         }
+                                       }
+
+                                       .sel2 {
+                                         prop2: val2;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Multiple rules',
+                               'expect' => '.X .sel1 A {prop1:val1;} .X T.sel2 
{prop2:val2;} ',
+                               'css' => <<<FIN
+                                       .sel1 A {
+                                         prop1: val1;
+                                       }
+
+                                       T.sel2 {
+                                         prop2: val2;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Multiple selectors',
+                               'expect' => '.X .sel1,.X TD .sel2["a,comma"],.X 
#id {prop:val;} ',
+                               'css' => <<<FIN
+                                       .sel1, TD .sel2["a,comma"], #id {
+                                         prop: val;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'No selector',
+                               'expect' => '{prop1:val1;} ',
+                               'css' => <<<FIN
+                                       {
+                                               prop1: val1;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Not a declaration',
+                               'expect' => '.X .sel {prop:val;} ',
+                               'css' => <<<FIN
+                                       .sel {
+                                         not a declaration;
+                                         prop: val;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Obfuscated properties',
+                               'expect' => '.X .sel {good:val2;} ',
+                               'css' => <<<FIN
+                                       .sel {
+                                         -\\065 vil: val1;
+                                         go\\00006fd: val2;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Rule within rule',
+                               'expect' => '.X .sel1 {prop1:val1;} .X .sel3 
{prop4:val4;} ',
+                               'css' => <<<FIN
+                                       .sel1 {
+                                         prop1: val1;
+                                         .sel2 {
+                                               prop2: val2;
+                                         }
+                                         prop3: val3;
+                                       }
+
+                                       .sel3 {
+                                         prop4: val4;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'String literals',
+                               'expect' => '.X .sel 
{prop1:\'val1\';prop3:"v/**/al\"3";bad:"broken" ;} ',
+                               'css' => <<<FIN
+                                       .sel {
+                                         prop1: 'val1';
+                                         prop3: "v/**/al\"3";
+                                         bad: "broken
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Unsupported block',
+                               'expect' => '.X .sel {prop2:val2;} ',
+                               'css' => <<<FIN
+                                       @font-face {
+                                         prop1: val1;
+                                       }
+
+                                       .sel {
+                                         prop2: val2;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Unwhitelisted function',
+                               'expect' => '.X .sel {prop1:whitelisted(val1);} 
',
+                               'css' => <<<FIN
+                                       .sel {
+                                         prop1: whitelisted(val1);
+                                         prop2: evil(val2);
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Values',
+                               'expect' => '.X .sel {prop:1em .5px 12% #FFF;} 
',
+                               'css' => <<<FIN
+                                       .sel {
+                                         prop: 1em .5px 12% #FFF;
+                                       }
+FIN
+                       ],
+                       [       'test' => 'Whitespace',
+                               'expect' => '.X .sel1 #id{prop2:whitelisted ( 
val2 ) ;prop3:not whitelisted( val3 );} ',
+                               'css' => <<<FIN
+                                       .sel1
+                                       #id{
+                                               -evil
+                                       :val1;
+                                       prop2/*
+                                               comment */: whitelisted ( val2 )
+                                        ;prop3         :not/**/whitelisted( 
val3 );}
+FIN
+                       ]
+               ];
+       }
+
+       /**
+        * @dataProvider provideCSSParser
+        */
+       public function testCSSParser( $test, $expect, $source ) {
+
+               $tree = new CSSParser( $source );
+               $rules = $tree->rules( '.X ' );
+               if ( !$rules ) {
+                       $this->fail( "$test: Stylesheet did not parse." );
+                       return;
+               }
+
+               $r = new CSSRenderer();
+               $r->add( $rules );
+               $css = $r->render( [ "whitelisted" ], [ "-evil" ] );
+
+               $this->assertEquals(
+                       $expect,
+                       preg_replace( '/[ \t\n]+/', ' ', $css ),
+                       "$test: parse did not return expected output."
+               );
+
+       }
+
+}
+

-- 
To view, visit https://gerrit.wikimedia.org/r/283772
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I484cc856b5696c1fa6265769320f79853365e1d6
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/TemplateStyles
Gerrit-Branch: master
Gerrit-Owner: coren <m...@uberbox.org>
Gerrit-Reviewer: Brion VIBBER <br...@wikimedia.org>
Gerrit-Reviewer: BryanDavis <bda...@wikimedia.org>
Gerrit-Reviewer: Jforrester <jforres...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to