blob: 1cb40503ff00e9cdbbcaa122fe1840bdadf63080 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.python.tests.model;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.dltk.core.IField;
import org.eclipse.dltk.core.IMethod;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelStatusConstants;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.tests.model.ModifyingResourceTests;
import org.eclipse.dltk.python.core.PythonNature;
import org.eclipse.dltk.python.tests.PythonTestsPlugin;
import junit.framework.Test;
/*
* Tests for ISourceManipulation.delete(...)
*/
public class DeleteTests extends ModifyingResourceTests {
private static final String[] PYTHON_NATURE = new String[] {
PythonNature.NATURE_ID
};
public DeleteTests(String name) {
super( PythonTestsPlugin.PLUGIN_NAME, name );
}
@Override
protected void setUp() throws Exception {
super.setUp();
// ensure that indexing is not going to interfer with deletion
// TODO: Turn on when indexing would be added
// waitUntilIndexesReady();
createScriptProject("P", PYTHON_NATURE, new String[]{""});
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
deleteProject("P");
}
@Override
public void setUpSuite() throws Exception {
super.setUpSuite();
}
public static Test suite() {
return new Suite(DeleteTests.class);
}
// Use this static initializer to specify subset for tests
// All specified tests which do not belong to the class are skipped...
static {
// TESTS_NAMES = new String[] { "testDeleteField5" };
// TESTS_NUMBERS = new int[] { 2, 12 };
// TESTS_RANGE = new int[] { 16, -1 };
}
@Override
public void tearDownSuite() throws Exception {
super.tearDownSuite();
}
/**
* Ensures that a field can be deleted.
*/
public void testDeleteField1() throws CoreException { // was testDeleteField
try {
createFile(
"P/X.py",
"class X:\n" +
" field=5;\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IField field = cu.getType("X").getField("field");
startDeltas();
assertDeletion(field);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[*]: {CHILDREN | FINE GRAINED}\n" +
" field[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
/**
* Ensures that deletion can be canceled.
*/
public void testDeleteField2() throws CoreException { // was testDeleteFieldWithCancel
try {
createFile(
"P/X.py",
"class X:\n" +
" field=5;\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IField field = cu.getType("X").getField("field");
boolean isCanceled = false;
try {
TestProgressMonitor monitor = TestProgressMonitor.getInstance();
monitor.setCancelledCounter(1);
getScriptModel().delete(new IModelElement[] {field}, false, monitor);
} catch (OperationCanceledException e) {
isCanceled = true;
}
assertTrue("Operation should have thrown an operation canceled exception", isCanceled);
} finally {
deleteFile("P/X.py");
}
}
/*
* Ensures that a field can be deleted inside a scheduling rule that include the resource only.
* (regression test for bug 73078 ISourceManipulation.delete() tries to run in WorkspaceRoot scheduling rule)
*/
public void testDeleteField3() throws CoreException {
try {
IFile file = createFile(
"P/X.py",
"class X:\n" +
" field = 5;\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
final IField field = cu.getType("X").getField("field");
startDeltas();
getWorkspace().run(
new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
assertDeletion(field);
}
},
file,
IWorkspace.AVOID_UPDATE,
null);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[*]: {CHILDREN | FINE GRAINED}\n" +
" field[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
//TODO: Source manipulations for in-file model elements
///*
// * Ensures that a field with initializer can be deleted.
// * (regression test for bug 112935 IField.delete is not deleting the value of the variable.)
// */
//public void testDeleteField4() throws CoreException {
// try {
// createFile(
// "P/X.py",
// "class X:\n" +
// " private String t = \"sample test\";\n" +
// " pass"
// );
// ISourceModule cu = getSourceModule("P/X.py");
// IField field = cu.getType("X").getField("t");
// field.delete(false, null);
// assertSourceEquals(
// "Unexpected source",
// "class X:\n" +
// " pass",
// cu.getSource());
// } finally {
// deleteFile("P/X.py");
// }
//}
//TODO: Source manipulations for in-file model elements
///**
// * Delete enum
// */
//public void testDeleteField5() throws CoreException {
// try {
// this.createScriptProject("P1", PYTHON_NATURE, new String[] {"JCL15_LIB"});
// createFile(
// "P1/X.py",
// "public enum X {\n" +
// " A, B, C\n" +
// " pass"
// );
// ISourceModule cu = getSourceModule("P1/X.py");
// IField field = cu.getType("X").getField("A");
// field.delete(false, null);
// assertSourceEquals(
// "Unexpected source",
// "public enum X {\n" +
// " B, C\n" +
// " pass",
// cu.getSource());
// } finally {
// deleteProject("P1");
// }
//}
//TODO: Implement import declarations
///**
// * Ensures that an import declaration can be deleted.
// */
//public void testDeleteImportDeclaration() throws CoreException {
// try {
// createFile(
// "P/X.py",
// "import java.util.*;\n" +
// "import q.Y;\n" +
// "class X:\n" +
// " pass"
// );
// ISourceModule cu = getSourceModule("P/X.py");
// IImportDeclaration imp= cu.getImport("q.Y");
//
// startDeltas();
// assertDeletion(imp);
// assertDeltas(
// "Unexpected delta",
// "P[*]: {CHILDREN}\n" +
// " <project root>[*]: {CHILDREN}\n" +
// " <default>[*]: {CHILDREN}\n" +
// " X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
// " <import container>[*]: {CHILDREN | FINE GRAINED}\n" +
// " import q.Y[-]: {}"
// );
// } finally {
// stopDeltas();
// deleteFile("P/X.py");
// }
//}
/**
* Ensures that a method can be deleted.
*/
public void testDeleteMethod() throws CoreException {
try {
createFile(
"P/X.py",
"class X:\n" +
" def foo(self):\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IMethod method = cu.getType("X").getMethod("foo");
startDeltas();
assertDeletion(method);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[*]: {CHILDREN | FINE GRAINED}\n" +
" foo()[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
////TODO: Implement imports
///**
// * Ensures that multiple member Script elements contained within different
// * compilation units can be deleted.
// * Verifies that the correct changed deltas are generated.
// */
//public void testDeleteMultipleMembersFromVariousCUs() throws CoreException {
// try {
// createFolder("P/a/b/c");
// createFile(
// "P/a/b/c/X.py",
// "package a.b.c;\n" +
// "import java.util.Vector;\n" +
// "import java.util.Enumeration;\n" +
// "class X:\n" +
// " public static void main(String[] args) {\n" +
// " System.out.println(\"Hello World\");\n" +
// " }\n" +
// " static class Bar {\n" +
// " private final java.lang.String test = \"testminor\";\n" +
// " public Bar() {\n" +
// " super();\n" +
// " }\n" +
// " private void test() {\n" +
// " }\n" +
// " }\n" +
// " pass"
// );
// createFile(
// "P/a/b/Y.py",
// "package a.b;\n" +
// "public class Y {\n" +
// " int foo;\n" +
// " public static void main(String[] args) {\n" +
// " System.out.println(\"Hello World\");\n" +
// " }\n" +
// " pass"
// );
//
// // elements to be deleted:
// // from a/b/c/X.py:
// // java.util.Vector
// // main
// // Bar (inner type)
// // Bar (constructor)
// // test
// // Bar (inner type, same as above)
//
// // from a/b/Y.py
// // foo
// // main
//
// ISourceModule cuX = getSourceModule("P/a/b/c/X.py");
// IType typeX = cuX.getType("X");
// IType typeBar = typeX.getType("Bar");
//
// IModelElement[] toBeDeleted = new IModelElement[8];
// toBeDeleted[0] = cuX.getImport("java.util.Vector");
// toBeDeleted[1] = typeX.getMethod("main");
// toBeDeleted[2] = typeBar;
// toBeDeleted[3] = typeBar.getMethod("Bar");
// toBeDeleted[4] = typeBar.getMethod("test");
// toBeDeleted[5] = typeBar;
//
// ISourceModule cuY = getSourceModule("P/a/b/Y.py");
// IType typeY = cuY.getType("Y");
//
// toBeDeleted[6] = typeY.getField("foo");
// toBeDeleted[7] = typeY.getMethod("main");
//
// startDeltas();
// assertDeletion(toBeDeleted);
// assertDeltas(
// "Unexpected delta",
// "P[*]: {CHILDREN}\n" +
// " <project root>[*]: {CHILDREN}\n" +
// " a.b.c[*]: {CHILDREN}\n" +
// " X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
// " <import container>[*]: {CHILDREN | FINE GRAINED}\n" +
// " import java.util.Vector[-]: {}\n" +
// " X[*]: {CHILDREN | FINE GRAINED}\n" +
// " main(String[])[-]: {}\n" +
// " Bar[-]: {}\n" +
// " a.b[*]: {CHILDREN}\n" +
// " Y.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
// " Y[*]: {CHILDREN | FINE GRAINED}\n" +
// " foo[-]: {}\n" +
// " main(String[])[-]: {}"
// );
// } finally {
// stopDeltas();
// deleteFolder("P/a");
// }
//}
//TODO: Implement package declarations
///**
// * Ensures that a package declaration can be deleted from a compilation unit.
// */
//public void testDeletePackageDeclaration() throws CoreException {
// try {
// createFolder("P/a/b/c");
// createFile(
// "P/a/b/c/X.py",
// "package a.b.c;\n" +
// "class X:\n" +
// " pass"
// );
// ISourceModule cu = getSourceModule("P/a/b/c/X.py");
// IPackageDeclaration packageDeclaration = cu.getPackageDeclaration("a.b.c");
//
// startDeltas();
// assertDeletion(packageDeclaration);
// assertDeltas(
// "Unexpected delta",
// "P[*]: {CHILDREN}\n" +
// " <project root>[*]: {CHILDREN}\n" +
// " a.b.c[*]: {CHILDREN}\n" +
// " X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
// " package a.b.c[-]: {}"
// );
// } finally {
// stopDeltas();
// deleteFolder("P/a");
// }
//}
/**
* Ensures that a field can be deleted if it contains syntax errors
*/
public void testDeleteSyntaxErrorField() throws CoreException {
try {
createFile(
"P/X.py",
"class X:\n" +
" field=\n" + // missing right side
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IField field = cu.getType("X").getField("field");
startDeltas();
assertDeletion(field);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[*]: {CHILDREN | FINE GRAINED}\n" +
" field[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
private void assertDeletion(IModelElement element) throws ModelException {
assertDeletion(new IModelElement[] {element});
}
/**
* Ensures that a method can be deleted if it contains syntax errors
*/
public void testDeleteSyntaxErrorInMethod1() throws CoreException {
try {
createFile(
"P/X.py",
"class X:\n" +
" def foo(self):\n" +
" s = \n" +
" print s\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IMethod method = cu.getType("X").getMethod("foo");
startDeltas();
assertDeletion(method);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[*]: {CHILDREN | FINE GRAINED}\n" +
" foo()[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
/**
* Ensures that a method can be deleted if it contains syntax errors
*/
public void testDeleteSyntaxErrorInMethod2() throws CoreException {
try {
createFile(
"P/X.py",
"class X:\n" +
" def foo() \n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IMethod method = cu.getType("X").getMethod("foo");
startDeltas();
assertDeletion(method);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[*]: {CHILDREN | FINE GRAINED}\n" +
" foo()[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
/**
* Ensures that a method can be deleted if it contains syntax errors
*/
public void testDeleteSyntaxErrorInMethod3() throws CoreException {
try {
createFile(
"P/X.py",
"class X:\n" +
" def foo(self: \n" +
" pass\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IMethod method = cu.getType("X").getMethod("foo");
startDeltas();
assertDeletion(method);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[*]: {CHILDREN | FINE GRAINED}\n" +
" foo()[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
/**
* Ensures that a type can be deleted if it contains syntax errors
*/
public void testDeleteSyntaxErrorType() throws CoreException {
try {
createFile(
"P/X.py",
"class X:\n" +
" def method(self):\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IType type = cu.getType("X");
startDeltas();
assertDeletion(type);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
/**
* Ensures that a type can be deleted from a compilation unit.
*/
public void testDeleteType1() throws CoreException{
try {
createFile(
"P/X.py",
"class X:\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
IType type = cu.getType("X");
startDeltas();
assertDeletion(type);
assertDeltas(
"Unexpected delta",
"P[*]: {CHILDREN}\n" +
" <project root>[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[-]: {}"
);
} finally {
stopDeltas();
deleteFile("P/X.py");
}
}
/**
* Delete a type in a default package that is nested
* in a root folder that is not the project folder.
*/
public void testDeleteType2() throws CoreException {
try {
createScriptProject("P1", PYTHON_NATURE, new String[] {"src", "bin"});
createFile(
"P1/src/X.py",
"class X:\n" +
" pass"
);
ISourceModule cu = getSourceModule("P1/src/X.py");
IType type = cu.getType("X");
startDeltas();
assertDeletion(type);
assertDeltas(
"Unexpected delta",
"P1[*]: {CHILDREN}\n" +
" src[*]: {CHILDREN}\n" +
" <default>[*]: {CHILDREN}\n" +
" X.py[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
" X[-]: {}"
);
} finally {
stopDeltas();
deleteProject("P1");
}
}
/**
* Ensure that the correct exception is thrown for invalid input to the <code>DeleteOperation</code>
*/
public void testDeleteWithInvalidInput() throws CoreException {
IType type = null;
try {
createFile(
"P/X.py",
"class X:\n" +
" pass"
);
ISourceModule cu = getSourceModule("P/X.py");
type = cu.getType("X");
getScriptModel().delete(null, false, null);
} catch (ModelException e) {
assertTrue("Should be an no elements to process: null supplied", e.getStatus().getCode() == IModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
try {
getScriptModel().delete(new IModelElement[] {type}, false, null);
} catch (ModelException e2) {
assertTrue("Should be an no elements to process: null in the array supplied", e2.getStatus().getCode() == IModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
}
return;
} finally {
deleteFile("P/X.py");
}
}
}