blob: c8bfa1ab1e873c8b73d5315957fa420ac6b7eee0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 xored software, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.javascript.core.tests.validation;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.dltk.compiler.problem.IProblem;
import org.eclipse.dltk.compiler.problem.IProblemIdentifier;
import org.eclipse.dltk.core.builder.IBuildParticipant;
import org.eclipse.dltk.core.tests.util.StringList;
import org.eclipse.dltk.internal.javascript.validation.FlowValidation;
import org.eclipse.dltk.javascript.core.JavaScriptProblems;
import org.eclipse.dltk.javascript.core.tests.AbstractValidationTest;
@SuppressWarnings("restriction")
public class FlowValidationTests extends AbstractValidationTest {
@Override
protected IBuildParticipant createValidator() {
return new FlowValidation();
}
public void testUnreachableCodeAfterReturn() {
StringList code = new StringList();
code.add("function q(a) {");
code.add(" if (a ==1) return 1");
code.add(" else return 0");
code.add(" var x = 1");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(1, problemIds.size());
assertTrue(problemIds.contains(JavaScriptProblems.UNREACHABLE_CODE));
}
public void testUnreachableCodeAfterBreak() {
StringList code = new StringList();
code.add("function x() {");
code.add(" for (;;) {");
code.add(" var q = 0");
code.add(" break;");
code.add(" ++q");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(1, problemIds.size());
assertTrue(problemIds.contains(JavaScriptProblems.UNREACHABLE_CODE));
}
public void testCodeAfterBreak() {
StringList code = new StringList();
code.add("function x() {");
code.add(" for (;;) {");
code.add(" var q = 0");
code.add(" break;");
code.add(" }");
code.add(" return true;");
code.add("}");
final List<IProblem> problems = validate(code.toString());
assertEquals(problems.toString(), 0, problems.size());
}
public void testUnreachableCodeAfterContinue() {
StringList code = new StringList();
code.add("function x() {");
code.add(" for (;;) {");
code.add(" var q = 0");
code.add(" continue;");
code.add(" ++q");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(1, problemIds.size());
assertTrue(problemIds.contains(JavaScriptProblems.UNREACHABLE_CODE));
}
public void testFunctionAlwaysReturnValue1() {
StringList code = new StringList();
code.add("function q(a) {");
code.add(" if (a ==1) return 1");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(1, problemIds.size());
assertTrue(problemIds
.contains(JavaScriptProblems.FUNCTION_NOT_ALWAYS_RETURN_VALUE));
}
public void testFunctionAlwaysReturnValue2() {
StringList code = new StringList();
code.add("function q(a) {");
code.add(" if (a ==1) return 1");
code.add(" return");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(2, problemIds.size());
assertTrue(problemIds
.contains(JavaScriptProblems.FUNCTION_NOT_ALWAYS_RETURN_VALUE));
assertTrue(problemIds.contains(JavaScriptProblems.RETURN_INCONSISTENT));
}
public void testFunctionWithIfThenNotAllReturningValuesWithReturn() {
StringList code = new StringList();
code.add("function q(a) {");
code.add(" if (a ==1) return 1");
code.add(" else a = 1");
code.add(" return 1");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(0, problemIds.size());
}
public void testFunctionWithIfThenNotAllReturningValues() {
StringList code = new StringList();
code.add("function q(a) {");
code.add(" if (a ==1) return 1");
code.add(" else if (a == 2) a = 1");
code.add(" else if (a == 3) a = 1");
code.add(" else return 2");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(1, problemIds.size());
assertTrue(problemIds
.contains(JavaScriptProblems.FUNCTION_NOT_ALWAYS_RETURN_VALUE));
}
public void testFunctionWithIfThenAllReturningValues() {
StringList code = new StringList();
code.add("function q(a) {");
code.add(" if (a ==1) return 1");
code.add(" else if (a == 2) return 2");
code.add(" else if (a == 3) return 3");
code.add(" else return -1");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(0, problemIds.size());
}
public void testFunctionWithThrowsStatement() {
StringList code = new StringList();
code.add("/**");
code.add("* @return {String} some result info");
code.add("* @throws {String} some error info");
code.add("*/");
code.add("function someFunction() {");
code.add("var result_1 = '';");
code.add("var condition_1 = false;");
code.add("if(condition_1) {");
code.add("return result_1;}");
code.add("throw 'Some error message';");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(0, problemIds.size());
}
public void testFunctionReturnInFinally() {
StringList code = new StringList();
code.add("function q(a) {");
code.add(" try {");
code.add(" if (a ==1) return 1");
code.add(" } finally {");
code.add(" return 0;");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(0, problemIds.size());
}
public void testThrowCatch() {
StringList code = new StringList();
code.add("function q() {");
code.add(" var x = 0");
code.add(" try {");
code.add(" throw new Error('aaa')");
code.add(" } catch (e) {");
code.add(" x++");
code.add(" }");
code.add(" return x");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 0, problemIds.size());
}
public void testReturnCatch() {
StringList code = new StringList();
code.add("function q() {");
code.add(" var x = 0");
code.add(" try {");
code.add(" return 0");
code.add(" } catch (e) {");
code.add(" x++");
code.add(" }");
code.add(" return x");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 0, problemIds.size());
}
public void testReturnCatchReturn() {
StringList code = new StringList();
code.add("function q() {");
code.add(" var x = 0");
code.add(" try {");
code.add(" return 0");
code.add(" } catch (e) {");
code.add(" return 1");
code.add(" }");
code.add(" return x");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 1, problemIds.size());
assertEquals(JavaScriptProblems.UNREACHABLE_CODE, problemIds.iterator()
.next());
}
public void testSwitchCaseWithDefaultReturn() throws Exception {
StringList code = new StringList();
code.add("function q() {");
code.add(" var x = new Array()");
code.add(" switch(x.length) {");
code.add(" case 1: return 'test1';break;");
code.add(" case 2: return 'test2';break;");
code.add(" default: return 'test3';break;");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 0, problemIds.size());
}
public void testSwitchCaseWithDefaultReturnAndOptionalReturn()
throws Exception {
StringList code = new StringList();
code.add("function q() {");
code.add(" var x = new Array()");
code.add(" switch(x.length) {");
code.add(" case 1: if (x.length> 0) return 'test1';break;");
code.add(" case 2: return 'test2';break;");
code.add(" default: return 'test3';break;");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 1, problemIds.size());
assertEquals(
Collections
.singleton(JavaScriptProblems.FUNCTION_NOT_ALWAYS_RETURN_VALUE),
problemIds);
}
public void testSwitchCase() throws Exception {
StringList code = new StringList();
code.add("function q() {");
code.add(" var x = new Array()");
code.add(" switch(x.length) {");
code.add(" case 1: return 'test1';break;");
code.add(" case 2: return 'test2';break;");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 1, problemIds.size());
assertEquals(
Collections
.singleton(JavaScriptProblems.FUNCTION_NOT_ALWAYS_RETURN_VALUE),
problemIds);
}
public void testSwitchCaseWithDefaultReturnAndNoAllCaseReturn()
throws Exception {
StringList code = new StringList();
code.add("function q() {");
code.add(" var x = new Array()");
code.add(" switch(x.length) {");
code.add(" case 1: return 'test1';break;");
code.add(" case 2: break;");
code.add(" default: return 'test3';break;");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 1, problemIds.size());
assertEquals(
Collections
.singleton(JavaScriptProblems.FUNCTION_NOT_ALWAYS_RETURN_VALUE),
problemIds);
}
public void testSwitchCaseWithEmptyDefault() {
StringList code = new StringList();
code.add("function a() {");
code.add("var x = new Array()");
code.add(" switch (x.length) {");
code.add(" case 0:");
code.add(" return 0;");
code.add(" default:");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(
Collections
.singleton(JavaScriptProblems.FUNCTION_NOT_ALWAYS_RETURN_VALUE),
problemIds);
}
public void testSwitchCaseFallThrough() {
StringList code = new StringList();
code.add("function a() {");
code.add("var x = new Array()");
code.add(" switch (x.length) {");
code.add(" case 0:");
code.add(" case 1:");
code.add(" return 0;");
code.add(" default:");
code.add(" return -1;");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 0, problemIds.size());
}
public void testUnreachableCodeInSwitchCase() {
StringList code = new StringList();
code.add("function a() {");
code.add("var x = new Array()");
code.add(" switch (x.length) {");
code.add(" case 1:");
code.add(" return 0;");
code.add(" return 1;");
code.add(" default:");
code.add(" return -1;");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(
Collections.singleton(JavaScriptProblems.UNREACHABLE_CODE),
problemIds);
}
public void testIfAndSwitchWithNoReturns() throws Exception {
StringList code = new StringList();
code.add("function criteria_tree_node_text() {");
code.add("var is_group = 1;");
code.add("var filter_operator = '=';");
code.add("if (is_group == 1)");
code.add(" return '<html><body></body></html>';");
code.add("else {");
code.add(" var _retText = '<html><body><b></b> ';");
code.add(" switch (filter_operator) {");
code.add(" case '=': _retText += 'equals';break;");
code.add(" case '<': _retText += 'is less than';break;");
code.add(" case '<=': _retText += 'is less than equals';break;");
code.add(" case '>': _retText += 'is greater than';break;");
code.add(" case '>=': _retText += 'is greater than equals';break;");
code.add(" case 'CONTAINS': _retText += 'contains';break;");
code.add(" }");
code.add(" _retText += ' <b>'+ filter_value + '</b></body></html>';");
code.add(" return _retText;");
code.add(" }");
code.add("}");
final Set<IProblemIdentifier> problemIds = extractIds(validate(code
.toString()));
assertEquals(problemIds.toString(), 0, problemIds.size());
}
public void testNestedFunctionDeclaration() {
final StringList code = new StringList();
code.add("function test() {");
code.add(" return 1");
code.add(" function nested() {");
code.add(" return 1;");
code.add(" }");
code.add("}");
final List<IProblem> problems = validate(code.toString());
assertEquals(problems.toString(), 0, problems.size());
}
public void testNestedFunctionDeclaration_nestedError() {
final StringList code = new StringList();
code.add("function test() {");
code.add(" return 1");
code.add(" function nested(x) {");
code.add(" if (a > 0) { return 1; }");
code.add(" else { return -1; }");
code.add(" return false;");
code.add(" }");
code.add("}");
final String sCode = code.toString();
final List<IProblem> problems = validate(sCode);
assertEquals(problems.toString(), 1, problems.size());
final IProblem problem = problems.get(0);
assertEquals(JavaScriptProblems.UNREACHABLE_CODE, problem.getID());
assertEquals(
"return false;",
sCode.substring(problem.getSourceStart(),
problem.getSourceEnd()));
}
public void testNestedFunctionDeclaration_outerError() {
final StringList code = new StringList();
code.add("function test() {");
code.add(" return 1");
code.add(" function nested() {");
code.add(" }");
code.add(" return false;");
code.add("}");
final String sCode = code.toString();
final List<IProblem> problems = validate(sCode);
assertEquals(problems.toString(), 1, problems.size());
final IProblem problem = problems.get(0);
assertEquals(JavaScriptProblems.UNREACHABLE_CODE, problem.getID());
assertEquals(
"return false;",
sCode.substring(problem.getSourceStart(),
problem.getSourceEnd()));
}
public void testDefinePropertyWithGet() {
final StringList code = new StringList();
code.add("function testing(args) {");
code.add(" this.data = args.data");
code.add(" Object.defineProperty(this,'data', {");
code.add(" get data() {return args.data}");
code.add("})");
code.add("}");
final String sCode = code.toString();
final List<IProblem> problems = validate(sCode);
assertEquals(problems.toString(), 0, problems.size());
}
public void testConstructorFunctionReturningItself() {
final StringList code = new StringList();
code.add("/**");
code.add(" * @constructor");
code.add(" */");
code.add("function MyConstructor(){");
code.add(" if (!(this instanceof MyConstructor))");
code.add(" { return new MyConstructor() }");
code.add("}");
final String sCode = code.toString();
final List<IProblem> problems = validate(sCode);
assertEquals(problems.toString(), 0, problems.size());
}
public void testFunctionReturningItself() {
final StringList code = new StringList();
code.add("function MyConstructor(){");
code.add(" if (!(this instanceof MyConstructor))");
code.add(" { return new MyConstructor() }");
code.add("}");
final String sCode = code.toString();
final List<IProblem> problems = validate(sCode);
assertEquals(problems.toString(), 1, problems.size());
}
}