blob: 86f54d2d5c15bc7fd8728a5ba654be12793b85d7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020 Simeon Andreev and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Simeon Andreev - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.builder;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.tests.util.Util;
import junit.framework.Test;
public class Bug564905Test extends BuilderTests {
private static final String OUTPUT_FOLDER_NAME = "bin";
private String projectName;
private IProject project;
private IPath projectPath;
private IPath src;
private IFolder outputFolder;
private boolean oldAutoBuilding;
public Bug564905Test(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(Bug564905Test.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
this.projectName = "Bug564905Test";
this.projectPath = env.addProject(this.projectName);
this.project = env.getWorkspace().getRoot().getProject(this.projectName);
env.addExternalJars(this.projectPath, Util.getJavaClassLibs());
env.removePackageFragmentRoot(this.projectPath, "");
String outputFolderPath = "tmp/" + OUTPUT_FOLDER_NAME;
this.src = env.addPackageFragmentRoot(this.projectPath, "src", null, outputFolderPath);
this.outputFolder = env.getWorkspace().getRoot().getFolder(this.projectPath.append(outputFolderPath));
this.oldAutoBuilding = env.isAutoBuilding();
env.setAutoBuilding(true);
waitForAutoBuild();
}
@Override
protected void tearDown() throws Exception {
TestBuilderParticipant.PARTICIPANT = null;
env.removeProject(this.projectPath);
env.setAutoBuilding(this.oldAutoBuilding);
waitForAutoBuild();
super.tearDown();
}
/**
* Test for Bug 564905, with option {@code org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder} enabled.
*
* When the output folder of a project is removed in file system, on refresh we expect a build.
*/
public void testBug564905_recreateModifiedClassFileInOutputFolder_enabled() throws Exception {
enableOption_recreateModifiedClassFileInOutputFolder();
assertOutputFolderEmpty();
addSourceAndBuild();
assertOutputFolderNotEmpty();
deleteOutputFolderAndWaitForAutoBuild();
// we enabled "recreateModifiedClassFileInOutputFolder", so we expect compile artifacts
assertOutputFolderNotEmpty();
}
/**
* Test for Bug 564905, with option {@code org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder} disabled.
*
* When the output folder of a project is removed in file system, on refresh we don't expect a build
* as we don't use the option {@link JavaCore#CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER}.
*/
public void testBug564905_recreateModifiedClassFileInOutputFolder_disabled() throws Exception {
disableOption_recreateModifiedClassFileInOutputFolder();
assertOutputFolderEmpty();
addSourceAndBuild();
assertOutputFolderNotEmpty();
deleteOutputFolderAndWaitForAutoBuild();
// we disabled "recreateModifiedClassFileInOutputFolder", so we don't expect compile artifacts
assertOutputFolderEmpty();
}
private void deleteOutputFolderAndWaitForAutoBuild() throws Exception {
// close the project, since the bug 564905 occurs when build state is read from disk
this.project.close(new NullProgressMonitor());
waitForAutoBuild();
URI outputFolderUri = this.outputFolder.getLocationURI();
// delete the output folder with file system API, so that Eclipse resources API "doesn't notice"
deleteFolderInFileSystem(outputFolderUri);
// re-open the project, refresh it, then wait for auto-build; expect that something was built
this.project.open(new NullProgressMonitor());
this.project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
waitForAutoBuild();
}
private void addSourceAndBuild() {
IPath srcPackage = env.addPackage(this.src, "p");
IFolder srcPackageFolder = env.getWorkspace().getRoot().getFolder(srcPackage);
assertTrue("package in source must exist", srcPackageFolder.exists());
env.addClass(this.src, "p", "X", "package p;\n public interface X { void foo() { /* we want something compiled, anything works */ } }");
fullBuild(this.projectPath);
}
private void enableOption_recreateModifiedClassFileInOutputFolder() throws Exception {
setJavaProjectOption(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER, JavaCore.ENABLED);
}
private void disableOption_recreateModifiedClassFileInOutputFolder() throws Exception {
setJavaProjectOption(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER, JavaCore.DISABLED);
}
private void setJavaProjectOption(String optionName, String optionValue) throws Exception {
IJavaProject javaProject = JavaCore.create(this.project);
javaProject.setOption(optionName, optionValue);
this.project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
waitForAutoBuild();
}
private void waitForAutoBuild() throws InterruptedException {
Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, new NullProgressMonitor());
}
private static void deleteFolderInFileSystem(URI uri) throws IOException {
Files.walkFileTree(Paths.get(uri), new DeleteVisitor());
}
private void assertOutputFolderEmpty() throws CoreException {
assertTrue("output folder must exist", this.outputFolder.exists());
IResource[] outputFolderContent = this.outputFolder.members();
assertEquals("output folder must be empty, instead had contents: " + toString(outputFolderContent), 0, outputFolderContent.length);
}
private void assertOutputFolderNotEmpty() throws CoreException {
assertTrue("output folder must exist", this.outputFolder.exists());
assertTrue("output folder must not be empty", this.outputFolder.members().length > 0);
}
private static String toString(IResource[] resources) {
StringBuilder result = new StringBuilder();
for (IResource resource : resources) {
result.append(resource.getName());
result.append(System.lineSeparator());
}
return result.toString();
}
static class DeleteVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (exc != null) {
throw exc;
}
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
}
}