001: package de.loskutov.bco.ui;
002:
003: import java.io.File;
004: import java.io.FileOutputStream;
005: import java.io.IOException;
006: import java.net.URL;
007: import java.util.ArrayList;
008: import java.util.HashMap;
009: import java.util.List;
010: import java.util.Map;
011:
012: import junit.framework.TestCase;
013:
014: import org.eclipse.core.resources.IContainer;
015: import org.eclipse.core.resources.IFolder;
016: import org.eclipse.core.resources.IProject;
017: import org.eclipse.core.resources.IProjectDescription;
018: import org.eclipse.core.resources.IResource;
019: import org.eclipse.core.resources.IWorkspace;
020: import org.eclipse.core.resources.IWorkspaceRoot;
021: import org.eclipse.core.resources.IWorkspaceRunnable;
022: import org.eclipse.core.resources.IncrementalProjectBuilder;
023: import org.eclipse.core.resources.ResourcesPlugin;
024: import org.eclipse.core.runtime.CoreException;
025: import org.eclipse.core.runtime.FileLocator;
026: import org.eclipse.core.runtime.IPath;
027: import org.eclipse.core.runtime.IProgressMonitor;
028: import org.eclipse.core.runtime.NullProgressMonitor;
029: import org.eclipse.core.runtime.Path;
030: import org.eclipse.core.runtime.Platform;
031: import org.eclipse.jdt.core.IClasspathAttribute;
032: import org.eclipse.jdt.core.IClasspathEntry;
033: import org.eclipse.jdt.core.ICompilationUnit;
034: import org.eclipse.jdt.core.IField;
035: import org.eclipse.jdt.core.IJavaElement;
036: import org.eclipse.jdt.core.IJavaProject;
037: import org.eclipse.jdt.core.IPackageFragment;
038: import org.eclipse.jdt.core.IPackageFragmentRoot;
039: import org.eclipse.jdt.core.IParent;
040: import org.eclipse.jdt.core.IType;
041: import org.eclipse.jdt.core.JavaCore;
042: import org.eclipse.jdt.core.JavaModelException;
043: import org.eclipse.jdt.core.compiler.CharOperation;
044: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
045: import org.eclipse.jdt.internal.core.ClasspathEntry;
046: import org.eclipse.swt.widgets.Display;
047: import org.eclipse.ui.PlatformUI;
048:
049: public abstract class TestJdtUtils extends TestCase {
050:
051: private boolean onlyPrintOutError = false;
052: private static String EXTERNAL_JAR_DIR_PATH;
053: private IWorkspace workspace;
054: private IWorkspaceRoot root;
055: private IJavaProject project;
056:
057: protected abstract String getFieldName();
058:
059: protected abstract String getJdkVersion();
060:
061: protected String getJavaProjectName() {
062: return "TestJdtUtils" + getFieldName();
063: }
064:
065: protected void setUp() throws Exception {
066: super .setUp();
067: if (project == null) {
068: workspace = ResourcesPlugin.getWorkspace();
069: root = workspace.getRoot();
070: project = setUpJavaProject(getJavaProjectName(),
071: getJdkVersion());
072: project.getProject().build(
073: IncrementalProjectBuilder.FULL_BUILD,
074: new NullProgressMonitor());
075: project.makeConsistent(null);
076: }
077: }
078:
079: protected void tearDown() throws Exception {
080: deleteProject(project.getProject());
081: super .tearDown();
082: }
083:
084: protected IJavaProject getJavaProject() {
085: return project;
086: }
087:
088: protected ICompilationUnit getCompilationUnit(String cuName)
089: throws JavaModelException {
090:
091: ICompilationUnit compilationUnit = getCompilationUnit("src",
092: "inner", cuName);
093: return compilationUnit;
094: }
095:
096: /**
097: * Returns the specified compilation unit in the given project, root, and package
098: * fragment or <code>null</code> if it does not exist.
099: */
100: protected ICompilationUnit getCompilationUnit(String rootPath,
101: String packageName, String cuName)
102: throws JavaModelException {
103: IPackageFragment pkg = getPackageFragment(rootPath, packageName);
104: if (pkg == null) {
105: return null;
106: }
107: return pkg.getCompilationUnit(cuName);
108: }
109:
110: /**
111: * Returns the specified package fragment in the given project and root, or
112: * <code>null</code> if it does not exist. The rootPath must be specified as a
113: * project relative path. The empty path refers to the default package fragment.
114: */
115: protected IPackageFragment getPackageFragment(String rootPath,
116: String packageName) throws JavaModelException {
117: IPackageFragmentRoot root1 = getPackageFragmentRoot(rootPath);
118: if (root1 == null) {
119: return null;
120: }
121: return root1.getPackageFragment(packageName);
122: }
123:
124: /**
125: * Returns the specified package fragment root in the given project, or
126: * <code>null</code> if it does not exist. If relative, the rootPath must be
127: * specified as a project relative path. The empty path refers to the package fragment
128: * root that is the project folder iteslf. If absolute, the rootPath refers to either
129: * an external jar, or a resource internal to the workspace
130: */
131: protected IPackageFragmentRoot getPackageFragmentRoot(
132: String rootPath) throws JavaModelException {
133:
134: IJavaProject project = getJavaProject();
135: if (project == null) {
136: return null;
137: }
138: IPath path = new Path(rootPath);
139: if (path.isAbsolute()) {
140: IWorkspaceRoot workspaceRoot = ResourcesPlugin
141: .getWorkspace().getRoot();
142: IResource resource = workspaceRoot.findMember(path);
143: IPackageFragmentRoot root1;
144: if (resource == null) {
145: // external jar
146: root1 = project.getPackageFragmentRoot(rootPath);
147: } else {
148: // resource in the workspace
149: root1 = project.getPackageFragmentRoot(resource);
150: }
151: return root1;
152: }
153: IPackageFragmentRoot[] roots = project
154: .getPackageFragmentRoots();
155: if (roots == null || roots.length == 0) {
156: return null;
157: }
158: for (int i = 0; i < roots.length; i++) {
159: IPackageFragmentRoot root1 = roots[i];
160: if (!root1.isExternal()
161: && root1.getUnderlyingResource()
162: .getProjectRelativePath().equals(path)) {
163: return root1;
164: }
165: }
166: return null;
167: }
168:
169: protected IJavaProject createJavaProject(final String projectName,
170: final String[] sourceFolders, final String[] libraries,
171: final String projectOutput, final String compliance)
172: throws CoreException {
173: final IJavaProject[] result = new IJavaProject[1];
174: IWorkspaceRunnable create = new IWorkspaceRunnable() {
175:
176: public void run(IProgressMonitor monitor)
177: throws CoreException {
178: // create project
179: createProject(projectName);
180:
181: // set java nature
182: addJavaNature(projectName);
183:
184: // create classpath entries
185: IProject project = root.getProject(projectName);
186: IPath projectPath = project.getFullPath();
187: int sourceLength = sourceFolders.length;
188: int libLength = libraries.length;
189:
190: IClasspathEntry[] entries = new IClasspathEntry[sourceLength
191: + libLength];
192: for (int i = 0; i < sourceLength; i++) {
193: IPath sourcePath = new Path(sourceFolders[i]);
194: int segmentCount = sourcePath.segmentCount();
195: if (segmentCount > 0) {
196: // create folder and its parents
197: IContainer container = project;
198: for (int j = 0; j < segmentCount; j++) {
199: IFolder folder = container
200: .getFolder(new Path(sourcePath
201: .segment(j)));
202: if (!folder.exists()) {
203: folder.create(true, true, null);
204: }
205: container = folder;
206: }
207: }
208:
209: // create source entry
210: entries[i] = JavaCore.newSourceEntry(projectPath
211: .append(sourcePath), new IPath[0],
212: new IPath[0], null);
213: }
214:
215: for (int i = 0; i < libLength; i++) {
216: String lib = libraries[i];
217: if (lib.startsWith("JCL")) {
218: // ensure JCL variables are set
219: try {
220: setUpJCLClasspathVariables(compliance);
221: } catch (IOException e) {
222: e.printStackTrace();
223: }
224: }
225:
226: if (lib.indexOf(File.separatorChar) == -1
227: && lib.charAt(0) != '/'
228: && lib.equals(lib.toUpperCase())) { // all upper case is a var
229: char[][] vars = CharOperation.splitOn(',', lib
230: .toCharArray());
231: entries[sourceLength + i] = JavaCore
232: .newVariableEntry(new Path(new String(
233: vars[0])),
234: vars.length > 1 ? new Path(
235: new String(vars[1]))
236: : null,
237: vars.length > 2 ? new Path(
238: new String(vars[2]))
239: : null);
240: } else {
241: IPath libPath = new Path(lib);
242: if (!libPath.isAbsolute()
243: && libPath.segmentCount() > 0
244: && libPath.getFileExtension() == null) {
245: project.getFolder(libPath).create(true,
246: true, null);
247: libPath = projectPath.append(libPath);
248: }
249: entries[sourceLength + i] = JavaCore
250: .newLibraryEntry(libPath, null, null,
251: ClasspathEntry.getAccessRules(
252: new IPath[0],
253: new IPath[0]),
254: new IClasspathAttribute[0],
255: false);
256: }
257: }
258:
259: // create project's output folder
260: IPath outputPath = new Path(projectOutput);
261: if (outputPath.segmentCount() > 0) {
262: IFolder output = project.getFolder(outputPath);
263: if (!output.exists()) {
264: output.create(true, true, null);
265: }
266: }
267:
268: // set classpath and output location
269: IJavaProject javaProject = JavaCore.create(project);
270: javaProject.setRawClasspath(entries, projectPath
271: .append(outputPath), null);
272:
273: // set compliance level options
274: if ("1.5".equals(compliance)) {
275: Map options = new HashMap();
276: options.put(CompilerOptions.OPTION_Compliance,
277: CompilerOptions.VERSION_1_5);
278: options.put(CompilerOptions.OPTION_Source,
279: CompilerOptions.VERSION_1_5);
280: options.put(CompilerOptions.OPTION_TargetPlatform,
281: CompilerOptions.VERSION_1_5);
282: javaProject.setOptions(options);
283: }
284:
285: result[0] = javaProject;
286: }
287: };
288: workspace.run(create, null);
289: return result[0];
290: }
291:
292: protected IProject createProject(final String projectName)
293: throws CoreException {
294: final IProject project1 = root.getProject(projectName);
295:
296: deleteProject(project1);
297:
298: IWorkspaceRunnable create = new IWorkspaceRunnable() {
299:
300: public void run(IProgressMonitor monitor)
301: throws CoreException {
302: project1.create(null);
303: project1.open(null);
304: }
305: };
306: workspace.run(create, null);
307: return project1;
308: }
309:
310: protected void addJavaNature(String projectName)
311: throws CoreException {
312: IProject project1 = root.getProject(projectName);
313: IProjectDescription description = project1.getDescription();
314: description.setNatureIds(new String[] { JavaCore.NATURE_ID });
315: project1.setDescription(description, null);
316: }
317:
318: protected void deleteProject(IProject project1)
319: throws CoreException {
320: if (project1.exists() && !project1.isOpen()) { // force opening so that project
321: // can be deleted without logging
322: // (see bug 23629)
323: project1.open(null);
324: }
325: project1.delete(true, null);
326: }
327:
328: protected IJavaProject setUpJavaProject(final String projectName,
329: String compliance) throws CoreException, IOException {
330: // copy files in project from source workspace to target workspace
331: String sourceWorkspacePath = getSourcesPath();
332:
333: String targetWorkspacePath = root.getLocation().toFile()
334: .getCanonicalPath();
335: copyDirectory(new File(sourceWorkspacePath), new File(
336: targetWorkspacePath + "/" + projectName, "src"));
337:
338: // ensure variables are set
339: setUpJCLClasspathVariables(compliance);
340:
341: String sdkLib = "JCL15_LIB";
342: if (!"1.5".equals(compliance)) {
343: sdkLib = "JCL_LIB";
344: }
345:
346: // create project
347: IJavaProject javaProject = createJavaProject(projectName,
348: new String[] { "src" }, new String[] { sdkLib }, "bin",
349: compliance);
350:
351: setUpProjectCompliance(javaProject, compliance);
352: return javaProject;
353: }
354:
355: protected void setUpProjectCompliance(IJavaProject javaProject,
356: String compliance) throws JavaModelException, IOException {
357: // Look for version to set and return if that's already done
358: String version = CompilerOptions.VERSION_1_4;
359: String jclLibString = null;
360: String newJclLibString = null;
361: switch (compliance.charAt(2)) {
362: case '5':
363: version = CompilerOptions.VERSION_1_5;
364: if (version.equals(javaProject.getOption(
365: CompilerOptions.OPTION_Compliance, false))) {
366: return;
367: }
368: jclLibString = "JCL_LIB";
369: newJclLibString = "JCL15_LIB";
370: break;
371: case '3':
372: version = CompilerOptions.VERSION_1_3;
373: default:
374: if (version.equals(javaProject.getOption(
375: CompilerOptions.OPTION_Compliance, false))) {
376: return;
377: }
378: jclLibString = "JCL15_LIB";
379: newJclLibString = "JCL_LIB";
380: break;
381: }
382:
383: // ensure variables are set
384: setUpJCLClasspathVariables(compliance);
385:
386: // set options
387: Map options = new HashMap();
388: options.put(CompilerOptions.OPTION_Compliance, version);
389: options.put(CompilerOptions.OPTION_Source, version);
390: options.put(CompilerOptions.OPTION_TargetPlatform, version);
391: javaProject.setOptions(options);
392:
393: // replace JCL_LIB with JCL15_LIB, and JCL_SRC with JCL15_SRC
394: IClasspathEntry[] classpath = javaProject.getRawClasspath();
395: IPath jclLib = new Path(jclLibString);
396: for (int i = 0, length = classpath.length; i < length; i++) {
397: IClasspathEntry entry = classpath[i];
398: if (entry.getPath().equals(jclLib)) {
399: classpath[i] = JavaCore.newVariableEntry(new Path(
400: newJclLibString), null, entry
401: .getSourceAttachmentRootPath(), entry
402: .getAccessRules(), new IClasspathAttribute[0],
403: entry.isExported());
404: break;
405: }
406: }
407: javaProject.setRawClasspath(classpath, null);
408: }
409:
410: protected void setUpJCLClasspathVariables(String compliance)
411: throws JavaModelException, IOException {
412: if ("1.5".equals(compliance)) {
413: if (JavaCore.getClasspathVariable("JCL15_LIB") == null) {
414: setupExternalJCL("jclMin1.5");
415: JavaCore.setClasspathVariables(new String[] {
416: "JCL15_LIB", "JCL15_SRC", "JCL_SRCROOT" },
417: new IPath[] { getExternalJCLPath(compliance),
418: null, null }, null);
419: }
420: } else {
421: if (JavaCore.getClasspathVariable("JCL_LIB") == null) {
422: setupExternalJCL("jclMin");
423: JavaCore
424: .setClasspathVariables(new String[] {
425: "JCL_LIB", "JCL_SRC", "JCL_SRCROOT" },
426: new IPath[] { getExternalJCLPath(),
427: null, null }, null);
428: }
429: }
430: }
431:
432: /**
433: * Returns the IPath to the external java class library (e.g. jclMin.jar)
434: */
435: protected IPath getExternalJCLPath() {
436: return new Path(getExternalJCLPathString(""));
437: }
438:
439: /**
440: * Returns the IPath to the external java class library (e.g. jclMin.jar)
441: */
442: protected IPath getExternalJCLPath(String compliance) {
443: return new Path(getExternalJCLPathString(compliance));
444: }
445:
446: /**
447: * Returns the java.io path to the external java class library (e.g. jclMin.jar)
448: */
449: protected String getExternalJCLPathString(String compliance) {
450: return getExternalPath() + "jclMin" + compliance + ".jar";
451: }
452:
453: /**
454: * Check locally for the required JCL files, <jclName>.jar and <jclName>src.zip.
455: * If not available, copy from the project resources.
456: */
457: protected void setupExternalJCL(String jclName) throws IOException {
458: String externalPath = getExternalPath();
459: String separator = java.io.File.separator;
460: String resourceJCLDir = getPluginDirectoryPath() + separator
461: + "test" + separator + "JCL";
462: java.io.File jclDir = new java.io.File(externalPath);
463: java.io.File jclMin = new java.io.File(externalPath + jclName
464: + ".jar");
465: if (!jclDir.exists()) {
466: if (!jclDir.mkdir()) {
467: //mkdir failed
468: throw new IOException("Could not create the directory "
469: + jclDir);
470: }
471: //copy the file to the JCL directory
472: java.io.File resourceJCLMin = new java.io.File(
473: resourceJCLDir + separator + jclName + ".jar");
474: copy(resourceJCLMin, jclMin);
475: } else {
476: //check that the file, jclMin.jar present
477: //copy either file that is missing or less recent than the one in workspace
478: java.io.File resourceJCLMin = new java.io.File(
479: resourceJCLDir + separator + jclName + ".jar");
480: if ((jclMin.lastModified() < resourceJCLMin.lastModified())
481: || (jclMin.length() != resourceJCLMin.length())) {
482: copy(resourceJCLMin, jclMin);
483: }
484: }
485: }
486:
487: /*
488: * Returns the OS path to the external directory that contains external jar files.
489: * This path ends with a File.separatorChar.
490: */
491: protected String getExternalPath() {
492: if (EXTERNAL_JAR_DIR_PATH == null)
493: try {
494: String path = root.getLocation().toFile()
495: .getParentFile().getCanonicalPath();
496: if (path.charAt(path.length() - 1) != File.separatorChar) {
497: path += File.separatorChar;
498: }
499: EXTERNAL_JAR_DIR_PATH = path;
500: } catch (IOException e) {
501: e.printStackTrace();
502: }
503: return EXTERNAL_JAR_DIR_PATH;
504: }
505:
506: /**
507: * Copy the given source directory (and all its contents) to the given target
508: * directory.
509: */
510: protected void copyDirectory(File source, File target)
511: throws IOException {
512: if (!target.exists()) {
513: target.mkdirs();
514: }
515: File[] files = source.listFiles();
516: if (files == null) {
517: return;
518: }
519: for (int i = 0; i < files.length; i++) {
520: File sourceChild = files[i];
521: String name = sourceChild.getName();
522: if (name.equals("CVS") || name.equals("loskutov")) {
523: continue;
524: }
525: File targetChild = new File(target, name);
526: if (sourceChild.isDirectory()) {
527: copyDirectory(sourceChild, targetChild);
528: } else {
529: copy(sourceChild, targetChild);
530: }
531: }
532: }
533:
534: /**
535: * Copy file from src (path to the original file) to dest (path to the destination
536: * file).
537: */
538: protected void copy(File src, File dest) throws IOException {
539: // read source bytes
540: byte[] srcBytes = this .read(src);
541:
542: // write bytes to dest
543: FileOutputStream out = new FileOutputStream(dest);
544: out.write(srcBytes);
545: out.close();
546: }
547:
548: protected byte[] read(java.io.File file) throws java.io.IOException {
549: int fileLength;
550: byte[] fileBytes = new byte[fileLength = (int) file.length()];
551: java.io.FileInputStream stream = new java.io.FileInputStream(
552: file);
553: int bytesRead = 0;
554: int lastReadSize = 0;
555: while ((lastReadSize != -1) && (bytesRead != fileLength)) {
556: lastReadSize = stream.read(fileBytes, bytesRead, fileLength
557: - bytesRead);
558: bytesRead += lastReadSize;
559: }
560: stream.close();
561: return fileBytes;
562: }
563:
564: /**
565: * Returns the OS path to the directory that contains this plugin.
566: */
567: protected String getPluginDirectoryPath() {
568: try {
569: URL platformURL = Platform.getBundle(
570: "de.loskutov.BytecodeOutline").getEntry("/");
571: return new File(FileLocator.toFileURL(platformURL)
572: .getFile()).getAbsolutePath();
573: } catch (IOException e) {
574: e.printStackTrace();
575: }
576: return null;
577: }
578:
579: protected String getSourcesPath() {
580: return getPluginDirectoryPath() + java.io.File.separator
581: + "test";
582: }
583:
584: protected IType[] getAllTypes(ICompilationUnit cu)
585: throws JavaModelException {
586: ArrayList list = new ArrayList();
587: collectAllTypes(cu, list);
588: return (IType[]) list.toArray(new IType[list.size()]);
589: }
590:
591: protected void collectAllTypes(IParent parent, List types)
592: throws JavaModelException {
593: // this call has a (good) side effect that the IParent will be opened
594: IJavaElement[] children = parent.getChildren();
595: for (int i = 0; i < children.length; i++) {
596: if (children[i] instanceof IType) {
597: types.add(children[i]);
598: collectAllTypes((IParent) children[i], types);
599: } else if (children[i] instanceof IParent) {
600: collectAllTypes((IParent) children[i], types);
601: }
602: }
603: }
604:
605: protected void doTest(String topClassName)
606: throws JavaModelException {
607: System.out.println("Test with " + topClassName + ".java");
608:
609: ICompilationUnit cu = getCompilationUnit(topClassName + ".java");
610: assertNotNull(cu);
611:
612: String packagePath = root.getLocation().append(
613: getJavaProjectName()).append("bin").append("inner")
614: .toOSString()
615: + File.separator;
616:
617: String fieldName = getFieldName();
618: IType[] allTypes = getAllTypes(cu);
619: for (int i = 0; i < allTypes.length; i++) {
620: IType type = allTypes[i];
621: IField field = type.getField(fieldName);
622: if (field == null) {
623: continue;
624: }
625: String constant = (String) field.getConstant();
626: if (constant != null) {
627: constant = constant.substring(1, constant.length() - 1);
628: }
629: String name = JdtUtils.getByteCodePath(type);
630: String expectedPath = packagePath + constant + ".class";
631: if (!(expectedPath).equals(name)) {
632: System.out.println("Expected/received: \nok -> "
633: + expectedPath + "\nbad -> " + name + "\n");
634: if (!onlyPrintOutError) {
635: assertEquals(expectedPath, name);
636: }
637: } else {
638: System.out.println("OK: " + name);
639: }
640: }
641: }
642:
643: protected void pauseTests() throws InterruptedException {
644: while (true) {
645: synchronized (this ) {
646: wait(50);
647: while (Display.getDefault().readAndDispatch()) {
648: // do events
649: }
650: }
651: if (PlatformUI.getWorkbench().isClosing()) {
652: break;
653: }
654: }
655: }
656: }
|