MediaWiki  REL1_19
JavaScriptMinifierTest.php
Go to the documentation of this file.
00001 <?php
00002 
00003 class JavaScriptMinifierTest extends MediaWikiTestCase {
00004 
00005         function provideCases() {
00006                 return array(
00007                         // Basic tokens
00008                         array( "\r\t\f \v\n\r", "" ),
00009                         array( "/* Foo *\n*bar\n*/", "" ),
00014                         array( "'  Foo  \\'  bar  \\\n  baz  \\'  quox  '  .length", "'  Foo  \\'  bar  \\\n  baz  \\'  quox  '.length" ),
00015                         array( "\"  Foo  \\\"  bar  \\\n  baz  \\\"  quox  \"  .length", "\"  Foo  \\\"  bar  \\\n  baz  \\\"  quox  \".length" ),
00016                         array( "// Foo b/ar baz", "" ),
00017                         array( "/  Foo  \\/  bar  [  /  \\]  /  ]  baz  /  .length", "/  Foo  \\/  bar  [  /  \\]  /  ]  baz  /.length" ),
00018                         // HTML comments
00019                         array( "<!-- Foo bar", "" ),
00020                         array( "<!-- Foo --> bar", "" ),
00021                         array( "--> Foo", "" ),
00022                         array( "x --> y", "x-->y" ),
00023                         // Semicolon insertion
00024                         array( "(function(){return\nx;})", "(function(){return\nx;})" ),
00025                         array( "throw\nx;", "throw\nx;" ),
00026                         array( "while(p){continue\nx;}", "while(p){continue\nx;}" ),
00027                         array( "while(p){break\nx;}", "while(p){break\nx;}" ),
00028                         array( "var\nx;", "var x;" ),
00029                         array( "x\ny;", "x\ny;" ),
00030                         array( "x\n++y;", "x\n++y;" ),
00031                         array( "x\n!y;", "x\n!y;" ),
00032                         array( "x\n{y}", "x\n{y}" ),
00033                         array( "x\n+y;", "x+y;" ),
00034                         array( "x\n(y);", "x(y);" ),
00035                         array( "5.\nx;", "5.\nx;" ),
00036                         array( "0xFF.\nx;", "0xFF.x;" ),
00037                         array( "5.3.\nx;", "5.3.x;" ),
00038                         // Token separation
00039                         array( "x  in  y", "x in y" ),
00040                         array( "/x/g  in  y", "/x/g in y" ),
00041                         array( "x  in  30", "x in 30" ),
00042                         array( "x  +  ++  y", "x+ ++y" ),
00043                         array( "x  /  /y/.exec(z)", "x/ /y/.exec(z)" ),
00044                         // State machine
00045                         array( "/  x/g", "/  x/g" ),
00046                         array( "(function(){return/  x/g})", "(function(){return/  x/g})" ),
00047                         array( "+/  x/g", "+/  x/g" ),
00048                         array( "++/  x/g", "++/  x/g" ),
00049                         array( "x/  x/g", "x/x/g" ),
00050                         array( "(/  x/g)", "(/  x/g)" ),
00051                         array( "if(/  x/g);", "if(/  x/g);" ),
00052                         array( "(x/  x/g)", "(x/x/g)" ),
00053                         array( "([/  x/g])", "([/  x/g])" ),
00054                         array( "+x/  x/g", "+x/x/g" ),
00055                         array( "{}/  x/g", "{}/  x/g" ),
00056                         array( "+{}/  x/g", "+{}/x/g" ),
00057                         array( "(x)/  x/g", "(x)/x/g" ),
00058                         array( "if(x)/  x/g", "if(x)/  x/g" ),
00059                         array( "for(x;x;{}/  x/g);", "for(x;x;{}/x/g);" ),
00060                         array( "x;x;{}/  x/g", "x;x;{}/  x/g" ),
00061                         array( "x:{}/  x/g", "x:{}/  x/g" ),
00062                         array( "switch(x){case y?z:{}/  x/g:{}/  x/g;}", "switch(x){case y?z:{}/x/g:{}/  x/g;}" ),
00063                         array( "function x(){}/  x/g", "function x(){}/  x/g" ),
00064                         array( "+function x(){}/  x/g", "+function x(){}/x/g" ),
00065                         
00066                         // Tests for things that broke in the past
00067                         // Multiline quoted string
00068                         array( "var foo=\"\\\nblah\\\n\";", "var foo=\"\\\nblah\\\n\";" ),
00069                         // Multiline quoted string followed by string with spaces
00070                         array( "var foo=\"\\\nblah\\\n\";\nvar baz = \" foo \";\n", "var foo=\"\\\nblah\\\n\";var baz=\" foo \";" ),
00071                         // URL in quoted string ( // is not a comment)
00072                         array( "aNode.setAttribute('href','http://foo.bar.org/baz');", "aNode.setAttribute('href','http://foo.bar.org/baz');" ),
00073                         // URL in quoted string after multiline quoted string
00074                         array( "var foo=\"\\\nblah\\\n\";\naNode.setAttribute('href','http://foo.bar.org/baz');", "var foo=\"\\\nblah\\\n\";aNode.setAttribute('href','http://foo.bar.org/baz');" ),
00075                         // Division vs. regex nastiness
00076                         array( "alert( (10+10) / '/'.charCodeAt( 0 ) + '//' );", "alert((10+10)/'/'.charCodeAt(0)+'//');" ),
00077                         array( "if(1)/a /g.exec('Pa ss');", "if(1)/a /g.exec('Pa ss');" ),
00078                         
00079                         // newline insertion after 1000 chars: break after the "++", not before
00080                         array( str_repeat( ';', 996 ) . "if(x++);", str_repeat( ';', 996 ) . "if(x++\n);" ),
00081 
00082                         // Unicode letter characters should pass through ok in identifiers (bug 31187)
00083                         array( "var KaŝSkatolVal = {}", 'var KaŝSkatolVal={}'),
00084                         // And also per spec unicode char escape values should work in identifiers,
00085                         // as long as it's a valid char. In future it might get normalized.
00086                         array( "var Ka\\u015dSkatolVal = {}", 'var Ka\\u015dSkatolVal={}'),
00087 
00088                         /* Some structures that might look invalid at first sight */
00089                         array( "var a = 5.;", "var a=5.;" ),
00090                         array( "5.0.toString();", "5.0.toString();" ),
00091                         array( "5..toString();", "5..toString();" ),
00092                         array( "5...toString();", false ),
00093                         array( "5.\n.toString();", '5..toString();' ),
00094                 );
00095         }
00096 
00100         function testJavaScriptMinifierOutput( $code, $expectedOutput ) {
00101                 $minified = JavaScriptMinifier::minify( $code );
00102 
00103                 // JSMin+'s parser will throw an exception if output is not valid JS.
00104                 // suppression of warnings needed for stupid crap
00105                 wfSuppressWarnings();
00106                 $parser = new JSParser();
00107                 wfRestoreWarnings();
00108                 $parser->parse( $minified, 'minify-test.js', 1 );
00109 
00110                 $this->assertEquals( $expectedOutput, $minified, "Minified output should be in the form expected." );
00111         }
00112 
00116         function testBug32548Exponent($num) {
00117                 // Long line breaking was being incorrectly done between the base and
00118                 // exponent part of a number, causing a syntax error. The line should
00119                 // instead break at the start of the number.
00120                 $prefix = 'var longVarName' . str_repeat('_', 973) . '=';
00121                 $suffix = ',shortVarName=0;';
00122 
00123                 $input = $prefix . $num . $suffix;
00124                 $expected = $prefix . "\n" . $num . $suffix;
00125 
00126                 $minified = JavaScriptMinifier::minify( $input );
00127 
00128                 $this->assertEquals( $expected, $minified, "Line breaks must not occur in middle of exponent");
00129         }
00130 
00131         function provideBug32548() {
00132                 return array(
00133                         array(
00134                                 // This one gets interpreted all together by the prior code;
00135                                 // no break at the 'E' happens.
00136                                 '1.23456789E55',                                
00137                         ),
00138                         array(
00139                                 // This one breaks under the bad code; splits between 'E' and '+'
00140                                 '1.23456789E+5',
00141                         ),
00142                         array(
00143                                 // This one breaks under the bad code; splits between 'E' and '-'
00144                                 '1.23456789E-5',
00145                         ),
00146                 );
00147         }
00148 }