| /******************************************************************************* |
| * Copyright (c) 2000, 2014 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.eval; |
| |
| import java.util.Map; |
| |
| import junit.framework.Test; |
| |
| import org.eclipse.jdt.core.compiler.CategorizedProblem; |
| import org.eclipse.jdt.core.compiler.IProblem; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; |
| import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; |
| import org.eclipse.jdt.internal.eval.GlobalVariable; |
| /** |
| * Negative tests for code snippet. Only compilation problems should be reported in |
| * these tests. |
| */ |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| public class NegativeCodeSnippetTest extends EvaluationTest implements ProblemSeverities, ProblemReasons { |
| /** |
| * Creates a new NegativeCodeSnippetTest. |
| */ |
| public NegativeCodeSnippetTest(String name) { |
| super(name); |
| } |
| public static Test suite() { |
| return setupSuite(testClass()); |
| } |
| /** |
| * Test a scenario where the change of the package declaration causes a problem in a code snippet. |
| */ |
| public void testChangePackage() { |
| if (isJRockitVM()) return; |
| try { |
| // define the package |
| this.context.setPackageName("java.util.zip".toCharArray()); |
| |
| // evaluate a code snippet that uses this variable |
| char[] codeSnippet = "new InflaterInputStream(new java.io.ByteArrayInputStream(new byte[0])).len".toCharArray(); |
| evaluateWithExpectedDisplayString( |
| codeSnippet, |
| "0".toCharArray()); |
| |
| // back to the default package but with correct import |
| this.context.setPackageName(new char[0]); |
| this.context.setImports(new char[][] {"java.util.zip.*".toCharArray()}); |
| |
| // evaluate same code snippet |
| evaluateWithExpectedProblem( |
| codeSnippet, |
| newProblem(IProblem.NotVisibleField, Error, 71, 73, 1)); // The field len is not visible |
| |
| // back to the default package and with no imports |
| this.context.setImports(new char[0][]); |
| |
| // evaluate same code snippet |
| evaluateWithExpectedProblem( |
| codeSnippet, |
| newProblem(IProblem.UndefinedType, Error, 4, 22, 1)); // The type InflaterInputStream is undefined |
| } finally { |
| // Clean up |
| this.context.setPackageName(new char[0]); |
| this.context.setImports(new char[0][]); |
| } |
| } |
| public static Class testClass() { |
| return NegativeCodeSnippetTest.class; |
| } |
| /** |
| * Test a code snippet which declares a class that uses an expression as a returned statement |
| * in one of its methods. |
| */ |
| public void testExpressionInInnerClass() { |
| //TODO (david) Syntax error diagnose should be improved in this case. |
| evaluateWithExpectedProblem(buildCharArray(new String[] { |
| "class X {", |
| " int foo() {", |
| " 1 + 1", |
| " }", |
| "}", |
| "return new X().foo();"}), |
| newProblem(IProblem.ParsingError, Error, 21, 21, 2)); // Syntax error on token "+" |
| } |
| /** |
| * Test extra closing curly bracket. |
| */ |
| public void testExtraClosingCurlyBracket() { |
| //TODO (david) Syntax error diagnose should be improved in this case. |
| // just an expression with an extra curly bracket |
| evaluateWithExpectedProblem( |
| "1 + 2}".toCharArray(), |
| newProblem(IProblem.ParsingError, Error, 0, 0, 1)); // Unmatched bracket |
| |
| // a statement followed by an unreachable expression with an extra curly bracket |
| evaluateWithExpectedProblem(buildCharArray(new String[] { |
| "return 1 + 1;", |
| " 2 + 2}"}), |
| newProblem(IProblem.ParsingError, Error, 15, 15, 2)); // Unmatched bracket |
| } |
| /** |
| * Test extra open round bracket. |
| */ |
| public void testExtraOpenRoundBracket() { |
| evaluateWithExpectedProblem( |
| "foo((a);".toCharArray(), |
| newProblem(IProblem.ParsingErrorInsertToComplete, Error, 6, 6, 1)); // Unmatched bracket |
| } |
| /** |
| * Test a code snippet that contains an expression followed by a semi-colon. |
| */ |
| public void testExtraSemiColonInExpression() { |
| evaluateWithExpectedProblem( |
| "1;".toCharArray(), |
| newProblem(IProblem.ParsingErrorInsertToComplete, Error, 0, 0, 1)); // Syntax error on token EOF |
| } |
| /** |
| * Test access to a non existing field. |
| * (regression test for bug 25250 Scrapbook shows wrong error message) |
| */ |
| public void testInvalidField() { |
| evaluateWithExpectedProblem( |
| ("String s = \"\";\n" + |
| "s.length").toCharArray(), |
| "length cannot be resolved or is not a field\n"); |
| } |
| /** |
| * Test a code snippet which is valid but the evaluation context imports have problems. |
| */ |
| public void testInvalidImport() { |
| try { |
| // problem on the first import |
| this.context.setImports(new char[][] {"bar.Y".toCharArray()}); |
| evaluateWithExpectedImportProblem(buildCharArray(new String[] { |
| "class X {", |
| " Y foo = new Y();", |
| "}", |
| "return new X().foo;"}), |
| "bar.Y".toCharArray(), |
| newProblem(IProblem.ImportNotFound, Error, 0, 4, 1)); // The import bar.Y could not be resolved |
| |
| // problem on the second import |
| this.context.setImports(new char[][] {"java.io.*".toCharArray(), "{".toCharArray()}); |
| evaluateWithExpectedImportProblem(buildCharArray(new String[] { |
| "new File(\"c:\\temp\")"}), |
| "{".toCharArray(), |
| newProblem(IProblem.ParsingErrorInvalidToken, Error, 0, 0, 1)); // Syntax error on token "{", "Identifier" expected |
| } finally { |
| // Clean up |
| this.context.setImports(new char[0][]); |
| } |
| } |
| /** |
| * Test use of this. |
| */ |
| public void testInvalidUseOfThisInSnippet() { |
| evaluateWithExpectedProblem( |
| "this".toCharArray(), |
| "Cannot use this in a static context\n"); |
| } |
| /** |
| * Test use of this. |
| */ |
| public void testInvalidUseOfThisInSnippet2() { |
| // just an expression with an extra curly bracket |
| evaluateWithExpectedProblem( |
| "return this;".toCharArray(), |
| "Cannot use this in a static context\n"); |
| } |
| /** |
| * Test a code snippet that misses a closing round bracket. |
| */ |
| public void testMissingClosingRoundBracket() { |
| evaluateWithExpectedProblem(buildCharArray(new String[] { |
| "System.out.println(\"3 + 3\";"}), |
| newProblem(IProblem.ParsingErrorInsertToComplete, Error, 19, 25, 1)); // Unmatched bracket |
| } |
| /** |
| * Test a code snippet that contains a string that misses the closing double quote . |
| */ |
| public void testMissingDoubleQuote() { |
| evaluateWithExpectedProblem(buildCharArray(new String[] { |
| "System.out.println(\"3 + 3 = );", |
| "3 + 3"}), |
| newProblem(IProblem.UnterminatedString , Error, 19, 29, 1)); // String literal is not properly closed by a double-quote |
| } |
| /** |
| * Test an expression which is not the last statement. |
| */ |
| public void testNonLastExpressionStatement() { |
| evaluateWithExpectedProblem(buildCharArray(new String[] { |
| "1 == '1';", |
| "true"}), |
| newProblem(IProblem.ParsingErrorInvalidToken, Error, 2, 3, 1)); // Syntax error on token "==" |
| } |
| /** |
| * Test a problem in the returned expression. |
| */ |
| public void testProblemInExpression() { |
| evaluateWithExpectedProblem( |
| "new Object(); 3 + ".toCharArray(), |
| newProblem(IProblem.ParsingErrorDeleteToken, Error, 16, 16, 1)); // Syntax error on token '+' |
| } |
| /** |
| * Test a problem in the returned expression. |
| */ |
| public void testProblemInExpression2() { |
| evaluateWithExpectedProblem( |
| "new UnknownClass()".toCharArray(), |
| newProblem(IProblem.UndefinedType, Error, 4, 15, 1)); // UnknownClass cannot be resolved to a type |
| } |
| /** |
| * Test a code snippet which declares a class that has a problem. |
| */ |
| public void testProblemInInnerClass() { |
| // class declared before the last expression |
| evaluateWithExpectedProblem(buildCharArray(new String[] { |
| "class X {", |
| " Y foo = new Y();", |
| "}", |
| "return new X().foo;"}), |
| newProblem(IProblem.UndefinedType, Error, 11, 11, 2)); // The type Y is undefined |
| |
| // class declared as part of the last expression |
| evaluateWithExpectedWarningAndDisplayString(buildCharArray(new String[] { |
| "return new Object() {", |
| " public String toString() {", |
| " int i = 0;", |
| " return \"an inner class\";", |
| " }", |
| "};"}), |
| new CategorizedProblem[] { |
| newProblem(IProblem.LocalVariableIsNeverUsed, Warning, 56, 56, 3), // The local variable i is never used |
| }, |
| "an inner class".toCharArray()); |
| } |
| /** |
| * Test a problem in the statement before the returned expression. |
| */ |
| public void testProblemInPreviousStatement() { |
| //TODO (david) Syntax error diagnose should be improved in this case. |
| evaluateWithExpectedProblem(buildCharArray(new String[] { |
| "return foo(a a);", |
| "1 + 3"}), |
| newProblem(IProblem.ParsingErrorDeleteToken, Error, 13, 13, 1)); // Syntax error on token "a" |
| } |
| /** |
| * Test a code snippet that has a problem in a return statement. |
| */ |
| public void testProblemInReturnStatement() { |
| evaluateWithExpectedProblem( |
| "return 1 ++ 1;".toCharArray(), |
| newProblem(IProblem.InvalidUnaryExpression, Error, 7, 7, 1)); // Invalid argument to operation ++/-- |
| } |
| /** |
| * Test a scenario where the removal of an import causes a problem in a code snippet. |
| */ |
| public void testRemoveImport() { |
| try { |
| // define the import |
| this.context.setImports(new char[][] {"java.io.*".toCharArray()}); |
| |
| // evaluate a code snippet that uses this variable |
| char[] codeSnippet = "new File(\"c:\\\\temp\")".toCharArray(); |
| evaluateWithExpectedDisplayString( |
| codeSnippet, |
| "c:\\temp".toCharArray()); |
| |
| // remove the import |
| this.context.setImports(new char[0][]); |
| |
| // evaluate same code snippet |
| evaluateWithExpectedProblem( |
| codeSnippet, |
| newProblem(IProblem.UndefinedType, Error, 4, 7, 1)); // The type File is undefined |
| } finally { |
| // Clean up |
| this.context.setImports(new char[0][]); |
| } |
| } |
| /** |
| * Test a scenario where the removal of a variable causes a problem in a code snippet. |
| */ |
| public void testRemoveVariable() { |
| GlobalVariable var = null; |
| try { |
| // define the variable |
| var = this.context.newVariable("int".toCharArray(), "i".toCharArray(), "1".toCharArray()); |
| installVariables(1); |
| |
| // evaluate a code snippet that uses this variable |
| char[] codeSnippet = "i".toCharArray(); |
| evaluateWithExpectedDisplayString( |
| codeSnippet, |
| "1".toCharArray()); |
| |
| // remove the variable |
| this.context.deleteVariable(var); |
| installVariables(0); |
| |
| // evaluate same code snippet |
| evaluateWithExpectedProblem( |
| codeSnippet, |
| newProblem(IProblem.UnresolvedVariable, Error, 0, 0, 1)); // i cannot be resolved to a variable |
| } finally { |
| // Clean up |
| if (var != null) { |
| this.context.deleteVariable(var); |
| } |
| } |
| } |
| /** |
| * Test a code snippet that contains an expression which is not reachable. |
| */ |
| public void testUnreachableExpression() { |
| evaluateWithExpectedProblem(buildCharArray(new String[] { |
| "return 1 + 1;", |
| "2 + 2"}), |
| newProblem(IProblem.CodeCannotBeReached, Error, 14, 18, 2)); // Unreachable code |
| } |
| /** |
| * Test a code snippet which is valid but never uses the evaluation context imports. |
| * (regression test for bug 18922 Scrapbook does not come back when errors in snippet) |
| */ |
| public void testUnusedImport() { |
| try { |
| this.context.setImports(new char[][] {"java.util.*".toCharArray()}); |
| |
| // evaluate with import as error |
| Map options = getCompilerOptions(); |
| options.put(CompilerOptions.OPTION_ReportUnusedImport, CompilerOptions.ERROR); |
| |
| // force evaluation so that the following evaluation will use a CodeSnippetEvaluator instead |
| // of a VariableEvualator |
| evaluateWithExpectedValue("1".toCharArray(), "1".toCharArray(), "int".toCharArray()); |
| |
| evaluateWithExpectedImportProblem( |
| "new String(\"NOPE\")".toCharArray(), |
| "java.util.*".toCharArray(), |
| options, |
| newProblem(IProblem.UnusedImport, Error, 0, 10, 1)); // The import java.util.* is unused |
| } finally { |
| // Clean up |
| this.context.setImports(new char[0][]); |
| } |
| } |
| /** |
| * Test a code snippet that has warnings but no errors. |
| */ |
| public void testWarning() { |
| evaluateWithExpectedWarningAndDisplayString(buildCharArray(new String[] { |
| "int i;", |
| "1 + 1"}), |
| new CategorizedProblem[] { |
| newProblem(IProblem.LocalVariableIsNeverUsed, Warning, 4, 4, 1), // The local variable i is never used |
| }, |
| "2".toCharArray()); |
| } |
| } |