/*
* Copyright 2011 The Closure Compiler Authors.
*
* 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.javascript.jscomp;
import com.google.javascript.jscomp.AstValidator.ViolationHandler;
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
import com.google.javascript.rhino.IR;
import com.google.javascript.rhino.InputId;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.SimpleSourceFile;
import com.google.javascript.rhino.Token;
/**
* @author johnlenz@google.com (John Lenz)
*/
public final class AstValidatorTest extends CompilerTestCase {
private boolean lastCheckWasValid = true;
@Override
protected CompilerPass getProcessor(Compiler compiler) {
return createValidator(compiler);
}
private AstValidator createValidator(Compiler compiler) {
lastCheckWasValid = true;
return new AstValidator(compiler, new ViolationHandler() {
@Override
public void handleViolation(String message, Node n) {
lastCheckWasValid = false;
}
});
}
@Override
protected int getNumRepetitions() {
return 1;
}
@Override
protected void setUp() throws Exception {
super.enableAstValidation(false);
super.disableNormalize();
super.enableLineNumberCheck(false);
super.setUp();
}
public void testForIn() {
valid("for(var a in b);");
valid("for(a in b);");
valid("for(a in []);");
valid("for(a in {});");
}
public void testQuestionableForIn() {
setExpectParseWarningsThisTest();
valid("for(var a = 1 in b);");
}
public void testDebugger() {
valid("debugger;");
}
public void testValidScript() {
Node n = new Node(Token.SCRIPT);
expectInvalid(n, Check.SCRIPT);
n.setInputId(new InputId("something_input"));
n.setStaticSourceFile(new SimpleSourceFile("something", false));
expectValid(n, Check.SCRIPT);
expectInvalid(n, Check.STATEMENT);
expectInvalid(n, Check.EXPRESSION);
}
public void testValidStatement1() {
Node n = new Node(Token.RETURN);
expectInvalid(n, Check.EXPRESSION);
expectValid(n, Check.STATEMENT);
expectInvalid(n, Check.SCRIPT);
}
public void testValidExpression1() {
Node n = new Node(Token.ARRAYLIT, new Node(Token.EMPTY));
expectValid(n, Check.EXPRESSION);
expectInvalid(n, Check.STATEMENT);
expectInvalid(n, Check.SCRIPT);
}
public void testValidExpression2() {
Node n = new Node(Token.NOT, new Node(Token.TRUE));
expectValid(n, Check.EXPRESSION);
expectInvalid(n, Check.STATEMENT);
expectInvalid(n, Check.SCRIPT);
}
public void testNewTargetIsValidExpression() {
Node n = new Node(Token.NEW_TARGET);
expectValid(n, Check.EXPRESSION);
}
public void testInvalidEmptyStatement() {
Node n = new Node(Token.EMPTY, new Node(Token.TRUE));
expectInvalid(n, Check.STATEMENT);
n.detachChildren();
expectValid(n, Check.STATEMENT);
}
public void testInvalidNumberStatement() {
Node n = IR.number(1);
expectInvalid(n, Check.STATEMENT);
n = IR.exprResult(n);
expectValid(n, Check.STATEMENT);
}
public void testValidRestParameter() {
setLanguage(LanguageMode.ECMASCRIPT_2015, LanguageMode.ECMASCRIPT5);
valid("function f(a,...rest){}");
valid("function f(a,...[re,...st]){}");
}
public void testAwaitExpression() {
setLanguage(LanguageMode.ECMASCRIPT_NEXT, LanguageMode.ECMASCRIPT5);
Node awaitNode = new Node(Token.AWAIT);
awaitNode.addChildToBack(IR.number(1));
Node parentFunction =
IR.function(IR.name("foo"), IR.paramList(), IR.block(IR.returnNode(awaitNode)));
parentFunction.setIsAsyncFunction(true);
expectValid(awaitNode, Check.EXPRESSION);
}
public void testAwaitExpressionNonAsyncFunction() {
setLanguage(LanguageMode.ECMASCRIPT_NEXT, LanguageMode.ECMASCRIPT5);
Node awaitNode = new Node(Token.AWAIT);
awaitNode.addChildToBack(IR.number(1));
Node parentFunction =
IR.function(IR.name("foo"), IR.paramList(), IR.block(IR.returnNode(awaitNode)));
parentFunction.setIsAsyncFunction(false);
expectInvalid(awaitNode, Check.EXPRESSION);
}
public void testAwaitExpressionNoFunction() {
setLanguage(LanguageMode.ECMASCRIPT_NEXT, LanguageMode.ECMASCRIPT5);
Node n = new Node(Token.AWAIT);
n.addChildToBack(IR.number(1));
expectInvalid(n, Check.EXPRESSION);
}
private void valid(String code) {
testSame(code);
assertTrue(lastCheckWasValid);
}
private enum Check {
SCRIPT,
STATEMENT,
EXPRESSION
}
private boolean doCheck(Node n, Check level) {
AstValidator validator = createValidator(createCompiler());
switch (level) {
case SCRIPT:
validator.validateScript(n);
break;
case STATEMENT:
validator.validateStatement(n);
break;
case EXPRESSION:
validator.validateExpression(n);
break;
}
return lastCheckWasValid;
}
private void expectInvalid(Node n, Check level) {
assertFalse(doCheck(n, level));
}
private void expectValid(Node n, Check level) {
assertTrue(doCheck(n, level));
}
}