Package com.google.caja.parser.js

Source Code of com.google.caja.parser.js.ExpressionTest

// Copyright (C) 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.caja.parser.js;

import com.google.caja.lexer.ParseException;
import com.google.caja.parser.js.Expression;
import com.google.caja.util.CajaTestCase;

@SuppressWarnings("static-method")
public class ExpressionTest extends CajaTestCase {
  public final void testConditionResult() throws ParseException {
    assertFalse(jsExpr(fromString("false")).conditionResult());
    assertTrue(jsExpr(fromString("true")).conditionResult());
    assertFalse(jsExpr(fromString("0")).conditionResult());
    assertTrue(jsExpr(fromString("1")).conditionResult());
    assertFalse(jsExpr(fromString("''")).conditionResult());
    assertTrue(jsExpr(fromString("'foo'")).conditionResult());
    assertFalse(jsExpr(fromString("null")).conditionResult());
    assertTrue(jsExpr(fromString("/foo/")).conditionResult());

    assertNull(jsExpr(fromString("foo")).conditionResult());
    assertNull(jsExpr(fromString("x.y")).conditionResult());
    assertNull(jsExpr(fromString("x[y]")).conditionResult());
    assertNull(jsExpr(fromString("-x")).conditionResult());

    assertFalse(jsExpr(fromString("!1")).conditionResult());
    assertTrue(jsExpr(fromString("!0")).conditionResult());
    assertNull(jsExpr(fromString("!foo")).conditionResult());

    assertTrue(jsExpr(fromString("[]")).conditionResult());
    assertTrue(jsExpr(fromString("{}")).conditionResult());
    assertTrue(jsExpr(fromString("function () {}")).conditionResult());

    assertTrue(jsExpr(fromString("true && true")).conditionResult());
    assertFalse(jsExpr(fromString("false && true")).conditionResult());
    assertFalse(jsExpr(fromString("true && false")).conditionResult());
    assertFalse(jsExpr(fromString("false && false")).conditionResult());
    assertFalse(jsExpr(fromString("false && x")).conditionResult());
    assertFalse(jsExpr(fromString("x && false")).conditionResult());
    assertNull(jsExpr(fromString("x && true")).conditionResult());

    assertTrue(jsExpr(fromString("true || true")).conditionResult());
    assertTrue(jsExpr(fromString("false || true")).conditionResult());
    assertTrue(jsExpr(fromString("true || false")).conditionResult());
    assertFalse(jsExpr(fromString("false || false")).conditionResult());
    assertTrue(jsExpr(fromString("true || x")).conditionResult());
    assertTrue(jsExpr(fromString("x || true")).conditionResult());
    assertNull(jsExpr(fromString("x || false")).conditionResult());

    assertFalse(jsExpr(fromString("x,false")).conditionResult());
    assertTrue(jsExpr(fromString("x,true")).conditionResult());
    assertNull(jsExpr(fromString("x,y")).conditionResult());

    assertFalse(jsExpr(fromString("x ? false : 0")).conditionResult());
    assertFalse(jsExpr(fromString("0 ? x : 0")).conditionResult());
    assertFalse(jsExpr(fromString("1 ? false : x")).conditionResult());
    assertTrue(jsExpr(fromString("x ? true : 1")).conditionResult());
    assertTrue(jsExpr(fromString("0 ? x : 1")).conditionResult());
    assertTrue(jsExpr(fromString("1 ? true : x")).conditionResult());
    assertNull(jsExpr(fromString("1 ? x : 0")).conditionResult());
    assertNull(jsExpr(fromString("0 ? false : x")).conditionResult());
    assertNull(jsExpr(fromString("1 ? x : 1")).conditionResult());
    assertNull(jsExpr(fromString("0 ? true : x")).conditionResult());
    assertNull(jsExpr(fromString("x ? true : y")).conditionResult());
    assertNull(jsExpr(fromString("x ? false : y")).conditionResult());
    assertNull(jsExpr(fromString("x ? y : true")).conditionResult());
    assertNull(jsExpr(fromString("x ? y : false")).conditionResult());

    assertFalse(jsExpr(fromString("void true")).conditionResult());

    assertTrue(jsExpr(fromString("new Boolean")).conditionResult());
    assertTrue(jsExpr(fromString("new Boolean(false)")).conditionResult());
    assertTrue(jsExpr(fromString("new Date")).conditionResult());
    assertTrue(jsExpr(fromString("new Date()")).conditionResult());
    assertTrue(jsExpr(fromString("new RegExp('')")).conditionResult());
    assertTrue(jsExpr(fromString("new String('')")).conditionResult());
    assertNull(jsExpr(fromString("Date")).conditionResult());
    assertNull(jsExpr(fromString("Date()")).conditionResult());
    assertNull(jsExpr(fromString("new Date()()")).conditionResult());
  }

  public final void testSimplifyForSideEffect() throws ParseException {
    assertSimplified(null, "1");
    assertSimplified(null, "0");
    assertSimplified(null, "void 1");
    assertSimplified(null, "void 0");
    assertSimplified("foo()", "foo(), 1");
    assertSimplified("foo()", "1, foo()");
    assertSimplified(null, "1, 2");
    assertSimplified("foo()", "foo() || 1");
    assertSimplified("foo()", "1 || foo()");
    assertSimplified(null, "1 || 2");
    assertSimplified("foo()", "foo() && 1");
    assertSimplified("foo()", "1 && foo()");
    assertSimplified(null, "1 && 2");
    assertSimplified("++x", "++x");
    assertSimplified("++x", "x++");
    assertSimplified("--x", "--x");
    assertSimplified("--x", "x--");
    assertSimplified("x -= 2", "x -= 2");
    assertSimplified("x = 2", "x = 2");
    assertSimplified("x + y", "x + y")// coercion might be side-effecting
  }

  public final void testTypeOf() throws Exception {
    assertTypeOf("boolean", "true");
    assertTypeOf("boolean", "false");
    assertTypeOf("number", "0");
    assertTypeOf("number", "1");
    assertTypeOf("number", "-1.5");
    assertTypeOf("number", "6.02e+23");
    assertTypeOf("string", "''");
    assertTypeOf("string", "'foo'");
    assertTypeOf("object", "null");
    assertTypeOf("object", "{}");
    assertTypeOf("function", "function () {}");
    assertTypeOf("boolean", "!x");
    assertTypeOf("boolean", "!x || !y");
    assertTypeOf(null, "!x || y");
    assertTypeOf(null, "x || !y");
    assertTypeOf("number", "+x");
    assertTypeOf("number", "-x");
    assertTypeOf("number", "x - y");
    assertTypeOf(null, "y++")// See browser-expectations.html
    assertTypeOf(null, "z--");
    assertTypeOf("number", "++y");
    assertTypeOf("number", "--z");
    assertTypeOf(null, "a + b");
    assertTypeOf("number", "+a + 1");
    assertTypeOf("string", "'' + b");
    assertTypeOf("number", "'4' - 1");
    assertTypeOf("string", "foo() ? 'bar' : 'baz'");
    assertTypeOf(null, "foo() ? 'bar' : null");
    assertTypeOf(null, "foo() ? bar : 'baz'");
    assertTypeOf("string", "'bar' && ('' + baz)");
    assertTypeOf(null, "'bar' && null");
    assertTypeOf(null, "bar && 'baz'");
    assertTypeOf("boolean", "foo(), !x");
    assertTypeOf(null, "'' + foo(), x");
    assertTypeOf(null, "/./");
  }

  public final void testFold() throws Exception {
    assertFolded("4.0", "1 + 3");
    assertFolded("'13'", "1 + '3'");
    assertFolded("'13'", "'1' + 3");
    assertFolded("'13'", "'1' + '3'");
    assertFolded("'-1.5'", "'' + -1.5");
    assertFolded("'undefined'", "'' + void 0");
    assertFolded("'null'", "null + ''");
    assertFolded("null + 0", "null + 0")// 0 in JS
    assertFolded("-2.0", "1 - 3");
    assertFolded("4.0", "2 * 2");
    assertFolded("true", "!''");
    assertFolded("true", "!0");
    assertFolded("false", "!'0'");
    assertFolded("true", "!null");
    assertFolded("true", "!(void 0)");
    assertFolded("!void foo()", "!(void foo())");
    assertFolded("false", "!(4,true)");
    assertFolded("! (foo() || true)", "!(foo()||true)");
    assertFolded("false", "false && foo()");
    assertFolded("true", "true || foo()");
    assertFolded("foo()", "false || foo()");
    assertFolded("foo()", "true && foo()");
    assertFolded("foo != bar", "foo != bar && true");
    assertFolded("foo != bar", "foo != bar || false");
    // Can't fold.  foo() might return non-boolean
    assertFolded("foo() && true", "foo() && true");
    assertFolded("foo() || false", "foo() || false");
    assertFolded("true", "'foo' == 'foo'");
    assertFolded("true", "'foo' === 'foo'");
    assertFolded("false", "'foo' == 'bar'");
    assertFolded("false", "'foo' === 'bar'");
    assertFolded("false", "4 === '4'");
    assertFolded("4 == '4'", "4 == '4'");
    assertFolded("false", "'foo' != 'foo'");
    assertFolded("false", "'foo' !== 'foo'");
    assertFolded("true", "'foo' != 'bar'");
    assertFolded("true", "'foo' !== 'bar'");
    assertFolded("true", "4 !== '4'");
    assertFolded("4 != '4'", "4 != '4'");
    assertFolded("a !== b", "!(a === b)")// Correct around NaN
    assertFolded("a === b", "!(a !== b)");
    assertFolded("a != b", "!(a == b)");
    assertFolded("a == b", "!(a != b)");
    assertFolded("0.5", "1 / 2");
    assertFolded("1 / '2'", "1 / '2'");
    assertFolded("(1/0)", "1 / 0");
    assertFolded("(-1/0)", "-1 / 0");
    assertFolded("(0/0)", "0 / 0");
    assertFolded("1.0", "1 % 3");
    assertFolded("1.0", "1 % -3");
    assertFolded("-1.0", "-1 % 3");
    assertFolded("1.0", "1 % -3");
    assertFolded("-1.0", "-1 % 3");
    assertFolded("-1.0", "-1 % -3");
    assertFolded("" + 0x7fffffffL, "0x7fffffff | 0");
    assertFolded("-" + 0x7fffffffL, "-0x7fffffff | 0");
    assertFolded("-" + 0x80000000L, "0x80000000 | 0");
    assertFolded("-1", "0xffffffff | 0");
    assertFolded("-1", "0x1ffffffff | 0");
    assertFolded("0", "0x100000000 | 0");
    assertFolded("0", "0x200000000 | 0");
    assertFolded("1", "0x100000001 | 0");
    assertFolded("1661992960", "1e20 | 0")// Outside the range of java longs
    assertFolded("-1661992960", "-1e20 | 0");
    assertFolded("1024", "1 << 10");
    assertFolded("" + (1 << 20), "1 << 20");
    assertFolded("1", "1 << 0/0");
    assertFolded("0", "0/0 << 0");
    assertFolded("1", "1 << 1/0");
    assertFolded("0", "1/0 << 0");
    assertFolded("2", "4 >> 1");
    assertFolded("1", "4 >> 2");
    assertFolded("0", "4 >> 3");
    assertFolded("-1", "-1 >> 1");
    assertFolded("1", "1 >> 1/0");
    assertFolded("0", "1/0 >> 0");
    assertFolded("" + (-1 >>> 1), "-1 >>> 1");
    assertFolded("1", "4 >>> 2");
    assertFolded("1", "1 >>> 1/0");
    assertFolded("0", "1/0 >>> 0");
    assertFolded("0", "1 & 2");
    assertFolded("2", "2 & 3");
    assertFolded("2", "3 & 2");
    assertFolded("0", "1 & 1/0");
    assertFolded("0", "1/0 & 0");
    assertFolded("3", "1 | 2");
    assertFolded("7", "6 | 5");
    assertFolded("11", "3 | 9");
    assertFolded("1", "1 | 1/0");
    assertFolded("0", "1/0 | 0");
    assertFolded("0", "0 ^ 0");
    assertFolded("0", "1 ^ 1");
    assertFolded("3", "1 ^ 2");
    assertFolded("-2", "-1 ^ 1");
    assertFolded("1", "1 ^ 1/0");
    assertFolded("0", "1/0 ^ 0");
    assertFolded("4.0", "4.0");
    assertFolded("4.0", "+4.0");
    assertFolded("-1", "~0");
    assertFolded("-1", "-1");
    assertFolded("(-0)", "-0");
    assertFolded("0.0", "-(-0)");
    assertFolded("3", "'foo'.length");
    assertFolded("1", "'foo'.indexOf('o')");
    assertFolded("-1", "'foo'.indexOf('bar')");
    assertFolded("foo[ 'bar' ]", "foo['bar']");
    assertFolded("foo[ 0 ]", "foo[0]");
    assertFolded("foo[ '0' ]", "foo['0']");
    assertFolded("foo[ 'null' ]", "foo['null']");
    assertFolded("new Date", "new Date()");
    assertFolded("new Date(0)", "new Date(0)");
    assertFolded(
        "(function () { return this; })()",
        "(function () { return this; })()");
    assertFolded(
        "(function () {\n   return -arguments[ i ];\n })()",
        "(function () { return -arguments[i]; })()");
    assertFolded("4", "(function () { return 4; })()");
    assertFolded("void 0", "(function () {})()");
    assertFolded("void 0", "(function () { return; })()");
    assertFolded("void foo()", "(function () { foo(); })()");
    assertFolded(
        "(function (i) { return i; })()",
        "(function (i) { return i; })()");
    assertFolded(
        "(function i() { return i; })()",
        "(function i() { return i; })()");
    assertFolded(
        "(function () {\n   arguments.callee();\n })()",
        "(function () { arguments.callee(); })()");
    assertFolded("eval", "0,eval", false);
    assertFolded("0, eval", "0,eval", true);
    assertFolded("foo.bar", "0,foo.bar", false);
    assertFolded("0, foo.bar", "0,foo.bar", true);
    assertFolded("foo[ bar ]", "0,foo[bar]", false);
    assertFolded("0, foo[ bar ]", "0,foo[bar]", true);
    assertFolded("foo[ 'bar' ]", "0,foo['bar']", false);
    assertFolded("0, foo[ 'bar' ]", "0,foo['bar']", true);
  }

  public final void testToInt32() {
    assertEquals(0, Operation.toInt32(0d));
    assertEquals(0, Operation.toInt32(-0d));
    assertEquals(0, Operation.toInt32(Double.POSITIVE_INFINITY));
    assertEquals(0, Operation.toInt32(Double.NEGATIVE_INFINITY));
    assertEquals(0, Operation.toInt32(Double.NaN));
    assertEquals(0, Operation.toInt32(0x100000000L));
    assertEquals(0, Operation.toInt32(-0x100000000L));
    assertEquals(0x7fffffffL, Operation.toInt32(0x7fffffffL));
    assertEquals(-0x7fffffffL, Operation.toInt32(-0x7fffffffL));
    assertEquals(-0x80000000L, Operation.toInt32(-0x80000000L));
    assertEquals(-0x80000000L, Operation.toInt32(0x80000000L));
    assertEquals(1, Operation.toInt32(1));
    assertEquals(-1, Operation.toInt32(-1));
    assertEquals(2, Operation.toInt32(2));
    assertEquals(-2, Operation.toInt32(-2));
    assertEquals((long) 1e6, Operation.toInt32(1e6));
    assertEquals((long) 1e7, Operation.toInt32(1e7));
    assertEquals((long) 1e8, Operation.toInt32(1e8));
    assertEquals((long) 1e9, Operation.toInt32(1e9));
    assertEquals(1410065408L, Operation.toInt32(1e10));
    assertEquals(1215752192L, Operation.toInt32(1e11));
    assertEquals(-727379968L, Operation.toInt32(1e12));
    assertEquals((long) -1e6, Operation.toInt32(-1e6));
    assertEquals((long) -1e7, Operation.toInt32(-1e7));
    assertEquals((long) -1e8, Operation.toInt32(-1e8));
    assertEquals((long) -1e9, Operation.toInt32(-1e9));
    assertEquals(-1410065408L, Operation.toInt32(-1e10));
    assertEquals(-1215752192L, Operation.toInt32(-1e11));
    assertEquals(727379968L, Operation.toInt32(-1e12));
    assertEquals(0, Operation.toInt32(0.5d));
    assertEquals(0, Operation.toInt32(-0.5d));
    assertEquals(1, Operation.toInt32(1.5d));
    assertEquals(-1, Operation.toInt32(-1.5d));
  }

  public final void testToUint32() {
    assertEquals(0, Operation.toUint32(0d));
    assertEquals(0, Operation.toUint32(-0d));
    assertEquals(0, Operation.toUint32(Double.POSITIVE_INFINITY));
    assertEquals(0, Operation.toUint32(Double.NEGATIVE_INFINITY));
    assertEquals(0, Operation.toUint32(Double.NaN));
    assertEquals(0, Operation.toUint32(0x100000000L));
    assertEquals(0, Operation.toUint32(-0x100000000L));
    assertEquals(0x7fffffffL, Operation.toUint32(0x7fffffffL));
    assertEquals(0x80000001L, Operation.toUint32(-0x7fffffffL));
    assertEquals(0x80000000L, Operation.toUint32(-0x80000000L));
    assertEquals(0x80000000L, Operation.toUint32(0x80000000L));
    assertEquals(1, Operation.toUint32(1));
    assertEquals(0xffffffffL, Operation.toUint32(-1));
    assertEquals(2, Operation.toUint32(2));
    assertEquals(0xfffffffeL, Operation.toUint32(-2));
    assertEquals((long) 1e6, Operation.toUint32(1e6));
    assertEquals((long) 1e7, Operation.toUint32(1e7));
    assertEquals((long) 1e8, Operation.toUint32(1e8));
    assertEquals((long) 1e9, Operation.toUint32(1e9));
    assertEquals(1410065408L, Operation.toUint32(1e10));
    assertEquals(1215752192L, Operation.toUint32(1e11));
    assertEquals(3567587328L, Operation.toUint32(1e12));
    assertEquals((long) (0x100000000L - 1e6), Operation.toUint32(-1e6));
    assertEquals((long) (0x100000000L - 1e7), Operation.toUint32(-1e7));
    assertEquals((long) (0x100000000L - 1e8), Operation.toUint32(-1e8));
    assertEquals((long) (0x100000000L - 1e9), Operation.toUint32(-1e9));
    assertEquals(2884901888L, Operation.toUint32(-1e10));
    assertEquals(3079215104L, Operation.toUint32(-1e11));
    assertEquals(727379968L, Operation.toUint32(-1e12));
    assertEquals(0, Operation.toUint32(0.5d));
    assertEquals(0, Operation.toUint32(-0.5d));
    assertEquals(1, Operation.toUint32(1.5d));
    assertEquals(0xffffffffL, Operation.toUint32(-1.5d));
  }

  private void assertSimplified(String golden, String input)
      throws ParseException {
    Expression simple = jsExpr(fromString(input)).simplifyForSideEffect();
    if (golden == null) {
      assertNull(input, simple);
      return;
    }
    assertEquals(input, render(jsExpr(fromString(golden))), render(simple));
  }

  private void assertTypeOf(String type, String expr) throws ParseException {
    assertEquals(type, jsExpr(fromString(expr)).typeOf());
  }

  private void assertFolded(String result, String expr) throws ParseException {
    assertFolded(result, expr, false);
  }

  private void assertFolded(String result, String expr, boolean isFn)
      throws ParseException {
    Expression input = jsExpr(fromString(expr));
    if (input instanceof Operation) {
      Operation op = (Operation) input;
      for (Expression operand : op.children()) {
        // Fold some operands so we can test negative numbers.
        if ((Operation.is(operand, Operator.NEGATION)
            // and so that we can test corner cases around NaN and Infinity.
            || Operation.is(operand, Operator.DIVISION))
            && operand.children().get(0) instanceof NumberLiteral) {
          op.replaceChild(operand.fold(false), operand);
        }
      }
    }
    Expression actual = input.fold(isFn);
    assertEquals(expr, result, actual != null ? render(actual) : null);
  }
}
TOP

Related Classes of com.google.caja.parser.js.ExpressionTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.