mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ApplyRandomIntentionsTest: perform mutations as random actions in a single test in different files
This commit is contained in:
+62
-23
@@ -18,6 +18,7 @@ package com.intellij.java.propertyBased;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.history.Label;
|
||||
import com.intellij.history.LocalHistory;
|
||||
import com.intellij.history.LocalHistoryException;
|
||||
import com.intellij.ide.impl.ProjectUtil;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.Application;
|
||||
@@ -33,6 +34,7 @@ import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.event.DocumentListener;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
@@ -43,19 +45,20 @@ import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
|
||||
import com.intellij.psi.search.FilenameIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.testFramework.CompilerTester;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import com.intellij.testFramework.TestDataProvider;
|
||||
import com.intellij.testFramework.UsefulTestCase;
|
||||
import com.intellij.testFramework.*;
|
||||
import com.intellij.util.ThrowableRunnable;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import slowCheck.Generator;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class AbstractApplyAndRevertTestCase extends PlatformTestCase {
|
||||
@@ -73,18 +76,28 @@ public abstract class AbstractApplyAndRevertTestCase extends PlatformTestCase {
|
||||
return Generator.sampledFrom(allFiles);
|
||||
}
|
||||
|
||||
protected Generator<PsiJavaFile> psiJavaFiles() {
|
||||
return javaFiles().map(vf -> (PsiJavaFile)PsiManager.getInstance(myProject).findFile(vf));
|
||||
}
|
||||
|
||||
protected static void restrictChangesToDocument(Document document, Runnable r) {
|
||||
watchDocumentChanges(r::run, event -> {
|
||||
Document changed = event.getDocument();
|
||||
if (changed != document) {
|
||||
VirtualFile file = FileDocumentManager.getInstance().getFile(changed);
|
||||
if (file != null && file.isInLocalFileSystem()) {
|
||||
throw new AssertionError("Unexpected document change: " + changed);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <E extends Throwable> void watchDocumentChanges(ThrowableRunnable<E> r, final Consumer<DocumentEvent> eventHandler) throws E {
|
||||
Disposable disposable = Disposer.newDisposable();
|
||||
EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void beforeDocumentChange(DocumentEvent event) {
|
||||
Document changed = event.getDocument();
|
||||
if (changed != document) {
|
||||
VirtualFile file = FileDocumentManager.getInstance().getFile(changed);
|
||||
if (file != null && file.isInLocalFileSystem()) {
|
||||
throw new AssertionError("Unexpected document change: " + changed);
|
||||
}
|
||||
}
|
||||
public void documentChanged(DocumentEvent event) {
|
||||
eventHandler.accept(event);
|
||||
}
|
||||
}, disposable);
|
||||
try {
|
||||
@@ -96,24 +109,50 @@ public abstract class AbstractApplyAndRevertTestCase extends PlatformTestCase {
|
||||
|
||||
protected void changeAndRevert(Runnable r) {
|
||||
Label label = LocalHistory.getInstance().putUserLabel(myProject, "changeAndRevert");
|
||||
boolean failed = false;
|
||||
try {
|
||||
r.run();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
failed = true;
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
restoreEverything(label, failed);
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreEverything(Label label, boolean failed) {
|
||||
try {
|
||||
WriteAction.run(() -> {
|
||||
try {
|
||||
PostprocessReformattingAspect.getInstance(myProject).doPostponedFormatting();
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
label.revert(myProject, myProject.getBaseDir());
|
||||
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
||||
assertEmpty(PsiDocumentManager.getInstance(myProject).getUncommittedDocuments());
|
||||
assertEmpty(FileDocumentManager.getInstance().getUnsavedDocuments());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
|
||||
new RunAll(
|
||||
() -> PostprocessReformattingAspect.getInstance(myProject).doPostponedFormatting(),
|
||||
() -> FileEditorManagerEx.getInstanceEx(myProject).closeAllFiles(),
|
||||
() -> FileDocumentManager.getInstance().saveAllDocuments(),
|
||||
() -> revertVfs(label, documentManager),
|
||||
() -> documentManager.commitAllDocuments(),
|
||||
() -> assertEmpty(documentManager.getUncommittedDocuments()),
|
||||
() -> assertEmpty(FileDocumentManager.getInstance().getUnsavedDocuments())
|
||||
).run();
|
||||
});
|
||||
}
|
||||
catch (Throwable e) {
|
||||
if (failed) {
|
||||
LOG.info("Exceptions while restoring state", e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void revertVfs(Label label, PsiDocumentManager documentManager) throws LocalHistoryException {
|
||||
watchDocumentChanges(() -> label.revert(myProject, myProject.getBaseDir()),
|
||||
__ -> {
|
||||
if (documentManager.getUncommittedDocuments().length > 3) {
|
||||
documentManager.commitAllDocuments();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -24,7 +25,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @author peter
|
||||
*/
|
||||
class ActionOnRange {
|
||||
private final RangeMarker myMarker;
|
||||
protected final RangeMarker myMarker;
|
||||
private TextRange finalRange;
|
||||
|
||||
ActionOnRange(Document document, int start, int end) {
|
||||
@@ -36,6 +37,10 @@ class ActionOnRange {
|
||||
return range == null ? -1 : range.getStartOffset();
|
||||
}
|
||||
|
||||
Segment getCurrentRange() {
|
||||
return finalRange == null ? myMarker : finalRange;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
TextRange getFinalRange() {
|
||||
if (finalRange == null) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiMethodCallExpression;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
|
||||
class AddNullArgument extends FilePsiMutation {
|
||||
|
||||
AddNullArgument(PsiFile file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performMutation() {
|
||||
PsiTreeUtil.findChildrenOfType(myFile, PsiMethodCallExpression.class).stream()
|
||||
.filter(PsiElement::isValid)
|
||||
.filter(call -> call.getArgumentList().getExpressions().length > 1)
|
||||
.forEach(call -> call.getArgumentList().add(
|
||||
JavaPsiFacade.getElementFactory(myFile.getProject()).createExpressionFromText("null", call)));
|
||||
}
|
||||
}
|
||||
+42
-108
@@ -15,18 +15,20 @@
|
||||
*/
|
||||
package com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.impl.PsiDocumentManagerImpl;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.testFramework.SkipSlowTestLocally;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import slowCheck.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import slowCheck.CheckerSettings;
|
||||
import slowCheck.Generator;
|
||||
import slowCheck.IntDistribution;
|
||||
import slowCheck.PropertyChecker;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@SkipSlowTestLocally
|
||||
public class ApplyRandomIntentionsTest extends AbstractApplyAndRevertTestCase {
|
||||
@@ -34,109 +36,18 @@ public class ApplyRandomIntentionsTest extends AbstractApplyAndRevertTestCase {
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject)).disableBackgroundCommit(getTestRootDisposable());
|
||||
}
|
||||
|
||||
public void testIntentionsInDifferentFiles() throws Throwable {
|
||||
initCompiler();
|
||||
}
|
||||
|
||||
public void testOpenFilesAndRevert() throws Throwable {
|
||||
doOpenFilesAndRevert(null);
|
||||
}
|
||||
|
||||
public void testOpenFilesAndRevertDeleteForeachInitializers() throws Throwable {
|
||||
doOpenFilesAndRevert(psiFile -> {
|
||||
WriteCommandAction.runWriteCommandAction(myProject, () -> PsiTreeUtil.findChildrenOfType(psiFile, PsiForStatement.class).stream()
|
||||
.limit(20)
|
||||
.forEach(stmt -> stmt.getInitialization().delete()));
|
||||
});
|
||||
}
|
||||
|
||||
public void testOpenFilesAndRevertDeleteSecondArgument() throws Throwable {
|
||||
doOpenFilesAndRevert(psiFile -> {
|
||||
WriteCommandAction.runWriteCommandAction(myProject, () -> PsiTreeUtil.findChildrenOfType(psiFile, PsiCallExpression.class)
|
||||
.stream()
|
||||
.filter(PsiElement::isValid)
|
||||
.map(PsiCall::getArgumentList)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(argList -> argList.getExpressions().length > 1)
|
||||
.limit(20)
|
||||
.forEach(argList -> {
|
||||
if (!argList.isValid()) return;
|
||||
PsiExpression arg = argList.getExpressions()[1];
|
||||
if (!arg.isValid()) return;
|
||||
arg.delete();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
public void testOpenFilesAndRevertAddNullArgument() throws Throwable {
|
||||
doOpenFilesAndRevert(psiFile -> {
|
||||
WriteCommandAction.runWriteCommandAction(myProject,
|
||||
() -> PsiTreeUtil.findChildrenOfType(psiFile, PsiMethodCallExpression.class).stream()
|
||||
.filter(PsiElement::isValid)
|
||||
.filter(call -> call.getArgumentList().getExpressions().length > 1)
|
||||
.forEach(call -> call.getArgumentList().add(JavaPsiFacade.getElementFactory(myProject).createExpressionFromText("null", call))));
|
||||
});
|
||||
}
|
||||
|
||||
public void testMakeAllMethodsVoid() throws Throwable {
|
||||
doOpenFilesAndRevert(psiFile -> {
|
||||
WriteCommandAction.runWriteCommandAction(myProject,
|
||||
() -> PsiTreeUtil.findChildrenOfType(psiFile, PsiMethod.class).stream()
|
||||
.filter(method -> method.getReturnTypeElement() != null)
|
||||
.forEach(method -> method.getReturnTypeElement().replace(JavaPsiFacade.getElementFactory(myProject).createTypeElement(PsiType.VOID))));
|
||||
});
|
||||
}
|
||||
|
||||
private void doOpenFilesAndRevert(@Nullable Consumer<PsiFile> mutation) throws Throwable {
|
||||
PsiManager psiManager = PsiManager.getInstance(myProject);
|
||||
CheckerSettings settings = CheckerSettings.DEFAULT_SETTINGS;
|
||||
PropertyChecker.forAll(settings.withIterationCount(10), javaFiles(), file -> {
|
||||
if (mutation == null) {
|
||||
checkCompiles(myCompilerTester.rebuild());
|
||||
}
|
||||
|
||||
PsiFile psiFile = psiManager.findFile(file);
|
||||
if (psiFile == null) return false;
|
||||
|
||||
Generator<InvokeIntention> genInvocation = Generator.from(data -> InvokeIntention.generate(psiFile, data)).noShrink();
|
||||
PropertyChecker.forAll(settings.withIterationCount(20), Generator.nonEmptyLists(genInvocation), list -> {
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
|
||||
changeAndRevert(() -> {
|
||||
if (mutation != null) {
|
||||
mutation.accept(psiFile);
|
||||
}
|
||||
documentManager.commitAllDocuments();
|
||||
long modCount = psiManager.getModificationTracker().getModificationCount();
|
||||
for (InvokeIntention invocation : list) {
|
||||
String textBefore = psiFile.getText();
|
||||
try {
|
||||
invocation.invokeIntention();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.debug("File " + file.getName() + " text before applying " + invocation + ":\n" + textBefore);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (mutation == null && modCount != psiManager.getModificationTracker().getModificationCount()) {
|
||||
checkCompiles(myCompilerTester.make());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public void testModificationsInDifferentFiles() throws Throwable {
|
||||
PsiManager psiManager = PsiManager.getInstance(myProject);
|
||||
PsiModificationTracker tracker = psiManager.getModificationTracker();
|
||||
PsiModificationTracker tracker = PsiManager.getInstance(myProject).getModificationTracker();
|
||||
|
||||
AtomicLong rebuildStamp = new AtomicLong();
|
||||
|
||||
CheckerSettings settings = CheckerSettings.DEFAULT_SETTINGS.withIterationCount(30);
|
||||
Generator<InvokeIntention> genIntention =
|
||||
Generator.from(data -> InvokeIntention.generate(psiManager.findFile(javaFiles().generateValue(data)), data));
|
||||
|
||||
Generator<InvokeIntention> genIntention = psiJavaFiles().flatMap(
|
||||
file -> Generator.from(data -> InvokeIntention.generate(file, data)));
|
||||
PropertyChecker.forAll(settings, Generator.listsOf(genIntention.noShrink()), list -> {
|
||||
long startModCount = tracker.getModificationCount();
|
||||
if (rebuildStamp.getAndSet(startModCount) != startModCount) {
|
||||
@@ -144,9 +55,8 @@ public class ApplyRandomIntentionsTest extends AbstractApplyAndRevertTestCase {
|
||||
}
|
||||
|
||||
changeAndRevert(() -> {
|
||||
for (InvokeIntention invocation : list) {
|
||||
invocation.invokeIntention();
|
||||
}
|
||||
MadTestingAction.runActions(list, myProject);
|
||||
|
||||
if (tracker.getModificationCount() != startModCount) {
|
||||
checkCompiles(myCompilerTester.make());
|
||||
}
|
||||
@@ -155,6 +65,30 @@ public class ApplyRandomIntentionsTest extends AbstractApplyAndRevertTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
public void testIntentionsAndModificationsInDifferentFiles() throws Throwable {
|
||||
CheckerSettings settings = CheckerSettings.DEFAULT_SETTINGS.withIterationCount(50);
|
||||
Generator<List<MadTestingAction>> genActionGroup = psiJavaFiles().flatMap(
|
||||
file -> {
|
||||
Generator<MadTestingAction> mutation = Generator.anyOf(DeleteRange.deletePsiRange(file),
|
||||
Generator.constant(new AddNullArgument(file)),
|
||||
Generator.constant(new DeleteForeachInitializers(file)),
|
||||
Generator.constant(new DeleteSecondArgument(file)),
|
||||
Generator.constant(new MakeAllMethodsVoid(file)));
|
||||
Generator<MadTestingAction> allActions = Generator.frequency(2, Generator.from(data -> InvokeIntention.generate(file, data)),
|
||||
1, Generator.constant(new RehighlightAllEditors(myProject)),
|
||||
1, mutation);
|
||||
return Generator.listsOf(IntDistribution.uniform(0, 5), allActions.noShrink());
|
||||
});
|
||||
|
||||
PropertyChecker.forAll(settings, Generator.listsOf(genActionGroup).map(ContainerUtil::flatten), list -> {
|
||||
changeAndRevert(() -> {
|
||||
//System.out.println(list);
|
||||
MadTestingAction.runActions(list, myProject);
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return SystemProperties.getUserHome() + "/IdeaProjects/univocity-parsers";
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiForStatement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
class DeleteForeachInitializers extends FilePsiMutation {
|
||||
|
||||
DeleteForeachInitializers(PsiFile file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performMutation() {
|
||||
PsiTreeUtil.findChildrenOfType(myFile, PsiForStatement.class).stream()
|
||||
.limit(20)
|
||||
.map(stmt -> stmt.getInitialization())
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(stmt -> stmt.delete());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import slowCheck.Generator;
|
||||
import slowCheck.IntDistribution;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
class DeleteRange extends ActionOnRange implements MadTestingAction {
|
||||
private final PsiFile myFile;
|
||||
|
||||
private DeleteRange(PsiFile file, int startOffset, int endOffset) {
|
||||
super(file.getViewProvider().getDocument(), startOffset, endOffset);
|
||||
assert myMarker.getDocument().getTextLength() == file.getTextLength();
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
static Generator<DeleteRange> deletePsiRange(@NotNull PsiFile psiFile) {
|
||||
return Generator.from(data -> {
|
||||
if (psiFile.getTextLength() == 0) return new DeleteRange(psiFile, 0, 0);
|
||||
|
||||
int startOffset = Generator.integers(0, psiFile.getTextLength() - 1).generateValue(data);
|
||||
PsiElement start = psiFile.findElementAt(startOffset);
|
||||
PsiElement end = psiFile.findElementAt(startOffset + data.drawInt(IntDistribution.geometric(10)));
|
||||
if (start == null || end == null) return null;
|
||||
|
||||
PsiElement commonParent = PsiTreeUtil.findCommonParent(start, end);
|
||||
return new DeleteRange(psiFile,
|
||||
commonParent.getTextRange().getStartOffset(),
|
||||
commonParent.getTextRange().getEndOffset());
|
||||
}).suchThat(Objects::nonNull);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeleteRange: " + myFile.getVirtualFile().getPath() + " " + getCurrentRange();
|
||||
}
|
||||
|
||||
public void performAction() {
|
||||
TextRange range = getFinalRange();
|
||||
if (range == null) return;
|
||||
|
||||
WriteCommandAction.runWriteCommandAction(myFile.getProject(), () -> myFile.getViewProvider().getDocument()
|
||||
.deleteString(range.getStartOffset(), range.getEndOffset()));
|
||||
|
||||
PsiUtilCore.ensureValid(myFile);
|
||||
PsiTestUtil.checkStubsMatchText(myFile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
class DeleteSecondArgument extends FilePsiMutation {
|
||||
DeleteSecondArgument(PsiFile file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performMutation() {
|
||||
PsiTreeUtil.findChildrenOfType(myFile, PsiCallExpression.class)
|
||||
.stream()
|
||||
.filter(PsiElement::isValid)
|
||||
.map(PsiCall::getArgumentList)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(argList -> argList.getExpressions().length > 1)
|
||||
.limit(20)
|
||||
.forEach(argList -> {
|
||||
if (!argList.isValid()) return;
|
||||
PsiExpression arg = argList.getExpressions()[1];
|
||||
if (!arg.isValid()) return;
|
||||
arg.delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
abstract class FilePsiMutation implements MadTestingAction {
|
||||
protected final PsiFile myFile;
|
||||
|
||||
FilePsiMutation(PsiFile file) {
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[" + myFile.getVirtualFile().getPath() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performAction() {
|
||||
WriteCommandAction.runWriteCommandAction(myFile.getProject(), this::performMutation);
|
||||
PsiTestUtil.checkStubsMatchText(myFile);
|
||||
}
|
||||
|
||||
protected abstract void performMutation();
|
||||
}
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
@@ -33,7 +35,7 @@ import slowCheck.Generator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class InvokeIntention extends ActionOnRange {
|
||||
class InvokeIntention extends ActionOnRange implements MadTestingAction {
|
||||
private final PsiFile myFile;
|
||||
private final int myIntentionIndex;
|
||||
private IntentionAction myIntentionAction;
|
||||
@@ -57,24 +59,23 @@ class InvokeIntention extends ActionOnRange {
|
||||
if (name == null) {
|
||||
name = myIntentionAction.toString();
|
||||
}
|
||||
return "Intention: " + myFile.getVirtualFile().getPath() + ", offset " + getStartOffset() + ", invoke " + name;
|
||||
return "InvokeIntention[" + myFile.getVirtualFile().getPath() + ", offset " + getStartOffset() + ", invoke '" + name + "']";
|
||||
}
|
||||
|
||||
void invokeIntention() {
|
||||
public void performAction() {
|
||||
int offset = getStartOffset();
|
||||
if (offset < 0) return;
|
||||
|
||||
Editor editor = FileEditorManager.getInstance(myFile.getProject()).openTextEditor(new OpenFileDescriptor(myFile.getProject(), myFile.getVirtualFile(), offset), true);
|
||||
|
||||
CodeInsightTestFixtureImpl.instantiateAndRun(myFile, editor, new int[0], false);
|
||||
|
||||
List<HighlightInfo> infos = RehighlightAllEditors.highlightEditor(editor, myFile.getProject());
|
||||
boolean hasErrors = infos.stream().anyMatch(i -> i.getSeverity() == HighlightSeverity.ERROR);
|
||||
|
||||
IntentionAction intention = myIntentionAction = getRandomIntention(editor);
|
||||
if (intention == null) return;
|
||||
|
||||
System.out.println("apply " + this);
|
||||
String currentFileText = myFile.getText();
|
||||
|
||||
Document changedDocument = getDocumentToBeChanged(intention);
|
||||
String textBefore = changedDocument == null ? null : changedDocument.getText();
|
||||
|
||||
Runnable r = () -> CodeInsightTestFixtureImpl.invokeIntention(intention, myFile, editor, intention.getText());
|
||||
if (changedDocument != null) {
|
||||
@@ -87,8 +88,8 @@ class InvokeIntention extends ActionOnRange {
|
||||
PsiDocumentManager.getInstance(myFile.getProject()).isDocumentBlockedByPsi(changedDocument)) {
|
||||
throw new AssertionError("Document is left blocked by PSI");
|
||||
}
|
||||
if (myFile.textMatches(currentFileText)) {
|
||||
throw new AssertionError("No change was performed: " + currentFileText);
|
||||
if (!hasErrors && textBefore != null && textBefore.equals(changedDocument.getText())) {
|
||||
throw new AssertionError("No change was performed in " + changedDocument + "\n" + textBefore);
|
||||
}
|
||||
|
||||
PsiTestUtil.checkStubsMatchText(myFile);
|
||||
@@ -114,8 +115,6 @@ class InvokeIntention extends ActionOnRange {
|
||||
actionText.startsWith("Attach annotations") ||
|
||||
actionText.startsWith("Convert to string literal") ||
|
||||
actionText.startsWith("Optimize imports") || // https://youtrack.jetbrains.com/issue/IDEA-173801
|
||||
actionText.startsWith("Move assignment to field declaration") || // https://youtrack.jetbrains.com/issue/IDEA-174956
|
||||
actionText.startsWith("Add on demand static import") || // https://youtrack.jetbrains.com/issue/IDEA-174965
|
||||
actionText.startsWith("Make method default") ||
|
||||
actionText.contains("to custom tags") || // changes only inspection settings
|
||||
actionText.startsWith("Typo: Change to...") || // doesn't change file text (starts live template)
|
||||
@@ -123,6 +122,10 @@ class InvokeIntention extends ActionOnRange {
|
||||
actionText.startsWith("Rename reference") || // doesn't change file text (starts live template)
|
||||
actionText.startsWith("Detail exceptions") || // can produce uncompilable code if 'catch' section contains 'instanceof's
|
||||
actionText.startsWith("Insert call to super method") || // super method can declare checked exceptions, unexpected at this point
|
||||
actionText.startsWith("Add qualifier") || // in javadoc; displays a popup which isn't allowed in tests
|
||||
actionText.startsWith("Cast to ") || // produces uncompilable code by design
|
||||
actionText.startsWith("Unwrap 'else' branch (changes semantics)") || // might produce code with final variables are initialized several times
|
||||
actionText.startsWith("Create missing 'switch' branches") || // if all existing branches do 'return something', we don't automatically generate compilable code for new branches
|
||||
actionText.startsWith("Unimplement");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
interface MadTestingAction {
|
||||
|
||||
void performAction();
|
||||
|
||||
static void runActions(List<? extends MadTestingAction> list, Project project) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
MadTestingAction action = list.get(i);
|
||||
if (i > 0 && action == list.get(i - 1)) continue;
|
||||
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
action.performAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
|
||||
class MakeAllMethodsVoid extends FilePsiMutation {
|
||||
|
||||
MakeAllMethodsVoid(PsiFile file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performMutation() {
|
||||
PsiTreeUtil.findChildrenOfType(myFile, PsiMethod.class).stream()
|
||||
.filter(method -> method.getReturnTypeElement() != null)
|
||||
.forEach(method -> method.getReturnTypeElement().replace(JavaPsiFacade.getElementFactory(myFile.getProject()).createTypeElement(PsiType.VOID)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.intellij.java.propertyBased;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class RehighlightAllEditors implements MadTestingAction {
|
||||
private final Project myProject;
|
||||
|
||||
RehighlightAllEditors(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performAction() {
|
||||
for (FileEditor editor : FileEditorManager.getInstance(myProject).getAllEditors()) {
|
||||
if (editor instanceof TextEditor) {
|
||||
highlightEditor(((TextEditor)editor).getEditor(), myProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RehighlightAllEditors";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static List<HighlightInfo> highlightEditor(Editor editor, Project project) {
|
||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||
return CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, new int[0], false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user