class members refactoring refactoring
[fedora-idea.git] / source / com / intellij / testIntegration / createTest / CreateTestAction.java
blobc34afe44439ebc25cc061f477d5cc24618ec1e68
1 package com.intellij.testIntegration.createTest;
3 import com.intellij.codeInsight.CodeInsightBundle;
4 import com.intellij.codeInsight.CodeInsightUtil;
5 import com.intellij.codeInsight.daemon.impl.analysis.HighlightNamesUtil;
6 import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
7 import com.intellij.openapi.application.ApplicationManager;
8 import com.intellij.openapi.editor.Editor;
9 import com.intellij.openapi.extensions.Extensions;
10 import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
11 import com.intellij.openapi.module.Module;
12 import com.intellij.openapi.module.ModuleUtil;
13 import com.intellij.openapi.project.Project;
14 import com.intellij.openapi.roots.ProjectRootManager;
15 import com.intellij.openapi.ui.Messages;
16 import com.intellij.openapi.util.TextRange;
17 import com.intellij.openapi.vfs.VirtualFile;
18 import com.intellij.psi.*;
19 import com.intellij.psi.impl.source.PostprocessReformattingAspect;
20 import com.intellij.psi.search.GlobalSearchScope;
21 import com.intellij.psi.util.PsiTreeUtil;
22 import com.intellij.refactoring.util.classMembers.MemberInfo;
23 import com.intellij.testIntegration.TestFrameworkDescriptor;
24 import com.intellij.testIntegration.TestIntegrationUtils;
25 import com.intellij.util.IncorrectOperationException;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.annotations.Nullable;
29 import java.util.Collection;
31 public class CreateTestAction extends PsiElementBaseIntentionAction {
32 @NotNull
33 public String getText() {
34 return CodeInsightBundle.message("intention.create.test");
37 @NotNull
38 public String getFamilyName() {
39 return getText();
42 public boolean isAvailable(@NotNull Project project, Editor editor, @Nullable PsiElement element) {
43 if (element == null) return false;
44 if (Extensions.getExtensions(TestFrameworkDescriptor.EXTENSION_NAME).length == 0) return false;
46 if (!isAvailableForElement(element)) return false;
48 PsiClass psiClass = getContainingClass(element);
50 PsiJavaToken leftBrace = psiClass.getLBrace();
51 if (leftBrace == null) return false;
52 if (element.getTextOffset() >= leftBrace.getTextOffset()) return false;
54 TextRange declarationRange = HighlightNamesUtil.getClassDeclarationTextRange(psiClass);
55 if (!declarationRange.contains(element.getTextRange())) return false;
57 return true;
60 public boolean isAvailableForElement(PsiElement element) {
61 if (element == null) return false;
63 PsiClass psiClass = getContainingClass(element);
65 if (psiClass == null) return false;
67 Module srcModule = ModuleUtil.findModuleForPsiElement(psiClass);
68 if (srcModule == null) return false;
70 if (psiClass.isAnnotationType() ||
71 psiClass.isInterface() ||
72 psiClass.isEnum() ||
73 psiClass instanceof PsiAnonymousClass ||
74 PsiTreeUtil.getParentOfType(psiClass, PsiClass.class) != null || // inner
75 isUnderTestSources(psiClass)) {
76 return false;
78 return true;
81 private boolean isUnderTestSources(PsiClass c) {
82 ProjectRootManager rm = ProjectRootManager.getInstance(c.getProject());
83 VirtualFile f = c.getContainingFile().getVirtualFile();
84 if (f == null) return false;
85 return rm.getFileIndex().isInTestSourceContent(f);
88 public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
89 PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
91 final Module srcModule = ModuleUtil.findModuleForPsiElement(file);
92 final PsiClass srcClass = getContainingClass(element);
94 if (srcClass == null) return;
96 PsiDirectory srcDir = file.getContainingDirectory();
97 PsiPackage srcPackage = JavaDirectoryService.getInstance().getPackage(srcDir);
99 final CreateTestDialog d = new CreateTestDialog(project,
100 getText(),
101 srcClass,
102 srcPackage,
103 srcModule);
104 d.show();
105 if (!d.isOK()) return;
107 PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(new Runnable() {
108 public void run() {
109 ApplicationManager.getApplication().runWriteAction(new Runnable() {
110 public void run() {
111 try {
112 IdeDocumentHistory.getInstance(project).includeCurrentPlaceAsChangePlace();
114 PsiClass targetClass = JavaDirectoryService.getInstance().createClass(d.getTargetDirectory(), d.getClassName());
115 addSuperClass(targetClass, project, d.getSuperClassName());
116 Editor editor = CodeInsightUtil.positionCursor(project, targetClass.getContainingFile(), targetClass.getLBrace());
118 addTestMethods(editor,
119 targetClass,
120 d.getSelectedTestFrameworkDescriptor(),
121 d.getSelectedMethods(),
122 d.shouldGeneratedBefore(),
123 d.shouldGeneratedAfter());
125 catch (IncorrectOperationException e) {
126 showErrorLater(project, d.getClassName());
134 private void showErrorLater(final Project project, final String targetClassName) {
135 ApplicationManager.getApplication().invokeLater(new Runnable() {
136 public void run() {
137 Messages.showErrorDialog(project,
138 CodeInsightBundle.message("intention.error.cannot.create.class.message", targetClassName),
139 CodeInsightBundle.message("intention.error.cannot.create.class.title"));
144 private void addSuperClass(PsiClass targetClass, Project project, String superClassName) throws IncorrectOperationException {
145 if (superClassName == null) return;
147 PsiElementFactory ef = JavaPsiFacade.getInstance(project).getElementFactory();
148 PsiJavaCodeReferenceElement superClassRef;
150 PsiClass superClass = findClass(project, superClassName);
151 if (superClass != null) {
152 superClassRef = ef.createClassReferenceElement(superClass);
154 else {
155 superClassRef = ef.createFQClassNameReferenceElement(superClassName, GlobalSearchScope.allScope(project));
157 targetClass.getExtendsList().add(superClassRef);
160 private PsiClass findClass(Project project, String fqName) {
161 GlobalSearchScope scope = GlobalSearchScope.allScope(project);
162 return JavaPsiFacade.getInstance(project).findClass(fqName, scope);
165 private void addTestMethods(Editor editor,
166 PsiClass targetClass,
167 TestFrameworkDescriptor descriptor,
168 Collection<MemberInfo> methods,
169 boolean generateBefore,
170 boolean generateAfter) throws IncorrectOperationException {
171 if (generateBefore) {
172 generateMethod(TestIntegrationUtils.MethodKind.SET_UP, descriptor, targetClass, editor, "setUp");
174 if (generateAfter) {
175 generateMethod(TestIntegrationUtils.MethodKind.TEAR_DOWN, descriptor, targetClass, editor, "tearUp");
177 for (MemberInfo m : methods) {
178 generateMethod(TestIntegrationUtils.MethodKind.TEST, descriptor, targetClass, editor, m.getMember().getName());
182 private void generateMethod(TestIntegrationUtils.MethodKind methodKind, TestFrameworkDescriptor descriptor, PsiClass targetClass, Editor editor, String name) {
183 PsiMethod method = (PsiMethod)targetClass.add(TestIntegrationUtils.createDummyMethod(targetClass.getProject()));
184 PsiDocumentManager.getInstance(targetClass.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument());
185 TestIntegrationUtils.runTestMethodTemplate(methodKind, descriptor, editor, targetClass, method, name, true);
188 private PsiClass getContainingClass(PsiElement element) {
189 return PsiTreeUtil.getParentOfType(element, PsiClass.class, false);
192 public boolean startInWriteAction() {
193 return false;