1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.pgm;
11
12 import static java.nio.charset.StandardCharsets.UTF_8;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertTrue;
15
16 import java.io.ByteArrayInputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.nio.file.Path;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26 import java.util.stream.Collectors;
27
28 import org.eclipse.jgit.api.Git;
29 import org.eclipse.jgit.diff.DiffEntry;
30 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
31 import org.eclipse.jgit.pgm.opt.CmdLineParser;
32 import org.eclipse.jgit.pgm.opt.SubcommandHandler;
33 import org.eclipse.jgit.revwalk.RevCommit;
34 import org.eclipse.jgit.treewalk.FileTreeIterator;
35 import org.eclipse.jgit.treewalk.TreeWalk;
36 import org.eclipse.jgit.util.SystemReader;
37 import org.junit.Assume;
38 import org.junit.Before;
39 import org.kohsuke.args4j.Argument;
40 import org.kohsuke.args4j.CmdLineException;
41
42
43
44
45 public abstract class ToolTestCase extends CLIRepositoryTestCase {
46
47 public static class GitCliJGitWrapperParser {
48 @Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class)
49 TextBuiltin subcommand;
50
51 @Argument(index = 1, metaVar = "metaVar_arg")
52 List<String> arguments = new ArrayList<>();
53 }
54
55 protected static final String TOOL_NAME = "some_tool";
56
57 private static final String TEST_BRANCH_NAME = "test_branch";
58
59 private Git git;
60
61 @Override
62 @Before
63 public void setUp() throws Exception {
64 super.setUp();
65 git = new Git(db);
66 git.commit().setMessage("initial commit").call();
67 git.branchCreate().setName(TEST_BRANCH_NAME).call();
68 }
69
70 protected String[] runAndCaptureUsingInitRaw(String... args)
71 throws Exception {
72 InputStream inputStream = null;
73 return runAndCaptureUsingInitRaw(inputStream, args);
74 }
75
76 protected String[] runAndCaptureUsingInitRaw(
77 List<String> expectedErrorOutput, String... args) throws Exception {
78 InputStream inputStream = null;
79 return runAndCaptureUsingInitRaw(inputStream, expectedErrorOutput,
80 args);
81 }
82
83 protected String[] runAndCaptureUsingInitRaw(InputStream inputStream,
84 String... args) throws Exception {
85 List<String> expectedErrorOutput = Collections.emptyList();
86 return runAndCaptureUsingInitRaw(inputStream, expectedErrorOutput,
87 args);
88 }
89
90 protected String[] runAndCaptureUsingInitRaw(InputStream inputStream,
91 List<String> expectedErrorOutput, String... args)
92 throws CmdLineException, Exception, IOException {
93 CLIGitCommand.Result result = new CLIGitCommand.Result();
94
95 GitCliJGitWrapperParser bean = new GitCliJGitWrapperParser();
96 CmdLineParser clp = new CmdLineParser(bean);
97 clp.parseArgument(args);
98
99 TextBuiltin cmd = bean.subcommand;
100 cmd.initRaw(db, null, inputStream, result.out, result.err);
101 cmd.execute(bean.arguments.toArray(new String[bean.arguments.size()]));
102 if (cmd.getOutputWriter() != null) {
103 cmd.getOutputWriter().flush();
104 }
105 if (cmd.getErrorWriter() != null) {
106 cmd.getErrorWriter().flush();
107 }
108
109 List<String> errLines = result.errLines().stream()
110 .filter(l -> !l.isBlank())
111 .collect(Collectors.toList());
112 assertEquals("Expected no standard error output from tool",
113 expectedErrorOutput.toString(), errLines.toString());
114
115 return result.outLines().toArray(new String[0]);
116 }
117
118 protected String[] createMergeConflict() throws Exception {
119
120 git.checkout().setName(TEST_BRANCH_NAME).call();
121 writeTrashFile("dir1/a", "Hello world a");
122 writeTrashFile("dir2/b", "Hello world b");
123 git.add().addFilepattern(".").call();
124 git.commit().setMessage("files a & b added").call();
125
126 git.branchCreate().setName("branch_1").call();
127 git.checkout().setName("branch_1").call();
128 writeTrashFile("dir1/a", "Hello world a 1");
129 writeTrashFile("dir2/b", "Hello world b 1");
130 git.add().addFilepattern(".").call();
131 RevCommit commit1 = git.commit()
132 .setMessage("files a & b modified commit 1").call();
133
134 git.checkout().setName(TEST_BRANCH_NAME).call();
135
136 git.branchCreate().setName("branch_2").call();
137 git.checkout().setName("branch_2").call();
138 writeTrashFile("dir1/a", "Hello world a 2");
139 writeTrashFile("dir2/b", "Hello world b 2");
140 git.add().addFilepattern(".").call();
141 git.commit().setMessage("files a & b modified commit 2").call();
142
143 git.cherryPick().include(commit1).call();
144 String[] conflictingFilenames = { "dir1/a", "dir2/b" };
145 return conflictingFilenames;
146 }
147
148 protected String[] createDeletedConflict() throws Exception {
149
150 git.checkout().setName(TEST_BRANCH_NAME).call();
151 writeTrashFile("dir1/a", "Hello world a");
152 writeTrashFile("dir2/b", "Hello world b");
153 git.add().addFilepattern(".").call();
154 git.commit().setMessage("files a & b added").call();
155
156 git.branchCreate().setName("branch_1").call();
157 git.checkout().setName("branch_1").call();
158 writeTrashFile("dir1/a", "Hello world a 1");
159 writeTrashFile("dir2/b", "Hello world b 1");
160 git.add().addFilepattern(".").call();
161 RevCommit commit1 = git.commit()
162 .setMessage("files a & b modified commit 1").call();
163
164 git.checkout().setName(TEST_BRANCH_NAME).call();
165
166 git.branchCreate().setName("branch_2").call();
167 git.checkout().setName("branch_2").call();
168 git.rm().addFilepattern("dir1/a").call();
169 git.rm().addFilepattern("dir2/b").call();
170 git.commit().setMessage("files a & b deleted commit 2").call();
171
172 git.cherryPick().include(commit1).call();
173 String[] conflictingFilenames = { "dir1/a", "dir2/b" };
174 return conflictingFilenames;
175 }
176
177 protected String[] createUnstagedChanges() throws Exception {
178 writeTrashFile("dir1/a", "Hello world a");
179 writeTrashFile("dir2/b", "Hello world b");
180 git.add().addFilepattern(".").call();
181 git.commit().setMessage("files a & b").call();
182 writeTrashFile("dir1/a", "New Hello world a");
183 writeTrashFile("dir2/b", "New Hello world b");
184 String[] conflictingFilenames = { "dir1/a", "dir2/b" };
185 return conflictingFilenames;
186 }
187
188 protected String[] createStagedChanges() throws Exception {
189 String[] conflictingFilenames = createUnstagedChanges();
190 git.add().addFilepattern(".").call();
191 return conflictingFilenames;
192 }
193
194 protected List<DiffEntry> getRepositoryChanges(RevCommit commit)
195 throws Exception {
196 TreeWalk tw = new TreeWalk(db);
197 tw.addTree(commit.getTree());
198 FileTreeIterator modifiedTree = new FileTreeIterator(db);
199 tw.addTree(modifiedTree);
200 List<DiffEntry> changes = DiffEntry.scan(tw);
201 return changes;
202 }
203
204 protected Path getFullPath(String repositoryFilename) {
205 Path dotGitPath = db.getDirectory().toPath();
206 Path repositoryRoot = dotGitPath.getParent();
207 Path repositoryFilePath = repositoryRoot.resolve(repositoryFilename);
208 return repositoryFilePath;
209 }
210
211 protected static InputStream createInputStream(String[] inputLines) {
212 return createInputStream(Arrays.asList(inputLines));
213 }
214
215 protected static InputStream createInputStream(List<String> inputLines) {
216 String input = String.join(System.lineSeparator(), inputLines);
217 InputStream inputStream = new ByteArrayInputStream(input.getBytes(UTF_8));
218 return inputStream;
219 }
220
221 protected static void assertArrayOfLinesEquals(String failMessage,
222 String[] expected, String[] actual) {
223 assertEquals(failMessage, toString(expected), toString(actual));
224 }
225
226 protected static void assertArrayOfMatchingLines(String failMessage,
227 Pattern[] expected, String[] actual) {
228 assertEquals(failMessage + System.lineSeparator()
229 + "Expected and actual lines count don't match. Expected: "
230 + Arrays.asList(expected) + ", actual: "
231 + Arrays.asList(actual), expected.length, actual.length);
232 int n = expected.length;
233 for (int i = 0; i < n; ++i) {
234 Pattern expectedPattern = expected[i];
235 String actualLine = actual[i];
236 Matcher matcher = expectedPattern.matcher(actualLine);
237 boolean matches = matcher.matches();
238 assertTrue(failMessage + System.lineSeparator() + "Line " + i + " '"
239 + actualLine + "' doesn't match expected pattern: "
240 + expectedPattern + System.lineSeparator() + "Expected: "
241 + Arrays.asList(expected) + ", actual: "
242 + Arrays.asList(actual),
243 matches);
244 }
245 }
246
247 protected static void assumeLinuxPlatform() {
248 Assume.assumeTrue("This test can run only in Linux tests",
249 SystemReader.getInstance().isLinux());
250 }
251 }