| /******************************************************************************* |
| * 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()); |
| } |
| } |