/*
* Copyright 2000-2012 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 com.intellij.testFramework;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.ContentEntryImpl;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import consulo.roots.types.BinariesOrderRootType;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.*;
import consulo.vfs.util.ArchiveVfsUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import junit.framework.Assert;
import consulo.compiler.ModuleCompilerPathsManager;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import consulo.roots.ContentFolderScopes;
import consulo.roots.impl.ExcludedContentFolderTypeProvider;
import consulo.roots.impl.ProductionContentFolderTypeProvider;
import consulo.roots.impl.TestContentFolderTypeProvider;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@NonNls
public class PsiTestUtil {
public static VirtualFile createTestProjectStructure(Project project, Module module, String rootPath, Collection<File> filesToDelete)
throws Exception {
return createTestProjectStructure(project, module, rootPath, filesToDelete, true);
}
public static VirtualFile createTestProjectStructure(Project project, Module module, Collection<File> filesToDelete) throws Exception {
return createTestProjectStructure(project, module, null, filesToDelete, true);
}
public static VirtualFile createTestProjectStructure(Project project,
Module module,
String rootPath,
Collection<File> filesToDelete,
boolean addProjectRoots) throws Exception {
VirtualFile vDir = createTestProjectStructure(module, rootPath, filesToDelete, addProjectRoots);
PsiDocumentManager.getInstance(project).commitAllDocuments();
return vDir;
}
public static VirtualFile createTestProjectStructure(final Module module,
final String rootPath,
final Collection<File> filesToDelete,
final boolean addProjectRoots) throws Exception {
return createTestProjectStructure("unitTest", module, rootPath, filesToDelete, addProjectRoots);
}
public static VirtualFile createTestProjectStructure(String tempName,
final Module module,
final String rootPath,
final Collection<File> filesToDelete,
final boolean addProjectRoots) throws Exception {
File dir = FileUtil.createTempDirectory(tempName, null, false);
filesToDelete.add(dir);
final VirtualFile vDir =
LocalFileSystem.getInstance().refreshAndFindFileByPath(dir.getCanonicalPath().replace(File.separatorChar, '/'));
assert vDir.isDirectory() : vDir;
final Exception[] exception = {null};
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
if (rootPath != null) {
VirtualFile vDir1 = LocalFileSystem.getInstance().findFileByPath(rootPath.replace(File.separatorChar, '/'));
if (vDir1 == null) {
exception[0] = new Exception(rootPath + " not found");
return;
}
try {
VfsUtil.copyDirectory(null, vDir1, vDir, null);
}
catch (IOException e) {
exception[0] = e;
return;
}
}
if (addProjectRoots) {
addSourceContentToRoots(module, vDir);
}
}
});
if (exception[0] != null) throw exception[0];
return vDir;
}
public static void removeAllRoots(final Module module, final Sdk jdk) {
new WriteCommandAction.Simple(module.getProject()) {
@Override
protected void run() throws Throwable {
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel rootModel = rootManager.getModifiableModel();
rootModel.clear();
rootModel.commit();
}
}.execute().throwException();
}
public static void addSourceContentToRoots(Module module, @NotNull VirtualFile vDir) {
addSourceContentToRoots(module, vDir, false);
}
public static void addSourceContentToRoots(final Module module, @NotNull final VirtualFile vDir, final boolean testSource) {
new WriteCommandAction.Simple(module.getProject()) {
@Override
protected void run() throws Throwable {
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel rootModel = rootManager.getModifiableModel();
final ContentEntry contentEntry = rootModel.addContentEntry(vDir);
contentEntry.addFolder(vDir, testSource ? TestContentFolderTypeProvider.getInstance() : ProductionContentFolderTypeProvider.getInstance());
rootModel.commit();
}
}.execute().throwException();
}
public static void addSourceRoot(Module module, final VirtualFile vDir) {
addSourceRoot(module, vDir, false);
}
public static void addSourceRoot(final Module module, final VirtualFile vDir, final boolean isTestSource) {
new WriteCommandAction.Simple(module.getProject()) {
@Override
protected void run() throws Throwable {
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel rootModel = rootManager.getModifiableModel();
ContentEntry entry = findContentEntry(rootModel, vDir);
if (entry == null) entry = rootModel.addContentEntry(vDir);
entry.addFolder(vDir, isTestSource ? TestContentFolderTypeProvider.getInstance() : ProductionContentFolderTypeProvider.getInstance());
rootModel.commit();
}
}.execute().throwException();
}
@Nullable
private static ContentEntry findContentEntry(ModuleRootModel rootModel, final VirtualFile file) {
return ContainerUtil.find(rootModel.getContentEntries(), new Condition<ContentEntry>() {
@Override
public boolean value(final ContentEntry object) {
VirtualFile entryRoot = object.getFile();
return entryRoot != null && VfsUtilCore.isAncestor(entryRoot, file, false);
}
});
}
public static ContentEntry addContentRoot(final Module module, final VirtualFile vDir) {
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
new WriteCommandAction.Simple(module.getProject()) {
@Override
protected void run() throws Throwable {
final ModifiableRootModel rootModel = rootManager.getModifiableModel();
rootModel.addContentEntry(vDir);
rootModel.commit();
}
}.execute().throwException();
for (ContentEntry entry : rootManager.getContentEntries()) {
if (Comparing.equal(entry.getFile(), vDir)) {
Assert.assertFalse(((ContentEntryImpl)entry).isDisposed());
return entry;
}
}
return null;
}
public static void addExcludedRoot(Module module, VirtualFile dir) {
final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
findContentEntryWithAssertion(model, dir).addFolder(dir, ExcludedContentFolderTypeProvider.getInstance());
commitModel(model);
}
@NotNull
private static ContentEntry findContentEntryWithAssertion(ModifiableRootModel model, VirtualFile dir) {
ContentEntry entry = findContentEntry(model, dir);
if (entry == null) {
throw new RuntimeException(dir + " is not under content roots: " + Arrays.toString(model.getContentRoots()));
}
return entry;
}
public static void removeContentEntry(final Module module, final ContentEntry e) {
ModuleRootManager rootModel = ModuleRootManager.getInstance(module);
final ModifiableRootModel model = rootModel.getModifiableModel();
model.removeContentEntry(e);
commitModel(model);
}
public static void removeSourceRoot(Module module, VirtualFile root) {
final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel();
ContentEntry entry = findContentEntryWithAssertion(rootModel, root);
for (ContentFolder sourceFolder : entry.getFolders(ContentFolderScopes.all())) {
if (root.equals(sourceFolder.getFile())) {
entry.removeFolder(sourceFolder);
break;
}
}
commitModel(rootModel);
}
public static void removeExcludedRoot(Module module, VirtualFile root) {
final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
ContentEntry entry = findContentEntryWithAssertion(model, root);
final ContentFolder[] excludeFolders = entry.getFolders(ContentFolderScopes.all());
for (ContentFolder excludeFolder : excludeFolders) {
if (root.equals(excludeFolder.getFile())) {
entry.removeFolder(excludeFolder);
}
}
commitModel(model);
}
private static void commitModel(final ModifiableRootModel model) {
new WriteCommandAction.Simple(model.getProject()) {
@Override
protected void run() throws Throwable {
model.commit();
}
}.execute().throwException();
}
public static void checkFileStructure(PsiFile file) throws IncorrectOperationException {
String originalTree = DebugUtil.psiTreeToString(file, false);
PsiFile dummyFile =
PsiFileFactory.getInstance(file.getProject()).createFileFromText(file.getName(), file.getFileType(), file.getText());
String reparsedTree = DebugUtil.psiTreeToString(dummyFile, false);
Assert.assertEquals(reparsedTree, originalTree);
}
public static void addLibrary(final Module module, final String libName, final String libPath, final String... jarArr) {
new WriteCommandAction(module.getProject()) {
@Override
protected void run(Result result) throws Throwable {
final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
addLibrary(module, model, libName, libPath, jarArr);
model.commit();
}
}.execute().throwException();
}
public static void addProjectLibrary(Module module, String libName, VirtualFile... classesRoots) {
final ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(module).getModifiableModel();
addProjectLibrary(module, modifiableModel, libName, classesRoots);
commitModel(modifiableModel);
}
private static void addProjectLibrary(final Module module,
final ModifiableRootModel model,
final String libName,
final VirtualFile... classesRoots) {
new WriteCommandAction.Simple(module.getProject()) {
@Override
protected void run() throws Throwable {
final LibraryTable libraryTable = ProjectLibraryTable.getInstance(module.getProject());
final Library library = libraryTable.createLibrary(libName);
final Library.ModifiableModel libraryModel = library.getModifiableModel();
for (VirtualFile root : classesRoots) {
libraryModel.addRoot(root, BinariesOrderRootType.getInstance());
}
libraryModel.commit();
model.addLibraryEntry(library);
final OrderEntry[] orderEntries = model.getOrderEntries();
OrderEntry last = orderEntries[orderEntries.length - 1];
System.arraycopy(orderEntries, 0, orderEntries, 1, orderEntries.length - 1);
orderEntries[0] = last;
model.rearrangeOrderEntries(orderEntries);
}
}.execute().throwException();
}
public static void addLibrary(final Module module,
final ModifiableRootModel model,
final String libName,
final String libPath,
final String... jarArr) {
List<VirtualFile> classesRoots = new ArrayList<VirtualFile>();
for (String jar : jarArr) {
if (!libPath.endsWith("/") && !jar.startsWith("/")) {
jar = "/" + jar;
}
final String path = libPath + jar;
VirtualFile root;
if (path.endsWith(".jar")) {
VirtualFile local = LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
assert local != null;
root = ArchiveVfsUtil.getArchiveRootForLocalFile(local);
}
else {
root = LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
}
assert root != null : "Library root folder not found: " + path + "!/";
classesRoots.add(root);
}
addProjectLibrary(module, model, libName, VfsUtil.toVirtualFileArray(classesRoots));
}
public static void addLibrary(final Module module,
final String libName,
final String libDir,
final String[] classRoots,
final String[] sourceRoots) {
final String parentUrl =
VirtualFileManager.constructUrl(classRoots[0].endsWith(".jar!/") ? StandardFileSystems.JAR_PROTOCOL : LocalFileSystem.PROTOCOL, libDir);
List<String> classesUrls = new ArrayList<String>();
List<String> sourceUrls = new ArrayList<String>();
for (String classRoot : classRoots) {
classesUrls.add(parentUrl + classRoot);
}
for (String sourceRoot : sourceRoots) {
sourceUrls.add(parentUrl + sourceRoot);
}
ModuleRootModificationUtil.addModuleLibrary(module, libName, classesUrls, sourceUrls);
}
public static Module addModule(final Project project, final String name, final VirtualFile root) {
return new WriteCommandAction<Module>(project) {
@Override
protected void run(Result<Module> result) throws Throwable {
final ModifiableModuleModel moduleModel = ModuleManager.getInstance(project).getModifiableModel();
String moduleName = moduleModel.newModule(name, root.getPath()).getName();
moduleModel.commit();
final Module dep = ModuleManager.getInstance(project).findModuleByName(moduleName);
final ModifiableRootModel model = ModuleRootManager.getInstance(dep).getModifiableModel();
final ContentEntry entry = model.addContentEntry(root);
entry.addFolder(root, ProductionContentFolderTypeProvider.getInstance());
model.commit();
result.setResult(dep);
}
}.execute().getResultObject();
}
public static void setCompilerOutputPath(Module module, String url, boolean forTests) {
ModuleCompilerPathsManager manager = ModuleCompilerPathsManager.getInstance(module);
manager.setCompilerOutputUrl(forTests ? TestContentFolderTypeProvider.getInstance() : ProductionContentFolderTypeProvider.getInstance(), url);
}
public static void setExcludeCompileOutput(Module module, boolean exclude) {
ModuleCompilerPathsManager manager = ModuleCompilerPathsManager.getInstance(module);
manager.setExcludeOutput(exclude);
}
}