cleanup
[fedora-idea.git] / ExtendedApi / src / com / intellij / testFramework / LightIdeaTestCase.java
blob07ff5ad09649dae044c5c61d36b3783987fcf854
1 package com.intellij.testFramework;
3 import com.intellij.ProjectTopics;
4 import com.intellij.codeHighlighting.HighlightDisplayLevel;
5 import com.intellij.codeInsight.daemon.HighlightDisplayKey;
6 import com.intellij.codeInsight.lookup.LookupManager;
7 import com.intellij.codeInspection.InspectionProfileEntry;
8 import com.intellij.codeInspection.LocalInspectionTool;
9 import com.intellij.codeInspection.ex.InspectionProfileImpl;
10 import com.intellij.codeInspection.ex.InspectionTool;
11 import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
12 import com.intellij.ide.startup.impl.StartupManagerImpl;
13 import com.intellij.ide.highlighter.ProjectFileType;
14 import com.intellij.idea.IdeaLogger;
15 import com.intellij.idea.IdeaTestApplication;
16 import com.intellij.openapi.actionSystem.DataConstants;
17 import com.intellij.openapi.actionSystem.DataProvider;
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.command.undo.UndoManager;
20 import com.intellij.openapi.editor.Document;
21 import com.intellij.openapi.editor.Editor;
22 import com.intellij.openapi.editor.EditorFactory;
23 import com.intellij.openapi.fileEditor.FileDocumentManager;
24 import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
25 import com.intellij.openapi.fileTypes.FileTypeManager;
26 import com.intellij.openapi.module.Module;
27 import com.intellij.openapi.module.ModuleManager;
28 import com.intellij.openapi.module.StdModuleTypes;
29 import com.intellij.openapi.project.ModuleListener;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.project.ProjectManager;
32 import com.intellij.openapi.project.ex.ProjectEx;
33 import com.intellij.openapi.project.ex.ProjectManagerEx;
34 import com.intellij.openapi.projectRoots.Sdk;
35 import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
36 import com.intellij.openapi.roots.*;
37 import com.intellij.openapi.startup.StartupManager;
38 import com.intellij.openapi.util.*;
39 import com.intellij.openapi.util.io.FileUtil;
40 import com.intellij.openapi.vfs.LocalFileSystem;
41 import com.intellij.openapi.vfs.VfsUtil;
42 import com.intellij.openapi.vfs.VirtualFile;
43 import com.intellij.openapi.vfs.VirtualFileManager;
44 import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
45 import com.intellij.openapi.vfs.newvfs.ManagingFS;
46 import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
47 import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
48 import com.intellij.profile.codeInspection.InspectionProfileManager;
49 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
50 import com.intellij.psi.PsiDocumentManager;
51 import com.intellij.psi.PsiFile;
52 import com.intellij.psi.PsiFileFactory;
53 import com.intellij.psi.PsiManager;
54 import com.intellij.psi.codeStyle.CodeStyleSettings;
55 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
56 import com.intellij.psi.impl.JavaPsiFacadeEx;
57 import com.intellij.psi.impl.PsiDocumentManagerImpl;
58 import com.intellij.psi.impl.PsiManagerEx;
59 import com.intellij.psi.impl.PsiManagerImpl;
60 import com.intellij.util.IncorrectOperationException;
61 import com.intellij.util.LocalTimeCounter;
62 import com.intellij.util.indexing.FileBasedIndex;
63 import com.intellij.util.indexing.IndexableFileSet;
64 import com.intellij.util.messages.MessageBusConnection;
65 import junit.framework.TestCase;
66 import org.jetbrains.annotations.NonNls;
67 import org.jetbrains.annotations.NotNull;
69 import javax.swing.*;
70 import java.io.File;
71 import java.io.IOException;
72 import java.lang.reflect.InvocationTargetException;
73 import java.util.Collection;
74 import java.util.HashMap;
75 import java.util.List;
76 import java.util.Map;
78 /**
79 * A testcase that provides IDEA application and project. Note both are reused for each test run in the session so
80 * be careful to return all the modification made to application and project components (such as settings) after
81 * test is finished so other test aren't affected. The project is initialized with single module that have single
82 * content&source entry. For your convinience the project may be equipped with some mock JDK so your tests may
83 * refer to external classes. In order to enable this feature you have to have a folder named "mockJDK" under
84 * idea installation home that is used for test running. Place src.zip under that folder. We'd suggest this is real mock
85 * so it contains classes that is really needed in order to speed up tests startup.
87 @SuppressWarnings({"HardCodedStringLiteral"})
88 @NonNls public class LightIdeaTestCase extends UsefulTestCase implements DataProvider {
89 protected static final String PROFILE = "Configurable";
90 private static IdeaTestApplication ourApplication;
91 private static Project ourProject;
92 private static Module ourModule;
93 private static Sdk ourJDK;
94 private static PsiManager ourPsiManager;
95 private static boolean ourAssertionsInTestDetected;
96 private static VirtualFile ourSourceRoot;
97 private static TestCase ourTestCase = null;
98 public static Thread ourTestThread;
100 private final Map<String, LocalInspectionTool> myAvailableTools = new HashMap<String, LocalInspectionTool>();
101 private final Map<String, LocalInspectionToolWrapper> myAvailableLocalTools = new HashMap<String, LocalInspectionToolWrapper>();
104 * @return Project to be used in tests for example for project components retrieval.
106 public static Project getProject() {
107 return ourProject;
111 * @return Module to be used in tests for example for module components retrieval.
113 public static Module getModule() {
114 return ourModule;
118 * Shortcut to PsiManager.getInstance(getProject())
120 public static PsiManager getPsiManager() {
121 if (ourPsiManager == null) {
122 ourPsiManager = PsiManager.getInstance(ourProject);
124 return ourPsiManager;
127 public static JavaPsiFacadeEx getJavaFacade() {
128 return JavaPsiFacadeEx.getInstanceEx(ourProject);
131 public static void initApplication(final DataProvider dataProvider) throws Exception {
132 ourApplication = IdeaTestApplication.getInstance();
133 ourApplication.setDataProvider(dataProvider);
136 private void cleanupApplicationCaches() {
137 ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).cleanupForNextTest();
138 if (ourProject != null) {
139 UndoManager.getInstance(ourProject).dropHistory();
140 ((PsiManagerEx)getPsiManager()).getFileManager().cleanupForNextTest();
143 resetAllFields();
146 if (ourPsiManager != null) {
147 ((PsiManagerImpl)ourPsiManager).cleanupForNextTest();
152 protected void resetAllFields() {
153 resetClassFields(getClass());
156 private void resetClassFields(final Class<?> aClass) {
157 try {
158 UsefulTestCase.clearDeclaredFields(this, aClass);
160 catch (IllegalAccessException e) {
161 throw new RuntimeException(e);
164 if (aClass == LightIdeaTestCase.class) return;
165 resetClassFields(aClass.getSuperclass());
168 private static void cleanPersistedVFSContent() {
169 ((PersistentFS)ManagingFS.getInstance()).cleanPersistedContents();
173 private static void initProject(final Sdk projectJDK) throws Exception {
174 final File projectFile = File.createTempFile("lighttemp", ProjectFileType.DOT_DEFAULT_EXTENSION);
175 ApplicationManager.getApplication().runWriteAction(new Runnable() {
176 @SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"})
177 public void run() {
178 if (ourProject != null) {
179 closeAndDeleteProject();
181 else {
182 cleanPersistedVFSContent();
185 LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectFile);
186 ourProject = ProjectManagerEx.getInstanceEx().newProject(FileUtil.getNameWithoutExtension(projectFile), projectFile.getPath(), false, false);
187 ourPsiManager = null;
188 ourModule = createMainModule();
191 //ourSourceRoot = DummyFileSystem.getInstance().createRoot("src");
193 final VirtualFile dummyRoot = VirtualFileManager.getInstance().findFileByUrl("temp:///");
195 try {
196 ourSourceRoot = dummyRoot.createChildDirectory(this, "src");
198 catch (IOException e) {
199 throw new RuntimeException(e);
202 FileBasedIndex.getInstance().registerIndexableSet(new IndexableFileSet() {
203 public boolean isInSet(final VirtualFile file) {
204 return file.getFileSystem() == ourSourceRoot.getFileSystem();
207 public void iterateIndexableFilesIn(final VirtualFile file, final ContentIterator iterator) {
208 if (file.isDirectory()) {
209 for (VirtualFile child : file.getChildren()) {
210 iterateIndexableFilesIn(child, iterator);
213 else {
214 iterator.processFile(file);
219 final ModuleRootManager rootManager = ModuleRootManager.getInstance(ourModule);
221 final ModifiableRootModel rootModel = rootManager.getModifiableModel();
223 if (projectJDK != null) {
224 ourJDK = projectJDK;
225 rootModel.setSdk(projectJDK);
228 final ContentEntry contentEntry = rootModel.addContentEntry(ourSourceRoot);
229 contentEntry.addSourceFolder(ourSourceRoot, false);
231 rootModel.commit();
233 final MessageBusConnection connection = ourProject.getMessageBus().connect();
234 connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
235 public void beforeRootsChange(ModuleRootEvent event) {
236 if (!event.isCausedByFileTypesChange()) {
237 fail("Root modification in LightIdeaTestCase is not allowed.");
241 public void rootsChanged(ModuleRootEvent event) {}
244 connection.subscribe(ProjectTopics.MODULES, new ModuleListener() {
245 public void moduleAdded(Project project, Module module) {
246 fail("Adding modules is not permitted in LightIdeaTestCase.");
249 public void beforeModuleRemoved(Project project, Module module) {}
250 public void moduleRemoved(Project project, Module module) {}
251 public void modulesRenamed(Project project, List<Module> modules) {}
255 //((PsiManagerImpl) PsiManager.getInstance(ourProject)).runPreStartupActivity();
256 ((StartupManagerImpl)StartupManager.getInstance(getProject())).runStartupActivities();
261 protected static Module createMainModule() {
262 return ApplicationManager.getApplication().runWriteAction(new Computable<Module>() {
263 public Module compute() {
264 return ModuleManager.getInstance(ourProject).newModule("light_idea_test_case.iml", StdModuleTypes.JAVA);
270 * @return The only source root
272 protected static VirtualFile getSourceRoot() {
273 return ourSourceRoot;
276 protected void setUp() throws Exception {
277 super.setUp();
278 initApplication(this);
279 doSetup(getProjectJDK(), configureLocalInspectionTools(), myAvailableTools, myAvailableLocalTools);
280 storeSettings();
283 public static void doSetup(final Sdk projectJDK,
284 final LocalInspectionTool[] localInspectionTools,
285 final Map<String, LocalInspectionTool> availableToolsMap,
286 final Map<String, LocalInspectionToolWrapper> availableLocalTools) throws Exception {
287 assertNull("Previous test " + ourTestCase + " hasn't called tearDown(). Probably overriden without super call.", ourTestCase);
288 IdeaLogger.ourErrorsOccurred = null;
290 if (ourProject == null || isJDKChanged(projectJDK)) {
291 initProject(projectJDK);
294 ProjectManagerEx.getInstanceEx().setCurrentTestProject(ourProject);
296 for (LocalInspectionTool tool : localInspectionTools) {
297 _enableInspectionTool(tool, availableToolsMap, availableLocalTools);
300 final InspectionProfileImpl profile = new InspectionProfileImpl("Configurable") {
301 @NotNull
302 public InspectionProfileEntry[] getInspectionTools() {
303 if (availableLocalTools != null){
304 final Collection<LocalInspectionToolWrapper> tools = availableLocalTools.values();
305 return tools.toArray(new LocalInspectionToolWrapper[tools.size()]);
307 return new InspectionProfileEntry[0];
310 public boolean isToolEnabled(HighlightDisplayKey key) {
311 return key != null && availableToolsMap.containsKey(key.toString());
314 public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key) {
315 final LocalInspectionTool localInspectionTool = key != null ? availableToolsMap.get(key.toString()) : null;
316 return localInspectionTool != null ? localInspectionTool.getDefaultLevel() : HighlightDisplayLevel.WARNING;
320 public InspectionTool getInspectionTool(@NotNull String shortName) {
321 if (availableToolsMap.containsKey(shortName)) {
322 return new LocalInspectionToolWrapper(availableToolsMap.get(shortName));
324 return null;
328 final InspectionProfileManager inspectionProfileManager = InspectionProfileManager.getInstance();
329 inspectionProfileManager.addProfile(profile);
330 inspectionProfileManager.setRootProfile(profile.getName());
331 InspectionProjectProfileManager.getInstance(getProject()).updateProfile(profile);
333 assertFalse(getPsiManager().isDisposed());
335 CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(new CodeStyleSettings());
338 protected void enableInspectionTool(LocalInspectionTool tool){
339 _enableInspectionTool(tool, myAvailableTools, myAvailableLocalTools);
342 private static void _enableInspectionTool(final LocalInspectionTool tool,
343 final Map<String, LocalInspectionTool> availableToolsMap,
344 final Map<String, LocalInspectionToolWrapper> availableLocalTools) {
345 final String shortName = tool.getShortName();
346 final HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
347 if (key == null){
348 HighlightDisplayKey.register(shortName, tool.getDisplayName(), tool.getID());
350 availableToolsMap.put(shortName, tool);
351 availableLocalTools.put(shortName, new LocalInspectionToolWrapper(tool));
354 protected LocalInspectionTool[] configureLocalInspectionTools() {
355 return new LocalInspectionTool[0];
358 protected void tearDown() throws Exception {
359 CodeStyleSettingsManager.getInstance(getProject()).dropTemporarySettings();
360 checkForSettingsDamage();
361 doTearDown();
362 super.tearDown();
365 public static void doTearDown() throws Exception {
366 IdeaTestCase.doPostponedFormatting(ourProject);
368 LookupManager.getInstance(ourProject).hideActiveLookup();
370 InspectionProfileManager.getInstance().deleteProfile(PROFILE);
371 assertNotNull("Application components damaged", ProjectManager.getInstance());
373 ApplicationManager.getApplication().runWriteAction(new Runnable() {
374 public void run() {
375 try {
376 final VirtualFile[] children = ourSourceRoot.getChildren();
377 for (VirtualFile aChildren : children) {
378 aChildren.delete(this);
381 catch (IOException e) {
382 //noinspection CallToPrintStackTrace
383 e.printStackTrace();
385 FileDocumentManager manager = FileDocumentManager.getInstance();
386 if (manager instanceof FileDocumentManagerImpl) {
387 ((FileDocumentManagerImpl)manager).dropAllUnsavedDocuments();
391 // final Project[] openProjects = ProjectManagerEx.getInstanceEx().getOpenProjects();
392 // assertTrue(Arrays.asList(openProjects).contains(ourProject));
393 assertFalse(PsiManager.getInstance(getProject()).isDisposed());
394 if (!ourAssertionsInTestDetected) {
395 if (IdeaLogger.ourErrorsOccurred != null) {
396 throw IdeaLogger.ourErrorsOccurred;
398 //assertTrue("Logger errors occurred. ", IdeaLogger.ourErrorsOccurred == null);
400 ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(getProject())).clearUncommitedDocuments();
404 UndoManager.getGlobalInstance().dropHistory();
406 ProjectManagerEx.getInstanceEx().setCurrentTestProject(null);
407 ourApplication.setDataProvider(null);
408 ourTestCase = null;
409 ((PsiManagerImpl)ourPsiManager).cleanupForNextTest();
411 final Editor[] allEditors = EditorFactory.getInstance().getAllEditors();
412 if (allEditors.length > 0) {
413 for (Editor allEditor : allEditors) {
414 EditorFactory.getInstance().releaseEditor(allEditor);
416 fail("Unreleased editors: " + allEditors.length);
420 public final void runBare() throws Throwable {
421 final Throwable[] throwables = new Throwable[1];
423 SwingUtilities.invokeAndWait(new Runnable() {
424 public void run() {
425 try {
426 ourTestThread = Thread.currentThread();
427 startRunAndTear();
429 catch (Throwable throwable) {
430 throwables[0] = throwable;
432 finally {
433 ourTestThread = null;
434 try {
435 cleanupApplicationCaches();
437 catch (Throwable e) {
438 e.printStackTrace();
444 if (throwables[0] != null) {
445 throw throwables[0];
448 // just to make sure all deffered Runnable's to finish
449 SwingUtilities.invokeAndWait(EmptyRunnable.getInstance());
451 if (IdeaLogger.ourErrorsOccurred != null) {
452 throw IdeaLogger.ourErrorsOccurred;
456 private void startRunAndTear() throws Throwable {
457 setUp();
458 try {
459 ourAssertionsInTestDetected = true;
460 runTest();
461 ourAssertionsInTestDetected = false;
463 finally {
464 //try{
465 tearDown();
467 //catch(Throwable th){
468 // noinspection CallToPrintStackTrace
469 //th.printStackTrace();
474 public Object getData(String dataId) {
475 if (dataId.equals(DataConstants.PROJECT)) {
476 return ourProject;
478 else {
479 return null;
483 private static boolean isJDKChanged(final Sdk newJDK) {
484 return ourJDK == null || newJDK == null || !Comparing.equal(ourJDK.getVersionString(), newJDK.getVersionString());
487 protected Sdk getProjectJDK() {
488 return JavaSdkImpl.getMockJdk("java 1.4");
492 * Creates dummy source file. One is not placed under source root so some PSI functions like resolve to external classes
493 * may not work. Though it works significantly faster and yet can be used if you need to create some PSI structures for
494 * test purposes
496 * @param fileName - name of the file to create. Extension is used to choose what PSI should be created like java, jsp, aj, xml etc.
497 * @param text - file text.
498 * @return dummy psi file.
499 * @throws IncorrectOperationException
501 protected static PsiFile createFile(@NonNls String fileName, String text) throws IncorrectOperationException {
502 return createPseudoPhysicalFile(fileName, text);
505 protected static PsiFile createLightFile(String fileName, String text) throws IncorrectOperationException {
506 return PsiFileFactory.getInstance(getProject()).createFileFromText(fileName, FileTypeManager.getInstance().getFileTypeByFileName(
507 fileName), text, LocalTimeCounter.currentTime(), false);
510 protected static PsiFile createPseudoPhysicalFile(String fileName, String text) throws IncorrectOperationException {
511 return PsiFileFactory.getInstance(getProject()).createFileFromText(fileName, FileTypeManager.getInstance().getFileTypeByFileName(
512 fileName), text, LocalTimeCounter.currentTime(), true);
516 * Convinient conversion of testSomeTest -> someTest | SomeTest where testSomeTest is the name of current test.
518 * @param lowercaseFirstLetter - whether first letter after test should be lowercased.
520 protected String getTestName(boolean lowercaseFirstLetter) {
521 String name = getName();
522 assertTrue("Test name should start with 'test'", name.startsWith("test"));
523 name = name.substring("test".length());
524 if (lowercaseFirstLetter) {
525 name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
527 return name;
530 protected static void commitDocument(final Document document) {
531 PsiDocumentManager.getInstance(getProject()).commitDocument(document);
533 protected static void commitAllDocuments() {
534 PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
537 @Override
538 protected CodeStyleSettings getCurrentCodeStyleSettings() {
539 return CodeStyleSettingsManager.getSettings(getProject());
542 protected static Document getDocument(final PsiFile file) {
543 return PsiDocumentManager.getInstance(getProject()).getDocument(file);
546 static {
547 System.setProperty("jbdt.test.fixture", "com.intellij.designer.dt.IJTestFixture");
549 ShutDownTracker.getInstance().registerShutdownThread(0, new Thread(new Runnable() {
550 public void run() {
551 try {
552 SwingUtilities.invokeAndWait(new Runnable() {
553 public void run() {
554 closeAndDeleteProject();
558 catch (InterruptedException e) {
559 e.printStackTrace();
561 catch (InvocationTargetException e) {
562 e.printStackTrace();
565 }));
568 private static synchronized void closeAndDeleteProject() {
569 if (ourProject != null) {
570 final VirtualFile projFile = ((ProjectEx)ourProject).getStateStore().getProjectFile();
571 final File projectFile = projFile == null ? null : VfsUtil.virtualToIoFile(projFile);
572 if (!ourProject.isDisposed()) Disposer.dispose(ourProject);
574 if (projectFile != null) {
575 FileUtil.delete(projectFile);