Skip to content

Commit

Permalink
Implement validation file rename refactoring on method or class rename
Browse files Browse the repository at this point in the history
  • Loading branch information
aykborstelmann committed Apr 19, 2024
1 parent fc49eb9 commit c17fa0a
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 7 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ wrapper {
intellij {
version.set('2022.2')
pluginName.set('Validation-File Comparison')
plugins = ['com.intellij.java']
}

patchPluginXml {
Expand All @@ -46,6 +47,8 @@ publishPlugin {
}

dependencies {
implementation 'de.cronn:validation-file-assertions:0.8.0'

testImplementation(platform('org.junit:junit-bom:5.10.2'))
testRuntimeOnly("org.junit.platform:junit-platform-launcher") {
because("Only needed to run tests in a version of IntelliJ IDEA that bundles older versions")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public interface ValidationDiffApplicationOptionsProvider {
boolean DEFAULT_SHOW_NEW_ON_TARGET = false;
boolean DEFAULT_SHOW_EQUAL = false;
boolean DEFAULT_SHOW_DIFFERENT = true;
boolean DEFAULT_RENAME_VALIDATION_FILE_ENABLED = true;

static ValidationDiffApplicationOptionsProvider getInstance() {
return ApplicationManager.getApplication().getService(ValidationDiffApplicationOptionsProvider.class);
Expand All @@ -33,4 +34,8 @@ static ValidationDiffApplicationOptionsProvider getInstance() {
boolean getShowDifferent();

void setShowDifferent(boolean showDifferent);

void setRenameValidationFilesEnabled(boolean enabled);

boolean isRenamingValidationFilesEnabled();
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package de.cronn.validation_files_diff;

import com.intellij.openapi.application.ApplicationManager;
import org.jetbrains.annotations.NotNull;

import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import de.cronn.assertions.validationfile.TestData;
import org.jetbrains.annotations.NotNull;

public interface ValidationDiffProjectOptionsProvider {
String DEFAULT_OUTPUT_DIRECTORY = "data/test/output";
String DEFAULT_VALIDATION_DIRECTORY = "data/test/validation";
String DEFAULT_OUTPUT_DIRECTORY = TestData.TEST_OUTPUT_DATA_DIR.toString();
String DEFAULT_VALIDATION_DIRECTORY = TestData.TEST_VALIDATION_DATA_DIR.toString();

static ValidationDiffProjectOptionsProvider getInstance(@NotNull Project project) {
return project.getService(ValidationDiffProjectOptionsProvider.class);
Expand All @@ -21,5 +19,4 @@ static ValidationDiffProjectOptionsProvider getInstance(@NotNull Project project
String getRelativeOutputDirPath();

void setRelativeOutputDirPath(String relativeOutputDirPath);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package de.cronn.validation_files_diff.helper;

import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import de.cronn.validation_files_diff.ValidationDiffProjectOptionsProvider;

import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

public class PsiElementValidationFileFinder {

private final Project project;
private final Module module;
private final PsiElement element;

private PsiElementValidationFileFinder(PsiElement element, Project project, Module module) {
this.project = project;
this.module = module;
this.element = element;
}

public static PsiElementValidationFileFinder of(PsiElement element) {
Project project = element.getProject();
Module currentModule = ModuleUtilCore.findModuleForFile(element.getContainingFile());
return new PsiElementValidationFileFinder(element, project, currentModule);
}

public boolean hasCorrespondingValidationFiles() {
return !findCorrespondingValidationFiles().isEmpty();
}

public List<VirtualFile> findCorrespondingValidationFiles() {
VirtualFile moduleRoot = getModuleRoot();
if (moduleRoot == null) {
return Collections.emptyList();
}

String validationFilePrefix = parseValidationFilePrefix();

return getValidationFileRelatedDirectories()
.map(moduleRoot::findFileByRelativePath)
.filter(Objects::nonNull)
.map(VirtualFile::getChildren)
.flatMap(Arrays::stream)
.filter(validationFile -> fileNameStartsWith(validationFile, validationFilePrefix))
.toList();
}

private Stream<String> getValidationFileRelatedDirectories() {
ValidationDiffProjectOptionsProvider options = ValidationDiffProjectOptionsProvider.getInstance(project);
return Stream.of(options.getRelativeOutputDirPath(), options.getRelativeValidationDirPath());
}

private boolean fileNameStartsWith(VirtualFile file, String prefix) {
return file.getName().startsWith(prefix);
}

private String parseValidationFilePrefix() {
if (element instanceof PsiMethod psiMethod) {
PsiClass psiClass = psiMethod.getContainingClass();
return PsiTestNameUtils.getTestName(psiClass, psiMethod);
}

if (element instanceof PsiClass psiClass) {
return PsiTestNameUtils.getTestClassName(psiClass);
}
return null;
}

private LocalFileSystem getLocalFileSystem() {
return (LocalFileSystem) VirtualFileManager
.getInstance()
.getFileSystem(LocalFileSystem.PROTOCOL);
}

private VirtualFile getModuleRoot() {
Module[] modules = ModuleManager.getInstance(project).getModules();
Path moduleRootPath = new ModuleAnalyser(module, modules).getMatchingContentRootForNextNonLeafModule();
if (moduleRootPath == null) {
return null;
}

return getLocalFileSystem().findFileByNioFile(moduleRootPath);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package de.cronn.validation_files_diff.helper;

import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;

public class PsiTestNameUtils {

private PsiTestNameUtils() {
}

public static String getTestName(PsiClass psiClass, PsiMethod psiMethod) {
return join(getTestClassName(psiClass), psiMethod.getName());
}

public static String getTestClassName(PsiClass psiClass) {
String nestingHierarchy = psiClass.getName();
PsiClass enclosingClass = psiClass.getContainingClass();
while (enclosingClass != null) {
nestingHierarchy = join(enclosingClass.getName(), nestingHierarchy);
enclosingClass = enclosingClass.getContainingClass();
}
return nestingHierarchy;
}

private static String join(String element, String other) {
return other.startsWith("_") ? (element + other) : (element + "_" + other);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,32 @@ public void setShowDifferent(boolean showDifferent) {
state.showDifferent = showDifferent;
}

@Override
public void setRenameValidationFilesEnabled(boolean enabled) {
state.validationFileRenameEnabled = enabled;
}

@Override
public boolean isRenamingValidationFilesEnabled() {
return state.validationFileRenameEnabled;
}

public static class State {
public State() {
outputSide = DEFAULT_OUTPUT_SIDE;
showNewOnTarget = DEFAULT_SHOW_NEW_ON_TARGET;
showNewOnSource = DEFAULT_SHOW_NEW_ON_SOURCE;
showEqual = DEFAULT_SHOW_EQUAL;
showDifferent = DEFAULT_SHOW_DIFFERENT;
validationFileRenameEnabled = DEFAULT_RENAME_VALIDATION_FILE_ENABLED;
}

public DiffSide outputSide;
public boolean showNewOnSource;
public boolean showNewOnTarget;
public boolean showEqual;
public boolean showDifferent;
public boolean validationFileRenameEnabled;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package de.cronn.validation_files_diff.impl;

import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.refactoring.rename.naming.AutomaticRenamer;
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory;
import com.intellij.usageView.UsageInfo;
import de.cronn.validation_files_diff.ValidationDiffApplicationOptionsProvider;
import de.cronn.validation_files_diff.helper.PsiElementValidationFileFinder;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;

public class ValidationFileAutomaticRenameFactory implements AutomaticRenamerFactory {

private static final String OPTION_NAME = "Rename Validation-Files";

@Override
public String getOptionName() {
return OPTION_NAME;
}

@Override
public boolean isEnabled() {
return ValidationDiffApplicationOptionsProvider.getInstance().isRenamingValidationFilesEnabled();
}

@Override
public void setEnabled(boolean enabled) {
ValidationDiffApplicationOptionsProvider.getInstance().setRenameValidationFilesEnabled(enabled);
}

@Override
public @NotNull AutomaticRenamer createRenamer(PsiElement element, String newName, Collection<UsageInfo> usages) {
return new ValidationFileAutomaticRenamer(element, newName);
}

@Override
public boolean isApplicable(@NotNull PsiElement element) {
if (!(element instanceof PsiMethod || element instanceof PsiClass)) {
return false;
}

return PsiElementValidationFileFinder.of(element).hasCorrespondingValidationFiles();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package de.cronn.validation_files_diff.impl;

import com.intellij.openapi.util.NlsContexts;
import com.intellij.psi.*;
import com.intellij.refactoring.rename.naming.AutomaticRenamer;
import de.cronn.validation_files_diff.helper.PsiElementValidationFileFinder;
import org.jetbrains.annotations.NotNull;

import java.util.Objects;

public class ValidationFileAutomaticRenamer extends AutomaticRenamer {

private static final boolean ARE_SELECTED_BY_DEFAULT = true;
private static final String TITLE = "Rename Validation-/Temp-/Output-File";
private static final String DESCRIPTION = "These Files Are Corresponding to the Test";
private static final String ENTITY_NAME = "Validation/Tmp/Output File";

protected ValidationFileAutomaticRenamer(PsiElement element, String newName) {
if (!(element instanceof PsiMethod || element instanceof PsiClass)) {
return;
}

PsiNamedElement psiNamedElement = (PsiNamedElement) element;

PsiManager psiManager = PsiManager.getInstance(element.getProject());

String oldName = psiNamedElement.getName();
PsiElementValidationFileFinder.of(element)
.findCorrespondingValidationFiles()
.stream()
.map(psiManager::findFile)
.filter(Objects::nonNull)
.forEach(psiFile -> suggestToRenameValidationFile(psiFile, getNewName(psiFile.getName(), oldName, newName)));
}

@NotNull
private static String getNewName(String currentName, String oldName, String newName) {
return currentName.replaceFirst(oldName, newName);
}

private void suggestToRenameValidationFile(PsiFile psiFile, String newFileName) {
myElements.add(psiFile);
suggestAllNames(psiFile.getName(), newFileName);
}

@Override
public @NlsContexts.DialogTitle String getDialogTitle() {
return TITLE;
}

@Override
public @NlsContexts.Button String getDialogDescription() {
return DESCRIPTION;
}

@Override
public @NlsContexts.ColumnName String entityName() {
return ENTITY_NAME;
}

@Override
public boolean isSelectedByDefault() {
return ARE_SELECTED_BY_DEFAULT;
}
}
3 changes: 3 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<vendor email="[email protected]" url="https://www.cronn.de">Cronn GmbH</vendor>

<depends>com.intellij.modules.platform</depends>
<depends>com.intellij.java</depends>

<description><![CDATA[
<a href="https://github.com/cronn-de/validation-files-comparison-intellij-plugin">Plugin on GitHub</a> |
Expand Down Expand Up @@ -55,6 +56,8 @@
serviceImplementation="de.cronn.validation_files_diff.impl.ValidationDiffProjectOptionsProviderImpl"/>
<applicationService serviceInterface="de.cronn.validation_files_diff.ValidationDiffApplicationOptionsProvider"
serviceImplementation="de.cronn.validation_files_diff.impl.ValidationDiffApplicationOptionsProviderImpl"/>
<automaticRenamerFactory
implementation="de.cronn.validation_files_diff.impl.ValidationFileAutomaticRenameFactory"/>
</extensions>

<actions>
Expand Down
Loading

0 comments on commit c17fa0a

Please sign in to comment.