blob: fb2a5b48fdc3481de3469968d5c154008aefdd65 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.model;
import junit.framework.Test;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.eclipse.jdt.internal.core.Util;
/**
* TO DO:
* - source attachment on external jar.
* - don't use assertTrue where assertEquals should be used
* - don't hardcode positions
*/
public class AttachSourceTests extends ModifyingResourceTests {
private IPackageFragmentRoot pkgFragmentRoot;
public AttachSourceTests(String name) {
super(name);
}
public static Test suite() {
return new Suite(AttachSourceTests.class);
}
public ASTNode runConversion(IClassFile classFile, boolean resolveBindings) {
return AST.parseCompilationUnit(classFile, resolveBindings);
}
protected void setUp() throws Exception {
super.setUp();
this.attachSource(this.pkgFragmentRoot, "/AttachSourceTests/attachsrc.zip", "");
}
/**
* Create project and set the jar placeholder.
*/
public void setUpSuite() throws Exception {
super.setUpSuite();
IJavaProject project = setUpJavaProject("AttachSourceTests");
this.pkgFragmentRoot = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/attach.jar"));
}
protected void tearDown() throws Exception {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot[] roots = project.getAllPackageFragmentRoots();
for (int i = 0; i < roots.length; i++) {
IPackageFragmentRoot root = roots[i];
if (root.getKind() == IPackageFragmentRoot.K_BINARY) {
this.attachSource(root, null, null); // detach source
}
}
super.tearDown();
}
/**
* Reset the jar placeholder and delete project.
*/
public void tearDownSuite() throws Exception {
this.deleteProject("AttachSourceTests");
super.tearDown();
}
/**
* Test AST.parseCompilationUnit(IClassFile, boolean).
*/
public void testASTParsing() throws JavaModelException {
this.attachSource(this.pkgFragmentRoot, "/AttachSourceTests/attachsrc.zip", "");
IClassFile classFile = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
ASTNode node = runConversion(classFile, true);
assertNotNull("No node", node);
this.attachSource(this.pkgFragmentRoot, null, null);
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
assertTrue("source code should no longer exist for A", cf.getSource() == null);
try {
node = runConversion(classFile, true);
assertTrue("Should not be here", false);
} catch(IllegalArgumentException e) {
assertTrue(true);
}
}
/**
* Test AST.parseCompilationUnit(IClassFile, boolean).
* Test for http://bugs.eclipse.org/bugs/show_bug.cgi?id=30471
*/
public void testASTParsing2() throws JavaModelException {
this.attachSource(this.pkgFragmentRoot, "/AttachSourceTests/attachsrc.zip", "");
IClassFile classFile = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
ASTNode node = runConversion(classFile, false);
assertNotNull("No node", node);
this.attachSource(this.pkgFragmentRoot, null, null);
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
assertTrue("source code should no longer exist for A", cf.getSource() == null);
try {
node = runConversion(classFile, false);
assertTrue("Should not be here", false);
} catch(IllegalArgumentException e) {
assertTrue(true);
}
}
/**
* Changing the source attachment file should update the java model.
* (regression test for bug 23292 Must restart Eclipse after debug of source in .zip is updated)
*/
public void testChangeSourceAttachmentFile() throws CoreException {
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
IMethod method = cf.getType().getMethod("foo", new String[] {});
// check initial source
assertSourceEquals(
"unexpected initial source for foo()",
"public void foo() {\n" +
" }",
method.getSource());
// replace source attachment file
this.swapFiles("AttachSourceTests/attachsrc.zip", "AttachSourceTests/attachsrc.new.zip");
assertSourceEquals(
"unexpected source for foo() after replacement",
"public void foo() {\n" +
" System.out.println(\"foo\");\n" +
" }",
method.getSource());
// delete source attachment file
this.deleteFile("AttachSourceTests/attachsrc.zip");
assertSourceEquals(
"unexpected source for foo() after deletion",
null,
method.getSource());
// add source attachment file back
this.moveFile("AttachSourceTests/attachsrc.new.zip", "AttachSourceTests/attachsrc.zip");
assertSourceEquals(
"unexpected source for foo() after addition",
"public void foo() {\n" +
" }",
method.getSource());
}
/**
* Ensure that a class file with an attached source can retrieve its children given a source index.
*/
public void testClassFileGetElementAt() throws JavaModelException {
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
IJavaElement elt = null;
elt = cf.getElementAt(15);
assertTrue("should have found \"A\"",
elt != null &&
elt.getElementType() == IJavaElement.TYPE &&
elt.getElementName().equals("A"));
elt = cf.getElementAt(53);
assertTrue("should have found \"public A()\"",
elt != null &&
elt.getElementType() == IJavaElement.METHOD &&
elt.getElementName().equals("A"));
elt = cf.getElementAt(72);
assertTrue("should have found \"public void foo()\"",
elt != null &&
elt.getElementType() == IJavaElement.METHOD &&
elt.getElementName().equals("foo"));
}
/**
* Retrieves the source code for "A.class", which is
* the entire CU for "A.java".
*/
public void testClassRetrieval() throws JavaModelException {
IClassFile objectCF = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
assertTrue("source code does not exist for the entire attached compilation unit", objectCF.getSource() != null);
}
/**
* Removes the source attachment from the jar.
*/
public void testDetachSource() throws JavaModelException {
this.attachSource(this.pkgFragmentRoot, null, null);
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
assertTrue("source code should no longer exist for A", cf.getSource() == null);
assertTrue("name range should no longer exist for A", cf.getType().getNameRange().getOffset() == -1);
assertTrue("source range should no longer exist for A", cf.getType().getSourceRange().getOffset() == -1);
assertTrue("Source attachment path should be null", null == this.pkgFragmentRoot.getSourceAttachmentPath());
assertTrue("Source attachment root path should be null", null ==this.pkgFragmentRoot.getSourceAttachmentRootPath());
}
/**
* Ensures that name ranges exists for BinaryMembers that have
* mapped source.
*/
public void testGetNameRange() throws JavaModelException {
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
IMethod method = cf.getType().getMethod("foo", null);
assertTrue("method name range not correct", method.getNameRange().getOffset() != -1 && method.getNameRange().getLength() != 0);
IClassFile objectCF = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
ISourceRange range= objectCF.getType().getNameRange();
int start, end;
start= range.getOffset();
end= start + range.getLength() - 1;
assertTrue("source code does not exist for the entire attached compilation unit", start != -1 && end != -1);
String source= objectCF.getSource().substring(start, end + 1);
assertSourceEquals("name should be 'A'", "A", source);
}
/**
* Retrieves the source attachment paths for jar root.
*/
public void testGetSourceAttachmentPath() throws JavaModelException {
IPath saPath= this.pkgFragmentRoot.getSourceAttachmentPath();
assertEquals("Source attachment path not correct for root " + this.pkgFragmentRoot, "/AttachSourceTests/attachsrc.zip", saPath.toString());
assertEquals("Source attachment root path should be empty", new Path(""), this.pkgFragmentRoot.getSourceAttachmentRootPath());
}
/**
* Ensures that a source range exists for the class file that has
* mapped source.
*/
public void testGetSourceRange() throws JavaModelException {
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
assertTrue("Class file source range not correct", cf.getSourceRange().getOffset() == 0 && cf.getSourceRange().getLength() != 0);
}
/**
* Ensures that a source range exists for the (inner) class file that has
* mapped source.
*/
public void testGetSourceRangeInnerClass() throws JavaModelException {
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A$Inner.class");
assertTrue("Inner Class file source range not correct", cf.getSourceRange().getOffset() == 0 && cf.getSourceRange().getLength() != 0);
}
/**
* Ensures that a source folder can be attached to a lib folder.
*/
public void testLibFolder() throws JavaModelException {
IPackageFragmentRoot root = this.getPackageFragmentRoot("/AttachSourceTests/lib");
this.attachSource(root, "/AttachSourceTests/srcLib", "");
IClassFile cf = root.getPackageFragment("p").getClassFile("X.class");
assertSourceEquals(
"Unexpected source for class file",
"package p;\n" +
"public class X {\n" +
" public void foo() {\n" +
" }\n" +
"}",
cf.getSource());
}
/**
* Retrieves the source code for methods of class A.
*/
public void testMethodRetrieval() throws JavaModelException {
IClassFile cf = this.pkgFragmentRoot.getPackageFragment("x.y").getClassFile("A.class");
IMethod[] methods = cf.getType().getMethods();
for (int i = 0; i < methods.length; i++) {
IMethod method = methods[i];
assertTrue("source code does not exist for the method " + method, method.getSource() != null);
assertTrue("method name range not correct", method.getNameRange().getOffset() != -1 && method.getNameRange().getLength() != 0);
}
}
/**
* Closes the jar, to ensure when it is re-opened the source
* attachment still exists.
*/
public void testPersistence() throws JavaModelException {
this.pkgFragmentRoot.close();
testClassRetrieval();
testMethodRetrieval();
}
/**
* Attaches a source zip to a jar. The source zip has
* a nested root structure and exists as a resource. Tests that
* the attachment is persisted as a server property for the jar.
*/
public void testRootPath() throws JavaModelException {
IJavaProject project = getJavaProject("AttachSourceTests");
IFile jar = (IFile) project.getProject().findMember("attach2.jar");
IFile srcZip=(IFile) project.getProject().findMember("attach2src.zip");
JarPackageFragmentRoot root = (JarPackageFragmentRoot) project.getPackageFragmentRoot(jar);
root.attachSource(srcZip.getFullPath(), new Path("src/nested"), null);
IClassFile cf = root.getPackageFragment("x.y").getClassFile("B.class");
assertTrue("source code does not exist for the entire attached compilation unit", cf.getSource() != null);
root.close();
cf = root.getPackageFragment("x.y").getClassFile("B.class");
assertTrue("source code does not exist for the entire attached compilation unit", cf.getSource() != null);
IPath rootSAPath= root.getSourceAttachmentRootPath();
assertEquals("Unexpected source attachment root path for " + root.getPath(), "src/nested", rootSAPath.toString());
IPath saPath= root.getSourceAttachmentPath();
assertEquals("Unexpected source attachment path for " + root.getPath(), "/AttachSourceTests/attach2src.zip", saPath.toString());
root.close();
}
/**
* Attaches a source zip to a jar specifying an invalid root path.
* Ensures that the root path is just used as a hint, and that the source is still retrieved.
*/
public void testRootPath2() throws JavaModelException {
IJavaProject project = getJavaProject("AttachSourceTests");
IFile jar = (IFile) project.getProject().findMember("attach2.jar");
IFile srcZip=(IFile) project.getProject().findMember("attach2src.zip");
JarPackageFragmentRoot root = (JarPackageFragmentRoot) project.getPackageFragmentRoot(jar);
root.attachSource(srcZip.getFullPath(), new Path(""), null);
IClassFile cf = root.getPackageFragment("x.y").getClassFile("B.class");
assertTrue("source code does not exist for the entire attached compilation unit", cf.getSource() != null);
root.close();
}
/**
* Attaches a sa source folder can be attached to a lib folder specifying an invalid root path.
* Ensures that the root path is just used as a hint, and that the source is still retrieved.
*/
public void testRootPath3() throws JavaModelException {
IPackageFragmentRoot root = this.getPackageFragmentRoot("/AttachSourceTests/lib");
this.attachSource(root, "/AttachSourceTests/srcLib", "invalid");
IClassFile cf = root.getPackageFragment("p").getClassFile("X.class");
assertSourceEquals(
"Unexpected source for class file",
"package p;\n" +
"public class X {\n" +
" public void foo() {\n" +
" }\n" +
"}",
cf.getSource());
root.close();
}
/**
* Attach a jar with a source attachement that doesn't contain the source folders
*/
public void testRootPath4() throws JavaModelException {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot root = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/test.jar"));
this.attachSource(root, "/AttachSourceTests/src.zip", "invalid");
IClassFile cf = root.getPackageFragment("test1").getClassFile("Test.class");
assertSourceEquals(
"Unexpected source for class file",
"package test1;\n" +
"\n" +
"public class Test {}",
cf.getSource());
root.close();
}
/**
* Attach a jar with a source attachement that doesn't contain the source folders
*/
public void testRootPath5() throws JavaModelException {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot root = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/update.jar"));
this.attachSource(root, "/AttachSourceTests/src.zip", "invalid");
IClassFile cf = root.getPackageFragment("p1.p2").getClassFile("A.class");
assertSourceEquals(
"Unexpected source for class file",
"package p1.p2;\n" +
"\n" +
"public class A {}",
cf.getSource());
cf = root.getPackageFragment("").getClassFile("B.class");
assertSourceEquals(
"Unexpected source for class file",
"public class B {}",
cf.getSource());
this.attachSource(root, null, null); // detach source
root.close();
}
/**
* Attach a jar with a source attachement that doesn't contain the source folders
*/
public void testRootPath6() throws JavaModelException {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot root = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/update.jar"));
this.attachSource(root, "/AttachSourceTests/src.zip", null);
IClassFile cf = root.getPackageFragment("p1.p2").getClassFile("A.class");
assertSourceEquals(
"Unexpected source for class file",
"package p1.p2;\n" +
"\n" +
"public class A {}",
cf.getSource());
cf = root.getPackageFragment("").getClassFile("B.class");
assertSourceEquals(
"Unexpected source for class file",
"public class B {}",
cf.getSource());
this.attachSource(root, null, null); // detach source
root.close();
}
/**
* Attach a jar with a source attachement that doesn't contain the source folders
*/
public void testRootPath7() throws JavaModelException {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot root = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/full.jar"));
this.attachSource(root, "/AttachSourceTests/src.zip", null);
IClassFile cf = root.getPackageFragment("p1.p2").getClassFile("A.class");
assertSourceEquals(
"Unexpected source for class file",
"package p1.p2;\n" +
"\n" +
"public class A {}",
cf.getSource());
cf = root.getPackageFragment("").getClassFile("B.class");
assertSourceEquals(
"Unexpected source for class file",
"public class B {}",
cf.getSource());
cf = root.getPackageFragment("test1").getClassFile("Test.class");
assertSourceEquals(
"Unexpected source for class file",
"package test1;\n" +
"\n" +
"public class Test {}",
cf.getSource());
this.attachSource(root, null, null); // detach source
root.close();
}
/**
* Attach a jar with a source attachement that contains the source folders
*/
public void testRootPath8() throws JavaModelException {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot root = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/full.jar"));
this.attachSource(root, "/AttachSourceTests/fullsrc.zip", null);
IClassFile cf = root.getPackageFragment("p1.p2").getClassFile("A.class");
assertSourceEquals(
"Unexpected source for class file",
"package p1.p2;\n" +
"\n" +
"public class A {}",
cf.getSource());
cf = root.getPackageFragment("").getClassFile("B.class");
assertSourceEquals(
"Unexpected source for class file",
"public class B {}",
cf.getSource());
cf = root.getPackageFragment("test1").getClassFile("Test.class");
assertSourceEquals(
"Unexpected source for class file",
"package test1;\n" +
"\n" +
"public class Test {}",
cf.getSource());
this.attachSource(root, null, null); // detach source
root.close();
}
/**
* Attach a jar with a source attachement that contains the source folders
*/
public void testRootPath9() throws JavaModelException {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot root = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/full.jar"));
this.attachSource(root, "/AttachSourceTests/fullsrc.zip", "invalid");
IClassFile cf = root.getPackageFragment("p1.p2").getClassFile("A.class");
assertSourceEquals(
"Unexpected source for class file",
"package p1.p2;\n" +
"\n" +
"public class A {}",
cf.getSource());
cf = root.getPackageFragment("").getClassFile("B.class");
assertSourceEquals(
"Unexpected source for class file",
"public class B {}",
cf.getSource());
cf = root.getPackageFragment("test1").getClassFile("Test.class");
assertSourceEquals(
"Unexpected source for class file",
"package test1;\n" +
"\n" +
"public class Test {}",
cf.getSource());
this.attachSource(root, null, null); // detach source
root.close();
}
/**
* Attach a jar with a source attachement that is itself
*/
public void testRootPath10() throws JavaModelException {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot root = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/test2.jar"));
this.attachSource(root, "/AttachSourceTests/test2.jar", null);
IClassFile cf = root.getPackageFragment("p").getClassFile("X.class");
assertSourceEquals(
"Unexpected source for class file",
"package p;\n" +
"\n" +
"public class X {\n" +
"\n" +
" public static void main(String[] args) {\n" +
" }\n" +
"}",
cf.getSource());
this.attachSource(root, null, null); // detach source
root.close();
}
/**
* http://bugs.eclipse.org/bugs/show_bug.cgi?id=35965
*/
public void testRootPath11() throws JavaModelException {
IJavaProject project = this.getJavaProject("/AttachSourceTests");
IPackageFragmentRoot root = project.getPackageFragmentRoot(this.getFile("/AttachSourceTests/test4.jar"));
this.attachSource(root, "/AttachSourceTests/test4_src.zip", null);
IClassFile cf = root.getPackageFragment("P1").getClassFile("D.class");
assertSourceEquals(
"Unexpected source for class file P1.D",
"package P1;\n" +
"\n" +
"public class D {}",
cf.getSource());
cf = root.getPackageFragment("P1.p2").getClassFile("A.class");
assertSourceEquals(
"Unexpected source for class file P1.p2.A",
"package P1.p2;\n" +
"\n" +
"public class A {}",
cf.getSource());
assertTrue("Not a binary root", root.getKind() == IPackageFragmentRoot.K_BINARY);
assertEquals("wrong jdk level", ClassFileConstants.JDK1_2, Util.getJdkLevel(root.getResource()));
this.attachSource(root, null, null); // detach source
root.close();
}
}