/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.codeInsight.gradle;
import com.intellij.compiler.CompilerTestUtil;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import com.intellij.testFramework.EdtTestUtil;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Before;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.kotlin.test.testFramework.EdtTestUtil.runInEdtAndWait;
// part of com.intellij.openapi.externalSystem.test.ExternalSystemTestCase
public abstract class ExternalSystemTestCase extends UsefulTestCase {
private File ourTempDir;
protected IdeaProjectTestFixture myTestFixture;
protected Project myProject;
private File myTestDir;
private VirtualFile myProjectRoot;
private final List<VirtualFile> myAllConfigs = new ArrayList<VirtualFile>();
@Before
@Override
public void setUp() throws Exception {
super.setUp();
ensureTempDirCreated();
myTestDir = new File(ourTempDir, getTestName(false));
FileUtil.ensureExists(myTestDir);
setUpFixtures();
myProject = myTestFixture.getProject();
invokeTestRunnable(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
setUpInWriteAction();
}
catch (Throwable e) {
try {
tearDown();
}
catch (Exception e1) {
e1.printStackTrace();
}
throw new RuntimeException(e);
}
}
});
}
});
List<String> allowedRoots = new ArrayList<String>();
collectAllowedRoots(allowedRoots);
if (!allowedRoots.isEmpty()) {
VfsRootAccess.allowRootAccess(getTestRootDisposable(), ArrayUtil.toStringArray(allowedRoots));
}
CompilerTestUtil.enableExternalCompiler();
}
protected void collectAllowedRoots(List<String> roots) throws IOException {
}
public static Collection<String> collectRootsInside(String root) {
final List<String> roots = ContainerUtil.newSmartList();
roots.add(root);
FileUtil.processFilesRecursively(new File(root), new Processor<File>() {
@Override
public boolean process(File file) {
try {
String path = file.getCanonicalPath();
if (!FileUtil.isAncestor(path, path, false)) {
roots.add(path);
}
}
catch (IOException ignore) {
}
return true;
}
});
return roots;
}
private void ensureTempDirCreated() throws IOException {
if (ourTempDir != null) return;
ourTempDir = new File(FileUtil.getTempDirectory(), getTestsTempDir());
FileUtil.delete(ourTempDir);
FileUtil.ensureExists(ourTempDir);
}
protected abstract String getTestsTempDir();
protected void setUpFixtures() throws Exception {
myTestFixture = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName()).getFixture();
myTestFixture.setUp();
}
private void setUpInWriteAction() throws Exception {
File projectDir = new File(myTestDir, "project");
FileUtil.ensureExists(projectDir);
myProjectRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectDir);
}
@After
@Override
public void tearDown() throws Exception {
try {
EdtTestUtil.runInEdtAndWait(new ThrowableRunnable<Throwable>() {
@Override
public void run() throws Throwable {
CompilerTestUtil.disableExternalCompiler(myProject);
tearDownFixtures();
}
});
myProject = null;
if (!FileUtil.delete(myTestDir) && myTestDir.exists()) {
System.err.println("Cannot delete " + myTestDir);
//printDirectoryContent(myDir);
myTestDir.deleteOnExit();
}
}
finally {
super.tearDown();
resetClassFields(getClass());
}
}
protected void tearDownFixtures() throws Exception {
myTestFixture.tearDown();
myTestFixture = null;
}
private void resetClassFields(Class<?> aClass) {
if (aClass == null) return;
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
final int modifiers = field.getModifiers();
if ((modifiers & Modifier.FINAL) == 0
&& (modifiers & Modifier.STATIC) == 0
&& !field.getType().isPrimitive()) {
field.setAccessible(true);
try {
field.set(this, null);
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
if (aClass == ExternalSystemTestCase.class) return;
resetClassFields(aClass.getSuperclass());
}
@Override
protected void runTest() throws Throwable {
try {
super.runTest();
}
catch (Exception throwable) {
Throwable each = throwable;
do {
if (each instanceof HeadlessException) {
printIgnoredMessage("Doesn't work in Headless environment");
return;
}
}
while ((each = each.getCause()) != null);
throw throwable;
}
}
@Override
protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
runInEdtAndWait(runnable);
}
protected static String getRoot() {
if (SystemInfo.isWindows) return "c:";
return "";
}
protected String getProjectPath() {
return myProjectRoot.getPath();
}
protected VirtualFile createProjectConfig(@NonNls String config) throws IOException {
return createConfigFile(myProjectRoot, config);
}
private VirtualFile createConfigFile(final VirtualFile dir, String config) throws IOException {
final String configFileName = getExternalSystemConfigFileName();
VirtualFile f = dir.findChild(configFileName);
if (f == null) {
f = new WriteAction<VirtualFile>() {
@Override
protected void run(@NotNull Result<VirtualFile> result) throws Throwable {
VirtualFile res = dir.createChildData(null, configFileName);
result.setResult(res);
}
}.execute().getResultObject();
myAllConfigs.add(f);
}
setFileContent(f, config, true);
return f;
}
protected abstract String getExternalSystemConfigFileName();
protected VirtualFile createProjectSubFile(String relativePath) throws IOException {
File f = new File(getProjectPath(), relativePath);
FileUtil.ensureExists(f.getParentFile());
FileUtil.ensureCanCreateFile(f);
boolean created = f.createNewFile();
if(!created) {
throw new AssertionError("Unable to create the project sub file: " + f.getAbsolutePath());
}
return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f);
}
protected VirtualFile createProjectSubFile(String relativePath, String content) throws IOException {
VirtualFile file = createProjectSubFile(relativePath);
setFileContent(file, content, false);
return file;
}
protected Module getModule(String name) {
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
try {
Module m = ModuleManager.getInstance(myProject).findModuleByName(name);
assertNotNull("Module " + name + " not found", m);
return m;
}
finally {
accessToken.finish();
}
}
private static void setFileContent(final VirtualFile file, final String content, final boolean advanceStamps) throws IOException {
new WriteAction<VirtualFile>() {
@Override
protected void run(@NotNull Result<VirtualFile> result) throws Throwable {
if (advanceStamps) {
file.setBinaryContent(content.getBytes(CharsetToolkit.UTF8_CHARSET), -1, file.getTimeStamp() + 4000);
}
else {
file.setBinaryContent(content.getBytes(CharsetToolkit.UTF8_CHARSET), file.getModificationStamp(), file.getTimeStamp());
}
}
}.execute().getResultObject();
}
private void printIgnoredMessage(String message) {
String toPrint = "Ignored";
if (message != null) {
toPrint += ", because " + message;
}
toPrint += ": " + getClass().getSimpleName() + "." + getName();
System.out.println(toPrint);
}
}