3 class JavaScriptMinifierTest
extends MediaWikiTestCase
{
5 function provideCases() {
8 array( "\r\t\f \v\n\r", "" ),
9 array( "/* Foo *\n*bar\n*/", "" ),
14 array( "' Foo \\' bar \\\n baz \\' quox ' .length", "' Foo \\' bar \\\n baz \\' quox '.length" ),
15 array( "\" Foo \\\" bar \\\n baz \\\" quox \" .length", "\" Foo \\\" bar \\\n baz \\\" quox \".length" ),
16 array( "// Foo b/ar baz", "" ),
17 array( "/ Foo \\/ bar [ / \\] / ] baz / .length", "/ Foo \\/ bar [ / \\] / ] baz /.length" ),
19 array( "<!-- Foo bar", "" ),
20 array( "<!-- Foo --> bar", "" ),
21 array( "--> Foo", "" ),
22 array( "x --> y", "x-->y" ),
23 // Semicolon insertion
24 array( "(function(){return\nx;})", "(function(){return\nx;})" ),
25 array( "throw\nx;", "throw\nx;" ),
26 array( "while(p){continue\nx;}", "while(p){continue\nx;}" ),
27 array( "while(p){break\nx;}", "while(p){break\nx;}" ),
28 array( "var\nx;", "var x;" ),
29 array( "x\ny;", "x\ny;" ),
30 array( "x\n++y;", "x\n++y;" ),
31 array( "x\n!y;", "x\n!y;" ),
32 array( "x\n{y}", "x\n{y}" ),
33 array( "x\n+y;", "x+y;" ),
34 array( "x\n(y);", "x(y);" ),
35 array( "5.\nx;", "5.\nx;" ),
36 array( "0xFF.\nx;", "0xFF.x;" ),
37 array( "5.3.\nx;", "5.3.x;" ),
39 array( "x in y", "x in y" ),
40 array( "/x/g in y", "/x/g in y" ),
41 array( "x in 30", "x in 30" ),
42 array( "x + ++ y", "x+ ++y" ),
43 array( "x / /y/.exec(z)", "x/ /y/.exec(z)" ),
45 array( "/ x/g", "/ x/g" ),
46 array( "(function(){return/ x/g})", "(function(){return/ x/g})" ),
47 array( "+/ x/g", "+/ x/g" ),
48 array( "++/ x/g", "++/ x/g" ),
49 array( "x/ x/g", "x/x/g" ),
50 array( "(/ x/g)", "(/ x/g)" ),
51 array( "if(/ x/g);", "if(/ x/g);" ),
52 array( "(x/ x/g)", "(x/x/g)" ),
53 array( "([/ x/g])", "([/ x/g])" ),
54 array( "+x/ x/g", "+x/x/g" ),
55 array( "{}/ x/g", "{}/ x/g" ),
56 array( "+{}/ x/g", "+{}/x/g" ),
57 array( "(x)/ x/g", "(x)/x/g" ),
58 array( "if(x)/ x/g", "if(x)/ x/g" ),
59 array( "for(x;x;{}/ x/g);", "for(x;x;{}/x/g);" ),
60 array( "x;x;{}/ x/g", "x;x;{}/ x/g" ),
61 array( "x:{}/ x/g", "x:{}/ x/g" ),
62 array( "switch(x){case y?z:{}/ x/g:{}/ x/g;}", "switch(x){case y?z:{}/x/g:{}/ x/g;}" ),
63 array( "function x(){}/ x/g", "function x(){}/ x/g" ),
64 array( "+function x(){}/ x/g", "+function x(){}/x/g" ),
66 // Tests for things that broke in the past
67 // Multiline quoted string
68 array( "var foo=\"\\\nblah\\\n\";", "var foo=\"\\\nblah\\\n\";" ),
69 // Multiline quoted string followed by string with spaces
70 array( "var foo=\"\\\nblah\\\n\";\nvar baz = \" foo \";\n", "var foo=\"\\\nblah\\\n\";var baz=\" foo \";" ),
71 // URL in quoted string ( // is not a comment)
72 array( "aNode.setAttribute('href','http://foo.bar.org/baz');", "aNode.setAttribute('href','http://foo.bar.org/baz');" ),
73 // URL in quoted string after multiline quoted string
74 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');" ),
75 // Division vs. regex nastiness
76 array( "alert( (10+10) / '/'.charCodeAt( 0 ) + '//' );", "alert((10+10)/'/'.charCodeAt(0)+'//');" ),
77 array( "if(1)/a /g.exec('Pa ss');", "if(1)/a /g.exec('Pa ss');" ),
79 // newline insertion after 1000 chars: break after the "++", not before
80 array( str_repeat( ';', 996 ) . "if(x++);", str_repeat( ';', 996 ) . "if(x++\n);" ),
82 // Unicode letter characters should pass through ok in identifiers (bug 31187)
83 array( "var KaŝSkatolVal = {}", 'var KaŝSkatolVal={}'),
84 // And also per spec unicode char escape values should work in identifiers,
85 // as long as it's a valid char. In future it might get normalized.
86 array( "var Ka\\u015dSkatolVal = {}", 'var Ka\\u015dSkatolVal={}'),
91 * @dataProvider provideCases
93 function testJavaScriptMinifierOutput( $code, $expectedOutput ) {
94 $minified = JavaScriptMinifier
::minify( $code );
96 // JSMin+'s parser will throw an exception if output is not valid JS.
97 // suppression of warnings needed for stupid crap
99 $parser = new JSParser();
101 $parser->parse( $minified, 'minify-test.js', 1 );
103 $this->assertEquals( $expectedOutput, $minified, "Minified output should be in the form expected." );
107 * @dataProvider provideBug32548
109 function testBug32548Exponent($num) {
110 // Long line breaking was being incorrectly done between the base and
111 // exponent part of a number, causing a syntax error. The line should
112 // instead break at the start of the number.
113 $prefix = 'var longVarName' . str_repeat('_', 973) . '=';
114 $suffix = ',shortVarName=0;';
116 $input = $prefix . $num . $suffix;
117 $expected = $prefix . $num . "\n" . $suffix;
119 $minified = JavaScriptMinifier
::minify( $input );
121 $this->assertEquals( $expected, $minified, "Line breaks must not occur in middle of exponent");
124 function provideBug32548() {
127 // This one gets interpreted all together by the prior code;
128 // no break at the 'E' happens.
132 // This one breaks under the bad code; splits between 'E' and '+'
136 // This one breaks under the bad code; splits between 'E' and '-'