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
;
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
;
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() {
111 * @return Module to be used in tests for example for module components retrieval.
113 public static Module
getModule() {
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();
146 if (ourPsiManager != null) {
147 ((PsiManagerImpl)ourPsiManager).cleanupForNextTest();
152 protected void resetAllFields() {
153 resetClassFields(getClass());
156 private void resetClassFields(final Class
<?
> aClass
) {
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"})
178 if (ourProject
!= null) {
179 closeAndDeleteProject();
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:///");
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
);
214 iterator
.processFile(file
);
219 final ModuleRootManager rootManager
= ModuleRootManager
.getInstance(ourModule
);
221 final ModifiableRootModel rootModel
= rootManager
.getModifiableModel();
223 if (projectJDK
!= null) {
225 rootModel
.setSdk(projectJDK
);
228 final ContentEntry contentEntry
= rootModel
.addContentEntry(ourSourceRoot
);
229 contentEntry
.addSourceFolder(ourSourceRoot
, false);
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
{
278 initApplication(this);
279 doSetup(getProjectJDK(), configureLocalInspectionTools(), myAvailableTools
, myAvailableLocalTools
);
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") {
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
));
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
);
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();
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() {
376 final VirtualFile
[] children
= ourSourceRoot
.getChildren();
377 for (VirtualFile aChildren
: children
) {
378 aChildren
.delete(this);
381 catch (IOException e
) {
382 //noinspection CallToPrintStackTrace
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);
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() {
426 ourTestThread
= Thread
.currentThread();
429 catch (Throwable throwable
) {
430 throwables
[0] = throwable
;
433 ourTestThread
= null;
435 cleanupApplicationCaches();
437 catch (Throwable e
) {
444 if (throwables
[0] != null) {
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
{
459 ourAssertionsInTestDetected
= true;
461 ourAssertionsInTestDetected
= false;
467 //catch(Throwable th){
468 // noinspection CallToPrintStackTrace
469 //th.printStackTrace();
474 public Object
getData(String dataId
) {
475 if (dataId
.equals(DataConstants
.PROJECT
)) {
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
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);
530 protected static void commitDocument(final Document document
) {
531 PsiDocumentManager
.getInstance(getProject()).commitDocument(document
);
533 protected static void commitAllDocuments() {
534 PsiDocumentManager
.getInstance(getProject()).commitAllDocuments();
538 protected CodeStyleSettings
getCurrentCodeStyleSettings() {
539 return CodeStyleSettingsManager
.getSettings(getProject());
542 protected static Document
getDocument(final PsiFile file
) {
543 return PsiDocumentManager
.getInstance(getProject()).getDocument(file
);
547 System
.setProperty("jbdt.test.fixture", "com.intellij.designer.dt.IJTestFixture");
549 ShutDownTracker
.getInstance().registerShutdownThread(0, new Thread(new Runnable() {
552 SwingUtilities
.invokeAndWait(new Runnable() {
554 closeAndDeleteProject();
558 catch (InterruptedException e
) {
561 catch (InvocationTargetException e
) {
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
);