MediaWiki  REL1_24
JavaScriptMinifierTest.php
Go to the documentation of this file.
00001 <?php
00002 
00003 class JavaScriptMinifierTest extends MediaWikiTestCase {
00004 
00005     public static function provideCases() {
00006         return array(
00007 
00008             // Basic whitespace and comments that should be stripped entirely
00009             array( "\r\t\f \v\n\r", "" ),
00010             array( "/* Foo *\n*bar\n*/", "" ),
00011 
00017             array(
00018                 "/**\n * Foo\n * {\n * 'bar' : {\n * "
00019                     . "//Multiple rules with configurable operators\n * 'baz' : false\n * }\n */",
00020                 "" ),
00021 
00026             array(
00027                 "'  Foo  \\'  bar  \\\n  baz  \\'  quox  '  .length",
00028                 "'  Foo  \\'  bar  \\\n  baz  \\'  quox  '.length"
00029             ),
00030             array(
00031                 "\"  Foo  \\\"  bar  \\\n  baz  \\\"  quox  \"  .length",
00032                 "\"  Foo  \\\"  bar  \\\n  baz  \\\"  quox  \".length"
00033             ),
00034             array( "// Foo b/ar baz", "" ),
00035             array(
00036                 "/  Foo  \\/  bar  [  /  \\]  /  ]  baz  /  .length",
00037                 "/  Foo  \\/  bar  [  /  \\]  /  ]  baz  /.length"
00038             ),
00039 
00040             // HTML comments
00041             array( "<!-- Foo bar", "" ),
00042             array( "<!-- Foo --> bar", "" ),
00043             array( "--> Foo", "" ),
00044             array( "x --> y", "x-->y" ),
00045 
00046             // Semicolon insertion
00047             array( "(function(){return\nx;})", "(function(){return\nx;})" ),
00048             array( "throw\nx;", "throw\nx;" ),
00049             array( "while(p){continue\nx;}", "while(p){continue\nx;}" ),
00050             array( "while(p){break\nx;}", "while(p){break\nx;}" ),
00051             array( "var\nx;", "var x;" ),
00052             array( "x\ny;", "x\ny;" ),
00053             array( "x\n++y;", "x\n++y;" ),
00054             array( "x\n!y;", "x\n!y;" ),
00055             array( "x\n{y}", "x\n{y}" ),
00056             array( "x\n+y;", "x+y;" ),
00057             array( "x\n(y);", "x(y);" ),
00058             array( "5.\nx;", "5.\nx;" ),
00059             array( "0xFF.\nx;", "0xFF.x;" ),
00060             array( "5.3.\nx;", "5.3.x;" ),
00061 
00062             // Semicolon insertion between an expression having an inline
00063             // comment after it, and a statement on the next line (bug 27046).
00064             array(
00065                 "var a = this //foo bar \n for ( b = 0; c < d; b++ ) {}",
00066                 "var a=this\nfor(b=0;c<d;b++){}"
00067             ),
00068 
00069             // Token separation
00070             array( "x  in  y", "x in y" ),
00071             array( "/x/g  in  y", "/x/g in y" ),
00072             array( "x  in  30", "x in 30" ),
00073             array( "x  +  ++  y", "x+ ++y" ),
00074             array( "x ++  +  y", "x++ +y" ),
00075             array( "x  /  /y/.exec(z)", "x/ /y/.exec(z)" ),
00076 
00077             // State machine
00078             array( "/  x/g", "/  x/g" ),
00079             array( "(function(){return/  x/g})", "(function(){return/  x/g})" ),
00080             array( "+/  x/g", "+/  x/g" ),
00081             array( "++/  x/g", "++/  x/g" ),
00082             array( "x/  x/g", "x/x/g" ),
00083             array( "(/  x/g)", "(/  x/g)" ),
00084             array( "if(/  x/g);", "if(/  x/g);" ),
00085             array( "(x/  x/g)", "(x/x/g)" ),
00086             array( "([/  x/g])", "([/  x/g])" ),
00087             array( "+x/  x/g", "+x/x/g" ),
00088             array( "{}/  x/g", "{}/  x/g" ),
00089             array( "+{}/  x/g", "+{}/x/g" ),
00090             array( "(x)/  x/g", "(x)/x/g" ),
00091             array( "if(x)/  x/g", "if(x)/  x/g" ),
00092             array( "for(x;x;{}/  x/g);", "for(x;x;{}/x/g);" ),
00093             array( "x;x;{}/  x/g", "x;x;{}/  x/g" ),
00094             array( "x:{}/  x/g", "x:{}/  x/g" ),
00095             array( "switch(x){case y?z:{}/  x/g:{}/  x/g;}", "switch(x){case y?z:{}/x/g:{}/  x/g;}" ),
00096             array( "function x(){}/  x/g", "function x(){}/  x/g" ),
00097             array( "+function x(){}/  x/g", "+function x(){}/x/g" ),
00098 
00099             // Multiline quoted string
00100             array( "var foo=\"\\\nblah\\\n\";", "var foo=\"\\\nblah\\\n\";" ),
00101 
00102             // Multiline quoted string followed by string with spaces
00103             array(
00104                 "var foo=\"\\\nblah\\\n\";\nvar baz = \" foo \";\n",
00105                 "var foo=\"\\\nblah\\\n\";var baz=\" foo \";"
00106             ),
00107 
00108             // URL in quoted string ( // is not a comment)
00109             array(
00110                 "aNode.setAttribute('href','http://foo.bar.org/baz');",
00111                 "aNode.setAttribute('href','http://foo.bar.org/baz');"
00112             ),
00113 
00114             // URL in quoted string after multiline quoted string
00115             array(
00116                 "var foo=\"\\\nblah\\\n\";\naNode.setAttribute('href','http://foo.bar.org/baz');",
00117                 "var foo=\"\\\nblah\\\n\";aNode.setAttribute('href','http://foo.bar.org/baz');"
00118             ),
00119 
00120             // Division vs. regex nastiness
00121             array(
00122                 "alert( (10+10) / '/'.charCodeAt( 0 ) + '//' );",
00123                 "alert((10+10)/'/'.charCodeAt(0)+'//');"
00124             ),
00125             array( "if(1)/a /g.exec('Pa ss');", "if(1)/a /g.exec('Pa ss');" ),
00126 
00127             // newline insertion after 1000 chars: break after the "++", not before
00128             array( str_repeat( ';', 996 ) . "if(x++);", str_repeat( ';', 996 ) . "if(x++\n);" ),
00129 
00130             // Unicode letter characters should pass through ok in identifiers (bug 31187)
00131             array( "var KaŝSkatolVal = {}", 'var KaŝSkatolVal={}' ),
00132 
00133             // Per spec unicode char escape values should work in identifiers,
00134             // as long as it's a valid char. In future it might get normalized.
00135             array( "var Ka\\u015dSkatolVal = {}", 'var Ka\\u015dSkatolVal={}' ),
00136 
00137             // Some structures that might look invalid at first sight
00138             array( "var a = 5.;", "var a=5.;" ),
00139             array( "5.0.toString();", "5.0.toString();" ),
00140             array( "5..toString();", "5..toString();" ),
00141             array( "5...toString();", false ),
00142             array( "5.\n.toString();", '5..toString();' ),
00143         );
00144     }
00145 
00150     public function testJavaScriptMinifierOutput( $code, $expectedOutput ) {
00151         $minified = JavaScriptMinifier::minify( $code );
00152 
00153         // JSMin+'s parser will throw an exception if output is not valid JS.
00154         // suppression of warnings needed for stupid crap
00155         wfSuppressWarnings();
00156         $parser = new JSParser();
00157         wfRestoreWarnings();
00158         $parser->parse( $minified, 'minify-test.js', 1 );
00159 
00160         $this->assertEquals(
00161             $expectedOutput,
00162             $minified,
00163             "Minified output should be in the form expected."
00164         );
00165     }
00166 
00167     public static function provideBug32548() {
00168         return array(
00169             array(
00170                 // This one gets interpreted all together by the prior code;
00171                 // no break at the 'E' happens.
00172                 '1.23456789E55',
00173             ),
00174             array(
00175                 // This one breaks under the bad code; splits between 'E' and '+'
00176                 '1.23456789E+5',
00177             ),
00178             array(
00179                 // This one breaks under the bad code; splits between 'E' and '-'
00180                 '1.23456789E-5',
00181             ),
00182         );
00183     }
00184 
00190     public function testBug32548Exponent( $num ) {
00191         // Long line breaking was being incorrectly done between the base and
00192         // exponent part of a number, causing a syntax error. The line should
00193         // instead break at the start of the number.
00194         $prefix = 'var longVarName' . str_repeat( '_', 973 ) . '=';
00195         $suffix = ',shortVarName=0;';
00196 
00197         $input = $prefix . $num . $suffix;
00198         $expected = $prefix . "\n" . $num . $suffix;
00199 
00200         $minified = JavaScriptMinifier::minify( $input );
00201 
00202         $this->assertEquals( $expected, $minified, "Line breaks must not occur in middle of exponent" );
00203     }
00204 }