/*******************************************************************************
* Copyright (c) 2000, 2017 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.builder;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.codehaus.jdt.groovy.model.ModuleNodeMapper;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.tests.junit.extension.TestCase;
import org.eclipse.jdt.core.tests.util.TestVerifier;
import org.eclipse.jdt.core.tests.util.Util;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.core.JavaModelManager;
/**
* Base class for Java image builder tests
*/
public abstract class BuilderTests extends TestCase {
protected static boolean DEBUG = false;
protected int moduleNodeMapperCacheSize = 0;
protected static TestingEnvironment env = null;
protected EfficiencyCompilerRequestor debugRequestor = null;
public BuilderTests(String name) {
super(name);
}
protected void setUp() throws Exception {
super.setUp();
System.out.println("----------------------------------------");
System.out.println("Starting: " + getName());
debugRequestor = new EfficiencyCompilerRequestor();
Compiler.DebugRequestor = debugRequestor;
if (env == null) {
env = new TestingEnvironment();
env.openEmptyWorkspace();
}
env.resetWorkspace();
env.setAutoBuilding(false);
this.moduleNodeMapperCacheSize = ModuleNodeMapper.size();
}
protected void tearDown() throws Exception {
env.resetWorkspace();
// Discard primary working copies and copies with owner left from failed tests
ICompilationUnit[] wcs = null;
int i = 0;
do {
wcs = JavaModelManager.getJavaModelManager().getWorkingCopies(null, true);
if (wcs != null) {
for (ICompilationUnit workingCopy : wcs) {
try {
workingCopy.discardWorkingCopy();
workingCopy.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
i++;
if (i > 20 && wcs != null) {
fail("Could not delete working copies " + wcs);
}
} while (wcs != null && wcs.length > 0);
assertTrue("ModuleNodeMapper should be empty when there are no working copies", moduleNodeMapperCacheSize >= ModuleNodeMapper.size());
JavaCore.setOptions(JavaCore.getDefaultOptions());
super.tearDown();
}
protected void cleanBuild() {
debugRequestor.clearResult();
debugRequestor.activate();
env.cleanBuild();
debugRequestor.deactivate();
}
/** Execute the given class. Expecting output and error must be specified - passing null for expectedError means no errors are expected!
*/
protected void executeClass(
IPath projectPath,
String className,
String expectingOutput,
String expectedError) {
TestVerifier verifier = new TestVerifier(false);
Vector<String> classpath = new Vector<String>(5);
IPath workspacePath = env.getWorkspaceRootPath();
classpath.addElement(workspacePath.append(env.getOutputLocation(projectPath)).toOSString());
IClasspathEntry[] cp = env.getClasspath(projectPath);
for (int i = 0; i < cp.length; i++) {
IPath c = cp[i].getPath();
String ext = c.getFileExtension();
if (ext != null && (ext.equals("zip") || ext.equals("jar"))) {
// this doesn't work on mac/*nix because device is usually (always?) null
// if (c.getDevice() == null) {
// classpath.addElement(workspacePath.append(c).toOSString());
// } else {
// classpath.addElement(c.toOSString());
// }
// this will work as long as the jar is contained in the same project
if (projectPath.isPrefixOf(c)) {
classpath.addElement(workspacePath.append(c).toOSString());
} else {
classpath.addElement(c.toOSString());
}
}
}
verifier.execute(className, classpath.toArray(new String[0]));
if (DEBUG) {
System.out.println("ERRORS\n");
System.out.println(Util.displayString(verifier.getExecutionError()));
System.out.println("OUTPUT\n");
System.out.println(Util.displayString(verifier.getExecutionOutput()));
}
String actualError = verifier.getExecutionError();
// workaround pb on 1.3.1 VM (line delimitor is not the platform line delimitor)
char[] error = actualError.toCharArray();
actualError = new String(CharOperation.replace(error, System.getProperty("line.separator").toCharArray(), new char[] { '\n' }));
if (expectedError==null && actualError.length()!=0) {
if (actualError.trim().endsWith("WARNING: Module [groovy-all] - Unable to load extension class [org.codehaus.groovy.runtime.NioGroovyMethods]")) {
// Allow this it indicates (usually) running the tests with groovy 2.3 on a pre 1.7 vm
} else {
fail("unexpected error : " + actualError);
}
}
if (expectedError!=null && actualError.indexOf(expectedError) == -1) {
System.out.println("ERRORS\n");
System.out.println(Util.displayString(actualError));
}
if (expectedError!=null) {
assertTrue("unexpected error : " + actualError + " expected : " + expectedError, actualError.indexOf(expectedError) != -1);
}
String actualOutput = verifier.getExecutionOutput();
if (actualOutput.indexOf(expectingOutput) == -1) {
System.out.println("OUTPUT\n");
System.out.println(Util.displayString(actualOutput));
}
// strip out carriage return for windoze testing
int idx=-1;
while ((idx=actualOutput.indexOf('\r'))!=-1) {
actualOutput = actualOutput.substring(0,idx)+actualOutput.substring(idx+1);
}
assertTrue("unexpected output.\nExpected:\n"+expectingOutput+"\nActual:\n"+actualOutput, actualOutput.indexOf(expectingOutput) != -1);
}
protected void expectingParticipantProblems(IPath path, String expected) {
Problem[] problems = env.getProblemsFor(path, "org.eclipse.jdt.core.tests.compile.problem");
StringBuffer buf = new StringBuffer();
for (int i = 0, length = problems.length; i < length; i++) {
Problem problem = problems[i];
buf.append(problem.getMessage());
if (i < length - 1) buf.append('\n');
}
assertEquals("Unexpected problems", expected, buf.toString());
}
/** Verifies that given element is not present.
*/
protected void expectingPresenceOf(IPath path) {
expectingPresenceOf(new IPath[] { path });
}
/** Verifies that given elements are not present.
*/
protected void expectingPresenceOf(IPath[] paths) {
IPath wRoot = env.getWorkspaceRootPath();
for (int i = 0; i < paths.length; i++)
assertTrue(paths[i] + " is not present", wRoot.append(paths[i]).toFile().exists());
}
/** Verifies that given element is not present.
*/
protected void expectingNoPresenceOf(IPath path) {
expectingNoPresenceOf(new IPath[] { path });
}
/** Verifies that given elements are not present.
*/
protected void expectingNoPresenceOf(IPath[] paths) {
IPath wRoot = env.getWorkspaceRootPath();
for (int i = 0; i < paths.length; i++)
assertTrue(paths[i] + " is present", !wRoot.append(paths[i]).toFile().exists());
}
/** Verifies that given classes have been compiled.
*/
protected void expectingCompiledClasses(String... expected) {
String[] actual = debugRequestor.getCompiledClasses();
org.eclipse.jdt.internal.core.util.Util.sort(actual);
org.eclipse.jdt.internal.core.util.Util.sort(expected);
expectingCompiling(actual, expected, "unexpected recompiled units. lenExpected="+expected.length+" lenActual="+actual.length);
}
protected void expectedCompiledClassCount(int expected) {
int actual = debugRequestor.getCompiledClasses().length;
assertEquals(expected,actual);
}
/**
* Verifies that the given classes and no others have been compiled,
* but permits the classes to have been compiled more than once.
*/
protected void expectingUniqueCompiledClasses(String[] expected) {
String[] actual = debugRequestor.getCompiledClasses();
org.eclipse.jdt.internal.core.util.Util.sort(actual);
// Eliminate duplicate entries
int dups = 0;
for (int i = 0; i < actual.length - 1; ++i) {
if (actual[i + 1].equals(actual[i])) {
++dups;
actual[i] = null;
}
}
String[] uniqueActual = new String[actual.length - dups];
for (int i = 0, j = 0; i < actual.length; ++i) {
if (actual[i] != null) {
uniqueActual[j++] = actual[i];
}
}
org.eclipse.jdt.internal.core.util.Util.sort(expected);
expectingCompiling(uniqueActual, expected, "unexpected compiled units");
}
/** Verifies that given classes have been compiled in the specified order.
*/
protected void expectingCompilingOrder(String[] expected) {
expectingCompiling(debugRequestor.getCompiledClasses(), expected, "unexpected compiling order");
}
private void expectingCompiling(String[] actual, String[] expected, String message) {
if (DEBUG)
for (int i = 0; i < actual.length; i++)
System.out.println(actual[i]);
StringBuffer actualBuffer = new StringBuffer("{");
for (int i = 0; i < actual.length; i++) {
if (i > 0)
actualBuffer.append(",");
actualBuffer.append(actual[i]);
}
actualBuffer.append('}');
StringBuffer expectedBuffer = new StringBuffer("{");
for (int i = 0; i < expected.length; i++) {
if (i > 0)
expectedBuffer.append(",");
expectedBuffer.append(expected[i]);
}
expectedBuffer.append('}');
assertEquals(message, expectedBuffer.toString(), actualBuffer.toString());
}
/** Verifies that the workspace has no problems.
*/
protected void expectingNoProblems() {
expectingNoProblemsFor(env.getWorkspaceRootPath());
}
protected void expectingNoErrors() {
expectingNoErrorsFor(env.getWorkspaceRootPath());
}
/** Verifies that the given element has no problems.
*/
protected void expectingNoProblemsFor(IPath root) {
expectingNoProblemsFor(new IPath[] { root });
}
protected void expectingNoErrorsFor(IPath root) {
expectingNoErrorsFor(new IPath[] { root });
}
/** Verifies that the given elements have no problems.
*/
protected void expectingNoProblemsFor(IPath[] roots) {
StringBuffer buffer = new StringBuffer();
Problem[] allProblems = allSortedProblems(roots);
if (allProblems != null) {
for (int i=0, length=allProblems.length; i<length; i++) {
buffer.append(allProblems[i]+"\n");
}
}
String actual = buffer.toString();
assumeEquals("Unexpected problem(s)!!!", "", actual);
}
protected void expectingNoErrorsFor(IPath[] roots) {
StringBuffer buffer = new StringBuffer();
Problem[] allProblems = allSortedProblems(roots);
int count = 0;
if (allProblems != null) {
for (int i=0, length=allProblems.length; i<length; i++) {
if (allProblems[i].getSeverity()==IMarker.SEVERITY_ERROR) {
// TODO could convert task markers into just warnings (or ignore), but this is easier right now...
if (allProblems[i].toString().indexOf("TODO")==-1) {
buffer.append(allProblems[i]+"\n");
count++;
}
}
}
}
String actual = buffer.toString();
assumeEquals("Unexpected problem(s)!!! number="+count, "", actual);
}
/** Verifies that the given element has problems and
* only the given element.
*/
protected void expectingOnlyProblemsFor(IPath expected) {
expectingOnlyProblemsFor(new IPath[] { expected });
}
/** Verifies that the given elements have problems and
* only the given elements.
*/
protected void expectingOnlyProblemsFor(IPath[] expected) {
if (DEBUG)
printProblems();
Problem[] rootProblems = env.getProblems();
Hashtable<IPath, IPath> actual = new Hashtable<IPath, IPath>(rootProblems.length * 2 + 1);
for (int i = 0; i < rootProblems.length; i++) {
IPath culprit = rootProblems[i].getResourcePath();
actual.put(culprit, culprit);
}
for (int i = 0; i < expected.length; i++)
if (!actual.containsKey(expected[i]))
assertTrue("missing expected problem with " + expected[i].toString(), false);
if (actual.size() > expected.length) {
for (Enumeration<IPath> e = actual.elements(); e.hasMoreElements();) {
IPath path = e.nextElement();
boolean found = false;
for (int i = 0; i < expected.length; ++i) {
if (path.equals(expected[i])) {
found = true;
break;
}
}
if (!found)
assertTrue("unexpected problem(s) with " + path.toString(), false);
}
}
}
/** Verifies that the given element has a specific problem and
* only the given problem.
*/
protected void expectingOnlySpecificProblemFor(IPath root, Problem problem) {
expectingOnlySpecificProblemsFor(root, new Problem[] { problem });
}
/** Verifies that the given element has specifics problems and
* only the given problems.
*/
protected void expectingOnlySpecificProblemsFor(IPath root, Problem[] expectedProblems) {
if (DEBUG)
printProblemsFor(root);
Problem[] rootProblems = env.getProblemsFor(root);
for (int i = 0; i < expectedProblems.length; i++) {
Problem expectedProblem = expectedProblems[i];
boolean found = false;
for (int j = 0; j < rootProblems.length; j++) {
if(expectedProblem.equals(rootProblems[j])) {
found = true;
rootProblems[j] = null;
break;
}
}
if (!found) {
printProblemsFor(root);
}
assertTrue("problem not found: " + expectedProblem.toString(), found);
}
for (int i = 0; i < rootProblems.length; i++) {
if(rootProblems[i] != null) {
printProblemsFor(root);
assertTrue("unexpected problem: " + rootProblems[i].toString(), false);
}
}
}
/** Verifies that the given element has problems.
*/
protected void expectingProblemsFor(IPath root, String expected) {
expectingProblemsFor(new IPath[] { root }, expected);
}
/** Verifies that the given elements have problems.
*/
protected void expectingProblemsFor(IPath[] roots, String expected) {
Problem[] problems = allSortedProblems(roots);
assumeEquals("Invalid problem(s)!!!", expected, arrayToString(problems));
}
/**
* Verifies that the given element has the expected problems.
*/
protected void expectingProblemsFor(IPath root, List<String> expected) {
expectingProblemsFor(new IPath[] { root }, expected);
}
/**
* Verifies that the given elements have the expected problems.
*/
protected void expectingProblemsFor(IPath[] roots, List<String> expected) {
Problem[] allProblems = allSortedProblems(roots);
assumeEquals("Invalid problem(s)!!!", arrayToString(expected.toArray()), arrayToString(allProblems));
}
/** Verifies that the given element has a specific problem.
*/
protected void expectingSpecificProblemFor(IPath root, Problem problem) {
expectingSpecificProblemsFor(root, new Problem[] { problem });
}
/** Verifies that the given element has specific problems.
*/
protected void expectingSpecificProblemsFor(IPath root, Problem[] problems) {
if (DEBUG)
printProblemsFor(root);
Problem[] rootProblems = env.getProblemsFor(root);
next : for (int i = 0; i < problems.length; i++) {
Problem problem = problems[i];
for (int j = 0; j < rootProblems.length; j++) {
Problem rootProblem = rootProblems[j];
if (rootProblem != null) {
if (problem.equals(rootProblem)) {
rootProblems[j] = null;
continue next;
}
}
}
/*
for (int j = 0; j < rootProblems.length; j++) {
Problem pb = rootProblems[j];
if (pb != null) {
System.out.print("got pb: new Problem(\"" + pb.getLocation() + "\", \"" + pb.getMessage() + "\", \"" + pb.getResourcePath() + "\"");
System.out.print(", " + pb.getStart() + ", " + pb.getEnd() + ", " + pb.getCategoryId()+ ", " + pb.getSeverity());
System.out.println(")");
}
}
*/
System.out.println("--------------------------------------------------------------------------------");
System.out.println("Missing problem while running test "+getName()+":");
System.out.println(" - expected : " + problem);
System.out.println(" - current: " + arrayToString(rootProblems));
assumeTrue("missing expected problem: " + problem, false);
}
}
/** Batch builds the workspace.
*/
protected void fullBuild() {
debugRequestor.clearResult();
debugRequestor.activate();
env.fullBuild();
debugRequestor.deactivate();
}
/** Batch builds the given project.
*/
protected void fullBuild(IPath projectPath) {
debugRequestor.clearResult();
debugRequestor.activate();
env.fullBuild(projectPath);
debugRequestor.deactivate();
}
/** Incrementally builds the given project.
*/
protected void incrementalBuild(IPath projectPath) {
debugRequestor.clearResult();
debugRequestor.activate();
env.incrementalBuild(projectPath);
debugRequestor.deactivate();
}
/** Incrementally builds the workspace.
*/
protected void incrementalBuild() {
debugRequestor.clearResult();
debugRequestor.activate();
env.incrementalBuild();
debugRequestor.deactivate();
}
protected void printProblems() {
printProblemsFor(env.getWorkspaceRootPath());
}
protected void printProblemsFor(IPath root) {
printProblemsFor(new IPath[] { root });
}
protected void printProblemsFor(IPath[] roots) {
for (int i = 0; i < roots.length; i++) {
IPath path = roots[i];
/* get the leaf problems for this type */
Problem[] problems = env.getProblemsFor(path);
System.out.println(arrayToString(problems));
System.out.println();
}
}
protected static String arrayToString(Object[] array) {
if (array == null) return "<null>";
StringBuilder buffer = new StringBuilder();
for (int i = 0, n = array.length; i < n; i += 1) {
if (array[i] != null) {
if (i > 0) buffer.append('\n');
buffer.append(array[i].toString());
}
}
return buffer.toString();
}
/**
* Concatenate and sort all problems for given root paths.
*
* @param roots The path to get the problems
* @return All sorted problems of all given path
*/
Problem[] allSortedProblems(IPath[] roots) {
Problem[] allProblems = null;
for (int i = 0, max=roots.length; i<max; i++) {
Problem[] problems = env.getProblemsFor(roots[i]);
int length = problems.length;
if (problems.length != 0) {
if (allProblems == null) {
allProblems = problems;
} else {
int all = allProblems.length;
System.arraycopy(allProblems, 0, allProblems = new Problem[all+length], 0, all);
System.arraycopy(problems, 0, allProblems , all, length);
}
}
}
if (allProblems != null) {
Arrays.sort(allProblems);
}
return allProblems;
}
public static void assertElements(Set<Object> actualSet, Object... expecteds) {
HashSet<Object> expectedSet = new HashSet<Object>(Arrays.asList(expecteds));
StringBuilder msg = new StringBuilder();
for (Object expected : expectedSet) {
if (!actualSet.contains(expected)) {
msg.append("Expected but not found: "+expected+"\n");
}
}
for (Object actual : actualSet) {
if (!expectedSet.contains(actual)) {
msg.append("Found but not expected: "+actual+"\n");
}
}
if (!"".equals(msg.toString())) {
fail(msg.toString());
}
}
}