diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java b/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java index faa6643c116c..157966250b20 100644 --- a/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java +++ b/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java @@ -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()) { diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java b/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java index 8875be7f3e6c..6b104173a664 100644 --- a/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java +++ b/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java @@ -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 methods, - boolean generateBefore, - boolean generateAfter) throws IncorrectOperationException { + PsiClass targetClass, + TestFramework descriptor, + Collection 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; + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/TestGenerator.java b/java/java-impl/src/com/intellij/testIntegration/createTest/TestGenerator.java index d7c013dbd1a0..5c372a2615ee 100644 --- a/java/java-impl/src/com/intellij/testIntegration/createTest/TestGenerator.java +++ b/java/java-impl/src/com/intellij/testIntegration/createTest/TestGenerator.java @@ -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(); } diff --git a/plugins/groovy/resources/fileTemplates/code/Groovy JUnit SetUp Method.groovy.ft b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit SetUp Method.groovy.ft new file mode 100644 index 000000000000..d7cc63c2793d --- /dev/null +++ b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit SetUp Method.groovy.ft @@ -0,0 +1,3 @@ +void setUp() { + ${BODY} +} \ No newline at end of file diff --git a/plugins/groovy/resources/fileTemplates/code/Groovy JUnit SetUp Method.groovy.html b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit SetUp Method.groovy.html new file mode 100644 index 000000000000..e77fbbdde211 --- /dev/null +++ b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit SetUp Method.groovy.html @@ -0,0 +1,27 @@ + + + + + + +
+ This is a template used by IDEA to create a setUp method in a Groovy JUnit test class. + +
+ + + + + + + + + + + + + + +
Predefined variables will take the following values:
${NAME} name of the created method.
${BODY} generated method body.
+ + \ No newline at end of file diff --git a/plugins/groovy/resources/fileTemplates/code/Groovy JUnit TearDown Method.groovy.ft b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit TearDown Method.groovy.ft new file mode 100644 index 000000000000..c81f2423687f --- /dev/null +++ b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit TearDown Method.groovy.ft @@ -0,0 +1,3 @@ +void tearDown() { + ${BODY} +} \ No newline at end of file diff --git a/plugins/groovy/resources/fileTemplates/code/Groovy JUnit TearDown Method.groovy.html b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit TearDown Method.groovy.html new file mode 100644 index 000000000000..b00c7f9ea97f --- /dev/null +++ b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit TearDown Method.groovy.html @@ -0,0 +1,27 @@ + + + + + + +
+ This is a template used by IDEA to create a tearDown method in a Groovy JUnit test class. + +
+ + + + + + + + + + + + + + +
Predefined variables will take the following values:
${NAME} name of the created method.
${BODY} generated method body.
+ + \ No newline at end of file diff --git a/plugins/groovy/resources/fileTemplates/code/Groovy JUnit Test Method.groovy.ft b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit Test Method.groovy.ft new file mode 100644 index 000000000000..a0013e9c55ee --- /dev/null +++ b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit Test Method.groovy.ft @@ -0,0 +1,3 @@ +void test${NAME}() { +${BODY} +} \ No newline at end of file diff --git a/plugins/groovy/resources/fileTemplates/code/Groovy JUnit Test Method.groovy.html b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit Test Method.groovy.html new file mode 100644 index 000000000000..a6ad719de2df --- /dev/null +++ b/plugins/groovy/resources/fileTemplates/code/Groovy JUnit Test Method.groovy.html @@ -0,0 +1,27 @@ + + + + + + +
+ This is a template used by IDEA to create a test method in a JUnit 3 test class. + +
+ + + + + + + + + + + + + + +
Predefined variables will take the following values:
${NAME} name of the created method.
${BODY} generated method body.
+ + diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 07814b42457e..f53fc87ce479 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -121,6 +121,7 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassActionBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassActionBase.java index 381523ea0024..d0192031d7f8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassActionBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassActionBase.java @@ -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() { - 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 diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java index b6270ac0c57a..75570c56ae7b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java @@ -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); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java index 3d43ad43138e..3eb8abcdf168 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java @@ -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 : ""); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java index 4d603346469c..db931442d89c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java @@ -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() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestFramework.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestFramework.java new file mode 100644 index 000000000000..db989b60ee48 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestFramework.java @@ -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; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestGenerator.java index 5c2affb12f23..06bb5f008c7a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestGenerator.java @@ -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() { + 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 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); + } }