EMMA Coverage Report (generated Mon Nov 01 16:48:29 PDT 2010)
[all classes][com.google.caja.parser.quasiliteral]

COVERAGE SUMMARY FOR SOURCE FILE [ES53RewriterTest.java]

nameclass, %method, %block, %line, %
ES53RewriterTest.java50%  (1/2)96%  (90/94)94%  (1515/1604)93%  (329.7/354)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ES53RewriterTest100% (1/1)98%  (90/92)97%  (1515/1561)95%  (330.4/348)
ES53RewriterTest (): void 100% (1/1)100% (3/3)100% (2/2)
access$000 (ES53RewriterTest, String, InputSource): FetchedData 0%   (0/1)0%   (0/5)0%   (0/1)
executePlain (String): Object 100% (1/1)100% (51/51)100% (2/2)
rewriteAndExecute (String, String, String): Object 100% (1/1)100% (230/230)100% (14/14)
setUp (): void 100% (1/1)100% (16/16)100% (4/4)
testApply (): void 100% (1/1)100% (7/7)100% (2/2)
testArray (): void 100% (1/1)100% (7/7)100% (3/3)
testAssertEqualsCajoled (): void 100% (1/1)20%  (2/10)33%  (2/6)
testAssertThrowsCajoledErrorNoMsg (): void 100% (1/1)20%  (2/10)33%  (2/6)
testAssertThrowsCajoledErrorWithMsg (): void 100% (1/1)20%  (2/10)33%  (2/6)
testAssertThrowsCajoledNoError (): void 100% (1/1)100% (9/9)100% (3/3)
testBadDelete (): void 100% (1/1)100% (11/11)100% (3/3)
testCallback (): void 100% (1/1)100% (20/20)100% (7/7)
testClosure (): void 100% (1/1)100% (4/4)100% (2/2)
testConcatArgs (): void 100% (1/1)100% (7/7)100% (2/2)
testConstant (): void 100% (1/1)100% (4/4)100% (2/2)
testConstructionWithFunction (): void 100% (1/1)100% (7/7)100% (3/3)
testDate (): void 100% (1/1)100% (11/11)100% (4/4)
testDelete (): void 100% (1/1)100% (7/7)100% (3/3)
testDeleteFails (): void 100% (1/1)100% (5/5)100% (2/2)
testDeleteNonLvalue (): void 100% (1/1)100% (5/5)100% (2/2)
testDeletePub (): void 100% (1/1)100% (11/11)100% (4/4)
testEmbeddedcajaVM (): void 100% (1/1)100% (4/4)100% (2/2)
testErrorFreeze (): void 100% (1/1)100% (5/5)100% (2/2)
testFrozenObjectPrototype (): void 100% (1/1)100% (5/5)100% (2/2)
testFuncAnonSimple (): void 100% (1/1)100% (4/4)100% (2/2)
testFuncArgs (): void 100% (1/1)100% (5/5)100% (2/2)
testFuncCtor (): void 100% (1/1)100% (13/13)100% (4/4)
testFuncNamedSimpleDecl (): void 100% (1/1)100% (12/12)100% (4/4)
testFunctionInstance (): void 100% (1/1)100% (17/17)100% (5/5)
testFunctionToStringCall (): void 0%   (0/1)0%   (0/17)0%   (0/5)
testIn2 (): void 100% (1/1)100% (7/7)100% (3/3)
testInMonkeyDelete (): void 100% (1/1)100% (4/4)100% (2/2)
testInVeil (): void 100% (1/1)100% (5/5)100% (2/2)
testIndexOf (): void 100% (1/1)100% (4/4)100% (2/2)
testInherit (): void 100% (1/1)100% (4/4)100% (2/2)
testInheritance (): void 100% (1/1)100% (5/5)100% (2/2)
testInit (): void 100% (1/1)100% (4/4)100% (2/2)
testInitializeMap (): void 100% (1/1)100% (4/4)100% (2/2)
testInstanceof (): void 100% (1/1)100% (10/10)100% (4/4)
testJSONClass (): void 100% (1/1)100% (21/21)100% (6/6)
testLabeledStatement (): void 100% (1/1)100% (23/23)100% (7/7)
testMapBadKeySuffix (): void 100% (1/1)100% (14/14)100% (2/2)
testMapNonEmpty (): void 100% (1/1)100% (17/17)100% (4/4)
testMapSingle (): void 100% (1/1)100% (5/5)100% (2/2)
testMaskingFunction (): void 100% (1/1)100% (15/15)100% (4/4)
testMonkeyOverride (): void 100% (1/1)100% (4/4)100% (2/2)
testMonkeyPatchPrimordialFunction (): void 100% (1/1)100% (4/4)100% (2/2)
testMultiDeclaration2 (): void 100% (1/1)100% (9/9)100% (3/3)
testNamedFunctionShadow (): void 100% (1/1)100% (7/7)100% (3/3)
testNew (): void 100% (1/1)100% (4/4)100% (2/2)
testNoCanSetInheritance (): void 100% (1/1)100% (5/5)100% (2/2)
testNoFastpathWritableInheritance (): void 100% (1/1)100% (5/5)100% (2/2)
testNoPrivilegeEscalation (): void 100% (1/1)100% (13/13)100% (4/4)
testObject (): void 100% (1/1)100% (4/4)100% (2/2)
testObjectFreeze (): void 100% (1/1)100% (21/21)100% (6/6)
testProtoCall (): void 100% (1/1)100% (22/22)100% (8/8)
testReadBadSuffix (): void 100% (1/1)100% (5/5)100% (2/2)
testReflectiveMethodInvocation (): void 100% (1/1)100% (19/19)100% (7/7)
testReformedGenerics (): void 100% (1/1)100% (16/16)100% (6/6)
testRegExpLeak (): void 100% (1/1)100% (5/5)100% (2/2)
testSetBadDeclare (): void 100% (1/1)100% (5/5)100% (2/2)
testSetBadFreeVariable (): void 100% (1/1)100% (18/18)100% (3/3)
testSetBadInitialize (): void 100% (1/1)100% (5/5)100% (2/2)
testSetBadSuffix (): void 100% (1/1)100% (5/5)100% (2/2)
testSetIncrDecr (): void 100% (1/1)100% (11/11)100% (4/4)
testSetIncrDecrOfComplexLValues (): void 100% (1/1)100% (12/12)100% (4/4)
testSetIncrDecrOnLocals (): void 100% (1/1)100% (8/8)100% (3/3)
testSetIncrDecrOrderOfAssignment (): void 100% (1/1)100% (7/7)100% (3/3)
testSetReadModifyWriteLocalVar (): void 100% (1/1)100% (90/90)100% (10/10)
testSetVar (): void 100% (1/1)100% (14/14)100% (2/2)
testStamp (): void 100% (1/1)100% (31/31)100% (8/8)
testStatic (): void 100% (1/1)100% (4/4)100% (2/2)
testSyntheticFormals (): void 100% (1/1)100% (141/141)100% (6/6)
testSyntheticIsUntouched (): void 100% (1/1)100% (38/38)100% (5/5)
testSyntheticMemberAccess (): void 100% (1/1)100% (29/29)100% (4/4)
testTable (): void 100% (1/1)100% (33/33)100% (9/9)
testTamedXo4aOkOnNull (): void 100% (1/1)100% (17/17)100% (4/4)
testThrowCatch (): void 100% (1/1)100% (25/25)100% (9/9)
testToString (): void 100% (1/1)100% (7/7)100% (3/3)
testToStringToxicity (): void 100% (1/1)100% (7/7)100% (2/2)
testToxicBind (): void 100% (1/1)100% (7/7)100% (2/2)
testTryCatch (): void 100% (1/1)100% (92/92)100% (14/14)
testTryCatchFinally (): void 100% (1/1)100% (42/42)100% (4/4)
testTryFinally (): void 100% (1/1)100% (4/4)100% (2/2)
testTypeof (): void 100% (1/1)100% (26/26)100% (9/9)
testValueOf (): void 100% (1/1)100% (4/4)100% (2/2)
testVarBadSuffix (): void 100% (1/1)100% (9/9)100% (3/3)
testVarBadSuffixDeclaration (): void 100% (1/1)100% (25/25)100% (7/7)
testVarFuncFreeze (): void 100% (1/1)100% (12/12)100% (4/4)
testWith (): void 100% (1/1)100% (9/9)100% (3/3)
testWrapperAccess (): void 100% (1/1)100% (7/7)100% (2/2)
     
class ES53RewriterTest$TestUriFetcher0%   (0/1)0%   (0/2)0%   (0/43)0%   (0/7)
ES53RewriterTest$TestUriFetcher (ES53RewriterTest): void 0%   (0/1)0%   (0/6)0%   (0/1)
fetch (ExternalReference, String): FetchedData 0%   (0/1)0%   (0/37)0%   (0/6)

1// Copyright (C) 2007 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14 
15package com.google.caja.parser.quasiliteral;
16 
17import java.io.IOException;
18import java.net.URI;
19import java.util.Arrays;
20import java.util.EnumSet;
21import java.util.List;
22 
23import junit.framework.AssertionFailedError;
24 
25import com.google.caja.lexer.ExternalReference;
26import com.google.caja.lexer.FetchedData;
27import com.google.caja.lexer.FilePosition;
28import com.google.caja.lexer.InputSource;
29import com.google.caja.lexer.ParseException;
30import com.google.caja.parser.ParseTreeNode;
31import com.google.caja.parser.js.Block;
32import com.google.caja.parser.js.FormalParam;
33import com.google.caja.parser.js.FunctionConstructor;
34import com.google.caja.parser.js.FunctionDeclaration;
35import com.google.caja.parser.js.Identifier;
36import com.google.caja.parser.js.Operation;
37import com.google.caja.parser.js.Operator;
38import com.google.caja.parser.js.Reference;
39import com.google.caja.parser.js.ReturnStmt;
40import com.google.caja.parser.js.Statement;
41import com.google.caja.parser.js.SyntheticNodes;
42import com.google.caja.parser.js.UncajoledModule;
43import com.google.caja.plugin.UriFetcher;
44import com.google.caja.reporting.MessageLevel;
45import com.google.caja.reporting.MessageType;
46import com.google.caja.reporting.TestBuildInfo;
47import com.google.caja.util.Executor;
48import com.google.caja.util.FailureIsAnOption;
49import com.google.caja.util.Lists;
50import com.google.caja.util.RhinoTestBed;
51 
52public class ES53RewriterTest extends CommonJsRewriterTestCase {
53  protected class TestUriFetcher implements UriFetcher {
54    public FetchedData fetch(ExternalReference ref, String mimeType)
55        throws UriFetchException {
56      try {
57        URI uri = ref.getReferencePosition().source().getUri()
58            .resolve(ref.getUri());
59        if ("resource".equals(uri.getScheme())) {
60          return dataFromResource(uri.getPath(), new InputSource(uri));
61        } else {
62          throw new UriFetchException(ref, mimeType);
63        }
64      } catch (IOException ex) {
65        throw new UriFetchException(ref, mimeType, ex);
66      }
67    }
68  }
69 
70  private Rewriter es53Rewriter;
71 
72  /**
73   * Tests that an inherited <tt>*_w___</tt> flag does not enable
74   * bogus writability.
75   * <p>
76   * See <a href="http://code.google.com/p/google-caja/issues/detail?id=1052"
77   * >issue 1052</a>.
78   */
79  public final void testNoFastpathWritableInheritance() throws Exception {
80    rewriteAndExecute(
81            "(function() {" +
82            "  var a = {};" +
83            "  var b = Object.freeze(Object.create(a));" +
84            "  a.x = 8;" +
85            "  assertThrows(function(){b.x = 9;});" +
86            "  assertEquals(b.x, 8);" +
87            "})();");
88  }
89 
90  public final void testConstant() throws Exception {
91    assertConsistent("1;");
92  }
93 
94  public final void testInit() throws Exception {
95    assertConsistent("var a = 0; a;");
96  }
97 
98  public final void testNew() throws Exception {
99    assertConsistent(
100        "function f() { this.x = 1; }" +
101        "var g = new f();" +
102        "g.x;");
103  }
104 
105  public final void testThrowCatch() throws Exception {
106    assertConsistent(
107        "var x = 0; try { throw 1; }" +
108        "catch (e) { x = e; }" +
109        "x;");
110    assertConsistent(
111        "var x = 0; try { throw { a: 1 }; }" +
112        "catch (e) { x = e; }" +
113        "'' + x;");
114    assertConsistent(
115        "var x = 0; try { throw 'err'; }" +
116        "catch (e) { x = e; }" +
117        "x;");
118    assertConsistent(
119        "var x = 0; try { throw new Error('err'); }" +
120        "catch (e) { x = e.message; }" +
121        "x;");
122    assertConsistent(
123        "var x = 0; try { throw 1; }" +
124        "catch (e) { x = e; }" +
125        "finally { x = 2; }" +
126        "x;");
127    assertConsistent(
128        "var x = 0; try { throw { a: 1 }; }" +
129        "catch (e) { x = e; }" +
130        "finally { x = 2; }" +
131        "x;");
132    assertConsistent(
133        "var x = 0; try { throw 'err'; }" +
134        "catch (e) { x = e; }" +
135        "finally { x = 2; }" +
136        "x;");
137    assertConsistent(
138        "var x = 0; try { throw new Error('err'); }" +
139        "catch (e) { x = e.message; }" +
140        "finally { x = 2; }" +
141        "x;");
142  }
143 
144  public final void testProtoCall() throws Exception {
145    assertConsistent("Array.prototype.sort.call([3, 1, 2]);");
146    assertConsistent("[3, 1, 2].sort();");
147    assertConsistent("[3, 1, 2].sort.call([4, 2, 7]);");
148 
149    assertConsistent("String.prototype.indexOf.call('foo', 'o');");
150    assertConsistent("'foo'.indexOf('o');");
151 
152    assertConsistent("'foo'.indexOf.call('bar', 'o');");
153    assertConsistent("'foo'.indexOf.call('bar', 'a');");
154  }
155 
156  public final void testInherit() throws Exception {
157    assertConsistent(
158        "function Point(x) { this.x = x; }\n" +
159        "Point.prototype.toString = function () {\n" +
160        "  return '<' + this.x + '>';\n" +
161        "};\n" +
162        "function WP(x) { Point.call(this,x); }\n" +
163        "WP.prototype = Object.create(Point.prototype);\n" +
164        "var pt = new WP(3);\n" +
165        "pt.toString();");
166  }
167 
168  /** See bug 528 */
169  public final void testRegExpLeak() throws Exception {
170    rewriteAndExecute(
171        "assertEquals('' + (/(.*)/).exec(), 'undefined,undefined');");
172  }
173 
174  public final void testClosure() throws Exception {
175    assertConsistent(
176        "function f() {" +
177        "  var y = 2; " +
178        "  this.x = function() {" +
179        "    return y;" +
180        "  }; " +
181        "}" +
182        "var g = new f();" +
183        "var h = {};" +
184        "f.call(h);" +
185        "h.y = g.x;" +
186        "h.x() + h.y();");
187  }
188 
189  public final void testNamedFunctionShadow() throws Exception {
190    assertConsistent("function f() { return f; } f === f();");
191    assertConsistent(
192        "(function () { function f() { return f; } return f === f(); })();");
193  }
194 
195  public final void testArray() throws Exception {
196    assertConsistent("[3, 2, 1].sort();");
197    assertConsistent("[3, 2, 1].sort.call([4, 2, 7]);");
198  }
199 
200  public final void testObject() throws Exception {
201    assertConsistent("({ x: 1, y: 2 });");
202  }
203 
204  //TODO(erights): Fix these tests to test for the output we now expect.
205  @FailureIsAnOption
206  public final void testFunctionToStringCall() throws Exception {
207    rewriteAndExecute(
208        "function foo() {}\n"
209        + "assertEquals(foo.toString(),\n"
210        + "             'function foo() {\\n  [cajoled code]\\n}');");
211    rewriteAndExecute(
212        "function foo (a, b) { xx; }\n"
213        + "assertEquals(foo.toString(),\n"
214        + "             'function foo(a, b) {\\n  [cajoled code]\\n}');");
215    rewriteAndExecute(
216        "function foo() {}\n"
217        + "assertEquals(Function.prototype.toString.call(foo),\n"
218        + "             'function foo() {\\n  [cajoled code]\\n}');");
219    rewriteAndExecute(
220        "var foo = function (x$x, y_y) {};\n"
221        + "assertEquals("
222        + "    Function.prototype.toString.call(foo),\n"
223        + "    'function foo$_var(x$x, y_y) {\\n  [cajoled code]\\n}');");
224  }
225 
226  public final void testDate() throws Exception {
227    assertConsistent("(new Date(0)).getTime();");
228    assertConsistent("'' + (new Date(0));");
229    rewriteAndExecute(
230        ""
231        + "var time = (new Date - 1);"
232        + "assertFalse(isNaN(time));"
233        + "assertEquals('number', typeof time);");
234  }
235 
236  public final void testMultiDeclaration2() throws Exception {
237    rewriteAndExecute("var a, b, c;");
238    rewriteAndExecute(
239        ""
240        + "var a = 0, b = ++a, c = ++a;"
241        + "assertEquals(++a * b / c, 1.5);");
242  }
243 
244  public final void testDelete() throws Exception {
245    assertConsistent(
246        "(function () { var a = { x: 1 }; delete a.x; return typeof a.x; })();"
247        );
248    assertConsistent("var a = { x: 1 }; delete a.x; typeof a.x;");
249  }
250 
251  public final void testIn2() throws Exception {
252    assertConsistent(
253        "(function () {" +
254        "  var a = { x: 1 };\n" +
255        "  return '' + ('x' in a) + ('y' in a);" +
256        "})();");
257    assertConsistent(
258        "var a = { x: 1 };\n" +
259        "[('x' in a), ('y' in a)];");
260  }
261 
262  /**
263   * Try to construct some class instances.
264   */
265  public final void testFuncCtor() throws Exception {
266    rewriteAndExecute(
267        "function Foo(x) { this.x = x; }" +
268        "var foo = new Foo(2);" +
269        "if (!foo) { fail('Failed to construct a global object.'); }" +
270        "assertEquals(2, foo.x);" +
271        "assertEquals(Foo, foo.constructor);");
272    rewriteAndExecute(
273        "(function () {" +
274        "  function Foo(x) { this.x = x; }" +
275        "  var foo = new Foo(2);" +
276        "  if (!foo) { fail('Failed to construct a local object.'); }" +
277        "  assertEquals(2, foo.x);" +
278        "})();");
279    rewriteAndExecute(
280        "function Foo() { }" +
281        "var foo = new Foo();" +
282        "if (!foo) {" +
283        "  fail('Failed to use a simple named function as a constructor.');" +
284        "}");
285  }
286 
287  public final void testFuncArgs() throws Exception {
288    rewriteAndExecute(
289        ""
290        + "var x = 0;"
291        + "function f() { x = arguments[0]; }"
292        + "f(3);"
293        + "assertEquals(3, x);");
294  }
295 
296  public final void testStatic() throws Exception {
297    assertConsistent("Array.slice([3, 4, 5, 6], 1);");
298  }
299 
300  public final void testConcatArgs() throws Exception {
301    rewriteAndExecute("", "(function(x, y){ return [x, y]; })",
302        "var f = ___.getNewModuleHandler().getLastValue();"
303        + "function g(var_args) { return f.apply(___.USELESS, arguments); }"
304        + "assertEquals(g(3, 4).toString(), [3, 4].toString());");
305  }
306 
307  public final void testReformedGenerics() throws Exception {
308    assertConsistent(
309        "var x = [33];" +
310        "x.foo = [].push;" +
311        "x.foo(44);" +
312        "x;");
313    assertConsistent(
314        "var x = {blue:'green'};" +
315        "x.foo = [].push;" +
316        "x.foo(44);" +
317        "var keys = [];" +
318        "for (var i in x) { if (x.hasOwnProperty(i)) { keys.push(i); } }" +
319        "keys.sort();");
320    assertConsistent(
321        "var x = [33];" +
322        "Array.prototype.push.apply(x, [3,4,5]);" +
323        "x;");
324    assertConsistent(
325        "var x = {blue:'green'};" +
326        "Array.prototype.push.apply(x, [3,4,5]);" +
327        "var keys = [];" +
328        "for (var i in x) { if (x.hasOwnProperty(i)) { keys.push(i); } }" +
329        "keys.sort();");
330    assertConsistent(
331        "var x = {blue:'green'};" +
332        "x.foo = [].push;" +
333        "x.foo.call(x, 44);" +
334        "var keys = [];" +
335        "for (var i in x) { if (x.hasOwnProperty(i)) { keys.push(i); } }" +
336        "keys.sort();");
337  }
338 
339  public final void testMonkeyPatchPrimordialFunction() throws Exception {
340    assertConsistent(
341        "isNaN.foo = 'bar';" +
342        "isNaN.foo;");
343  }
344 
345  public final void testInMonkeyDelete() throws Exception {
346    assertConsistent(
347        "var x = {y:1 };" +
348        "delete x.y;" +
349        "('y' in x);");
350  }
351 
352  public final void testMonkeyOverride() throws Exception {
353    assertConsistent(
354        // TODO(erights): Fix when bug 953 is fixed.
355        "Date.prototype.propertyIsEnumerable = function(p) { return true; };" +
356        "(new Date()).propertyIsEnumerable('foo');");
357  }
358 
359  public final void testEmbeddedcajaVM() throws Exception {
360    assertConsistent(
361        ""
362        + "\"use strict,cajaVM\"; \n"
363        + "var foo; \n"
364        + "(function () { \n"
365        + "  foo = function () { return 8; }; \n"
366        + "})(); \n"
367        + "foo();"
368        );
369  }
370 
371  /**
372   * Tests that Error objects are frozen
373   *
374   * See issue 1097, issue 1038,
375   *     and {@link CommonJsRewriterTestCase#testErrorTaming()}}.
376   */
377  public final void testErrorFreeze() throws Exception {
378    rewriteAndExecute(
379            "try {" +
380            "  throw new Error('foo');" +
381            "} catch (ex) {" +
382            "  assertTrue(Object.isFrozen(ex));" +
383            "}");
384  }
385 
386  /**
387   *
388   */
389  public final void testObjectFreeze() throws Exception {
390    rewriteAndExecute(
391        "var r = Object.freeze({});" +
392        "assertThrows(function(){r.foo = 8;});");
393    rewriteAndExecute(
394        "var f = function(){};" +
395        "f.foo = 8;");
396    rewriteAndExecute(
397        "var f = Object.freeze(function(){});" +
398        "assertThrows(function(){f.foo = 8;});");
399    rewriteAndExecute(
400        "function Point(x,y) {" +
401        "  this.x = x;" +
402        "  this.y = y;" +
403        "}" +
404        "var pt = new Point(3,5);" +
405        "pt.x = 8;" +
406        "Object.freeze(pt);" +
407        "assertThrows(function(){pt.y = 9;});");
408    // Check that deferred creation of prototype property doesn't make it
409    // writable.
410    rewriteAndExecute(
411        "function f(){}" +
412        "Object.freeze(f);" +
413        "assertThrows(function() { f.prototype = {}; });");
414  }
415 
416  /**
417   * Tests that the {@code prototype}, {@code name}, and {@code length}
418   * properties of function instances are set properly.
419   */
420  public final void testFunctionInstance() throws Exception {
421    rewriteAndExecute(
422        "assertTrue(!!((function(){}).prototype));");
423    rewriteAndExecute(
424        "assertEquals((function(a,b,c){}).length, 3);");
425    rewriteAndExecute(
426        "assertEquals((function x(a,b,c){}).name, 'x');");
427    // Check frozen functions created early in es53.js
428    rewriteAndExecute(
429        "assertTrue(!!(cajaVM.USELESS.toString.prototype));");
430  }
431 
432  /**
433   * Tests that the special handling of null on tamed exophora works.
434   * <p>
435   * The reification of tamed exophoric functions contains
436   * special cases for when the first argument to call, bind, or apply
437   * is null or undefined, in order to protect against privilege escalation.
438   * {@code #testNoPrivilegeEscalation()} tests that we do prevent the
439   * privilege escalation. Here, we test that this special case preserves
440   * correct functionality.
441   */
442  public final void testTamedXo4aOkOnNull() throws Exception {
443    rewriteAndExecute("this.foo = 8;",
444 
445        "var x = Object.create(cajaVM.USELESS);" +
446        "assertFalse(({foo: 7}).hasOwnProperty.call(null, 'foo'));" +
447        "assertTrue(cajaVM.USELESS.isPrototypeOf(x));" +
448        "assertTrue(({foo: 7}).isPrototypeOf.call(null, x));",
449 
450        "assertTrue(({}).hasOwnProperty.call(null, 'foo'));" +
451        "assertFalse(({bar: 7}).hasOwnProperty.call(null, 'bar'));");
452    rewriteAndExecute("this.foo = 8;",
453 
454        "var x = Object.create(cajaVM.USELESS);" +
455        "assertFalse(({foo: 7}).hasOwnProperty.apply(null, ['foo']));" +
456        "assertTrue(cajaVM.USELESS.isPrototypeOf(x));" +
457        "assertTrue(({foo: 7}).isPrototypeOf.apply(null, [x]));",
458 
459        "assertTrue(({}).hasOwnProperty.apply(null, ['foo']));" +
460        "assertFalse(({bar: 7}).hasOwnProperty.apply(null, ['bar']));");
461    rewriteAndExecute(
462        "var x = Object.create(cajaVM.USELESS);" +
463        "assertFalse(({foo: 7}).hasOwnProperty.bind(null)('foo'));" +
464        "assertTrue(cajaVM.USELESS.isPrototypeOf(x));" +
465        "assertTrue(({foo: 7}).isPrototypeOf.bind(null)(x));");
466  }
467 
468  public final void testToString() throws Exception {
469    assertConsistent(
470        "var z = { toString: function () { return 'blah'; } };" +
471        "try {" +
472        "  '' + z;" +
473        "} catch (e) {" +
474        "  throw new Error('PlusPlus error: ' + e);" +
475        "}");
476    assertConsistent(
477        "  function foo() {"
478        + "  var x = 1;"
479        + "  return {"
480        + "    toString: function () {"
481        + "      return x;"
482        + "    }"
483        + "  };"
484        + "}"
485        + "'' + (new foo);");
486  }
487 
488  public final void testToStringToxicity() throws Exception {
489    rewriteAndExecute(
490        "",
491        "function objMaker(f) {return {toString:f};}",
492        ""
493        + "assertThrows("
494        + "    function() {testImports.objMaker(function(){return '1';});});"
495        );
496  }
497 
498  public final void testInitializeMap() throws Exception {
499    assertConsistent("var zerubabel = {bobble:2, apple:1}; zerubabel.apple;");
500  }
501 
502  public final void testValueOf() throws Exception {
503    assertConsistent("''+{valueOf:function(){return 5;}}");
504  }
505 
506  public final void testAssertEqualsCajoled() throws Exception {
507    try {
508      rewriteAndExecute("assertEquals(1, 2);");
509    } catch (AssertionFailedError e) {
510      return;
511    }
512    fail("Assertions do not work in cajoled mode");
513  }
514 
515  public final void testAssertThrowsCajoledNoError() throws Exception {
516    rewriteAndExecute(
517        "  assertThrows(function() { throw 'foo'; });");
518    rewriteAndExecute(
519        "  assertThrows("
520        + "    function() { throw 'foo'; },"
521        + "    'foo');");
522  }
523 
524  public final void testAssertThrowsCajoledErrorNoMsg() throws Exception {
525    try {
526      rewriteAndExecute("assertThrows(function() {});");
527    } catch (AssertionFailedError e) {
528      return;
529    }
530    fail("Assertions do not work in cajoled mode");
531  }
532 
533  public final void testAssertThrowsCajoledErrorWithMsg() throws Exception {
534    try {
535      rewriteAndExecute("assertThrows(function() {}, 'foo');");
536    } catch (AssertionFailedError e) {
537      return;
538    }
539    fail("Assertions do not work in cajoled mode");
540  }
541 
542  public final void testConstructionWithFunction() throws Exception {
543    assertConsistent(
544        "  function Point() {}"
545        + "var p = new Point();"
546        + "(p !== undefined);");
547    assertConsistent(
548        "  var Point = function() {};"
549        + "var p = new Point();"
550        + "(p !== undefined);");
551  }
552 
553  public final void testReflectiveMethodInvocation() throws Exception {
554    assertConsistent(
555        "(function (first, second) { return 'a' + first + 'b' + second; })"
556        + ".call([], 8, 9);");
557    assertConsistent(
558        "var a = []; [].push.call(a, 5, 6); a;");
559    assertConsistent(
560        "(function (a, b) { return 'a' + a + 'b' + b; }).apply([], [8, 9]);");
561    assertConsistent(
562        "var a = []; [].push.apply(a, [5, 6]); a;");
563    assertConsistent(
564        "[].sort.apply([6, 5]);");
565    assertConsistent(
566        "(function (first, second) { return 'a' + first + 'b' + second; })"
567        + ".bind([], 8)(9);");
568  }
569 
570  /**
571   * Tests that <a href=
572   * "http://code.google.com/p/google-caja/issues/detail?id=242"
573   * >bug#242</a> is fixed.
574   * <p>
575   * The actual Function.bind() method used to be whitelisted and
576   * written to return a frozen simple-function, allowing it to be called
577   * from all code on all functions. As a result, if an <i>outer hull breach</i>
578   * occurs -- if Caja code obtains a reference to a JavaScript
579   * function value not marked as Caja-callable -- then
580   * that Caja code could call the whitelisted bind() on it,
581   * and then call the result, causing an <i>inner hull breach</i>,
582   * which threatens kernel integrity.
583   */
584  public final void testToxicBind() throws Exception {
585    rewriteAndExecute(
586        "var confused = false;" +
587        "testImports.keystone = function keystone() { confused = true; };",
588        "assertThrows(function() {keystone.bind()();});",
589        "assertFalse(confused);");
590  }
591 
592  /**
593   * Tests that <a href=
594   * "http://code.google.com/p/google-caja/issues/detail?id=590"
595   * >bug#590</a> is fixed.
596   * <p>
597   * As a client of an object, Caja code must only be able to directly delete
598   * <i>public</i> properties of non-frozen JSON containers. Due to this bug,
599   * Caja code was able to delete properties in the Caja namespace.
600   */
601  public final void testBadDelete() throws Exception {
602    rewriteAndExecute(
603        "testImports.badContainer = {secret__: 3469};",
604        "assertThrows(function() {delete badContainer['secret__'];});",
605        "assertEquals(testImports.badContainer.secret__, 3469);");
606    rewriteAndExecute(
607        "assertThrows(function() {delete ({})['proto___'];});");
608  }
609 
610  /**
611   * Tests that apply works.
612   */
613  public final void testApply() throws Exception {
614    rewriteAndExecute(
615        "",
616        "var x = 0;" +
617        "function f() { x = 1 }\n" +
618        "f.apply({});",
619        "assertEquals(testImports.x, 1);");
620    // TODO(erights): Need more tests.
621  }
622 
623  /**
624   * Tests that <a href=
625   * "http://code.google.com/p/google-caja/issues/detail?id=347"
626   * >bug#347</a> is fixed.
627   * <p>
628   * The <tt>in</tt> operator should only test for properties visible to Caja.
629   */
630  public final void testInVeil() throws Exception {
631    rewriteAndExecute(
632        "assertFalse('f___' in Object);");
633  }
634 
635  ////////////////////////////////////////////////////////////////////////
636  // Handling of synthetic nodes
637  ////////////////////////////////////////////////////////////////////////
638 
639  public final void testSyntheticIsUntouched() throws Exception {
640    String source = "function foo() { this; arguments; }";
641    ParseTreeNode input = js(fromString(source));
642    syntheticTree(input);
643    checkSucceeds(input, js(fromString("var dis___ = IMPORTS___;" + source)));
644  }
645 
646  public final void testSyntheticMemberAccess() throws Exception {
647    ParseTreeNode input = js(fromString("({}).foo"));
648    syntheticTree(input);
649    checkSucceeds(
650        input,
651        js(fromString("var dis___ = IMPORTS___; ___.iM([]).foo;")));
652  }
653 
654  public final void testSyntheticFormals() throws Exception {
655    FilePosition unk = FilePosition.UNKNOWN;
656    FunctionConstructor fc = new FunctionConstructor(
657        unk,
658        new Identifier(unk, "f"),
659        Arrays.asList(
660            new FormalParam(new Identifier(unk, "x")),
661            new FormalParam(
662                SyntheticNodes.s(new Identifier(unk, "y___")))),
663        new Block(
664            unk,
665            Arrays.<Statement>asList(new ReturnStmt(
666                unk,
667                Operation.createInfix(
668                    Operator.MULTIPLICATION,
669                    Operation.createInfix(
670                        Operator.ADDITION,
671                        new Reference(new Identifier(unk, "x")),
672                        new Reference(SyntheticNodes.s(
673                            new Identifier(unk, "y___")))),
674                    new Reference(new Identifier(unk, "z")))))));
675    checkSucceeds(
676        new Block(
677            unk,
678            Arrays.asList(
679                new FunctionDeclaration((FunctionConstructor) fc.clone()))),
680        js(fromString(
681            ""
682            // x and y___ are formals, but z is free to the function.
683            + "var dis___ = IMPORTS___;"
684            + "{"
685            + "  function f(x, y___) {"
686            + "    return (x + y___) *"
687            + "        (IMPORTS___.z_v___ ?"
688            + "        IMPORTS___.z :"
689            + "        ___.ri(IMPORTS___, 'z'));"
690            + "  }"
691            + "  IMPORTS___.w___('f', ___.f(f, 'f'));"
692            + "}")));
693 
694    SyntheticNodes.s(fc);
695    checkSucceeds(
696        new Block(
697            unk,
698            Arrays.asList(
699                new FunctionDeclaration((FunctionConstructor) fc.clone()))),
700        js(fromString(
701            ""
702            // x and y___ are formals, but z is free to the function.
703            + "var dis___ = IMPORTS___;"
704            + "function f(x, y___) {"
705            + "  return (x + y___) *"
706            + "        (IMPORTS___.z_v___ ?"
707            + "        IMPORTS___.z :"
708            + "        ___.ri(IMPORTS___, 'z'));"
709            + "}"
710            // Since the function is synthetic, it is not marked.
711            )));
712  }
713 
714  ////////////////////////////////////////////////////////////////////////
715  // Specific rules
716  ////////////////////////////////////////////////////////////////////////
717 
718  public final void testWith() throws Exception {
719    checkFails("with (dreams || ambiguousScoping) anything.isPossible();",
720               "\"with\" blocks are not allowed");
721    checkFails("with (dreams || ambiguousScoping) { anything.isPossible(); }",
722               "\"with\" blocks are not allowed");
723  }
724 
725  public final void testTryCatch() throws Exception {
726    checkAddsMessage(js(fromString(
727        "try {" +
728        "  throw 2;" +
729        "} catch (e) {" +
730        "  var e;" +
731        "}")),
732        MessageType.MASKING_SYMBOL,
733        MessageLevel.ERROR);
734    checkAddsMessage(js(fromString(
735        "var e;" +
736        "try {" +
737        "  throw 2;" +
738        "} catch (e) {" +
739        "}")),
740        MessageType.MASKING_SYMBOL,
741        MessageLevel.ERROR);
742    checkAddsMessage(js(fromString(
743        "try {} catch (x__) { }")),
744        RewriterMessageType.VARIABLES_CANNOT_END_IN_DOUBLE_UNDERSCORE);
745    checkAddsMessage(js(fromString(
746        "var x;" +
747        "try {" +
748        "  g[x + 0];" +
749        "  g[x + 1];" +
750        "} catch (e) {" +
751        "  g[x + 2];" +
752        "  e;" +
753        "  g[x + 3];" +
754        "}" +
755        "var e;")),
756        MessageType.MASKING_SYMBOL,
757        MessageLevel.ERROR);
758    rewriteAndExecute(
759        "var handled = false;" +
760        "try {" +
761        "  throw null;" +
762        "} catch (ex) {" +
763        "  assertEquals(null, ex);" +  // Right value in ex.
764        "  handled = true;" +
765        "}" +
766        "assertTrue(handled);");  // Control reached and left the catch block.
767    rewriteAndExecute(
768        "var handled = false;" +
769        "try {" +
770        "  throw undefined;" +
771        "} catch (ex) {" +
772        "  assertEquals(undefined, ex);" +
773        "  handled = true;" +
774        "}" +
775        "assertTrue(handled);");
776    rewriteAndExecute(
777        "var handled = false;" +
778        "try {" +
779        "  throw true;" +
780        "} catch (ex) {" +
781        "  assertEquals(true, ex);" +
782        "  handled = true;" +
783        "}" +
784        "assertTrue(handled);");
785    rewriteAndExecute(
786        "var handled = false;" +
787        "try {" +
788        "  throw 37639105;" +
789        "} catch (ex) {" +
790        "  assertEquals(37639105, ex);" +
791        "  handled = true;" +
792        "}" +
793        "assertTrue(handled);");
794    rewriteAndExecute(
795        "var handled = false;" +
796        "try {" +
797        "  throw 'panic';" +
798        "} catch (ex) {" +
799        "  assertEquals('panic', ex);" +
800        "  handled = true;" +
801        "}" +
802        "assertTrue(handled);");
803    rewriteAndExecute(
804        "var handled = false;" +
805        "try {" +
806        "  throw new Error('hello');" +
807        "} catch (ex) {" +
808        "  assertEquals('hello', ex.message);" +
809        "  assertEquals('Error', ex.name);" +
810        "  handled = true;" +
811        "}" +
812        "assertTrue(handled);");
813    rewriteAndExecute(
814        "var handled = false;" +
815        "try {" +
816        "  throw function foo() { throw 'should not be called'; };" +
817        "} catch (ex) {" +
818        "  assertEquals('In lieu of thrown function: foo', ex());" +
819        "  handled = true;" +
820        "}" +
821        "assertTrue(handled);");
822    rewriteAndExecute(
823        "var handled = false;" +
824        "try {" +
825        "  throw { toString: function () { return 'hiya'; }, y: 4 };" +
826        "} catch (ex) {" +
827        "  assertEquals('string', typeof ex);" +
828        "  assertEquals('hiya', ex);" +
829        "  handled = true;" +
830        "}" +
831        "assertTrue(handled);");
832    rewriteAndExecute(
833        "var handled = false;" +
834        "try {" +
835        "  throw { toString: function () { throw new Error(); } };" +
836        "} catch (ex) {" +
837        "  assertEquals('Exception during exception handling.', ex);" +
838        "  handled = true;" +
839        "}" +
840        "assertTrue(handled);");
841  }
842 
843  public final void testTryCatchFinally() throws Exception {
844    checkAddsMessage(js(fromString(
845        "try {" +
846        "} catch (e) {" +
847        "  var e;" +
848        "} finally {" +
849        "}")),
850        MessageType.MASKING_SYMBOL,
851        MessageLevel.ERROR);
852    checkAddsMessage(js(fromString(
853        "var e;" +
854        "try {" +
855        "} catch (e) {" +
856        "} finally {" +
857        "}")),
858        MessageType.MASKING_SYMBOL,
859        MessageLevel.ERROR);
860    checkAddsMessage(js(fromString(
861        "try {} catch (x__) { } finally { }")),
862        RewriterMessageType.VARIABLES_CANNOT_END_IN_DOUBLE_UNDERSCORE);
863  }
864 
865  public final void testTryFinally() throws Exception {
866    assertConsistent(
867        "var out = 0;" +
868        "try {" +
869        "  try {" +
870        "    throw 2;" +
871        "  } finally {" +
872        "    out = 1;" +
873        "  }" +
874        "  out = 2;" +
875        "} catch (e) {" +
876        "}" +
877        "out;");
878  }
879 
880  public final void testVarBadSuffix() throws Exception {
881    checkFails(
882        "function() { foo__; };",
883        "Variables cannot end in \"__\"");
884    // Make sure *single* underscore is okay
885    checkSucceeds(
886        "function() { var foo_ = 3; };",
887        "var dis___ = IMPORTS___;" +
888        "___.f(function () {" +
889        "    var foo_;" +
890        "    foo_ = 3;" +
891        "  });");
892  }
893 
894  public final void testVarBadSuffixDeclaration() throws Exception {
895    checkFails(
896        "function foo__() { }",
897        "Variables cannot end in \"__\"");
898    checkFails(
899        "var foo__ = 3;",
900        "Variables cannot end in \"__\"");
901    checkFails(
902        "var foo__;",
903        "Variables cannot end in \"__\"");
904    checkFails(
905        "function() { function foo__() { } };",
906        "Variables cannot end in \"__\"");
907    checkFails(
908        "function() { var foo__ = 3; };",
909        "Variables cannot end in \"__\"");
910    checkFails(
911        "function() { var foo__; };",
912        "Variables cannot end in \"__\"");
913  }
914 
915  public final void testVarFuncFreeze() throws Exception {
916    // We can cajole and refer to a function
917    rewriteAndExecute(
918        "function foo() {}" +
919        "foo();");
920    // We can assign a dotted property of a variable
921    rewriteAndExecute(
922        "var foo = {};" +
923        "foo.x = 3;" +
924        "assertEquals(foo.x, 3);");
925    assertConsistent(
926        "function foo() {}" +
927        "var bar = foo;" +
928        "bar.x = 3;" +
929        "bar.x;");
930  }
931 
932  public final void testReadBadSuffix() throws Exception {
933    checkFails(
934        "x.y__;",
935        "Properties cannot end in \"__\"");
936  }
937 
938  /**
939   * Tests assignment to unmaskable and maskable globals.
940   */
941  public final void testSetBadFreeVariable() throws Exception {
942    // Array is in Scope.UNMASKABLE_IDENTIFIERS
943    checkAddsMessage(
944        js(fromString("Array = function () { return [] };")),
945        RewriterMessageType.CANNOT_MASK_IDENTIFIER);
946    // Throws a ReferenceError
947    rewriteAndExecute("assertThrows(function () { x = 1; })");
948  }
949 
950  public final void testSetBadSuffix() throws Exception {
951    checkFails(
952        "x.y__ = z;",
953        "Properties cannot end in \"__\"");
954  }
955 
956  public final void testSetBadInitialize() throws Exception {
957    checkFails(
958        "var x__ = 3;",
959        "Variables cannot end in \"__\"");
960  }
961 
962  public final void testSetBadDeclare() throws Exception {
963    checkFails(
964        "var x__;",
965        "Variables cannot end in \"__\"");
966  }
967 
968  public final void testSetVar() throws Exception {
969    checkAddsMessage(
970        js(fromString("try {} catch (x__) { x__ = 3; }")),
971        RewriterMessageType.VARIABLES_CANNOT_END_IN_DOUBLE_UNDERSCORE);
972  }
973 
974  public final void testSetReadModifyWriteLocalVar() throws Exception {
975    checkFails("x__ *= 2;", "");
976    checkFails("x *= y__;", "");
977 
978    assertConsistent("var x = 3; x *= 2;");
979    assertConsistent("var x = 1; x += 7;");
980    assertConsistent("var x = 1; x /= '2';");
981    assertConsistent("var o = { x: 'a' }; o.x += 'b'; o;");
982 
983    EnumSet<Operator> ops = EnumSet.of(
984        Operator.ASSIGN_MUL,
985        Operator.ASSIGN_DIV,
986        Operator.ASSIGN_MOD,
987        Operator.ASSIGN_SUM,
988        Operator.ASSIGN_SUB,
989        Operator.ASSIGN_LSH,
990        Operator.ASSIGN_RSH,
991        Operator.ASSIGN_USH,
992        Operator.ASSIGN_AND,
993        Operator.ASSIGN_XOR,
994        Operator.ASSIGN_OR
995        );
996    for (Operator op : ops) {
997      assertConsistent("var x = 41, y = 0, g = [17]; x " +
998          op.getSymbol() + " g[y];");
999    }
1000  }
1001 
1002  public final void testSetIncrDecr() throws Exception {
1003    checkFails("x__--;", "");
1004    assertConsistent(
1005        "var x = 2;" +
1006        "var arr = [--x, x, x--, x, ++x, x, x++, x];" +
1007        "assertEquals('1,1,1,0,1,1,1,2', arr.join(','));" +
1008        "arr;");
1009    assertConsistent(
1010        "var x = '2';" +
1011        "var arr = [--x, x, x--, x, ++x, x, x++, x];" +
1012        "assertEquals('1,1,1,0,1,1,1,2', arr.join(','));" +
1013        "arr;");
1014  }
1015 
1016  public final void testSetIncrDecrOnLocals() throws Exception {
1017    checkFails("++x__;", "");
1018    assertConsistent(
1019        "(function () {" +
1020        "  var x = 2;" +
1021        "  var arr = [--x, x, x--, x, ++x, x, x++, x];" +
1022        "  assertEquals('1,1,1,0,1,1,1,2', arr.join(','));" +
1023        "  return arr;" +
1024        "})();");
1025  }
1026 
1027  public final void testSetIncrDecrOfComplexLValues() throws Exception {
1028    checkFails("arr[x__]--;", "Variables cannot end in \"__\"");
1029    checkFails("arr__[x]--;", "Variables cannot end in \"__\"");
1030 
1031    assertConsistent(
1032        "(function () {" +
1033        "  var o = { x: 2 };" +
1034        "  var arr = [--o.x, o.x, o.x--, o.x, ++o.x, o.x, o.x++, o.x];" +
1035        "  assertEquals('1,1,1,0,1,1,1,2', arr.join(','));" +
1036        "  return arr;" +
1037        "})();");
1038  }
1039 
1040  public final void testSetIncrDecrOrderOfAssignment() throws Exception {
1041    assertConsistent(
1042        "(function () {" +
1043        "  var arrs = [1, 2];" +
1044        "  var j = 0;" +
1045        "  arrs[++j] *= ++j;" +
1046        "  assertEquals(2, j);" +
1047        "  assertEquals(1, arrs[0]);" +
1048        "  assertEquals(4, arrs[1]);" +
1049        "  return arrs;" +
1050        "})();");
1051    assertConsistent(
1052        "(function () {" +
1053        "  var foo = (function () {" +
1054        "               var k = 0;" +
1055        "               return function () {" +
1056        "                 switch (k++) {" +
1057        "                   case 0: return [10, 20, 30];" +
1058        "                   case 1: return 1;" +
1059        "                   case 2: return 2;" +
1060        "                   default: throw new Error(k);" +
1061        "                 }" +
1062        "               };" +
1063        "             })();" +
1064        "  return foo()[foo()] -= foo();" +
1065        "})();"
1066        );
1067  }
1068 
1069  public final void testDeletePub() throws Exception {
1070    checkFails("delete x.foo___;", "Properties cannot end in \"__\"");
1071    assertConsistent(
1072        "(function() {" +
1073        "  var o = { x: 3, y: 4 };" +    // A JSON object.
1074        "  function ptStr(o) { return '(' + o.x + ',' + o.y + ')'; }" +
1075        "  var history = [ptStr(o)];" +  // Record state before deletion.
1076        "  delete o.y;" +                // Delete
1077        "  delete o.z;" +                // Not present.  Delete a no-op
1078        "  history.push(ptStr(o));" +    // Record state after deletion.
1079        "  return history.toString();" +
1080        "})();");
1081    assertConsistent(
1082        "var alert = 'a';" +
1083        "var o = { a: 1 };" +
1084        "delete o[alert];" +
1085        "assertEquals(undefined, o.a);" +
1086        "o;");
1087  }
1088 
1089  public final void testDeleteFails() throws Exception {
1090    rewriteAndExecute(
1091        "assertThrows(function (){delete (function f(){}).name;});");
1092  }
1093 
1094  public final void testDeleteNonLvalue() throws Exception {
1095    checkFails("delete 4;", "Invalid operand to delete");
1096  }
1097 
1098  public final void testFuncAnonSimple() throws Exception {
1099    assertConsistent(
1100        "var foo = (function () {" +
1101        "             function foo() {}" +
1102        "             foo.x = 3;" +
1103        "             return foo;" +
1104        "           })();" +
1105        "foo();" +
1106        "foo.x;");
1107  }
1108 
1109  public final void testFuncNamedSimpleDecl() throws Exception {
1110    rewriteAndExecute(
1111        "(function () {" +
1112        "  function foo() {}" +
1113        "  Object.freeze(foo);" +
1114        "  foo();" +
1115        "  try {" +
1116        "    foo.x = 3;" +
1117        "  } catch (e) { return; }" +
1118        "  fail('mutated frozen function');" +
1119        "})();");
1120    assertConsistent(
1121        "function foo() {}" +
1122        "foo.x = 3;" +
1123        "foo();" +
1124        "foo.x;");
1125    rewriteAndExecute(
1126        "  function f_() { return 31415; }"
1127        + "var x = f_();"
1128        + "assertEquals(x, 31415);");
1129  }
1130 
1131  public final void testMapSingle() throws Exception {
1132    checkFails("var o = { x___: p.x, k1: p.y };",
1133               "Properties cannot end in \"__\"");
1134  }
1135 
1136  public final void testInstanceof() throws Exception {
1137    assertConsistent("[ (({}) instanceof Object)," +
1138                     "  ((new Date) instanceof Date)," +
1139                     "  (({}) instanceof Date)" +
1140                     "];");
1141    assertConsistent("function foo() {}  (new foo) instanceof foo;");
1142    assertConsistent("function foo() {}  !(({}) instanceof foo);");
1143  }
1144 
1145  public final void testTypeof() throws Exception {
1146    rewriteAndExecute("assertThrows(function () { return typeof ___; })");
1147    assertConsistent("typeof true;");
1148    assertConsistent("typeof 0;");
1149    assertConsistent("typeof undefined;");
1150    assertConsistent("typeof null;");
1151    assertConsistent("typeof 'string';");
1152    assertConsistent("typeof function () {};");
1153    assertConsistent("typeof ({});");
1154  }
1155 
1156  public final void testMaskingFunction() throws Exception {
1157    assertAddsMessage(
1158        "function Goo() { function Goo() {} }",
1159        MessageType.SYMBOL_REDEFINED,
1160        MessageLevel.ERROR );
1161    assertAddsMessage(
1162        "function Goo() { var Goo = 1; }",
1163        MessageType.MASKING_SYMBOL,
1164        MessageLevel.LINT );
1165    assertMessageNotPresent(
1166        "function Goo() { this.x = 1; }",
1167        MessageType.MASKING_SYMBOL );
1168  }
1169 
1170  public final void testMapBadKeySuffix() throws Exception {
1171    checkAddsMessage(
1172        js(fromString("var o = { x__: 3 };")),
1173        RewriterMessageType.PROPERTIES_CANNOT_END_IN_DOUBLE_UNDERSCORE);
1174  }
1175 
1176  public final void testMapNonEmpty() throws Exception {
1177    // Ensure that calling an untamed function throws
1178    rewriteAndExecute(
1179        "testImports.f = function() {};",
1180        "assertThrows(function() { f(); });",
1181        ";");
1182    // Ensure that calling a tamed function in an object literal works
1183    rewriteAndExecute(
1184        "  var f = function() {};"
1185        + "var m = { f : f };"
1186        + "m.f();");
1187    // Ensure that putting an untamed function into an object literal
1188    // causes an exception.
1189    rewriteAndExecute(
1190        "testImports.f = function() {};",
1191        "assertThrows(function(){({ isPrototypeOf : f });});",
1192        ";");
1193  }
1194 
1195  public final void testLabeledStatement() throws Exception {
1196    checkFails("IMPORTS___: 1;", "Labels cannot end in \"__\"");
1197    checkFails("IMPORTS___: while (1);", "Labels cannot end in \"__\"");
1198    checkFails("while (1) { break x__; }", "Labels cannot end in \"__\"");
1199    checkFails("while (1) { continue x__; }", "Labels cannot end in \"__\"");
1200    assertConsistent(
1201        "var k = 0;" +
1202        "a: for (var i = 0; i < 10; ++i) {" +
1203        "  b: for (var j = 0; j < 10; ++j) {" +
1204        "    if (++k > 5) break a;" +
1205        "  }" +
1206        "}" +
1207        "k;");
1208    assertConsistent(
1209        "var k = 0;" +
1210        "a: for (var i = 0; i < 10; ++i) {" +
1211        "  b: for (var j = 0; j < 10; ++j) {" +
1212        "    if (++k > 5) break b;" +
1213        "  }" +
1214        "}" +
1215        "k;");
1216  }
1217 
1218  /**
1219   * Tests that the container can get access to
1220   * "virtual globals" defined in cajoled code.
1221   */
1222  public final void testWrapperAccess() throws Exception {
1223    rewriteAndExecute(
1224        "",
1225        "var x = 'test';",
1226        "if (___.getNewModuleHandler().getImports().x != 'test') {" +
1227          "fail('Cannot see inside the wrapper');" +
1228        "}");
1229  }
1230 
1231  /**
1232   * Tests that Object.prototype cannot be modified.
1233   */
1234  public final void testFrozenObjectPrototype() throws Exception {
1235    rewriteAndExecute(
1236        "var success = false;" +
1237        "try {" +
1238          "Object.prototype.x = 'X';" +
1239        "} catch (e){" +
1240          "success = true;" +
1241        "}" +
1242        "if (!success) { fail('Object.prototype not frozen.'); }");
1243  }
1244 
1245  public final void testStamp() throws Exception {
1246    rewriteAndExecute(
1247        "function Foo(){}" +
1248        "var foo = new Foo();" +
1249        "Object.freeze(foo);" +
1250        "var TestMark = cajaVM.Trademark('Test');" +
1251        "var passed = false;" +
1252        "try { " +
1253        "  cajaVM.stamp([TestMark.stamp], foo);" +
1254        "} catch (e) {" +
1255        "  if (e.message !== " +
1256        "      'Can\\'t stamp frozen objects: [object Object]') {" +
1257        "    fail(e.message);" +
1258        "  }" +
1259        "  passed = true;" +
1260        "}" +
1261        "if (!passed) { fail ('Able to stamp frozen objects.'); }");
1262    rewriteAndExecute(
1263        // Shows how privileged or uncajoled code can stamp
1264        // frozen objects anyway.
1265        "___.getNewModuleHandler()." +
1266        "    getImports().DefineOwnProperty___('stampAnyway', {" +
1267        "      value: ___.markFuncFreeze(function(stamp, obj) {" +
1268        "          stamp.mark___(obj);" +
1269        "        })," +
1270        "      enumerable: false," +
1271        "      writable: true," +
1272        "      configurable: false" +
1273        "    });",
1274        "function Foo(){}" +
1275        "var foo = new Foo();" +
1276        "Object.freeze(foo);" +
1277        "var TestMark = cajaVM.Trademark('Test');" +
1278        "try { " +
1279        "  stampAnyway(TestMark.stamp, foo);" +
1280        "} catch (e) {" +
1281        "  fail(e.message);" +
1282        "}" +
1283        "cajaVM.guard(TestMark.guard, foo);",
1284        "");
1285    rewriteAndExecute(
1286        "var foo = {};" +
1287        "var TestMark = cajaVM.Trademark('Test');" +
1288        "cajaVM.stamp([TestMark.stamp], foo);" +
1289        "cajaVM.guard(TestMark.guard, foo);");
1290    rewriteAndExecute(
1291        "var foo = {};" +
1292        "var TestMark = cajaVM.Trademark('Test');" +
1293        "cajaVM.stamp([TestMark.stamp], foo);" +
1294        "TestMark.guard.coerce(foo);");
1295    rewriteAndExecute(
1296        "var foo = {};" +
1297        "var TestMark = cajaVM.Trademark('Test');" +
1298        "var passed = false;" +
1299        "try { " +
1300        "  cajaVM.guard(TestMark.guard, foo);" +
1301        "} catch (e) {" +
1302        "  if (e.message !== " +
1303        "      'Specimen does not have the \"Test\" trademark') {" +
1304        "    fail(e.message);" +
1305        "  }" +
1306        "  passed = true;" +
1307        "}" +
1308        "if (!passed) { fail ('Able to forge trademarks.'); }");
1309    rewriteAndExecute(
1310        "var foo = {};" +
1311        "var T1Mark = cajaVM.Trademark('T1');" +
1312        "var T2Mark = cajaVM.Trademark('T2');" +
1313        "var passed = false;" +
1314        "try { " +
1315        "  cajaVM.stamp([T1Mark.stamp], foo);" +
1316        "  cajaVM.guard(T2Mark.guard, foo);" +
1317        "} catch (e) {" +
1318        "  if (e.message !== 'Specimen does not have the \"T2\" trademark') {" +
1319        "    fail(e.message);" +
1320        "  }" +
1321        "  passed = true;" +
1322        "}" +
1323        "if (!passed) { fail ('Able to forge trademarks.'); }");
1324    rewriteAndExecute(
1325        "var foo = {};" +
1326        "var bar = Object.create(foo);" +
1327        "var baz = Object.create(bar);" +
1328        "var TestMark = cajaVM.Trademark('Test');" +
1329        "cajaVM.stamp([TestMark.stamp], bar);" +
1330        "assertFalse(cajaVM.passesGuard(TestMark.guard, foo));" +
1331        "assertTrue(cajaVM.passesGuard(TestMark.guard, bar));" +
1332        "assertFalse(cajaVM.passesGuard(TestMark.guard, baz));");
1333  }
1334 
1335  public final void testIndexOf() throws Exception {
1336    assertConsistent("''.indexOf('1');");
1337  }
1338 
1339  public final void testCallback() throws Exception {
1340    assertConsistent(
1341        "(function(){}).apply.call(function(a, b) {return a + b;}, {}, [3, 4]);"
1342        );
1343    assertConsistent(
1344        "(function(){}).call.call(function(a, b) {return a + b;}, {}, 3, 4);");
1345    rewriteAndExecute(
1346        "var a = [], b = {x:3};\n" +
1347        "for (var i in b) { a.push(i, b[i]); };" +
1348        "assertEquals(a.toString(), 'x,3');");
1349    assertConsistent(
1350        "Function.prototype.apply.call(" +
1351        "    function(a, b) {" +
1352        "      return a + b;" +
1353        "    }, " +
1354        "    {}, " +
1355        "    [3, 4]);");  
1356    assertConsistent(
1357        "Function.prototype.call.call(" +
1358        "    function(a, b) {" +
1359        "      return a + b;" +
1360        "    }," +
1361        "    {}," +
1362        "    3," +
1363        "    4);"); 
1364    assertConsistent(
1365        "Function.prototype.bind.call(" +
1366        "    function(a, b) {" +
1367        "      return a + b;" +
1368        "    }," +
1369        "    {}," +
1370        "    3)(4);");
1371  }
1372 
1373  /**
1374   * Tests the cajaVM.newTable(opt_useKeyLifetime) abstraction.
1375   * <p>
1376   * From here, we are not in a position to test the weak-GC properties this
1377   * abstraction is designed to provide, nor its O(1) complexity measure.
1378   * However, we can test that it works as a simple lookup table.
1379   */
1380  public final void testTable() throws Exception {
1381    rewriteAndExecute(
1382        "var t = cajaVM.newTable();" +
1383        "var k1 = {};" +
1384        "var k2 = {};" +
1385        "var k3 = {};" +
1386        "t.set(k1, 'v1');" +
1387        "t.set(k2, 'v2');" +
1388        "assertEquals(t.get(k1), 'v1');" +
1389        "assertEquals(t.get(k2), 'v2');" +
1390        "assertTrue(t.get(k3) === void 0);");
1391    rewriteAndExecute(
1392        "var t = cajaVM.newTable(true);" +
1393        "var k1 = {};" +
1394        "var k2 = {};" +
1395        "var k3 = {};" +
1396        "t.set(k1, 'v1');" +
1397        "t.set(k2, 'v2');" +
1398        "assertEquals(t.get(k1), 'v1');" +
1399        "assertEquals(t.get(k2), 'v2');" +
1400        "assertTrue(t.get(k3) === void 0);");
1401    rewriteAndExecute(
1402        "var t = cajaVM.newTable();" +
1403        "t.set('foo', 'v1');" +
1404        "t.set(null, 'v2');" +
1405        "assertEquals(t.get('foo'), 'v1');" +
1406        "assertEquals(t.get(null), 'v2');" +
1407        "assertTrue(t.get({toString: function(){return 'foo';}}) === void 0);");
1408    rewriteAndExecute(
1409        "var t = cajaVM.newTable(true);" +
1410        "assertThrows(function(){t.set('foo', 'v1');});");
1411    rewriteAndExecute(
1412        "var t = cajaVM.newTable(true);" +
1413        "var k1 = {};" +
1414        "var k2 = Object.create(k1);" +
1415        "var k3 = Object.create(k2);" +
1416        "var k4 = Object.create(k3);" +
1417        "t.set(k2, 'foo');" +
1418        "t.set(k3, 'bar');" +
1419        "assertEquals(t.get(k2), 'foo');\n" +
1420        "assertEquals(t.get(k3), 'bar');\n" +
1421        "assertTrue(t.get(k1) === void 0);\n" +
1422        "assertTrue(t.get(k4) === void 0);");
1423    rewriteAndExecute(
1424        "var t = cajaVM.newTable();" +
1425        "var k1 = {};" +
1426        "var k2 = Object.create(k1);" +
1427        "var k3 = Object.create(k2);" +
1428        "var k4 = Object.create(k3);" +
1429        "t.set(k2, 'foo');" +
1430        "t.set(k3, 'bar');" +
1431        "assertEquals(t.get(k2), 'foo');\n" +
1432        "assertEquals(t.get(k3), 'bar');\n" +
1433        "assertTrue(t.get(k1) === void 0);\n" +
1434        "assertTrue(t.get(k4) === void 0);");
1435    rewriteAndExecute(
1436        "var t1 = cajaVM.newTable(true);" +
1437        "var t2 = cajaVM.newTable(true);" +
1438        "var k = {};" +
1439        "t1.set(k, 'foo');" +
1440        "t2.set(k, 'bar');" +
1441        "assertEquals(t1.get(k), 'foo');" +
1442        "assertEquals(t2.get(k), 'bar');" +
1443        "t1.set(k, void 0);" +
1444        "assertTrue(t1.get(k) === void 0);" +
1445        "assertEquals(t2.get(k), 'bar');");
1446    rewriteAndExecute(
1447        "var t1 = cajaVM.newTable();" +
1448        "var t2 = cajaVM.newTable();" +
1449        "var k = {};" +
1450        "t1.set(k, 'foo');" +
1451        "t2.set(k, 'bar');" +
1452        "assertEquals(t1.get(k), 'foo');" +
1453        "assertEquals(t2.get(k), 'bar');" +
1454        "t1.set(k, void 0);" +
1455        "assertTrue(t1.get(k) === void 0);" +
1456        "assertEquals(t2.get(k), 'bar');");
1457  }
1458 
1459  /**
1460   * Tests that begetting works.
1461   */
1462  public final void testInheritance() throws Exception {
1463    rewriteAndExecute(
1464        "var x = {a:8}, y = Object.create(x); assertTrue(y.a === 8);");
1465  }
1466 
1467  /**
1468   * Tests that ES5/3 code can't cause a privilege
1469   * escalation by calling a tamed exophoric function with null as the
1470   * this-value.
1471   * <p>
1472   * The uncajoled branch of the tests below establish that a null does cause
1473   * a privilege escalation for normal non-strict JavaScript.
1474   */
1475  public final void testNoPrivilegeEscalation() throws Exception {
1476    rewriteAndExecute("assertTrue([].valueOf.call(null) === cajaVM.USELESS);");
1477    rewriteAndExecute("assertTrue([].valueOf.apply(null) === cajaVM.USELESS);");
1478    rewriteAndExecute(
1479        "assertTrue([].valueOf.bind(null)() === cajaVM.USELESS);");
1480  }
1481 
1482  /**
1483   * Tests that the apparent [[Class]] of the tamed JSON object is 'JSON', as
1484   * it should be according to ES5.  Also tests parse and stringify.
1485   *
1486   * See issue 1086
1487   */
1488  public final void testJSONClass() throws Exception {
1489    rewriteAndExecute("assertTrue(''+JSON === '[object JSON]');");
1490    rewriteAndExecute(
1491        "assertTrue(({}).toString.call(JSON) === '[object JSON]');");
1492    rewriteAndExecute(
1493        "var x = JSON.parse('{\"a\":[{\"b\":33}]}');" +
1494        "assertEquals(33, x.a[0].b);");
1495    rewriteAndExecute(
1496        "var x = JSON.stringify({a:33});" +
1497        "assertEquals('{\"a\":33}', x);");
1498    rewriteAndExecute(
1499        "var pass = false;" +
1500        "try { var x = JSON.parse('{\"b\":1, \"a___\":33}'); }" +
1501        "catch (e) { " +
1502        "  assertTrue(e.message.indexOf('a___') !== -1);" +
1503        "  pass = true;" +
1504        "}" +
1505        "assertTrue(pass);");
1506  }
1507 
1508  /**
1509   * Tests that an inherited <tt>*_w___</tt> flag does not enable
1510   * bogus writability.
1511   * <p>
1512   * See <a href="http://code.google.com/p/google-caja/issues/detail?id=1052"
1513   * >issue 1052</a>.
1514   */
1515  public final void testNoCanSetInheritance() throws Exception {
1516    rewriteAndExecute(
1517            "(function() {" +
1518            "  var a = {};" +
1519            "  var b = Object.freeze(Object.create(a));" +
1520            "  a.x = 8;" +
1521            "  assertThrows(function(){b.x = 9;});" +
1522            "  assertEquals(b.x, 8);" +
1523            "})();");
1524  }
1525 
1526  @Override
1527  public void setUp() throws Exception {
1528    super.setUp();
1529    es53Rewriter = new ES53Rewriter(TestBuildInfo.getInstance(), mq, false);
1530    setRewriter(es53Rewriter);
1531  }
1532  
1533  @Override
1534  protected Object executePlain(String caja) throws IOException {
1535    mq.getMessages().clear();
1536    return RhinoTestBed.runJs(
1537        new Executor.Input(
1538            getClass(), "../../../../../js/json_sans_eval/json_sans_eval.js"),
1539        new Executor.Input(getClass(), "/com/google/caja/es53.js"),
1540        new Executor.Input(
1541            getClass(), "../../../../../js/jsunit/2.2/jsUnitCore.js"),
1542        new Executor.Input(caja, getName() + "-uncajoled"));
1543  }
1544 
1545  @Override
1546  protected Object rewriteAndExecute(String pre, String caja, String post)
1547      throws IOException, ParseException {
1548    mq.getMessages().clear();
1549 
1550    List<Statement> children = Lists.newArrayList();
1551    children.add(js(fromString(caja, is)));
1552    String cajoledJs = render(rewriteTopLevelNode(
1553        new UncajoledModule(new Block(FilePosition.UNKNOWN, children))));
1554 
1555    assertNoErrors();
1556 
1557    final String[] assertFunctions = new String[] {
1558        "fail",
1559        "assertEquals",
1560        "assertTrue",
1561        "assertFalse",
1562        "assertLessThan",
1563        "assertNull",
1564        "assertThrows",
1565    };
1566 
1567    StringBuilder importsSetup = new StringBuilder();
1568    importsSetup.append(
1569        "var testImports = ___.copy(___.whitelistAll(___.sharedImports));");
1570    for (String f : assertFunctions) {
1571      importsSetup
1572          .append("testImports." + f + " = ___.markFuncFreeze(" + f + ");")
1573          .append("___.grantRead(testImports, '" + f + "');");
1574    }
1575    importsSetup.append(
1576        "___.getNewModuleHandler().setImports(___.whitelistAll(testImports));");
1577 
1578    Object result = RhinoTestBed.runJs(
1579        new Executor.Input(
1580            getClass(), "/com/google/caja/plugin/console-stubs.js"),
1581        new Executor.Input(
1582            getClass(), "../../../../../js/json_sans_eval/json_sans_eval.js"),
1583        new Executor.Input(getClass(), "/com/google/caja/es53.js"),
1584        new Executor.Input(
1585            getClass(), "../../../../../js/jsunit/2.2/jsUnitCore.js"),
1586        new Executor.Input(
1587            getClass(), "/com/google/caja/log-to-console.js"),
1588        new Executor.Input(
1589            importsSetup.toString(),
1590            getName() + "-test-fixture"),
1591        new Executor.Input(pre, getName()),
1592        // Load the cajoled code.
1593        new Executor.Input(cajoledJs, getName() + "-cajoled"),
1594        new Executor.Input(post, getName()),
1595        // Return the output field as the value of the run.
1596        new Executor.Input(
1597            "___.getNewModuleHandler().getLastValue();", getName()));
1598 
1599    assertNoErrors();
1600    return result;
1601  }
1602}

[all classes][com.google.caja.parser.quasiliteral]
EMMA 2.0.5312 (C) Vladimir Roubtsov