mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Generators for files and methods
GitOrigin-RevId: 93b45a72817ce4571d2302b4cfd0726730644d9e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1b22bba054
commit
68a5740171
@@ -2270,6 +2270,7 @@
|
||||
<notificationGroup id="Remove redundant exports/opens" displayType="BALLOON" bundle="messages.JavaBundle" key="notification.group.redundant.exports"/>
|
||||
<notificationGroup id="Setup SDK" displayType="BALLOON" bundle="messages.JavaBundle" key="notification.group.setup.sdk"/>
|
||||
<notificationGroup id="External annotations" displayType="BALLOON" bundle="messages.JavaBundle" key="notification.group.setup.external.annotations"/>
|
||||
<notificationGroup id="Test integration" displayType="BALLOON" bundle="messages.JavaBundle" key="notification.group.testintegration"/>
|
||||
|
||||
<compiler.task execute="AFTER" implementation="com.intellij.execution.scratch.JavaScratchCompilationSupport"/>
|
||||
<registryKey key="load.maven.dependencies.timeout" defaultValue="120" description="How long (in minutes) idea will wait for results of synchronized maven dependencies resolution"/>
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.testIntegration;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.CodeInsightActionHandler;
|
||||
import com.intellij.codeInsight.generation.actions.BaseGenerateAction;
|
||||
import com.intellij.find.FindBundle;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.ui.components.JBPanel;
|
||||
import com.intellij.ui.components.JBTextField;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UAnnotation;
|
||||
import org.jetbrains.uast.UastContextKt;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class GenerateTestDataPathCommon extends BaseGenerateAction {
|
||||
|
||||
@NonNls
|
||||
private static final String CONTENT_ROOT_VARIABLE = "$CONTENT_ROOT";
|
||||
@NonNls
|
||||
private static final String PROJECT_ROOT_VARIABLE = "$PROJECT_ROOT";
|
||||
@NonNls
|
||||
protected static final String ANNOTATION_FQN = "com.intellij.testFramework.TestDataPath";
|
||||
protected static final Logger LOG = Logger.getInstance(GenerateTestDataPathCommon.class);
|
||||
|
||||
GenerateTestDataPathCommon(CodeInsightActionHandler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static String annotationValue(@NotNull PsiModifierListOwner owner, String annotationFqName) {
|
||||
var annotationNames = Collections.singleton(annotationFqName);
|
||||
var nestedClass = owner instanceof PsiClass && ((PsiClass)owner).getContainingClass() != null;
|
||||
var element = nestedClass
|
||||
? AnnotationUtil.findAnnotation(owner, annotationNames)
|
||||
: AnnotationUtil.findAnnotationInHierarchy(owner, annotationNames);
|
||||
final var annotation = UastContextKt.toUElement(element, UAnnotation.class);
|
||||
if (annotation != null) {
|
||||
var value = annotation.findAttributeValue(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME);
|
||||
if (value != null) {
|
||||
final var project = owner.getProject();
|
||||
final var constantValue = value.evaluate();
|
||||
if (constantValue instanceof String) {
|
||||
var path = (String)constantValue;
|
||||
if (path.contains(CONTENT_ROOT_VARIABLE)) {
|
||||
final var fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
|
||||
final var file = owner.getContainingFile().getVirtualFile();
|
||||
if (file == null) return null;
|
||||
final var contentRoot = fileIndex.getContentRootForFile(file);
|
||||
if (contentRoot == null) return null;
|
||||
path = path.replace(CONTENT_ROOT_VARIABLE, contentRoot.getPath());
|
||||
}
|
||||
if (path.contains(PROJECT_ROOT_VARIABLE)) {
|
||||
var baseDir = project.getBasePath();
|
||||
if (baseDir == null) {
|
||||
return null;
|
||||
}
|
||||
path = path.replace(PROJECT_ROOT_VARIABLE, baseDir);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidForClass(PsiClass targetClass) {
|
||||
return AnnotationUtil.findAnnotation(targetClass, "com.intellij.testFramework.TestDataPath") != null;
|
||||
}
|
||||
|
||||
protected static abstract class TestDataPathDialog extends DialogWrapper {
|
||||
protected TestDataPathDialog(@Nullable Project project, @NlsSafe @NotNull String titleText, boolean canBeParent) {
|
||||
super(project, canBeParent);
|
||||
setTitle(titleText);
|
||||
setOKButtonText(JavaBundle.message("generate.button.title"));
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable JComponent createCenterPanel() {
|
||||
var mainPanel = createMainPanel();
|
||||
getPanelContent().forEach(mainPanel::add);
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
abstract protected List<Component> getPanelContent();
|
||||
|
||||
protected JBPanel createMainPanel() {
|
||||
var mainPanel = new JBPanel<>().withPreferredWidth(250);
|
||||
var layout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS);
|
||||
mainPanel.setLayout(layout);
|
||||
return mainPanel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.testIntegration;
|
||||
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.notification.NotificationGroupManager;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.components.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GenerateTestDataPathFileAction extends GenerateTestDataPathCommon {
|
||||
|
||||
public GenerateTestDataPathFileAction() {
|
||||
super(((project, editor, file) -> {
|
||||
var currentClass = PsiTreeUtil.findChildOfType(file, PsiClass.class);
|
||||
if (currentClass == null) return;
|
||||
|
||||
var annotationValue = annotationValue(currentClass, ANNOTATION_FQN);
|
||||
if (annotationValue == null) return;
|
||||
|
||||
var directoryPath = LocalFileSystem.getInstance().findFileByPath(annotationValue);
|
||||
if (directoryPath == null || !directoryPath.isDirectory() || directoryPath.getChildren() == null) {
|
||||
NotificationGroupManager.getInstance().getNotificationGroup("Test integration")
|
||||
.createNotification(JavaBundle.message("generate.method.nosuites.warn", annotationValue), NotificationType.WARNING)
|
||||
.notify(project);
|
||||
return;
|
||||
}
|
||||
|
||||
var suggestedFileNames = Arrays
|
||||
.stream(currentClass.getAllMethods())
|
||||
.filter(method -> method.getName().startsWith("test"))
|
||||
.map(method -> method.getName().substring(4))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (suggestedFileNames.isEmpty()) {
|
||||
NotificationGroupManager.getInstance().getNotificationGroup("Test integration")
|
||||
.createNotification(JavaBundle.message("generate.method.nofiles.warn", currentClass.getName(), annotationValue),
|
||||
NotificationType.WARNING)
|
||||
.notify(project);
|
||||
return;
|
||||
}
|
||||
|
||||
var dialog = new TestDataPathDialog(project, JavaBundle.message("dialog.title.testdatapath.file.generate"), false) {
|
||||
|
||||
private JBList<String> suggestedFileList;
|
||||
private JCheckBox qfCheckbox;
|
||||
private JBTextField extensionField;
|
||||
|
||||
@Override
|
||||
protected List<Component> getPanelContent() {
|
||||
suggestedFileList = new JBList<String>(suggestedFileNames);
|
||||
suggestedFileList.setSelectionInterval(0, suggestedFileList.getItemsCount());
|
||||
var scrollPane = new JBScrollPane(suggestedFileList);
|
||||
scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
|
||||
qfCheckbox = new JCheckBox();
|
||||
qfCheckbox.setText(JavaBundle.message("generate.quickfix.files"));
|
||||
qfCheckbox.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
qfCheckbox.setSelected(false);
|
||||
|
||||
extensionField = new JBTextField();
|
||||
extensionField.getEmptyText().setText(JavaBundle.message("generate.file.extension.text"));
|
||||
extensionField.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
|
||||
return List.of(scrollPane, qfCheckbox, extensionField);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
getSelectedMethod().forEach(fileName -> {
|
||||
var requester = new Object();
|
||||
var folder = VirtualFileManager.getInstance().findFileByNioPath(Path.of(annotationValue));
|
||||
WriteCommandAction.runWriteCommandAction(project, (Runnable)() -> {
|
||||
try {
|
||||
folder.createChildData(requester, fileName + extensionField.getText());
|
||||
if (isQFFileNeeded()) folder.createChildData(requester, fileName + ".after" + extensionField.getText());
|
||||
}
|
||||
catch (IOException | NullPointerException e) {
|
||||
LOG.warn(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ValidationInfo doValidate() {
|
||||
var in = extensionField.getText().trim();
|
||||
if (in.isBlank() || !in.startsWith(".") || in.contains(" ")) {
|
||||
return new ValidationInfo(JavaBundle.message("generate.file.extension.validation.error", in));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> getSelectedMethod() { return suggestedFileList.getSelectedValuesList(); }
|
||||
|
||||
boolean isQFFileNeeded() { return qfCheckbox.isSelected(); }
|
||||
};
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> dialog.show());
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.testIntegration;
|
||||
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.notification.NotificationGroupManager;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElementFactory;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GenerateTestDataPathMethodAction extends GenerateTestDataPathCommon {
|
||||
|
||||
public GenerateTestDataPathMethodAction() {
|
||||
super(((project, editor, file) -> {
|
||||
var currentClass = PsiTreeUtil.findChildOfType(file, PsiClass.class);
|
||||
if (currentClass == null) return;
|
||||
|
||||
var existingMethodNames = Arrays
|
||||
.stream(currentClass.getAllMethods())
|
||||
.map(PsiMethod::getName)
|
||||
.filter(name -> name.startsWith("test"))
|
||||
.collect(Collectors.toCollection(HashSet<String>::new));
|
||||
|
||||
var annotationValue = annotationValue(currentClass, ANNOTATION_FQN);
|
||||
if (annotationValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var directoryPath = LocalFileSystem.getInstance().findFileByPath(annotationValue);
|
||||
if (directoryPath == null || !directoryPath.isDirectory() || directoryPath.getChildren() == null) {
|
||||
NotificationGroupManager.getInstance().getNotificationGroup("Test integration")
|
||||
.createNotification(JavaBundle.message("generate.method.nosuites.warn", annotationValue), NotificationType.WARNING)
|
||||
.notify(project);
|
||||
return;
|
||||
}
|
||||
|
||||
var preparedMethodNames = Arrays.stream(directoryPath.getChildren())
|
||||
.filter(vFile -> vFile.getExtension() != null && (!vFile.getExtension().equals("java") || !vFile.getExtension().equals("kt")))
|
||||
.map(vFile -> "test" + capitalizeFirstChar(normalizeMethodName(vFile.getName())))
|
||||
.filter(methodName -> !existingMethodNames.contains(methodName))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
var dialog = new TestDataPathDialog(project, JavaBundle.message("dialog.title.testdatapath.method.generate"), false) {
|
||||
|
||||
private JBList<String> suggestedFileList;
|
||||
private ComboBox<String> selectModifierBox;
|
||||
|
||||
@Override
|
||||
protected List<Component> getPanelContent() {
|
||||
suggestedFileList = new JBList<>(preparedMethodNames);
|
||||
suggestedFileList.setSelectionInterval(0, suggestedFileList.getItemsCount());
|
||||
var scrollPane = new JBScrollPane(suggestedFileList);
|
||||
scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
|
||||
final var choices = new String[]{JavaBundle.message("generate.select.default.modifier.text"), Modifier.PUBLIC.toString(), Modifier.PROTECTED.toString(), Modifier.PRIVATE.toString()};
|
||||
selectModifierBox = new ComboBox<String>(choices);
|
||||
selectModifierBox.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
|
||||
return List.of(scrollPane, selectModifierBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
suggestedFileList.getSelectedValuesList().forEach(methodName -> {
|
||||
WriteCommandAction.runWriteCommandAction(project, (Runnable)() -> currentClass.add(
|
||||
PsiElementFactory.getInstance(project).createMethodFromText(getSelectedModifier() + "void " + methodName + "(){ }", currentClass))
|
||||
);
|
||||
});
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
String getSelectedModifier() {
|
||||
return selectModifierBox.getSelectedIndex() == 0 ? "" : selectModifierBox.getSelectedItem().toString() + " ";
|
||||
}
|
||||
};
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> dialog.show());
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private static String capitalizeFirstChar(@NotNull String inString) {
|
||||
if (Character.isUpperCase(inString.charAt(0))) return inString;
|
||||
if (inString.length() == 1) return inString.toUpperCase();
|
||||
return inString.charAt(0) + inString.substring(1);
|
||||
}
|
||||
|
||||
private static String normalizeMethodName(@NotNull String inString) {
|
||||
return inString.substring(0, inString.indexOf("."));
|
||||
}
|
||||
}
|
||||
@@ -223,6 +223,8 @@ dialog.title.infer.nullity.results=Infer Nullity Results
|
||||
dialog.title.no.test.roots.found=No Test Roots Found
|
||||
dialog.title.process.duplicates=Process Duplicates
|
||||
dialog.title.super.method.found=Super Method Found
|
||||
dialog.title.testdatapath.method.generate=Generate methods from @TestDataPath
|
||||
dialog.title.testdatapath.file.generate=Generate files from class to @TestDataPath
|
||||
do.not.import.inner.classes.for=Exclude inner classes by short name:
|
||||
do.not.import.inner.classes.no.classes=No inner classes defined
|
||||
editbox.blanklines.around.initializer=Around initializer:
|
||||
@@ -325,6 +327,12 @@ generate.tostring.sort.super=Super class members first
|
||||
generate.tostring.tab.title=toString() Generation Settings
|
||||
generate.tostring.template.label=&Template:
|
||||
generate.tostring.title=Generate toString()
|
||||
generate.quickfix.files=Create QF scenarios(with '.after' suffix)
|
||||
generate.select.default.modifier.text=Select modifier
|
||||
generate.file.extension.text=Enter file extension: .php, .java, .kt, .cpp ....
|
||||
generate.file.extension.validation.error=File extension ''{0}'' isn't valid. It must start from ''.'', can't contain space symbols or be blank
|
||||
generate.method.nosuites.warn=No test suites were found in @TestDataPath("{0}")
|
||||
generate.method.nofiles.warn=No test methods were found in class {0}
|
||||
goto.super.class.chooser.title=Choose super class or interface
|
||||
group.javadoc.alignment=Alignment
|
||||
group.javadoc.blank.lines=Blank lines
|
||||
@@ -1738,6 +1746,7 @@ notification.group.preview.features=Preview Java language level may be discontin
|
||||
notification.group.redundant.exports=Redundant exports/opens can be removed
|
||||
notification.group.setup.sdk=JDK configured
|
||||
notification.group.setup.external.annotations=Failed to load external annotations
|
||||
notification.group.testintegration=Failed to generate tests for @TestDataPath
|
||||
popup.title.effective.visibility=Effective Visibility
|
||||
inspection.io.stream.constructor.description='InputStream' and 'OutputStream' can be constructed using 'Files' methods
|
||||
inspection.input.stream.constructor.message='InputStream' can be constructed using 'Files.newInputStream'
|
||||
|
||||
@@ -227,6 +227,8 @@ action.GenerateBeforeClassMethod.text=BeforeClass Method
|
||||
action.GenerateTearDownMethod.text=TearDown Method
|
||||
action.GenerateAfterClassMethod.text=AfterClass Method
|
||||
action.GenerateDataMethod.text=Parameters Method
|
||||
action.GenerateTestDataPathMethods.text=@TestDataPath Methods
|
||||
action.GenerateTestDataPathFiles.text=@TestDataPath Files
|
||||
action.GenerateConstructor.text=Constructor
|
||||
action.GenerateConstructor.description=Generate constructor
|
||||
action.GenerateCreateUI.text=createUI(...)
|
||||
|
||||
@@ -280,6 +280,8 @@
|
||||
<action id="GenerateBeforeClassMethod" class="com.intellij.testIntegration.GenerateBeforeClassMethodAction"/>
|
||||
<action id="GenerateAfterClassMethod" class="com.intellij.testIntegration.GenerateAfterClassMethodAction"/>
|
||||
<action id="GenerateDataMethod" class="com.intellij.testIntegration.GenerateDataMethodAction"/>
|
||||
<action id="GenerateTestDataPathMethods" class="com.intellij.testIntegration.GenerateTestDataPathMethodAction"/>
|
||||
<action id="GenerateTestDataPathFiles" class="com.intellij.testIntegration.GenerateTestDataPathFileAction"/>
|
||||
<separator/>
|
||||
<action id="GenerateConstructor" class="com.intellij.codeInsight.generation.actions.GenerateConstructorAction"/>
|
||||
<action id="GenerateGetter" class="com.intellij.codeInsight.generation.actions.GenerateGetterAction"/>
|
||||
|
||||
Reference in New Issue
Block a user