'generate test' improvements for Groovy

This commit is contained in:
Maxim.Medvedev
2011-10-27 15:53:23 +04:00
parent 1fa7bdb518
commit fbaf72456a
16 changed files with 460 additions and 98 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -22,6 +22,7 @@ import com.intellij.ide.util.PackageUtil;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
@@ -30,6 +31,7 @@ import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.module.Module;
@@ -56,6 +58,7 @@ import com.intellij.testIntegration.TestIntegrationUtils;
import com.intellij.ui.*;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -70,7 +73,6 @@ public class CreateTestDialog extends DialogWrapper {
private static final String RECENTS_KEY = "CreateTestDialog.RecentsKey";
private static final String DEFAULT_LIBRARY_NAME_PROPERTY = CreateTestDialog.class.getName() + ".defaultLibrary";
private static final String SHOW_INHERITED_MEMBERS_PROPERTY = CreateTestDialog.class.getName() + ".includeInheritedMembers";
private static final String DEFAULT_LANGUAGE = CreateTestDialog.class.getName() + ".defaultLanguage";
private final Project myProject;
private final PsiClass myTargetClass;
@@ -171,20 +173,18 @@ public class CreateTestDialog extends DialogWrapper {
TestGenerator[] generators = TestGenerator.EP_NAME.getExtensions();
myLanguageCombo = new ComboBox(generators, -1);
final String defaultLanguage = getDefaultLanguage();
if (defaultLanguage != null) {
for (TestGenerator generator : generators) {
if (defaultLanguage.equals(generator.toString())) {
myLanguageCombo.setSelectedItem(generator);
break;
}
final Language curLang = myTargetClass.getLanguage();
for (TestGenerator generator : generators) {
if (curLang == generator.getLanguage()) {
myLanguageCombo.setSelectedItem(generator);
break;
}
}
myTargetClassNameField = new EditorTextField(targetClass.getName() + "Test");
myTargetClassNameField.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
public void documentChanged(com.intellij.openapi.editor.event.DocumentEvent e) {
public void documentChanged(DocumentEvent e) {
getOKAction().setEnabled(JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(getClassName()));
}
});
@@ -249,14 +249,6 @@ public class CreateTestDialog extends DialogWrapper {
getProperties().setValue(DEFAULT_LIBRARY_NAME_PROPERTY, mySelectedFramework.getName());
}
private String getDefaultLanguage() {
return getProperties().getValue(DEFAULT_LANGUAGE);
}
private void saveDefaultLanguage() {
getProperties().setValue(DEFAULT_LANGUAGE, myLanguageCombo.getSelectedItem().toString());
}
private void restoreShowInheritedMembersStatus() {
String v = getProperties().getValue(SHOW_INHERITED_MEMBERS_PROPERTY);
myShowInheritedMethodsBox.setSelected(v != null && v.equals("true"));
@@ -416,6 +408,7 @@ public class CreateTestDialog extends DialogWrapper {
return myTargetClassNameField.getText();
}
@Nullable
public String getSuperClassName() {
String result = mySuperClassField.getText().trim();
if (result.length() == 0) return null;
@@ -461,10 +454,10 @@ public class CreateTestDialog extends DialogWrapper {
saveDefaultLibraryName();
saveShowInheritedMembersStatus();
saveDefaultLanguage();
super.doOKAction();
}
@Nullable
private PsiDirectory selectTargetDirectory() throws IncorrectOperationException {
final String packageName = getPackageName();
final PackageWrapper targetPackage = new PackageWrapper(PsiManager.getInstance(myProject), packageName);
@@ -493,6 +486,7 @@ public class CreateTestDialog extends DialogWrapper {
}.execute().getResultObject();
}
@Nullable
private PsiDirectory chooseDefaultDirectory(String packageName) {
for (ContentEntry e : ModuleRootManager.getInstance(myTargetModule).getContentEntries()) {
for (SourceFolder f : e.getSourceFolders()) {
@@ -17,6 +17,8 @@ package com.intellij.testIntegration.createTest;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.lang.Language;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
@@ -34,7 +36,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public class JavaTestGenerator implements TestGenerator{
public class JavaTestGenerator implements TestGenerator {
public JavaTestGenerator() {
}
@@ -91,11 +93,11 @@ public class JavaTestGenerator implements TestGenerator{
}
private static void addTestMethods(Editor editor,
PsiClass targetClass,
TestFramework descriptor,
Collection<MemberInfo> methods,
boolean generateBefore,
boolean generateAfter) throws IncorrectOperationException {
PsiClass targetClass,
TestFramework descriptor,
Collection<MemberInfo> methods,
boolean generateBefore,
boolean generateAfter) throws IncorrectOperationException {
if (generateBefore) {
generateMethod(TestIntegrationUtils.MethodKind.SET_UP, descriptor, targetClass, editor, null);
}
@@ -117,7 +119,11 @@ public class JavaTestGenerator implements TestGenerator{
});
}
private static void generateMethod(TestIntegrationUtils.MethodKind methodKind, TestFramework descriptor, PsiClass targetClass, Editor editor, String name) {
private static void generateMethod(TestIntegrationUtils.MethodKind methodKind,
TestFramework descriptor,
PsiClass targetClass,
Editor editor,
@Nullable String name) {
PsiMethod method = (PsiMethod)targetClass.add(TestIntegrationUtils.createDummyMethod(targetClass.getProject()));
PsiDocumentManager.getInstance(targetClass.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument());
TestIntegrationUtils.runTestMethodTemplate(methodKind, descriptor, editor, targetClass, method, name, true);
@@ -127,4 +133,9 @@ public class JavaTestGenerator implements TestGenerator{
public String toString() {
return CodeInsightBundle.message("intention.create.test.dialog.java");
}
@Override
public Language getLanguage() {
return JavaLanguage.INSTANCE;
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.testIntegration.createTest;
import com.intellij.lang.Language;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
@@ -37,4 +38,6 @@ public interface TestGenerator {
* should return text to show in dialog
*/
String toString();
Language getLanguage();
}
@@ -0,0 +1,3 @@
void setUp() {
${BODY}
}
@@ -0,0 +1,27 @@
<html>
<body>
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td colspan="3"><font face="verdana" size="-1">
This is a template used by <b>IDEA</b> to create a setUp method in a Groovy JUnit test class.
</font>
</td>
</tr>
</table>
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td colspan="3"><font face="verdana" size="-1">Predefined variables will take the following values:</font></td>
</tr>
<tr>
<td valign="top"><nobr><font face="verdana" size="-2" color="#7F0000"><b><i>${NAME}</i></b></font></nobr></td>
<td width="10">&nbsp;</td>
<td valign="top"><font face="verdana" size="-1">name of the created method.</font></td>
</tr>
<tr>
<td valign="top"><nobr><font face="verdana" size="-2" color="#7F0000"><b><i>${BODY}</i></b></font></nobr></td>
<td width="10">&nbsp;</td>
<td valign="top"><font face="verdana" size="-1">generated method body.</font></td>
</tr>
</table>
</body>
</html>
@@ -0,0 +1,3 @@
void tearDown() {
${BODY}
}
@@ -0,0 +1,27 @@
<html>
<body>
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td colspan="3"><font face="verdana" size="-1">
This is a template used by <b>IDEA</b> to create a tearDown method in a Groovy JUnit test class.
</font>
</td>
</tr>
</table>
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td colspan="3"><font face="verdana" size="-1">Predefined variables will take the following values:</font></td>
</tr>
<tr>
<td valign="top"><nobr><font face="verdana" size="-2" color="#7F0000"><b><i>${NAME}</i></b></font></nobr></td>
<td width="10">&nbsp;</td>
<td valign="top"><font face="verdana" size="-1">name of the created method.</font></td>
</tr>
<tr>
<td valign="top"><nobr><font face="verdana" size="-2" color="#7F0000"><b><i>${BODY}</i></b></font></nobr></td>
<td width="10">&nbsp;</td>
<td valign="top"><font face="verdana" size="-1">generated method body.</font></td>
</tr>
</table>
</body>
</html>
@@ -0,0 +1,3 @@
void test${NAME}() {
${BODY}
}
@@ -0,0 +1,27 @@
<html>
<body>
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td colspan="3"><font face="verdana" size="-1">
This is a template used by <b>IDEA</b> to create a test method in a JUnit 3 test class.
</font>
</td>
</tr>
</table>
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<td colspan="3"><font face="verdana" size="-1">Predefined variables will take the following values:</font></td>
</tr>
<tr>
<td valign="top"><nobr><font face="verdana" size="-2" color="#7F0000"><b><i>${NAME}</i></b></font></nobr></td>
<td width="10">&nbsp;</td>
<td valign="top"><font face="verdana" size="-1">name of the created method.</font></td>
</tr>
<tr>
<td valign="top"><nobr><font face="verdana" size="-2" color="#7F0000"><b><i>${BODY}</i></b></font></nobr></td>
<td width="10">&nbsp;</td>
<td valign="top"><font face="verdana" size="-1">generated method body.</font></td>
</tr>
</table>
</body>
</html>
+1
View File
@@ -121,6 +121,7 @@
</extensions>
<extensions defaultExtensionNs="com.intellij">
<testFramework implementation="org.jetbrains.plugins.groovy.testIntegration.GroovyTestFramework"/>
<testCreator language="Groovy" implementationClass="com.intellij.testIntegration.JavaTestCreator"/>
<testGenerator implementation="org.jetbrains.plugins.groovy.testIntegration.GroovyTestGenerator"/>
<editorNotificationProvider implementation="org.jetbrains.plugins.groovy.annotator.ConfigureGroovyLibraryNotificationProvider"/>
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -17,14 +17,15 @@
package org.jetbrains.plugins.groovy.annotator.intentions;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
@@ -75,47 +76,49 @@ public abstract class CreateClassActionBase implements IntentionAction {
public static PsiClass createClassByType(final PsiDirectory directory,
final String name,
final PsiManager manager,
final PsiElement contextElement, final String templateName) {
return ApplicationManager.getApplication().runWriteAction(
new Computable<PsiClass>() {
public PsiClass compute() {
try {
PsiClass targetClass = null;
try {
PsiFile file = GroovyTemplatesFactory.createFromTemplate(directory, name, name + ".groovy", templateName);
for (PsiElement element : file.getChildren()) {
if (element instanceof PsiClass) {
targetClass = ((PsiClass) element);
break;
}
}
if (targetClass == null) {
throw new IncorrectOperationException(GroovyBundle.message("no.class.in.file.template"));
}
}
catch (final IncorrectOperationException e) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
Messages.showErrorDialog(
GroovyBundle.message("cannot.create.class.error.text", name, e.getLocalizedMessage()),
GroovyBundle.message("cannot.create.class.error.title"));
}
});
return null;
}
PsiModifierList modifiers = targetClass.getModifierList();
if (!JavaPsiFacade.getInstance(manager.getProject()).getResolveHelper().isAccessible(targetClass, contextElement, null) &&
modifiers != null) {
modifiers.setModifierProperty(PsiKeyword.PUBLIC, true);
}
return targetClass;
}
catch (IncorrectOperationException e) {
LOG.error(e);
return null;
}
@Nullable final PsiElement contextElement,
final String templateName) {
AccessToken accessToken = WriteAction.start();
try {
PsiClass targetClass = null;
try {
PsiFile file = GroovyTemplatesFactory.createFromTemplate(directory, name, name + ".groovy", templateName);
for (PsiElement element : file.getChildren()) {
if (element instanceof PsiClass) {
targetClass = ((PsiClass)element);
break;
}
}
if (targetClass == null) {
throw new IncorrectOperationException(GroovyBundle.message("no.class.in.file.template"));
}
}
catch (final IncorrectOperationException e) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
Messages.showErrorDialog(
GroovyBundle.message("cannot.create.class.error.text", name, e.getLocalizedMessage()),
GroovyBundle.message("cannot.create.class.error.title"));
}
});
return null;
}
PsiModifierList modifiers = targetClass.getModifierList();
if (contextElement != null &&
!JavaPsiFacade.getInstance(manager.getProject()).getResolveHelper().isAccessible(targetClass, contextElement, null) &&
modifiers != null) {
modifiers.setModifierProperty(PsiKeyword.PUBLIC, true);
}
return targetClass;
}
catch (IncorrectOperationException e) {
LOG.error(e);
return null;
}
finally {
accessToken.finish();
}
}
@Nullable
@@ -59,6 +59,10 @@ public abstract class GroovyPsiElementFactory implements JVMElementFactory {
@NonNls public static final String DUMMY_FILE_NAME = "DUMMY__";
public abstract GrCodeReferenceElement createCodeReferenceElementFromClass(PsiClass aClass);
public abstract GrCodeReferenceElement createCodeReferenceElementFromText(String text);
public static GroovyPsiElementFactory getInstance(Project project) {
return ServiceManager.getService(project, GroovyPsiElementFactory.class);
}
@@ -465,7 +465,7 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory {
return createAnnotationFromText(annoText, null);
}
public PsiFile createGroovyFile(String idText) {
public GroovyFile createGroovyFile(String idText) {
return createGroovyFile(idText, false, null);
}
@@ -553,6 +553,28 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory {
return ((GrMethodCallExpression)file.getChildren()[0]);
}
@Override
public GrCodeReferenceElement createCodeReferenceElementFromClass(PsiClass aClass) {
if (aClass instanceof PsiAnonymousClass) {
throw new IncorrectOperationException("cannot create code reference element for anonymous class " + aClass.getText());
}
return createCodeReferenceElementFromText(aClass.getQualifiedName());
}
@Override
public GrCodeReferenceElement createCodeReferenceElementFromText(String text) {
GroovyFile file = createGroovyFile("class X extends " + text + "{}");
PsiClass[] classes = file.getClasses();
if (classes.length != 1) throw new IncorrectOperationException("cannot create code reference element for class" + text);
GrExtendsClause extendsClause = ((GrTypeDefinition)classes[0]).getExtendsClause();
if (extendsClause == null) throw new IncorrectOperationException("cannot create code reference element for class" + text);
GrCodeReferenceElement[] refElements = extendsClause.getReferenceElements();
if (refElements.length != 1) throw new IncorrectOperationException("cannot create code reference element for class" + text);
return refElements[0];
}
public GrImportStatement createImportStatementFromText(String qName, boolean isStatic, boolean isOnDemand, String alias) {
final String text = "import " + (isStatic ? "static " : "") + qName + (isOnDemand ? ".*" : "") +
(alias != null && alias.length() > 0 ? " as " + alias : "");
@@ -48,6 +48,7 @@ public final class GroovyCommonClassNames {
@NonNls public static final String GROOVY_LANG_CATEGORY = "groovy.lang.Category";
@NonNls public static final String GROOVY_LANG_USE = "groovy.lang.Use";
@NonNls public static final String GROOVY_LANG_MIXIN = "groovy.lang.Mixin";
@NonNls public static final String GROOVY_UTIL_TEST_CASE = "groovy.util.GroovyTestCase";
private GroovyCommonClassNames() {
@@ -0,0 +1,142 @@
/*
* Copyright 2000-2011 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 org.jetbrains.plugins.groovy.testIntegration;
import com.intellij.execution.junit.JUnitUtil;
import com.intellij.ide.fileTemplates.FileTemplateDescriptor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.testIntegration.JavaTestFramework;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.GroovyIcons;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import javax.swing.*;
/**
* @author Max Medvedev
*/
public class GroovyTestFramework extends JavaTestFramework {
private static final Logger LOG = Logger.getInstance(GroovyTestFramework.class);
@Override
protected String getMarkerClassFQName() {
return GroovyCommonClassNames.GROOVY_UTIL_TEST_CASE;
}
@Override
protected boolean isTestClass(PsiClass clazz, boolean canBePotential) {
return clazz.getLanguage() == GroovyFileType.GROOVY_LANGUAGE &&
JUnitUtil.isTestClass(clazz) &&
InheritanceUtil.isInheritor(clazz, GroovyCommonClassNames.GROOVY_UTIL_TEST_CASE);
}
@Override
protected PsiMethod findSetUpMethod(@NotNull PsiClass clazz) {
for (PsiMethod method : clazz.getMethods()) {
if (method.getName().equals("setUp")) return method;
}
return null;
}
@Override
protected PsiMethod findTearDownMethod(@NotNull PsiClass clazz) {
for (PsiMethod method : clazz.getMethods()) {
if (method.getName().equals("tearDown")) return method;
}
return null;
}
@Override
protected PsiMethod findOrCreateSetUpMethod(PsiClass clazz) throws IncorrectOperationException {
LOG.assertTrue(clazz.getLanguage() == GroovyFileType.GROOVY_LANGUAGE);
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(clazz.getProject());
final PsiMethod patternMethod = factory.createMethodFromText("protected void setUp() {\nsuper.setUp()\n}", null);
final PsiClass baseClass = clazz.getSuperClass();
if (baseClass != null) {
final PsiMethod baseMethod = baseClass.findMethodBySignature(patternMethod, false);
if (baseMethod != null && baseMethod.hasModifierProperty(PsiModifier.PUBLIC)) {
PsiUtil.setModifierProperty(patternMethod, PsiModifier.PROTECTED, false);
PsiUtil.setModifierProperty(patternMethod, PsiModifier.PUBLIC, true);
}
}
PsiMethod inClass = clazz.findMethodBySignature(patternMethod, false);
if (inClass == null) {
PsiMethod testMethod = JUnitUtil.findFirstTestMethod(clazz);
if (testMethod != null) {
return (PsiMethod)clazz.addBefore(patternMethod, testMethod);
}
return (PsiMethod)clazz.add(patternMethod);
}
else if (inClass.getBody() == null) {
return (PsiMethod)inClass.replace(patternMethod);
}
return inClass;
}
@NotNull
@Override
public String getName() {
return "Groovy JUnit";
}
@NotNull
@Override
public Icon getIcon() {
return GroovyIcons.GROOVY_ICON_16x16;
}
@NotNull
@Override
public String getLibraryPath() {
return JavaSdkUtil.getJunit3JarPath();
}
@Override
public String getDefaultSuperClass() {
return GroovyCommonClassNames.GROOVY_UTIL_TEST_CASE;
}
@Override
public FileTemplateDescriptor getSetUpMethodFileTemplateDescriptor() {
return new FileTemplateDescriptor("Groovy JUnit SetUp Method.groovy");
}
public FileTemplateDescriptor getTearDownMethodFileTemplateDescriptor() {
return new FileTemplateDescriptor("Groovy JUnit TearDown Method.groovy");
}
public FileTemplateDescriptor getTestMethodFileTemplateDescriptor() {
return new FileTemplateDescriptor("Groovy JUnit Test Method.groovy");
}
@Override
public boolean isTestMethod(PsiElement element) {
return element instanceof PsiMethod && JUnitUtil.getTestMethod(element) != null;
}
}
@@ -16,25 +16,38 @@
package org.jetbrains.plugins.groovy.testIntegration;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.lang.Language;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.testIntegration.TestFramework;
import com.intellij.testIntegration.TestIntegrationUtils;
import com.intellij.testIntegration.createTest.CreateTestDialog;
import com.intellij.testIntegration.createTest.JavaTestGenerator;
import com.intellij.testIntegration.createTest.TestGenerator;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.codeInspection.local.GroovyUnusedImportPass;
import org.jetbrains.plugins.groovy.actions.NewGroovyClassAction;
import org.jetbrains.plugins.groovy.annotator.intentions.CreateClassActionBase;
import org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.GrReferenceAdjuster;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import java.util.Collection;
/**
* @author Maxim.Medvedev
@@ -44,35 +57,42 @@ public class GroovyTestGenerator implements TestGenerator {
@Nullable
@Override
public PsiElement generateTest(final Project project, final CreateTestDialog d) {
final PsiClass test = (PsiClass)new JavaTestGenerator().generateTest(project, d);
if (test == null) return null;
AccessToken accessToken = WriteAction.start();
try {
final PsiFile file = test.getContainingFile();
final String name = file.getName();
final String newName = FileUtil.getNameWithoutExtension(name) + "." + GroovyFileType.DEFAULT_EXTENSION;
final PsiClass test = (PsiClass)PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(
new Computable<PsiElement>() {
public PsiElement compute() {
try {
IdeDocumentHistory.getInstance(project).includeCurrentPlaceAsChangePlace();
final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
try {
final PsiElement element = file.setName(newName);
GrTypeDefinition targetClass = (GrTypeDefinition)CreateClassActionBase.createClassByType(
d.getTargetDirectory(),
d.getClassName(),
PsiManager.getInstance(project),
null,
NewGroovyClassAction.GROOVY_CLASS);
final GroovyFile newFile = (GroovyFile)codeStyleManager.reformat(element);
GroovyUnusedImportPass.optimizeImports(project, newFile);
return newFile.getClasses()[0];
}
catch (IncorrectOperationException e) {
file.delete();
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
Messages.showErrorDialog(project,
CodeInsightBundle.message("intention.error.cannot.create.class.message", d.getClassName()),
CodeInsightBundle.message("intention.error.cannot.create.class.title"));
addSuperClass(targetClass, project, d.getSuperClassName());
Editor editor = CodeInsightUtil.positionCursor(project, targetClass.getContainingFile(), targetClass.getLBrace());
addTestMethods(editor,
targetClass,
d.getSelectedTestFrameworkDescriptor(),
d.getSelectedMethods(),
d.shouldGeneratedBefore(),
d.shouldGeneratedAfter());
return targetClass;
}
catch (IncorrectOperationException e1) {
showErrorLater(project, d.getClassName());
return null;
}
}
});
return null;
}
if (test == null) return null;
GrReferenceAdjuster.shortenReferences(test);
CodeStyleManager.getInstance(project).reformat(test);
return test;
}
finally {
accessToken.finish();
@@ -83,4 +103,75 @@ public class GroovyTestGenerator implements TestGenerator {
public String toString() {
return GroovyIntentionsBundle.message("intention.crete.test.groovy");
}
@Override
public Language getLanguage() {
return GroovyFileType.GROOVY_LANGUAGE;
}
private static void addSuperClass(GrTypeDefinition targetClass, Project project, @Nullable String superClassName)
throws IncorrectOperationException {
if (superClassName == null) return;
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
PsiClass superClass = findClass(project, superClassName);
GrCodeReferenceElement superClassRef;
if (superClass != null) {
superClassRef = factory.createCodeReferenceElementFromClass(superClass);
}
else {
superClassRef = factory.createCodeReferenceElementFromText(superClassName);
}
GrExtendsClause extendsClause = targetClass.getExtendsClause();
if (extendsClause == null) {
extendsClause = (GrExtendsClause)targetClass.addAfter(factory.createExtendsClause(), targetClass.getNameIdentifierGroovy());
}
extendsClause.add(superClassRef);
}
@Nullable
private static PsiClass findClass(Project project, String fqName) {
GlobalSearchScope scope = GlobalSearchScope.allScope(project);
return JavaPsiFacade.getInstance(project).findClass(fqName, scope);
}
private static void addTestMethods(Editor editor,
PsiClass targetClass,
TestFramework descriptor,
Collection<MemberInfo> methods,
boolean generateBefore,
boolean generateAfter) throws IncorrectOperationException {
if (generateBefore) {
generateMethod(TestIntegrationUtils.MethodKind.SET_UP, descriptor, targetClass, editor, null);
}
if (generateAfter) {
generateMethod(TestIntegrationUtils.MethodKind.TEAR_DOWN, descriptor, targetClass, editor, null);
}
for (MemberInfo m : methods) {
generateMethod(TestIntegrationUtils.MethodKind.TEST, descriptor, targetClass, editor, m.getMember().getName());
}
}
private static void showErrorLater(final Project project, final String targetClassName) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
Messages.showErrorDialog(project,
CodeInsightBundle.message("intention.error.cannot.create.class.message", targetClassName),
CodeInsightBundle.message("intention.error.cannot.create.class.title"));
}
});
}
private static void generateMethod(TestIntegrationUtils.MethodKind methodKind,
TestFramework descriptor,
PsiClass targetClass,
Editor editor,
@Nullable String name) {
GroovyPsiElementFactory f = GroovyPsiElementFactory.getInstance(targetClass.getProject());
PsiMethod method = (PsiMethod)targetClass.add(f.createMethod("dummy", PsiType.VOID));
PsiDocumentManager.getInstance(targetClass.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument());
TestIntegrationUtils.runTestMethodTemplate(methodKind, descriptor, editor, targetClass, method, name, true);
}
}