ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / plugins / testng / src / com / theoryinpractice / testng / inspection / UndeclaredTestInspection.java
blob2ea97409b3fb107f8a4e6b8707ea59a5d59d016b
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * User: anna
19 * Date: 18-Jun-2007
21 package com.theoryinpractice.testng.inspection;
23 import com.intellij.codeInspection.*;
24 import com.intellij.openapi.application.Result;
25 import com.intellij.openapi.command.WriteCommandAction;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.openapi.fileChooser.FileChooser;
28 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
29 import com.intellij.openapi.module.Module;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.text.StringUtil;
32 import com.intellij.openapi.vfs.LocalFileSystem;
33 import com.intellij.openapi.vfs.VirtualFile;
34 import com.intellij.psi.*;
35 import com.intellij.psi.search.GlobalSearchScope;
36 import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor;
37 import com.intellij.psi.util.PsiClassUtil;
38 import com.intellij.psi.util.PsiTreeUtil;
39 import com.intellij.psi.xml.XmlAttribute;
40 import com.intellij.psi.xml.XmlFile;
41 import com.intellij.psi.xml.XmlTag;
42 import com.intellij.util.IncorrectOperationException;
43 import com.theoryinpractice.testng.configuration.browser.SuiteBrowser;
44 import com.theoryinpractice.testng.util.TestNGUtil;
45 import org.jetbrains.annotations.Nls;
46 import org.jetbrains.annotations.NonNls;
47 import org.jetbrains.annotations.NotNull;
48 import org.jetbrains.annotations.Nullable;
50 import javax.swing.*;
52 public class UndeclaredTestInspection extends BaseJavaLocalInspectionTool {
53 private static final Logger LOG = Logger.getInstance("#" + UndeclaredTestInspection.class.getName());
55 @Nls
56 @NotNull
57 public String getGroupDisplayName() {
58 return TestNGUtil.TESTNG_GROUP_NAME;
61 @Nls
62 @NotNull
63 public String getDisplayName() {
64 return "Undeclared test";
67 @NonNls
68 @NotNull
69 public String getShortName() {
70 return "UndeclaredTests";
73 @Nullable
74 public ProblemDescriptor[] checkClass(@NotNull final PsiClass aClass,
75 @NotNull final InspectionManager manager,
76 final boolean isOnTheFly) {
77 if (TestNGUtil.hasTest(aClass) && PsiClassUtil.isRunnableClass(aClass, true)) {
78 final Project project = aClass.getProject();
79 final String qName = aClass.getQualifiedName();
80 if (qName == null) return null;
81 final String packageQName = ((PsiJavaFile)aClass.getContainingFile()).getPackageName();
82 final String packageName = StringUtil.getShortName(packageQName);
83 final String[] names;
84 if (packageQName.length() > 0) {
85 final String pName = packageName.length() > 0 ? packageName : packageQName;
86 names = new String[]{qName, pName};
88 else {
89 names = new String[]{qName};
91 for (final String name : names) {
92 final boolean[] found = new boolean[]{false};
93 PsiManager.getInstance(project).getSearchHelper()
94 .processUsagesInNonJavaFiles(name, new PsiNonJavaFileReferenceProcessor() {
95 public boolean process(final PsiFile file, final int startOffset, final int endOffset) {
96 if (file.findReferenceAt(startOffset) != null) {
97 if (packageQName.endsWith(name)) { //special package tag required
98 final XmlTag tag = PsiTreeUtil.getParentOfType(file.findElementAt(startOffset), XmlTag.class);
99 if (tag == null || !tag.getName().equals("package")){
100 return true;
102 final XmlAttribute attribute = tag.getAttribute("name");
103 if (attribute == null) return true;
104 final String value = attribute.getValue();
105 if (!value.equals(StringUtil.getQualifiedName(packageQName, "*"))) return true;
107 found[0] = true;
108 return false;
110 return true;
112 }, new TestNGSearchScope());
113 if (found[0]) return null;
115 final PsiIdentifier nameIdentifier = aClass.getNameIdentifier();
116 LOG.assertTrue(nameIdentifier != null);
117 return new ProblemDescriptor[]{manager.createProblemDescriptor(nameIdentifier, "Undeclared test \'" + aClass.getName() + "\'",
118 isOnTheFly, new LocalQuickFix[]{new RegisterClassFix(aClass),
119 new CreateTestngFix()},
120 ProblemHighlightType.GENERIC_ERROR_OR_WARNING)};
122 return null;
125 private static class RegisterClassFix implements LocalQuickFix {
126 private final PsiClass myClass;
128 public RegisterClassFix(final PsiClass aClass) {
129 myClass = aClass;
132 @NotNull
133 public String getName() {
134 return "Register \'" + myClass.getName() + "\'";
137 @NotNull
138 public String getFamilyName() {
139 return getName();
142 public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) {
143 final PsiClass psiClass = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiClass.class);
144 LOG.assertTrue(psiClass != null);
145 SwingUtilities.invokeLater(new Runnable() { //need to show dialog
147 public void run() {
148 final String testngXmlPath = new SuiteBrowser(project).showDialog();
149 if (testngXmlPath == null) return;
150 final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(testngXmlPath);
151 LOG.assertTrue(virtualFile != null);
152 final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
153 LOG.assertTrue(psiFile instanceof XmlFile);
154 final XmlFile testngXML = (XmlFile)psiFile;
155 new WriteCommandAction(project, getName(), testngXML) {
156 protected void run(final Result result) throws Throwable {
157 patchTestngXml(testngXML, psiClass);
159 }.execute();
165 //make public for tests only
166 public static void patchTestngXml(final XmlFile testngXML, final PsiClass psiClass) {
167 final XmlTag rootTag = testngXML.getDocument().getRootTag();
168 if (rootTag != null && rootTag.getName().equals("suite")) {
169 try {
170 XmlTag testTag = rootTag.findFirstSubTag("test");
171 if (testTag == null) {
172 testTag = (XmlTag)rootTag.add(rootTag.createChildTag("test", rootTag.getNamespace(), null, false));
173 testTag.setAttribute("name", psiClass.getName());
175 XmlTag classesTag = testTag.findFirstSubTag("classes");
176 if (classesTag == null) {
177 classesTag = (XmlTag)testTag.add(testTag.createChildTag("classes", testTag.getNamespace(), null, false));
179 final XmlTag classTag = (XmlTag)classesTag.add(classesTag.createChildTag("class", classesTag.getNamespace(), null, false));
180 final String qualifiedName = psiClass.getQualifiedName();
181 LOG.assertTrue(qualifiedName != null);
182 classTag.setAttribute("name", qualifiedName);
184 catch (IncorrectOperationException e) {
185 LOG.error(e);
190 private static class CreateTestngFix implements LocalQuickFix {
191 @NotNull
192 public String getName() {
193 return "Create suite";
196 @NotNull
197 public String getFamilyName() {
198 return getName();
201 public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
202 final PsiClass psiClass = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiClass.class);
203 SwingUtilities.invokeLater(new Runnable() {
204 public void run() {
205 final VirtualFile[] files = FileChooser.chooseFiles(project, new FileChooserDescriptor(false, true, false, false, false, false));
206 if (files.length == 1) {
207 final PsiManager psiManager = PsiManager.getInstance(project);
208 final PsiDirectory directory = psiManager.findDirectory(files[0]);
209 LOG.assertTrue(directory != null);
210 new WriteCommandAction(project, getName(), null) {
211 protected void run(final Result result) throws Throwable {
212 XmlFile testngXml = (XmlFile)PsiFileFactory.getInstance(psiManager.getProject())
213 .createFileFromText("testng.xml", "<!DOCTYPE suite SYSTEM \"http://testng.org/testng-1.0.dtd\">\n<suite></suite>");
214 try {
215 testngXml = (XmlFile)directory.add(testngXml);
217 catch (IncorrectOperationException e) {
218 //todo suggest new name
219 return;
221 patchTestngXml(testngXml, psiClass);
223 }.execute();
230 private static class TestNGSearchScope extends GlobalSearchScope {
231 public boolean contains(VirtualFile file) {
232 return TestNGUtil.isTestngXML(file);
235 public int compare(VirtualFile file1, VirtualFile file2) {
236 return 0;
239 public boolean isSearchInModuleContent(@NotNull Module aModule) {
240 return true;
243 public boolean isSearchInLibraries() {
244 return false;