252 lines
9.0 KiB
Java
252 lines
9.0 KiB
Java
/*
|
|
* Copyright (C) 2022, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others.
|
|
*
|
|
* This program and the accompanying materials are made available under the
|
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
|
* https://www.eclipse.org/org/documents/edl-v10.php.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
package org.eclipse.jgit.pgm;
|
|
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.nio.file.Path;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import java.util.stream.Collectors;
|
|
|
|
import org.eclipse.jgit.api.Git;
|
|
import org.eclipse.jgit.diff.DiffEntry;
|
|
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
|
|
import org.eclipse.jgit.pgm.opt.CmdLineParser;
|
|
import org.eclipse.jgit.pgm.opt.SubcommandHandler;
|
|
import org.eclipse.jgit.revwalk.RevCommit;
|
|
import org.eclipse.jgit.treewalk.FileTreeIterator;
|
|
import org.eclipse.jgit.treewalk.TreeWalk;
|
|
import org.eclipse.jgit.util.SystemReader;
|
|
import org.junit.Assume;
|
|
import org.junit.Before;
|
|
import org.kohsuke.args4j.Argument;
|
|
import org.kohsuke.args4j.CmdLineException;
|
|
|
|
/**
|
|
* Base test case for the {@code difftool} and {@code mergetool} commands.
|
|
*/
|
|
public abstract class ToolTestCase extends CLIRepositoryTestCase {
|
|
|
|
public static class GitCliJGitWrapperParser {
|
|
@Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class)
|
|
TextBuiltin subcommand;
|
|
|
|
@Argument(index = 1, metaVar = "metaVar_arg")
|
|
List<String> arguments = new ArrayList<>();
|
|
}
|
|
|
|
protected static final String TOOL_NAME = "some_tool";
|
|
|
|
private static final String TEST_BRANCH_NAME = "test_branch";
|
|
|
|
private Git git;
|
|
|
|
@Override
|
|
@Before
|
|
public void setUp() throws Exception {
|
|
super.setUp();
|
|
git = new Git(db);
|
|
git.commit().setMessage("initial commit").call();
|
|
git.branchCreate().setName(TEST_BRANCH_NAME).call();
|
|
}
|
|
|
|
protected String[] runAndCaptureUsingInitRaw(String... args)
|
|
throws Exception {
|
|
InputStream inputStream = null; // no input stream
|
|
return runAndCaptureUsingInitRaw(inputStream, args);
|
|
}
|
|
|
|
protected String[] runAndCaptureUsingInitRaw(
|
|
List<String> expectedErrorOutput, String... args) throws Exception {
|
|
InputStream inputStream = null; // no input stream
|
|
return runAndCaptureUsingInitRaw(inputStream, expectedErrorOutput,
|
|
args);
|
|
}
|
|
|
|
protected String[] runAndCaptureUsingInitRaw(InputStream inputStream,
|
|
String... args) throws Exception {
|
|
List<String> expectedErrorOutput = Collections.emptyList();
|
|
return runAndCaptureUsingInitRaw(inputStream, expectedErrorOutput,
|
|
args);
|
|
}
|
|
|
|
protected String[] runAndCaptureUsingInitRaw(InputStream inputStream,
|
|
List<String> expectedErrorOutput, String... args)
|
|
throws CmdLineException, Exception, IOException {
|
|
CLIGitCommand.Result result = new CLIGitCommand.Result();
|
|
|
|
GitCliJGitWrapperParser bean = new GitCliJGitWrapperParser();
|
|
CmdLineParser clp = new CmdLineParser(bean);
|
|
clp.parseArgument(args);
|
|
|
|
TextBuiltin cmd = bean.subcommand;
|
|
cmd.initRaw(db, null, inputStream, result.out, result.err);
|
|
cmd.execute(bean.arguments.toArray(new String[bean.arguments.size()]));
|
|
if (cmd.getOutputWriter() != null) {
|
|
cmd.getOutputWriter().flush();
|
|
}
|
|
if (cmd.getErrorWriter() != null) {
|
|
cmd.getErrorWriter().flush();
|
|
}
|
|
|
|
List<String> errLines = result.errLines().stream()
|
|
.filter(l -> !l.isBlank()) // we care only about error messages
|
|
.collect(Collectors.toList());
|
|
assertEquals("Expected no standard error output from tool",
|
|
expectedErrorOutput.toString(), errLines.toString());
|
|
|
|
return result.outLines().toArray(new String[0]);
|
|
}
|
|
|
|
protected String[] createMergeConflict() throws Exception {
|
|
// create files on initial branch
|
|
git.checkout().setName(TEST_BRANCH_NAME).call();
|
|
writeTrashFile("dir1/a", "Hello world a");
|
|
writeTrashFile("dir2/b", "Hello world b");
|
|
git.add().addFilepattern(".").call();
|
|
git.commit().setMessage("files a & b added").call();
|
|
// create another branch and change files
|
|
git.branchCreate().setName("branch_1").call();
|
|
git.checkout().setName("branch_1").call();
|
|
writeTrashFile("dir1/a", "Hello world a 1");
|
|
writeTrashFile("dir2/b", "Hello world b 1");
|
|
git.add().addFilepattern(".").call();
|
|
RevCommit commit1 = git.commit()
|
|
.setMessage("files a & b modified commit 1").call();
|
|
// checkout initial branch
|
|
git.checkout().setName(TEST_BRANCH_NAME).call();
|
|
// create another branch and change files
|
|
git.branchCreate().setName("branch_2").call();
|
|
git.checkout().setName("branch_2").call();
|
|
writeTrashFile("dir1/a", "Hello world a 2");
|
|
writeTrashFile("dir2/b", "Hello world b 2");
|
|
git.add().addFilepattern(".").call();
|
|
git.commit().setMessage("files a & b modified commit 2").call();
|
|
// cherry-pick conflicting changes
|
|
git.cherryPick().include(commit1).call();
|
|
String[] conflictingFilenames = { "dir1/a", "dir2/b" };
|
|
return conflictingFilenames;
|
|
}
|
|
|
|
protected String[] createDeletedConflict() throws Exception {
|
|
// create files on initial branch
|
|
git.checkout().setName(TEST_BRANCH_NAME).call();
|
|
writeTrashFile("dir1/a", "Hello world a");
|
|
writeTrashFile("dir2/b", "Hello world b");
|
|
git.add().addFilepattern(".").call();
|
|
git.commit().setMessage("files a & b added").call();
|
|
// create another branch and change files
|
|
git.branchCreate().setName("branch_1").call();
|
|
git.checkout().setName("branch_1").call();
|
|
writeTrashFile("dir1/a", "Hello world a 1");
|
|
writeTrashFile("dir2/b", "Hello world b 1");
|
|
git.add().addFilepattern(".").call();
|
|
RevCommit commit1 = git.commit()
|
|
.setMessage("files a & b modified commit 1").call();
|
|
// checkout initial branch
|
|
git.checkout().setName(TEST_BRANCH_NAME).call();
|
|
// create another branch and change files
|
|
git.branchCreate().setName("branch_2").call();
|
|
git.checkout().setName("branch_2").call();
|
|
git.rm().addFilepattern("dir1/a").call();
|
|
git.rm().addFilepattern("dir2/b").call();
|
|
git.commit().setMessage("files a & b deleted commit 2").call();
|
|
// cherry-pick conflicting changes
|
|
git.cherryPick().include(commit1).call();
|
|
String[] conflictingFilenames = { "dir1/a", "dir2/b" };
|
|
return conflictingFilenames;
|
|
}
|
|
|
|
protected String[] createUnstagedChanges() throws Exception {
|
|
writeTrashFile("dir1/a", "Hello world a");
|
|
writeTrashFile("dir2/b", "Hello world b");
|
|
git.add().addFilepattern(".").call();
|
|
git.commit().setMessage("files a & b").call();
|
|
writeTrashFile("dir1/a", "New Hello world a");
|
|
writeTrashFile("dir2/b", "New Hello world b");
|
|
String[] conflictingFilenames = { "dir1/a", "dir2/b" };
|
|
return conflictingFilenames;
|
|
}
|
|
|
|
protected String[] createStagedChanges() throws Exception {
|
|
String[] conflictingFilenames = createUnstagedChanges();
|
|
git.add().addFilepattern(".").call();
|
|
return conflictingFilenames;
|
|
}
|
|
|
|
protected List<DiffEntry> getRepositoryChanges(RevCommit commit)
|
|
throws Exception {
|
|
TreeWalk tw = new TreeWalk(db);
|
|
tw.addTree(commit.getTree());
|
|
FileTreeIterator modifiedTree = new FileTreeIterator(db);
|
|
tw.addTree(modifiedTree);
|
|
List<DiffEntry> changes = DiffEntry.scan(tw);
|
|
return changes;
|
|
}
|
|
|
|
protected Path getFullPath(String repositoryFilename) {
|
|
Path dotGitPath = db.getDirectory().toPath();
|
|
Path repositoryRoot = dotGitPath.getParent();
|
|
Path repositoryFilePath = repositoryRoot.resolve(repositoryFilename);
|
|
return repositoryFilePath;
|
|
}
|
|
|
|
protected static InputStream createInputStream(String[] inputLines) {
|
|
return createInputStream(Arrays.asList(inputLines));
|
|
}
|
|
|
|
protected static InputStream createInputStream(List<String> inputLines) {
|
|
String input = String.join(System.lineSeparator(), inputLines);
|
|
InputStream inputStream = new ByteArrayInputStream(input.getBytes(UTF_8));
|
|
return inputStream;
|
|
}
|
|
|
|
protected static void assertArrayOfLinesEquals(String failMessage,
|
|
String[] expected, String[] actual) {
|
|
assertEquals(failMessage, toString(expected), toString(actual));
|
|
}
|
|
|
|
protected static void assertArrayOfMatchingLines(String failMessage,
|
|
Pattern[] expected, String[] actual) {
|
|
assertEquals(failMessage + System.lineSeparator()
|
|
+ "Expected and actual lines count don't match. Expected: "
|
|
+ Arrays.asList(expected) + ", actual: "
|
|
+ Arrays.asList(actual), expected.length, actual.length);
|
|
int n = expected.length;
|
|
for (int i = 0; i < n; ++i) {
|
|
Pattern expectedPattern = expected[i];
|
|
String actualLine = actual[i];
|
|
Matcher matcher = expectedPattern.matcher(actualLine);
|
|
boolean matches = matcher.matches();
|
|
assertTrue(failMessage + System.lineSeparator() + "Line " + i + " '"
|
|
+ actualLine + "' doesn't match expected pattern: "
|
|
+ expectedPattern + System.lineSeparator() + "Expected: "
|
|
+ Arrays.asList(expected) + ", actual: "
|
|
+ Arrays.asList(actual),
|
|
matches);
|
|
}
|
|
}
|
|
|
|
protected static void assumeLinuxPlatform() {
|
|
Assume.assumeTrue("This test can run only in Linux tests",
|
|
SystemReader.getInstance().isLinux());
|
|
}
|
|
}
|