blob: d66988ab2ef53ecb29a5960844a7da09669101ed [file] [log] [blame]
/*
* Copyright 2000-2014 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.codeInsight.actions;
import com.intellij.lang.LanguageFormatting;
import com.intellij.openapi.components.impl.ComponentManagerImpl;
import com.intellij.openapi.fileTypes.PlainTextLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.SimpleContentRevision;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.testFramework.LightPlatformTestCase;
import com.intellij.testFramework.PlatformTestCase;
import com.intellij.testFramework.vcs.MockChangeListManager;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.picocontainer.MutablePicoContainer;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class ReformatOnlyVcsChangedTextTest extends LightPlatformTestCase {
private static final String TEMP_DIR_NAME = "dir";
private PsiDirectory myWorkingDirectory;
private MockChangeListManager myMockChangeListManager;
private MockCodeStyleManager myMockCodeStyleManager;
private MockPlainTextFormattingModelBuilder myMockPlainTextFormattingModelBuilder;
private ChangeListManager myRealChangeListManager;
private CodeStyleManager myRealCodeStyleManger;
private final static String COMMITTED =
"class Test {\n" +
" int a = 22;\n" +
" public String getName() { return \"Test\"; }\n" +
"}";
private final static String MODIFIED =
"class Test {\n" +
" int a = 22;\n" +
" long l;\n" +
" double d;\n" +
" int i;\n" +
" public String getName() { return \"Test\"; }\n" +
" String test1;\n" +
" String test2;\n" +
"}";
private final static ChangedLines[] CHANGED_LINES = new ChangedLines[] { line(2, 4), line(6, 7) };
private final static ChangedLines[] NO_CHANGED_LINES = new ChangedLines[0];
@Override
public void setUp() throws Exception {
PlatformTestCase.initPlatformLangPrefix();
super.setUp();
myWorkingDirectory = TestFileStructure.createDirectory(getProject(), getSourceRoot(), TEMP_DIR_NAME);
myRealChangeListManager = ChangeListManager.getInstance(getProject());
myMockChangeListManager = new MockChangeListManager();
registerChangeListManager(myMockChangeListManager);
myRealCodeStyleManger = CodeStyleManager.getInstance(getProject());
myMockCodeStyleManager = new MockCodeStyleManager();
registerCodeStyleManager(myMockCodeStyleManager);
myMockPlainTextFormattingModelBuilder = new MockPlainTextFormattingModelBuilder();
LanguageFormatting.INSTANCE.addExplicitExtension(PlainTextLanguage.INSTANCE, myMockPlainTextFormattingModelBuilder);
}
@Override
public void tearDown() throws Exception {
registerChangeListManager(myRealChangeListManager);
registerCodeStyleManager(myRealCodeStyleManger);
LanguageFormatting.INSTANCE.removeExplicitExtension(PlainTextLanguage.INSTANCE, myMockPlainTextFormattingModelBuilder);
TestFileStructure.delete(myWorkingDirectory.getVirtualFile());
super.tearDown();
}
public void testInsertion() throws IOException {
doTest(
"public class B {\n" +
" int a = 3;\n" +
" String text;\n" +
" Object last = null;\n" +
"}",
"public class B {\n" +
" int a = 3;\n" +
" int toIndent1 = 1;\n" +
" String text;\n" +
" int toIndent2\n" +
" Object last = null;\n" +
"}",
line(2, 2), line(4, 4)
);
}
private static ChangedLines line(int from, int to) {
return new ChangedLines(from, to);
}
public void testDeletion() throws IOException {
doTest(
"public class B {\n" +
" int a = 3;\n" +
" String text;\n" +
" Object last = null;\n" +
" Object first = null;\n" +
" Object second = null;\n" +
"}",
"public class B {\n" +
" int newInt = 1;\n" +
" Object last = null;\n" +
"}",
line(1, 1)
);
}
public void testModification() throws IOException {
doTest(
"public class B {\n" +
" int a = 3;\n" +
" String text;\n" +
" Object last = null;\n" +
" Object first = null;\n" +
" Object second = null;\n" +
"}",
"public class B {\n" +
" int a = 33;\n" +
" String text;\n" +
" Object last = new Object();\n" +
" Object first = null;\n" +
" Object second = new Object();\n" +
"}",
line(1, 1), line(3,3), line(5,5)
);
}
public void testModificationCRLF() throws IOException {
doTest(
"public class B {\r\n" +
" int a = 3;\r\n" +
" String text;\r\n" +
" Object last = null;\r\n" +
" Object first = null;\r\n" +
" Object second = null;\r\n" +
"}",
"public class B {\r\n" +
" int a = 33;\r\n" +
" String text;\r\n" +
" Object last = new Object();\r\n" +
" Object first = null;\r\n" +
" Object second = new Object();\r\n" +
"}",
line(1, 1), line(3,3), line(5,5)
);
}
public void testReformatFiles() throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile m1 = fs.createFile("Test1.java", COMMITTED, MODIFIED);
PsiFile u1 = fs.createFile("Test2.java", COMMITTED, COMMITTED);
fs.createDirectoryAndMakeItCurrent();
PsiFile m2 = fs.createFile("Test3.java", COMMITTED, MODIFIED);
PsiFile u2 = fs.createFile("Test4.java", COMMITTED, COMMITTED);
new ReformatCodeProcessor(getProject(), new PsiFile[] {m1, m2, u1, u2}, null, true).run();
assertFormattedLines(CHANGED_LINES, m1, m2);
assertFormattedLines(NO_CHANGED_LINES, u1, u2);
}
public void testNoChangesNoFormatting() throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile u1 = fs.createFile("Test1.java", COMMITTED, COMMITTED);
PsiFile u2 = fs.createFile("Test2.java", COMMITTED, COMMITTED);
reformatDirectory(fs.getCurrentDirectory());
assertFormattedLines(NO_CHANGED_LINES, u1, u2);
}
public void testReformatOnlyChanged() throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile untouched1 = fs.createFile("Test1.java", COMMITTED, COMMITTED);
PsiFile untouched2 = fs.createFile("Test2.java", COMMITTED, COMMITTED);
PsiFile modified1 = fs.createFile("Test4.java", COMMITTED, MODIFIED);
PsiFile modified2 = fs.createFile("Test5.java", COMMITTED, MODIFIED);
PsiFile modified3 = fs.createFile("Test6.java", COMMITTED, MODIFIED);
reformatDirectory(fs.getCurrentDirectory());
assertFormattedLines(CHANGED_LINES, modified1, modified2, modified3);
assertFormattedLines(NO_CHANGED_LINES, untouched1, untouched2);
}
public void testReformatInAllSubtree() throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile modified11 = fs.createFile("Test4.java", COMMITTED, MODIFIED);
PsiFile modified12 = fs.createFile("Test5.java", COMMITTED, MODIFIED);
fs.createDirectoryAndMakeItCurrent();
PsiDirectory dirToReformat = fs.getCurrentDirectory();
PsiFile modified21 = fs.createFile("Test6.java", COMMITTED, MODIFIED);
PsiFile modified22 = fs.createFile("Test7.java", COMMITTED, MODIFIED);
fs.createDirectoryAndMakeItCurrent();
PsiFile modified31 = fs.createFile("Test8.java", COMMITTED, MODIFIED);
PsiFile modified32 = fs.createFile("Test9.java", COMMITTED, MODIFIED);
reformatDirectory(dirToReformat);
assertFormattedLines(CHANGED_LINES, modified21, modified22, modified31, modified32);
assertFormattedLines(NO_CHANGED_LINES, modified11, modified12);
}
private static void registerChangeListManager(@NotNull ChangeListManager manager) {
Project project = getProject();
assert (project instanceof ComponentManagerImpl);
ComponentManagerImpl projectComponentManager = (ComponentManagerImpl)project;
projectComponentManager.registerComponentInstance(ChangeListManager.class, manager);
}
private static void registerCodeStyleManager(@NotNull CodeStyleManager manager) {
String componentKey = CodeStyleManager.class.getName();
MutablePicoContainer container = (MutablePicoContainer)getProject().getPicoContainer();
container.unregisterComponent(componentKey);
container.registerComponentInstance(componentKey, manager);
}
private void doTest(@NotNull String committed, @NotNull String modified, @NotNull ChangedLines... lines) throws IOException {
ChangedFilesStructure fs = new ChangedFilesStructure(myWorkingDirectory);
PsiFile file = fs.createFile("Test.java", committed, modified);
reformatDirectory(myWorkingDirectory);
assertFormattedRangesEqualsTo(file, lines);
}
private void assertFormattedLines(@NotNull ChangedLines[] expectedLines, @NotNull PsiFile... files) {
for (PsiFile file : files)
assertFormattedRangesEqualsTo(file, expectedLines);
}
private void assertFormattedRangesEqualsTo(@NotNull PsiFile file, ChangedLines... expected) {
ChangedLines[] formatted = myMockCodeStyleManager.getFormattedLinesFor(file);
Comparator<ChangedLines> cmp = new Comparator<ChangedLines>() {
@Override
public int compare(ChangedLines o1, ChangedLines o2) {
return o1.from < o2.from ? -1 : 1;
}
};
Arrays.sort(expected, cmp);
Arrays.sort(formatted, cmp);
assertTrue(getErrorMessage(expected, formatted), Arrays.equals(expected, formatted));
}
@NotNull
private static String getErrorMessage(ChangedLines[] expected, ChangedLines[] actual) {
return "Expected: " + Arrays.toString(expected) + " Actual: " + Arrays.toString(actual);
}
private static void reformatDirectory(@NotNull PsiDirectory dir) {
ReformatCodeProcessor processor = new ReformatCodeProcessor(getProject(), dir, true, true);
processor.run();
}
class ChangedFilesStructure {
private TestFileStructure myFileStructure;
public ChangedFilesStructure(@NotNull PsiDirectory directory) {
myFileStructure = new TestFileStructure(getModule(), directory);
}
public void createDirectoryAndMakeItCurrent() throws IOException {
myFileStructure.createDirectoryAndMakeItCurrent("inner");
}
@NotNull
public PsiFile createFile(@NotNull String fileName,
@NotNull String committedContent,
@NotNull String actualContent) throws IOException
{
PsiFile file = myFileStructure.addTestFile(fileName, actualContent);
if (committedContent != actualContent) {
registerCommittedRevision(committedContent, file);
}
return file;
}
private void registerCommittedRevision(@NotNull String committedContent, @NotNull PsiFile... files) {
List<Change> changes = createChanges(committedContent, files);
injectChanges(changes);
}
@NotNull
private List<Change> createChanges(@NotNull String committed, @NotNull PsiFile... files) {
List<Change> changes = ContainerUtil.newArrayList();
for (PsiFile file : files) {
changes.add(createChange(committed, file));
}
return changes;
}
private void injectChanges(@NotNull List<Change> changes) {
Change[] arr = new Change[changes.size()];
ContainerUtil.toArray(changes, arr);
myMockChangeListManager.addChanges(arr);
}
@NotNull
private Change createChange(@NotNull String committed, @NotNull PsiFile file) {
FilePathImpl filePath = new FilePathImpl(file.getVirtualFile());
ContentRevision before = new SimpleContentRevision(committed, filePath, "");
ContentRevision after = new SimpleContentRevision("", filePath, "");
return new Change(before, after);
}
@NotNull
public PsiDirectory getCurrentDirectory() {
return myFileStructure.getCurrentDirectory();
}
}
}