blob: 42e7c70579624e6da255a14c7ddcad3efd5703c4 [file] [log] [blame]
/*
* Copyright 2000-2014 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.ProjectTopics;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.completion.CompletionProgressIndicator;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.hint.HintManagerImpl;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInspection.InspectionEP;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.codeInspection.LocalInspectionEP;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ex.*;
import com.intellij.ide.highlighter.ProjectFileType;
import com.intellij.ide.startup.StartupManagerEx;
import com.intellij.ide.startup.impl.StartupManagerImpl;
import com.intellij.idea.IdeaLogger;
import com.intellij.idea.IdeaTestApplication;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.ApplicationEx;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.command.impl.UndoManagerImpl;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.impl.EditorFactoryImpl;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl;
import com.intellij.openapi.module.EmptyModuleType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.project.ModuleAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.encoding.EncodingManagerImpl;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.profile.codeInspection.InspectionProfileManager;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSchemes;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.impl.DocumentCommitThread;
import com.intellij.psi.impl.PsiDocumentManagerImpl;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl;
import com.intellij.psi.templateLanguages.TemplateDataLanguageMappings;
import com.intellij.util.Consumer;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.IndexableFileSet;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import gnu.trove.THashMap;
import junit.framework.TestCase;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
import static com.intellij.openapi.roots.ModuleRootModificationUtil.updateModel;
/**
* @author yole
*/
public abstract class LightPlatformTestCase extends UsefulTestCase implements DataProvider {
@NonNls public static final String PROFILE = "Configurable";
@NonNls private static final String LIGHT_PROJECT_MARK = "Light project: ";
private static IdeaTestApplication ourApplication;
protected static Project ourProject;
private static Module ourModule;
private static PsiManager ourPsiManager;
private static boolean ourAssertionsInTestDetected;
private static VirtualFile ourSourceRoot;
private static TestCase ourTestCase = null;
public static Thread ourTestThread;
private static LightProjectDescriptor ourProjectDescriptor;
private static boolean ourHaveShutdownHook;
private final Map<String, InspectionToolWrapper> myAvailableInspectionTools = new THashMap<String, InspectionToolWrapper>();
private ThreadTracker myThreadTracker;
/**
* @return Project to be used in tests for example for project components retrieval.
*/
public static Project getProject() {
return ourProject;
}
/**
* @return Module to be used in tests for example for module components retrieval.
*/
public static Module getModule() {
return ourModule;
}
/**
* Shortcut to PsiManager.getInstance(getProject())
*/
public static PsiManager getPsiManager() {
if (ourPsiManager == null) {
ourPsiManager = PsiManager.getInstance(ourProject);
}
return ourPsiManager;
}
public static IdeaTestApplication initApplication() {
ourApplication = IdeaTestApplication.getInstance(null);
return ourApplication;
}
@TestOnly
public static void disposeApplication() {
if (ourApplication != null) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
Disposer.dispose(ourApplication);
}
});
ourApplication = null;
}
}
public static IdeaTestApplication getApplication() {
return ourApplication;
}
protected void resetAllFields() {
resetClassFields(getClass());
}
private void resetClassFields(final Class<?> aClass) {
try {
UsefulTestCase.clearDeclaredFields(this, aClass);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
if (aClass == LightPlatformTestCase.class) return;
resetClassFields(aClass.getSuperclass());
}
private static void cleanPersistedVFSContent() {
((PersistentFSImpl)PersistentFS.getInstance()).cleanPersistedContents();
}
public static boolean isLight(Project project) {
String creationPlace = project.getUserData(CREATION_PLACE);
return creationPlace != null && StringUtil.startsWith(creationPlace, LIGHT_PROJECT_MARK);
}
private static void initProject(@NotNull final LightProjectDescriptor descriptor) throws Exception {
ourProjectDescriptor = descriptor;
final File projectFile = FileUtil.createTempFile("light_temp_", ProjectFileType.DOT_DEFAULT_EXTENSION);
new WriteCommandAction.Simple(null) {
@SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
@Override
protected void run() throws Throwable {
if (ourProject != null) {
closeAndDeleteProject();
}
else {
cleanPersistedVFSContent();
}
LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectFile);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
new Throwable(projectFile.getPath()).printStackTrace(new PrintStream(buffer));
ourProject = PlatformTestCase.createProject(projectFile, LIGHT_PROJECT_MARK + buffer.toString());
ourPathToKeep = projectFile.getPath();
if (!ourHaveShutdownHook) {
ourHaveShutdownHook = true;
registerShutdownHook();
}
ourPsiManager = null;
ourModule = createMainModule(descriptor.getModuleType());
VirtualFile dummyRoot = VirtualFileManager.getInstance().findFileByUrl("temp:///");
assert dummyRoot != null;
dummyRoot.refresh(false, false);
try {
ourSourceRoot = dummyRoot.createChildDirectory(this, "src");
cleanSourceRoot();
}
catch (IOException e) {
throw new RuntimeException(e);
}
FileBasedIndex.getInstance().registerIndexableSet(new IndexableFileSet() {
@Override
public boolean isInSet(@NotNull final VirtualFile file) {
return ourSourceRoot != null &&
file.getFileSystem() == ourSourceRoot.getFileSystem() &&
ourProject != null &&
ourProject.isOpen();
}
@Override
public void iterateIndexableFilesIn(@NotNull final VirtualFile file, @NotNull final ContentIterator iterator) {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
iterator.processFile(file);
return true;
}
});
}
}, null);
updateModel(ourModule, new Consumer<ModifiableRootModel>() {
@Override
public void consume(ModifiableRootModel model) {
if (descriptor.getSdk() != null) {
model.setSdk(descriptor.getSdk());
}
ContentEntry contentEntry = model.addContentEntry(ourSourceRoot);
contentEntry.addSourceFolder(ourSourceRoot, false);
descriptor.configureModule(ourModule, model, contentEntry);
}
});
MessageBusConnection connection = ourProject.getMessageBus().connect();
connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
@Override
public void beforeRootsChange(ModuleRootEvent event) {
/*if (!event.isCausedByFileTypesChange()) {
fail("Root modification in LightIdeaTestCase is not allowed.");
}*/
}
});
connection.subscribe(ProjectTopics.MODULES, new ModuleAdapter() {
@Override
public void moduleAdded(Project project, Module module) {
fail("Adding modules is not permitted in LightIdeaTestCase.");
}
});
StartupManagerImpl startupManager = (StartupManagerImpl)StartupManager.getInstance(ourProject);
startupManager.runStartupActivities();
startupManager.startCacheUpdate();
}
private void cleanSourceRoot() throws IOException {
TempFileSystem tempFs = (TempFileSystem)ourSourceRoot.getFileSystem();
for (VirtualFile child : ourSourceRoot.getChildren()) {
if (!tempFs.exists(child)) {
tempFs.createChildFile(this, ourSourceRoot, child.getName());
}
child.delete(this);
}
}
}.execute().throwException();
// project creation may make a lot of pointers, do not regard them as leak
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).storePointers();
}
protected static Module createMainModule(final ModuleType moduleType) {
return ApplicationManager.getApplication().runWriteAction(new Computable<Module>() {
@Override
public Module compute() {
return ModuleManager.getInstance(ourProject).newModule("light_idea_test_case.iml", moduleType.getId());
}
});
}
/**
* @return The only source root
*/
public static VirtualFile getSourceRoot() {
return ourSourceRoot;
}
@Override
protected void setUp() throws Exception {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
try {
LightPlatformTestCase.super.setUp();
initApplication();
ourApplication.setDataProvider(LightPlatformTestCase.this);
doSetup(new SimpleLightProjectDescriptor(getModuleType(), getProjectJDK()), configureLocalInspectionTools(),
myAvailableInspectionTools);
InjectedLanguageManagerImpl.pushInjectors(getProject());
storeSettings();
myThreadTracker = new ThreadTracker();
ModuleRootManager.getInstance(ourModule).orderEntries().getAllLibrariesAndSdkClassesRoots();
VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
filePointerManager.storePointers();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
public static void doSetup(@NotNull LightProjectDescriptor descriptor,
@NotNull LocalInspectionTool[] localInspectionTools,
@NotNull final Map<String, InspectionToolWrapper> availableInspectionTools) throws Exception {
assertNull("Previous test " + ourTestCase + " hasn't called tearDown(). Probably overridden without super call.", ourTestCase);
IdeaLogger.ourErrorsOccurred = null;
if (ourProject == null || ourProjectDescriptor == null || !ourProjectDescriptor.equals(descriptor)) {
initProject(descriptor);
}
((ProjectImpl)ourProject).setTemporarilyDisposed(false);
ProjectManagerEx projectManagerEx = ProjectManagerEx.getInstanceEx();
projectManagerEx.openTestProject(ourProject);
clearUncommittedDocuments(getProject());
for (LocalInspectionTool tool : localInspectionTools) {
enableInspectionTool(availableInspectionTools, new LocalInspectionToolWrapper(tool));
}
final InspectionProfileImpl profile = new InspectionProfileImpl(PROFILE) {
@Override
@NotNull
public InspectionToolWrapper[] getInspectionTools(PsiElement element) {
final Collection<InspectionToolWrapper> tools = availableInspectionTools.values();
return tools.toArray(new InspectionToolWrapper[tools.size()]);
}
@NotNull
@Override
public List<Tools> getAllEnabledInspectionTools(Project project) {
List<Tools> result = new ArrayList<Tools>();
for (InspectionToolWrapper toolWrapper : getInspectionTools(null)) {
result.add(new ToolsImpl(toolWrapper, toolWrapper.getDefaultLevel(), true));
}
return result;
}
@Override
public boolean isToolEnabled(HighlightDisplayKey key, PsiElement element) {
return key != null && availableInspectionTools.containsKey(key.toString());
}
@Override
public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, PsiElement element) {
InspectionToolWrapper toolWrapper = availableInspectionTools.get(key.toString());
return toolWrapper == null ? HighlightDisplayLevel.WARNING : toolWrapper.getDefaultLevel();
}
@Override
public InspectionToolWrapper getInspectionTool(@NotNull String shortName, @NotNull PsiElement element) {
return availableInspectionTools.get(shortName);
}
@Override
public InspectionToolWrapper getToolById(@NotNull String id, @NotNull PsiElement element) {
return availableInspectionTools.get(id);
}
};
final InspectionProfileManager inspectionProfileManager = InspectionProfileManager.getInstance();
inspectionProfileManager.addProfile(profile);
inspectionProfileManager.setRootProfile(profile.getName());
InspectionProjectProfileManager.getInstance(getProject()).updateProfile(profile);
InspectionProjectProfileManager.getInstance(getProject()).setProjectProfile(profile.getName());
assertFalse(getPsiManager().isDisposed());
Boolean passed = null;
try {
passed = StartupManagerEx.getInstanceEx(getProject()).startupActivityPassed();
}
catch (Exception e) {
}
assertTrue("open: " + getProject().isOpen() +
"; disposed:" + getProject().isDisposed() +
"; startup passed:" + passed +
"; all open projects: " + Arrays.asList(ProjectManager.getInstance().getOpenProjects()), getProject().isInitialized());
CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(new CodeStyleSettings());
final FileDocumentManager manager = FileDocumentManager.getInstance();
if (manager instanceof FileDocumentManagerImpl) {
Document[] unsavedDocuments = manager.getUnsavedDocuments();
manager.saveAllDocuments();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
((FileDocumentManagerImpl)manager).dropAllUnsavedDocuments();
}
});
assertEmpty("There are unsaved documents", Arrays.asList(unsavedDocuments));
}
((FileTypeManagerImpl)FileTypeManager.getInstance()).drainReDetectQueue();
}
// todo: use Class<? extends InspectionProfileEntry> once on Java 7
protected void enableInspectionTools(@NotNull Class<?>... classes) {
final InspectionProfileEntry[] tools = new InspectionProfileEntry[classes.length];
final List<InspectionEP> eps = ContainerUtil.newArrayList();
ContainerUtil.addAll(eps, Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION));
ContainerUtil.addAll(eps, Extensions.getExtensions(InspectionEP.GLOBAL_INSPECTION));
next:
for (int i = 0; i < classes.length; i++) {
for (InspectionEP ep : eps) {
if (classes[i].getName().equals(ep.implementationClass)) {
tools[i] = ep.instantiateTool();
continue next;
}
}
throw new IllegalArgumentException("Unable to find extension point for " + classes[i].getName());
}
enableInspectionTools(tools);
}
protected void enableInspectionTools(@NotNull InspectionProfileEntry... tools) {
for (InspectionProfileEntry tool : tools) {
enableInspectionTool(tool);
}
}
protected void enableInspectionTool(@NotNull InspectionToolWrapper toolWrapper) {
enableInspectionTool(myAvailableInspectionTools, toolWrapper);
}
protected void enableInspectionTool(@NotNull InspectionProfileEntry tool) {
InspectionToolWrapper toolWrapper = InspectionToolRegistrar.wrapTool(tool);
enableInspectionTool(myAvailableInspectionTools, toolWrapper);
}
public static void enableInspectionTool(@NotNull Map<String, InspectionToolWrapper> availableLocalTools,
@NotNull InspectionToolWrapper toolWrapper) {
final String shortName = toolWrapper.getShortName();
final HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
if (key == null) {
String id = toolWrapper instanceof LocalInspectionToolWrapper
? ((LocalInspectionToolWrapper)toolWrapper).getTool().getID()
: toolWrapper.getShortName();
HighlightDisplayKey.register(shortName, toolWrapper.getDisplayName(), id);
}
availableLocalTools.put(shortName, toolWrapper);
}
@NotNull
protected LocalInspectionTool[] configureLocalInspectionTools() {
return LocalInspectionTool.EMPTY_ARRAY;
}
@Override
protected void tearDown() throws Exception {
Project project = getProject();
CodeStyleSettingsManager.getInstance(project).dropTemporarySettings();
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
CompositeException damage = checkForSettingsDamage();
VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
doTearDown(project, ourApplication, true);
try {
super.tearDown();
}
finally {
myThreadTracker.checkLeak();
InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project);
filePointerManager.assertPointersAreDisposed();
}
damage.throwIfNotEmpty();
}
public static void doTearDown(@NotNull final Project project, IdeaTestApplication application, boolean checkForEditors) throws Exception {
((FileTypeManagerImpl)FileTypeManager.getInstance()).drainReDetectQueue();
DocumentCommitThread.getInstance().clearQueue();
CodeStyleSettingsManager.getInstance(project).dropTemporarySettings();
checkAllTimersAreDisposed();
UsefulTestCase.doPostponedFormatting(project);
LookupManager lookupManager = LookupManager.getInstance(project);
if (lookupManager != null) {
lookupManager.hideActiveLookup();
}
((StartupManagerImpl)StartupManager.getInstance(project)).prepareForNextTest();
InspectionProfileManager.getInstance().deleteProfile(PROFILE);
assertNotNull("Application components damaged", ProjectManager.getInstance());
new WriteCommandAction.Simple(project) {
@Override
protected void run() throws Throwable {
if (ourSourceRoot != null) {
try {
final VirtualFile[] children = ourSourceRoot.getChildren();
for (VirtualFile child : children) {
child.delete(this);
}
}
catch (IOException e) {
//noinspection CallToPrintStackTrace
e.printStackTrace();
}
}
EncodingManager encodingManager = EncodingManager.getInstance();
if (encodingManager instanceof EncodingManagerImpl) ((EncodingManagerImpl)encodingManager).clearDocumentQueue();
FileDocumentManager manager = FileDocumentManager.getInstance();
ApplicationManager.getApplication().runWriteAction(EmptyRunnable.getInstance()); // Flush postponed formatting if any.
manager.saveAllDocuments();
if (manager instanceof FileDocumentManagerImpl) {
((FileDocumentManagerImpl)manager).dropAllUnsavedDocuments();
}
}
}.execute().throwException();
assertFalse(PsiManager.getInstance(project).isDisposed());
if (!ourAssertionsInTestDetected) {
if (IdeaLogger.ourErrorsOccurred != null) {
throw IdeaLogger.ourErrorsOccurred;
}
}
PsiDocumentManagerImpl documentManager = clearUncommittedDocuments(project);
((HintManagerImpl)HintManager.getInstance()).cleanup();
DocumentCommitThread.getInstance().clearQueue();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
((UndoManagerImpl)UndoManager.getGlobalInstance()).dropHistoryInTests();
((UndoManagerImpl)UndoManager.getInstance(project)).dropHistoryInTests();
UIUtil.dispatchAllInvocationEvents();
}
});
TemplateDataLanguageMappings.getInstance(project).cleanupForNextTest();
ProjectManagerEx.getInstanceEx().closeTestProject(project);
application.setDataProvider(null);
ourTestCase = null;
((PsiManagerImpl)PsiManager.getInstance(project)).cleanupForNextTest();
CompletionProgressIndicator.cleanupForNextTest();
if (checkForEditors) {
checkEditorsReleased();
}
if (isLight(project)) {
// mark temporarily as disposed so that rogue component trying to access it will fail
((ProjectImpl)project).setTemporarilyDisposed(true);
documentManager.clearUncommittedDocuments();
}
}
public static PsiDocumentManagerImpl clearUncommittedDocuments(@NotNull Project project) {
PsiDocumentManagerImpl documentManager = (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project);
documentManager.clearUncommittedDocuments();
ProjectManagerImpl projectManager = (ProjectManagerImpl)ProjectManager.getInstance();
if (projectManager.isDefaultProjectInitialized()) {
Project defaultProject = projectManager.getDefaultProject();
((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(defaultProject)).clearUncommittedDocuments();
}
return documentManager;
}
public static void checkEditorsReleased() throws Exception {
CompositeException result = new CompositeException();
final Editor[] allEditors = EditorFactory.getInstance().getAllEditors();
if (allEditors.length > 0) {
for (Editor editor : allEditors) {
try {
EditorFactoryImpl.throwNotReleasedError(editor);
}
catch (Throwable e) {
result.add(e);
}
finally {
EditorFactory.getInstance().releaseEditor(editor);
}
}
try {
((EditorImpl)allEditors[0]).throwDisposalError("Unreleased editors: " + allEditors.length);
}
catch (Throwable e) {
e.printStackTrace();
result.add(e);
}
}
if (!result.isEmpty()) throw result;
}
@Override
public final void runBare() throws Throwable {
if (!shouldRunTest()) {
return;
}
final Throwable[] throwables = new Throwable[1];
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
try {
ourTestThread = Thread.currentThread();
startRunAndTear();
}
catch (Throwable throwable) {
throwables[0] = throwable;
}
finally {
ourTestThread = null;
try {
Application application = ApplicationManager.getApplication();
if (application instanceof ApplicationEx) {
PlatformTestCase.cleanupApplicationCaches(ourProject);
}
resetAllFields();
}
catch (Throwable e) {
e.printStackTrace();
}
}
}
});
if (throwables[0] != null) {
throw throwables[0];
}
// just to make sure all deferred Runnables to finish
SwingUtilities.invokeAndWait(EmptyRunnable.getInstance());
if (IdeaLogger.ourErrorsOccurred != null) {
throw IdeaLogger.ourErrorsOccurred;
}
}
private void startRunAndTear() throws Throwable {
setUp();
try {
ourAssertionsInTestDetected = true;
runTest();
ourAssertionsInTestDetected = false;
}
finally {
//try{
tearDown();
//}
//catch(Throwable th){
// noinspection CallToPrintStackTrace
//th.printStackTrace();
//}
}
}
@Override
public Object getData(String dataId) {
if (CommonDataKeys.PROJECT.is(dataId)) {
return ourProject;
}
return null;
}
protected Sdk getProjectJDK() {
return null;
}
protected ModuleType getModuleType() {
return EmptyModuleType.getInstance();
}
/**
* Creates dummy source file. One is not placed under source root so some PSI functions like resolve to external classes
* may not work. Though it works significantly faster and yet can be used if you need to create some PSI structures for
* test purposes
*
* @param fileName - name of the file to create. Extension is used to choose what PSI should be created like java, jsp, aj, xml etc.
* @param text - file text.
* @return dummy psi file.
* @throws com.intellij.util.IncorrectOperationException
*
*/
protected static PsiFile createFile(@NonNls String fileName, @NonNls String text) throws IncorrectOperationException {
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName);
return PsiFileFactory.getInstance(getProject())
.createFileFromText(fileName, fileType, text, LocalTimeCounter.currentTime(), true, false);
}
protected static PsiFile createLightFile(@NonNls String fileName, String text) throws IncorrectOperationException {
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName);
return PsiFileFactory.getInstance(getProject())
.createFileFromText(fileName, fileType, text, LocalTimeCounter.currentTime(), false, false);
}
/**
* Convenient conversion of testSomeTest -> someTest | SomeTest where testSomeTest is the name of current test.
*
* @param lowercaseFirstLetter - whether first letter after test should be lowercased.
*/
@Override
protected String getTestName(boolean lowercaseFirstLetter) {
String name = getName();
assertTrue("Test name should start with 'test': " + name, name.startsWith("test"));
name = name.substring("test".length());
if (!name.isEmpty() && lowercaseFirstLetter && !UsefulTestCase.isAllUppercaseName(name)) {
name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
}
return name;
}
protected static void commitDocument(final Document document) {
PsiDocumentManager.getInstance(getProject()).commitDocument(document);
}
protected static void commitAllDocuments() {
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
}
@Override
protected CodeStyleSettings getCurrentCodeStyleSettings() {
if (CodeStyleSchemes.getInstance().getCurrentScheme() == null) return new CodeStyleSettings();
return CodeStyleSettingsManager.getSettings(getProject());
}
protected static Document getDocument(final PsiFile file) {
return PsiDocumentManager.getInstance(getProject()).getDocument(file);
}
@SuppressWarnings("NonPrivateFieldAccessedInSynchronizedContext")
public static synchronized void closeAndDeleteProject() {
if (ourProject != null) {
ApplicationManager.getApplication().assertWriteAccessAllowed();
((ProjectImpl)ourProject).setTemporarilyDisposed(false);
VirtualFile projectFile = ((ProjectEx)ourProject).getStateStore().getProjectFile();
File ioFile = projectFile == null ? null : VfsUtilCore.virtualToIoFile(projectFile);
if (!ourProject.isDisposed()) Disposer.dispose(ourProject);
if (ioFile != null) {
File dir = ioFile.getParentFile();
if (dir.getName().startsWith(UsefulTestCase.TEMP_DIR_MARKER)) {
FileUtil.delete(dir);
}
else {
FileUtil.delete(ioFile);
}
}
ProjectManagerEx.getInstanceEx().closeTestProject(ourProject);
ourProject = null;
ourPathToKeep = null;
}
}
private static void registerShutdownHook() {
ShutDownTracker.getInstance().registerShutdownTask(new Runnable() {
@Override
public void run() {
ShutDownTracker.invokeAndWait(true, true, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
closeAndDeleteProject();
}
});
}
});
}
});
}
private static class SimpleLightProjectDescriptor implements LightProjectDescriptor {
private final ModuleType myModuleType;
private final Sdk mySdk;
SimpleLightProjectDescriptor(ModuleType moduleType, Sdk sdk) {
myModuleType = moduleType;
mySdk = sdk;
}
@Override
public ModuleType getModuleType() {
return myModuleType;
}
@Override
public Sdk getSdk() {
return mySdk;
}
@Override
public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SimpleLightProjectDescriptor that = (SimpleLightProjectDescriptor)o;
if (myModuleType != null ? !myModuleType.equals(that.myModuleType) : that.myModuleType != null) return false;
return areJdksEqual(that.getSdk());
}
@Override
public int hashCode() {
return myModuleType != null ? myModuleType.hashCode() : 0;
}
private boolean areJdksEqual(final Sdk newSdk) {
if (mySdk == null || newSdk == null) return mySdk == newSdk;
final String[] myUrls = mySdk.getRootProvider().getUrls(OrderRootType.CLASSES);
final String[] newUrls = newSdk.getRootProvider().getUrls(OrderRootType.CLASSES);
return ContainerUtil.newHashSet(myUrls).equals(ContainerUtil.newHashSet(newUrls));
}
}
}