mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-89754 Add a pre-commit check on core.autocrlf option and warn if CRLF is about to be committed to the repository. Step #2
* Write the detector according to the following algorithm: - check core.autocrlf - check if files to commit have CRLFs - check if there are CRLF-related attributes on these files. * Respect multi-roots. Tests: * Write a test on the detector and the parser of the output of `git check-attr`. * Try one more approach on unit testing Git: declare GitTestImpl as more real Git implementation than MockGit is: this one calls git. The tests are fast enough. * Several fixes and enhancements in the mocks. * Introduce GitExecutor which allows a nice syntax of calling to Git. This can be used as a mixin in tests.
This commit is contained in:
@@ -17,6 +17,7 @@ package git4idea;
|
||||
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
@@ -86,4 +87,6 @@ public interface PlatformFacade {
|
||||
@Nullable
|
||||
IdeaPluginDescriptor getPluginByClassName(@NotNull String name);
|
||||
|
||||
@NotNull
|
||||
FileDocumentManager getFileDocumentManager();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.ide.plugins.PluginManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
@@ -109,6 +110,12 @@ public class PlatformFacadeImpl implements PlatformFacade {
|
||||
return PluginManager.getPlugin(PluginManager.getPluginByClassName(name));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileDocumentManager getFileDocumentManager() {
|
||||
return FileDocumentManager.getInstance();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AbstractVcs getVcs(@NotNull Project project) {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 git4idea.attributes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
public enum GitAttribute {
|
||||
TEXT("text"),
|
||||
CRLF("crlf");
|
||||
|
||||
@NotNull private final String myName;
|
||||
|
||||
GitAttribute(@NotNull String name) {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GitAttribute forName(String attribute) {
|
||||
for (GitAttribute attr : values()) {
|
||||
if (attr.myName.equalsIgnoreCase(attribute)) {
|
||||
return attr;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 git4idea.attributes;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Parses the output of {@code git check-attr}.
|
||||
* All supported attributes are instances of {@link GitAttribute}. Others just ignored until needed.
|
||||
* Values are also ignored: we just need to know if there is a specified attribute on a file, or not.
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
public class GitCheckAttrParser {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(GitCheckAttrParser.class);
|
||||
private static final String UNSPECIFIED_VALUE = "unspecified";
|
||||
|
||||
@NotNull private final Map<String, Collection<GitAttribute>> myAttributes;
|
||||
|
||||
private GitCheckAttrParser(@NotNull List<String> output) {
|
||||
myAttributes = new HashMap<String, Collection<GitAttribute>>();
|
||||
|
||||
for (String line : output) {
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<String> split = StringUtil.split(line, ":");
|
||||
LOG.assertTrue(split.size() == 3, String.format("Output doesn't match the expected format. Line: %s%nAll output:%n%s",
|
||||
line, StringUtil.join(output, "\n")));
|
||||
String file = split.get(0).trim();
|
||||
String attribute = split.get(1).trim();
|
||||
String info = split.get(2).trim();
|
||||
|
||||
GitAttribute attr = GitAttribute.forName(attribute);
|
||||
if (attr == null || info.equalsIgnoreCase(UNSPECIFIED_VALUE)) {
|
||||
// ignoring attributes that we are not interested in
|
||||
continue;
|
||||
}
|
||||
|
||||
if (myAttributes.get(file) == null) {
|
||||
myAttributes.put(file, new ArrayList<GitAttribute>());
|
||||
}
|
||||
myAttributes.get(file).add(attr);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static GitCheckAttrParser parse(@NotNull List<String> output) {
|
||||
return new GitCheckAttrParser(output);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, Collection<GitAttribute>> getAttributes() {
|
||||
return myAttributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package git4idea.checkin;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
@@ -33,6 +34,8 @@ import com.intellij.util.PairConsumer;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.PlatformFacade;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.config.GitVcsSettings;
|
||||
import git4idea.config.GitVersion;
|
||||
@@ -102,7 +105,11 @@ public class GitCheckinHandlerFactory extends VcsCheckinHandlerFactory {
|
||||
return ReturnResult.COMMIT;
|
||||
}
|
||||
|
||||
GitCrlfProblemsDetector crlfHelper = GitCrlfProblemsDetector.detect(myPanel.getVirtualFiles());
|
||||
PlatformFacade platformFacade = ServiceManager.getService(myProject, PlatformFacade.class);
|
||||
Git git = ServiceManager.getService(Git.class);
|
||||
|
||||
Collection<VirtualFile> files = myPanel.getVirtualFiles(); // deleted files aren't included, but for them we don't care about CRLFs.
|
||||
GitCrlfProblemsDetector crlfHelper = GitCrlfProblemsDetector.detect(myProject, platformFacade, git, files);
|
||||
if (crlfHelper.shouldWarn()) {
|
||||
final GitCrlfDialog dialog = new GitCrlfDialog(myProject);
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
|
||||
@@ -48,6 +48,9 @@ public interface Git {
|
||||
@NotNull
|
||||
GitCommandResult clone(@NotNull Project project, @NotNull File parentDirectory, @NotNull String url, @NotNull String clonedDirectoryName);
|
||||
|
||||
@NotNull
|
||||
GitCommandResult config(@NotNull GitRepository repository, String... params);
|
||||
|
||||
@NotNull
|
||||
GitCommandResult merge(@NotNull GitRepository repository, @NotNull String branchToMerge, @Nullable List<String> additionalParams,
|
||||
@NotNull GitLineHandlerListener... listeners);
|
||||
@@ -101,4 +104,7 @@ public interface Git {
|
||||
@NotNull
|
||||
GitCommandResult getUnmergedFiles(@NotNull GitRepository repository);
|
||||
|
||||
@NotNull
|
||||
GitCommandResult checkAttr(@NotNull GitRepository repository, @NotNull Collection<String> attributes,
|
||||
@NotNull Collection<VirtualFile> files);
|
||||
}
|
||||
|
||||
@@ -136,6 +136,25 @@ public class GitImpl implements Git {
|
||||
return run(handler, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult config(@NotNull GitRepository repository, String... params) {
|
||||
final GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.CONFIG);
|
||||
h.addParameters(params);
|
||||
return run(h);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult checkAttr(@NotNull GitRepository repository, @NotNull Collection<String> attributes,
|
||||
@NotNull Collection<VirtualFile> files) {
|
||||
final GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.CONFIG);
|
||||
h.addParameters(new ArrayList<String>(attributes));
|
||||
h.endOptions();
|
||||
h.addRelativeFiles(files);
|
||||
return run(h);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public GitCommandResult merge(@NotNull GitRepository repository, @NotNull String branchToMerge,
|
||||
|
||||
@@ -15,10 +15,22 @@
|
||||
*/
|
||||
package git4idea.crlf;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.PlatformFacade;
|
||||
import git4idea.attributes.GitAttribute;
|
||||
import git4idea.attributes.GitCheckAttrParser;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.commands.GitCommandResult;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.repo.GitRepository;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Given a number of files, detects if CRLF line separators in them are about to be committed to Git. That is:
|
||||
@@ -32,17 +44,152 @@ import java.util.Collection;
|
||||
* </ul>
|
||||
* All checks are made only for Windows system.
|
||||
*
|
||||
* Everywhere in the detection process we fail gracefully in case of exceptions: we log the fact, but don't fail totally, preferring to
|
||||
* tell that the calling code should not warn the user.
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
public class GitCrlfProblemsDetector {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(GitCrlfProblemsDetector.class);
|
||||
private static final String CRLF = "\r\n";
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final PlatformFacade myPlatformFacade;
|
||||
@NotNull private final Git myGit;
|
||||
|
||||
private final boolean myShouldWarn;
|
||||
|
||||
@NotNull
|
||||
public static GitCrlfProblemsDetector detect(Collection<VirtualFile> files) {
|
||||
return new GitCrlfProblemsDetector();
|
||||
public static GitCrlfProblemsDetector detect(@NotNull Project project, @NotNull PlatformFacade platformFacade,
|
||||
@NotNull Git git, @NotNull Collection<VirtualFile> files) {
|
||||
return new GitCrlfProblemsDetector(project, platformFacade, git, files);
|
||||
}
|
||||
|
||||
private GitCrlfProblemsDetector(@NotNull Project project, @NotNull PlatformFacade platformFacade, @NotNull Git git,
|
||||
@NotNull Collection<VirtualFile> files) {
|
||||
myProject = project;
|
||||
myPlatformFacade = platformFacade;
|
||||
myGit = git;
|
||||
|
||||
Map<VirtualFile, List<VirtualFile>> filesByRoots = sortFilesByRoots(files);
|
||||
|
||||
boolean shouldWarn = false;
|
||||
Collection<VirtualFile> rootsWithIncorrectAutoCrlf = getRootsWithIncorrectAutoCrlf(filesByRoots);
|
||||
if (!rootsWithIncorrectAutoCrlf.isEmpty()) {
|
||||
Map<VirtualFile, Collection<VirtualFile>> crlfFilesByRoots = findFilesWithCrlf(filesByRoots, rootsWithIncorrectAutoCrlf);
|
||||
if (!crlfFilesByRoots.isEmpty()) {
|
||||
Map<VirtualFile, Collection<VirtualFile>> crlfFilesWithoutAttrsByRoots = findFilesWithoutAttrs(crlfFilesByRoots);
|
||||
shouldWarn = !crlfFilesWithoutAttrsByRoots.isEmpty();
|
||||
}
|
||||
}
|
||||
myShouldWarn = shouldWarn;
|
||||
}
|
||||
|
||||
private Map<VirtualFile, Collection<VirtualFile>> findFilesWithoutAttrs(Map<VirtualFile, Collection<VirtualFile>> filesByRoots) {
|
||||
Map<VirtualFile, Collection<VirtualFile>> filesWithoutAttrsByRoot = new HashMap<VirtualFile, Collection<VirtualFile>>();
|
||||
for (Map.Entry<VirtualFile, Collection<VirtualFile>> entry : filesByRoots.entrySet()) {
|
||||
VirtualFile root = entry.getKey();
|
||||
Collection<VirtualFile> files = entry.getValue();
|
||||
Collection<VirtualFile> filesWithoutAttrs = findFilesWithoutAttrs(root, files);
|
||||
if (!filesWithoutAttrs.isEmpty()) {
|
||||
filesWithoutAttrsByRoot.put(root, filesWithoutAttrs);
|
||||
}
|
||||
}
|
||||
return filesWithoutAttrsByRoot;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<VirtualFile> findFilesWithoutAttrs(@NotNull VirtualFile root, @NotNull Collection<VirtualFile> files) {
|
||||
GitRepository repository = myPlatformFacade.getRepositoryManager(myProject).getRepositoryForRoot(root);
|
||||
if (repository == null) {
|
||||
LOG.warn("Repository is null for " + root);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Collection<String> interestingAttributes = Arrays.asList(GitAttribute.TEXT.getName(), GitAttribute.CRLF.getName());
|
||||
GitCommandResult result = myGit.checkAttr(repository, interestingAttributes, files);
|
||||
GitCheckAttrParser parser = GitCheckAttrParser.parse(result.getOutput());
|
||||
Map<String, Collection<GitAttribute>> attributes = parser.getAttributes();
|
||||
Collection<VirtualFile> filesWithoutAttrs = new ArrayList<VirtualFile>();
|
||||
for (VirtualFile file : files) {
|
||||
String relativePath = FileUtil.getRelativePath(root.getPath(), file.getPath(), '/');
|
||||
Collection<GitAttribute> attrs = attributes.get(relativePath);
|
||||
if (attrs == null || !attrs.contains(GitAttribute.TEXT) && !attrs.contains(GitAttribute.CRLF)) {
|
||||
filesWithoutAttrs.add(file);
|
||||
}
|
||||
}
|
||||
return filesWithoutAttrs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<VirtualFile, Collection<VirtualFile>> findFilesWithCrlf(@NotNull Map<VirtualFile, List<VirtualFile>> allFilesByRoots,
|
||||
@NotNull Collection<VirtualFile> rootsWithIncorrectAutoCrlf) {
|
||||
Map<VirtualFile, Collection<VirtualFile>> filesWithCrlfByRoots = new HashMap<VirtualFile, Collection<VirtualFile>>();
|
||||
for (Map.Entry<VirtualFile, List<VirtualFile>> entry : allFilesByRoots.entrySet()) {
|
||||
VirtualFile root = entry.getKey();
|
||||
List<VirtualFile> files = entry.getValue();
|
||||
if (rootsWithIncorrectAutoCrlf.contains(root)) {
|
||||
Collection<VirtualFile> filesWithCrlf = findFilesWithCrlf(files);
|
||||
if (!filesWithCrlf.isEmpty()) {
|
||||
filesWithCrlfByRoots.put(root, filesWithCrlf);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filesWithCrlfByRoots;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<VirtualFile> findFilesWithCrlf(@NotNull Collection<VirtualFile> files) {
|
||||
Collection<VirtualFile> filesWithCrlf = new ArrayList<VirtualFile>();
|
||||
for (VirtualFile file : files) {
|
||||
if (CRLF.equals(myPlatformFacade.getFileDocumentManager().getLineSeparator(file, myProject))) {
|
||||
filesWithCrlf.add(file);
|
||||
}
|
||||
}
|
||||
return filesWithCrlf;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<VirtualFile> getRootsWithIncorrectAutoCrlf(@NotNull Map<VirtualFile, List<VirtualFile>> filesByRoots) {
|
||||
Collection<VirtualFile> rootsWithIncorrectAutoCrlf = new ArrayList<VirtualFile>();
|
||||
for (Map.Entry<VirtualFile, List<VirtualFile>> entry : filesByRoots.entrySet()) {
|
||||
VirtualFile root = entry.getKey();
|
||||
boolean autocrlf = isAutoCrlfSetRight(root);
|
||||
if (!autocrlf) {
|
||||
rootsWithIncorrectAutoCrlf.add(root);
|
||||
}
|
||||
}
|
||||
return rootsWithIncorrectAutoCrlf;
|
||||
}
|
||||
|
||||
private boolean isAutoCrlfSetRight(@NotNull VirtualFile root) {
|
||||
GitRepository repository = myPlatformFacade.getRepositoryManager(myProject).getRepositoryForRoot(root);
|
||||
if (repository == null) {
|
||||
LOG.warn("Repository is null for " + root);
|
||||
return true;
|
||||
}
|
||||
GitCommandResult result = myGit.config(repository, GitConfigUtil.CORE_AUTOCRLF);
|
||||
if (!result.success()) {
|
||||
LOG.warn("Couldn't get git config core.autocrlf for " + root);
|
||||
return true;
|
||||
}
|
||||
String value = result.getOutputAsJoinedString();
|
||||
return value.equalsIgnoreCase("true") || value.equalsIgnoreCase("input");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<VirtualFile, List<VirtualFile>> sortFilesByRoots(@NotNull Collection<VirtualFile> files) {
|
||||
try {
|
||||
return GitUtil.sortFilesByGitRoot(files, true);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.error("Should never happen, since we passed 'ignore non-git' parameter", e);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldWarn() {
|
||||
return false;
|
||||
return myShouldWarn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 git4idea.attributes
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.assertEquals
|
||||
import static org.junit.Assert.assertTrue
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitCheckAttrParserTest {
|
||||
|
||||
@Test
|
||||
void "test"() {
|
||||
String output =
|
||||
"""
|
||||
org/example/MyClass.java: crlf: unset
|
||||
org/example/MyClass.java: diff: java
|
||||
org/example/MyClass.java: myAttr: set
|
||||
"""
|
||||
GitCheckAttrParser parse = GitCheckAttrParser.parse(Arrays.asList(output.split("\n")))
|
||||
String path = "org/example/MyClass.java"
|
||||
assertTrue "Missing path", parse.attributes.containsKey(path)
|
||||
Collection<GitAttribute> attrs = parse.attributes.get(path)
|
||||
assertTrue "CRLF attribute not found", attrs.contains(GitAttribute.CRLF)
|
||||
assertEquals "Too many attributes", 1, attrs.size()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 git4idea.crlf
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import git4idea.PlatformFacade
|
||||
import git4idea.commands.Git
|
||||
import git4idea.repo.GitRepository
|
||||
import git4idea.repo.GitRepositoryImpl
|
||||
import git4idea.test.*
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.assertFalse
|
||||
import static org.junit.Assert.assertTrue
|
||||
/**
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
@Mixin(GitExecutor)
|
||||
class GitCrlfProblemsDetectorTest {
|
||||
|
||||
private GitMockProject myProject
|
||||
private String myRootDir
|
||||
|
||||
private PlatformFacade myPlatformFacade
|
||||
private Git myGit
|
||||
|
||||
private String myOldCoreAutoCrlfValue
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
myRootDir = FileUtil.createTempDirectory("", "").getPath()
|
||||
myProject = new GitMockProject(myRootDir)
|
||||
myPlatformFacade = new GitTestPlatformFacade()
|
||||
myGit = new GitTestImpl()
|
||||
|
||||
cd myRootDir
|
||||
myOldCoreAutoCrlfValue = git "config --global core.autocrlf"
|
||||
|
||||
git "init"
|
||||
git "config --global --unset core.autocrlf"
|
||||
|
||||
GitRepository repository = GitRepositoryImpl.getLightInstance(new GitMockVirtualFile(myRootDir), myProject, myProject)
|
||||
((GitTestRepositoryManager)myPlatformFacade.getRepositoryManager(myProject)).add(repository)
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (!StringUtil.isEmptyOrSpaces(myOldCoreAutoCrlfValue)) {
|
||||
git "config --global core.autocrlf " + myOldCoreAutoCrlfValue;
|
||||
}
|
||||
FileUtil.delete(new File(myRootDir))
|
||||
}
|
||||
|
||||
@Test
|
||||
void "core.autocrlf is true = no warning"() {
|
||||
git "config core.autocrlf true"
|
||||
assertFalse "No warning should be done if core.autocrlf is true", detect("temp").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "core.autocrlf is input = no warning"() {
|
||||
git "config core.autocrlf input"
|
||||
assertFalse "No warning should be done if core.autocrlf is input", detect("temp").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "no files with CRLF = no warning"() {
|
||||
createFile("temp", "Unix file\nNice separators\nOnly LF\n")
|
||||
assertFalse "No warning should be done if all files are LFs", detect("temp").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "file with CRLF, no attrs, core.autocrlf is false = warning"() {
|
||||
createCrlfFile("win")
|
||||
assertFalse "Warning should be done for a CRLF file with core.autocrlf = false", detect("temp").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "file with CRLF, but text is set = no warning"() {
|
||||
gitattributes("* text=auto")
|
||||
createCrlfFile("win")
|
||||
assertFalse "No warning should be done if the file has a text attribute", detect("win").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "file with CRLF, but crlf is set = no warning"() {
|
||||
gitattributes("win crlf")
|
||||
createCrlfFile("win")
|
||||
assertFalse "No warning should be done if the file has a crlf attribute", detect("win").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "file with CRLF, but crlf is explicitly unset = no warning"() {
|
||||
gitattributes("win -crlf")
|
||||
createCrlfFile("win")
|
||||
assertFalse "No warning should be done if the file has an explicitly unset crlf attribute", detect("win").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "file with CRLF, but crlf is set to input = no warning"() {
|
||||
gitattributes("wi* crlf=input")
|
||||
createCrlfFile("win")
|
||||
assertFalse "No warning should be done if the file has a crlf attribute", detect("win").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "file with CRLF, nothing is set = warning"() {
|
||||
createCrlfFile("win")
|
||||
assertTrue "Warning should be done if the file has CRLFs inside, and no explicit attributes", detect("win").shouldWarn()
|
||||
}
|
||||
|
||||
@Test
|
||||
void "various files with various attributes, one doesn't match = warning"() {
|
||||
gitattributes """
|
||||
win1 text crlf diff
|
||||
win2 -text
|
||||
win3 text=auto
|
||||
win4 crlf
|
||||
win5 -crlf
|
||||
win6 crlf=input
|
||||
"""
|
||||
|
||||
createFile("unix", "Unix file\nNice separators\nOnly LF\n")
|
||||
createCrlfFile("win1")
|
||||
createCrlfFile("win2")
|
||||
createCrlfFile("win3")
|
||||
createCrlfFile("src/win4")
|
||||
createCrlfFile("src/win5")
|
||||
createCrlfFile("src/win6")
|
||||
createCrlfFile("src/win7")
|
||||
|
||||
assertTrue "Warning should be done, since one of the files has CRLFs and no related attributes",
|
||||
GitCrlfProblemsDetector.detect(myProject, myPlatformFacade, myGit,
|
||||
["unix", "win1", "win2", "win3", "src/win4", "src/win5", "src/win6", "src/win7"]
|
||||
.collect { it -> GitMockVirtualFile.fromPath(it, myRootDir) as VirtualFile})
|
||||
.shouldWarn()
|
||||
}
|
||||
|
||||
private void gitattributes(String content) {
|
||||
createFile(".gitattributes", content)
|
||||
}
|
||||
|
||||
private GitCrlfProblemsDetector detect(String relPath) {
|
||||
return detect(createVirtualFile(relPath))
|
||||
}
|
||||
|
||||
private GitCrlfProblemsDetector detect(VirtualFile file) {
|
||||
GitCrlfProblemsDetector.detect(myProject, myPlatformFacade, myGit, Collections.<VirtualFile> singleton(file))
|
||||
}
|
||||
|
||||
private void createCrlfFile(String relPath) {
|
||||
createFile(relPath, "Windows file\r\nBad separators\r\nCRLF in action\r\n")
|
||||
}
|
||||
|
||||
private void createFile(String relPath, String content) {
|
||||
String path = createFile(relPath)
|
||||
File file = new File(path)
|
||||
FileUtil.appendToFile(file, content)
|
||||
}
|
||||
|
||||
private VirtualFile createVirtualFile(String relPath) {
|
||||
return new GitMockVirtualFile(createFile(relPath))
|
||||
}
|
||||
|
||||
private String createFile(String relPath) {
|
||||
List<String> split = StringUtil.split(relPath, "/")
|
||||
File parent = new File(myRootDir)
|
||||
for (Iterator<String> it = split.iterator(); it.hasNext(); ) {
|
||||
String item = it.next()
|
||||
File file = new File(parent, item)
|
||||
if (it.hasNext()) {
|
||||
parent = file
|
||||
parent.mkdir()
|
||||
}
|
||||
else {
|
||||
file.createNewFile()
|
||||
return file.getPath()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -153,7 +153,7 @@ public class GitExec {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String run(@NotNull GitRepository repository, @NotNull String command, String... params) throws IOException {
|
||||
public static String run(@NotNull GitRepository repository, @NotNull String command, String... params) throws IOException {
|
||||
return new GitTestRunEnv(new File(repository.getRoot().getPath())).run(command, params);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 git4idea.test
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.util.ArrayUtil
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitExecutor {
|
||||
|
||||
private String myCurrentDir
|
||||
|
||||
void cd(String path) {
|
||||
myCurrentDir = path
|
||||
}
|
||||
|
||||
String git(String command) {
|
||||
List<String> split = StringUtil.split(command, " ")
|
||||
String[] params = split.size() > 1 ? ArrayUtil.toObjectArray(split.subList(1, split.size()), String) : ArrayUtil.EMPTY_STRING_ARRAY
|
||||
return new GitTestRunEnv(new File(myCurrentDir)).run(split.get(0), params);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 git4idea.test;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitMockFileDocumentManager extends FileDocumentManager {
|
||||
@Override
|
||||
public Document getDocument(@NotNull VirtualFile file) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document getCachedDocument(@NotNull VirtualFile file) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getFile(@NotNull Document document) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAllDocuments() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveDocument(@NotNull Document document) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveDocumentAsIs(@NotNull Document document) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Document[] getUnsavedDocuments() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDocumentUnsaved(@NotNull Document document) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFileModified(@NotNull VirtualFile file) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadFromDisk(@NotNull Document document) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getLineSeparator(@Nullable VirtualFile file, @Nullable Project project) {
|
||||
try {
|
||||
return FileUtil.loadFile(new File(file.getPath())).contains("\r\n") ? "\r\n" : "\n";
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestWriting(@NotNull Document document, @Nullable Project project) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadFiles(VirtualFile... files) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ class GitMockProject implements Project {
|
||||
|
||||
@Override
|
||||
MessageBus getMessageBus() {
|
||||
throw new UnsupportedOperationException()
|
||||
null
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,7 +155,7 @@ class GitMockProject implements Project {
|
||||
@NotNull
|
||||
@Override
|
||||
Condition getDisposed() {
|
||||
throw new UnsupportedOperationException()
|
||||
Condition.FALSE
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,6 +42,11 @@ class GitMockVirtualFile extends VirtualFile {
|
||||
return fromPath(new File(project.getBaseDir().getPath() + "/" + relativePath).getCanonicalPath())
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static VirtualFile fromPath(@NotNull String relativePath, @NotNull String basePath) {
|
||||
return fromPath(new File(basePath + "/" + relativePath).getCanonicalPath())
|
||||
}
|
||||
|
||||
GitMockVirtualFile(@NotNull String path) {
|
||||
myPath = FileUtil.toSystemIndependentName(path);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 git4idea.test
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vcs.VcsException
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import git4idea.commands.Git
|
||||
import git4idea.commands.GitCommandResult
|
||||
import git4idea.commands.GitLineHandlerListener
|
||||
import git4idea.push.GitPushSpec
|
||||
import git4idea.repo.GitRepository
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.Nullable
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
@Mixin(GitExecutor)
|
||||
public class GitTestImpl implements Git {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<VirtualFile> untrackedFiles(@NotNull Project project, @NotNull VirtualFile root, @Nullable Collection<VirtualFile> files)
|
||||
throws VcsException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<VirtualFile> untrackedFilesNoChunk(@NotNull Project project,
|
||||
@NotNull VirtualFile root,
|
||||
@Nullable List<String> relativePaths) throws VcsException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult clone(@NotNull Project project,
|
||||
@NotNull File parentDirectory,
|
||||
@NotNull String url,
|
||||
@NotNull String clonedDirectoryName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult config(@NotNull GitRepository repository, String... params) {
|
||||
cd repository.getRoot().getPath()
|
||||
String output = git "config " + params.join(" ")
|
||||
return new GitCommandResult(!output.contains("fatal"), 0, Collections.<String>emptyList(),
|
||||
Arrays.asList(StringUtil.splitByLines(output)))
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
GitCommandResult checkAttr(@NotNull GitRepository repository, @NotNull Collection<String> attributes, @NotNull Collection<VirtualFile> files) {
|
||||
String root = repository.getRoot().getPath()
|
||||
cd root
|
||||
String output = git "check-attr " + attributes.join(" ") + " -- " +
|
||||
files.collect({it -> FileUtil.getRelativePath(root, it.path, (char)'/')}).join(" ")
|
||||
return new GitCommandResult(!output.contains("fatal"), 0, Collections.<String>emptyList(),
|
||||
Arrays.asList(StringUtil.splitByLines(output)))
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult merge(@NotNull GitRepository repository,
|
||||
@NotNull String branchToMerge,
|
||||
@Nullable List<String> additionalParams,
|
||||
@NotNull GitLineHandlerListener... listeners) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult checkout(@NotNull GitRepository repository,
|
||||
@NotNull String reference,
|
||||
@Nullable String newBranch,
|
||||
boolean force,
|
||||
@NotNull GitLineHandlerListener... listeners) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult checkoutNewBranch(@NotNull GitRepository repository,
|
||||
@NotNull String branchName,
|
||||
@Nullable GitLineHandlerListener listener) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult createNewTag(@NotNull GitRepository repository,
|
||||
@NotNull String tagName,
|
||||
@Nullable GitLineHandlerListener listener,
|
||||
@NotNull String reference) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult branchDelete(@NotNull GitRepository repository,
|
||||
@NotNull String branchName,
|
||||
boolean force,
|
||||
@NotNull GitLineHandlerListener... listeners) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult branchContains(@NotNull GitRepository repository, @NotNull String commit) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult branchCreate(@NotNull GitRepository repository, @NotNull String branchName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult resetHard(@NotNull GitRepository repository, @NotNull String revision) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult resetMerge(@NotNull GitRepository repository, @Nullable String revision) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult tip(@NotNull GitRepository repository, @NotNull String branchName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult push(@NotNull GitRepository repository,
|
||||
@NotNull String remote,
|
||||
@NotNull String spec,
|
||||
@NotNull GitLineHandlerListener... listeners) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult push(@NotNull GitRepository repository,
|
||||
@NotNull GitPushSpec pushSpec,
|
||||
@NotNull GitLineHandlerListener... listeners) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult show(@NotNull GitRepository repository, @NotNull String... params) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult cherryPick(@NotNull GitRepository repository,
|
||||
@NotNull String hash,
|
||||
boolean autoCommit,
|
||||
@NotNull GitLineHandlerListener... listeners) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GitCommandResult getUnmergedFiles(@NotNull GitRepository repository) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package git4idea.test;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.mock.MockLocalFileSystem;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
@@ -145,6 +146,12 @@ public class GitTestPlatformFacade implements PlatformFacade {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileDocumentManager getFileDocumentManager() {
|
||||
return new GitMockFileDocumentManager();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AbstractVcs getVcs(@NotNull Project project) {
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.List;
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
class GitTestRepositoryManager implements GitRepositoryManager {
|
||||
public class GitTestRepositoryManager implements GitRepositoryManager {
|
||||
|
||||
private final Collection<GitRepository> myRepositories = new ArrayList<GitRepository>();
|
||||
|
||||
@@ -40,7 +40,12 @@ class GitTestRepositoryManager implements GitRepositoryManager {
|
||||
|
||||
@Override
|
||||
public GitRepository getRepositoryForRoot(@Nullable VirtualFile root) {
|
||||
return myRepositories.iterator().next();
|
||||
for (GitRepository repository : myRepositories) {
|
||||
if (repository.getRoot().equals(root)) {
|
||||
return repository;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -35,11 +36,14 @@ import org.picocontainer.MutablePicoContainer;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@@ -225,6 +229,21 @@ public class GitTestUtil {
|
||||
return new File(pluginRoot, "testData");
|
||||
}
|
||||
|
||||
// for testing purposes we test the behavior of windows and unix gits on both platforms
|
||||
// this method sets SystemInfo.isWindows to whatever we want
|
||||
public static void setWindows(boolean windows) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field win = SystemInfo.class.getDeclaredField("isWindows");
|
||||
win.setAccessible(true);
|
||||
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
modifiersField.setAccessible(true);
|
||||
modifiersField.setInt(win, win.getModifiers() & ~Modifier.FINAL);
|
||||
|
||||
win.set(null, windows);
|
||||
|
||||
assertEquals(SystemInfo.isWindows, windows);
|
||||
}
|
||||
|
||||
public interface EqualityChecker<T, E> {
|
||||
boolean areEqual(T actual, E expected);
|
||||
}
|
||||
|
||||
@@ -86,6 +86,12 @@ class MockGit implements Git {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
GitCommandResult config(@NotNull GitRepository repository, String... params) {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
GitCommandResult merge(@NotNull GitRepository repository, @NotNull String branchToMerge, @Nullable List<String> additionalParams,
|
||||
@@ -187,6 +193,12 @@ class MockGit implements Git {
|
||||
return FAKE_SUCCESS_RESULT
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
GitCommandResult checkAttr(@NotNull GitRepository repository, @NotNull Collection<String> attributes, @NotNull Collection<VirtualFile> files) {
|
||||
|
||||
}
|
||||
|
||||
private void produceOutput(String output, GitLineHandlerListener... listeners) {
|
||||
for (String line : output.split("\n")) { // for simplicity all output goes to OUTPUT, no ERROR
|
||||
listeners.each { it.onLineAvailable(line, ProcessOutputTypes.STDOUT) }
|
||||
|
||||
@@ -15,12 +15,11 @@
|
||||
*/
|
||||
package git4idea.tests;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import git4idea.config.GitVersion;
|
||||
import git4idea.test.GitTestUtil;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import static git4idea.config.GitVersion.Type;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
@@ -53,13 +52,13 @@ public class GitVersionTest {
|
||||
*/
|
||||
@Test
|
||||
public void testParse() throws Exception {
|
||||
setWindows(false);
|
||||
GitTestUtil.setWindows(false);
|
||||
for (TestGitVersion test : commonTests) {
|
||||
GitVersion version = GitVersion.parse(test.output);
|
||||
assertEqualVersions(version, test, Type.UNIX);
|
||||
}
|
||||
|
||||
setWindows(true);
|
||||
GitTestUtil.setWindows(true);
|
||||
for (TestGitVersion test : commonTests) {
|
||||
GitVersion version = GitVersion.parse(test.output);
|
||||
assertEqualVersions(version, test, Type.CYGWIN);
|
||||
@@ -73,7 +72,7 @@ public class GitVersionTest {
|
||||
|
||||
@Test
|
||||
public void testEqualsAndCompare() throws Exception {
|
||||
setWindows(true);
|
||||
GitTestUtil.setWindows(true);
|
||||
GitVersion v1 = GitVersion.parse("git version 1.6.3");
|
||||
GitVersion v2 = GitVersion.parse("git version 1.7.3");
|
||||
GitVersion v3 = GitVersion.parse("git version 1.7.3");
|
||||
@@ -119,21 +118,6 @@ public class GitVersionTest {
|
||||
assertEquals(type, expectedType);
|
||||
}
|
||||
|
||||
// for testing purposes we test the behavior of windows and unix gits on both platforms
|
||||
// this method sets SystemInfo.isWindows to whatever we want
|
||||
private static void setWindows(boolean windows) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field win = SystemInfo.class.getDeclaredField("isWindows");
|
||||
win.setAccessible(true);
|
||||
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
modifiersField.setAccessible(true);
|
||||
modifiersField.setInt(win, win.getModifiers() & ~Modifier.FINAL);
|
||||
|
||||
win.set(null, windows);
|
||||
|
||||
assertEquals(SystemInfo.isWindows, windows);
|
||||
}
|
||||
|
||||
private static class TestGitVersion {
|
||||
private final String output;
|
||||
private final int major;
|
||||
|
||||
Reference in New Issue
Block a user