View Javadoc
1   /*
2    * Copyright (C) 2011, 2021 IBM Corporation and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.api;
11  
12  import static org.junit.Assert.assertArrayEquals;
13  import static org.junit.Assert.assertEquals;
14  import static org.junit.Assert.assertFalse;
15  import static org.junit.Assert.assertTrue;
16  import static org.junit.Assert.fail;
17  
18  import java.io.ByteArrayOutputStream;
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.nio.charset.StandardCharsets;
23  import java.nio.file.Files;
24  
25  import org.eclipse.jgit.api.errors.PatchApplyException;
26  import org.eclipse.jgit.api.errors.PatchFormatException;
27  import org.eclipse.jgit.diff.RawText;
28  import org.eclipse.jgit.junit.RepositoryTestCase;
29  import org.eclipse.jgit.util.FS;
30  import org.eclipse.jgit.util.IO;
31  import org.junit.Test;
32  
33  public class ApplyCommandTest extends RepositoryTestCase {
34  
35  	private RawText a;
36  
37  	private RawText b;
38  
39  	private ApplyResult init(String name) throws Exception {
40  		return init(name, true, true);
41  	}
42  
43  	private ApplyResult init(final String name, final boolean preExists,
44  			final boolean postExists) throws Exception {
45  		try (Git git = new Git(db)) {
46  			if (preExists) {
47  				a = new RawText(readFile(name + "_PreImage"));
48  				write(new File(db.getDirectory().getParent(), name),
49  						a.getString(0, a.size(), false));
50  
51  				git.add().addFilepattern(name).call();
52  				git.commit().setMessage("PreImage").call();
53  			}
54  
55  			if (postExists) {
56  				b = new RawText(readFile(name + "_PostImage"));
57  			}
58  
59  			return git
60  					.apply()
61  					.setPatch(getTestResource(name + ".patch")).call();
62  		}
63  	}
64  
65  	private void checkBinary(String name, boolean hasPreImage)
66  			throws Exception {
67  		checkBinary(name, hasPreImage, 1);
68  	}
69  
70  	private void checkBinary(String name, boolean hasPreImage,
71  			int numberOfFiles) throws Exception {
72  		try (Git git = new Git(db)) {
73  			byte[] post = IO
74  					.readWholeStream(getTestResource(name + "_PostImage"), 0)
75  					.array();
76  			File f = new File(db.getWorkTree(), name);
77  			if (hasPreImage) {
78  				byte[] pre = IO
79  						.readWholeStream(getTestResource(name + "_PreImage"), 0)
80  						.array();
81  				Files.write(f.toPath(), pre);
82  				git.add().addFilepattern(name).call();
83  				git.commit().setMessage("PreImage").call();
84  			}
85  			ApplyResult result = git.apply()
86  					.setPatch(getTestResource(name + ".patch")).call();
87  			assertEquals(numberOfFiles, result.getUpdatedFiles().size());
88  			assertEquals(f, result.getUpdatedFiles().get(0));
89  			assertArrayEquals(post, Files.readAllBytes(f.toPath()));
90  		}
91  	}
92  
93  	@Test
94  	public void testEncodingChange() throws Exception {
95  		// This is a text patch that changes a file containing ÄÖÜ in UTF-8 to
96  		// the same characters in ISO-8859-1. The patch file itself uses mixed
97  		// encoding. Since checkFile() works with strings use the binary check.
98  		checkBinary("umlaut", true);
99  	}
100 
101 	@Test
102 	public void testEmptyLine() throws Exception {
103 		// C git accepts completely empty lines as empty context lines.
104 		// According to comments in the C git sources (apply.c), newer GNU diff
105 		// may produce such diffs.
106 		checkBinary("emptyLine", true);
107 	}
108 
109 	@Test
110 	public void testMultiFileNoNewline() throws Exception {
111 		// This test needs two files. One is in the test resources.
112 		try (Git git = new Git(db)) {
113 			Files.write(db.getWorkTree().toPath().resolve("yello"),
114 					"yello".getBytes(StandardCharsets.US_ASCII));
115 			git.add().addFilepattern("yello").call();
116 			git.commit().setMessage("yello").call();
117 		}
118 		checkBinary("hello", true, 2);
119 	}
120 
121 	@Test
122 	public void testAddA1() throws Exception {
123 		ApplyResult result = init("A1", false, true);
124 		assertEquals(1, result.getUpdatedFiles().size());
125 		assertEquals(new File(db.getWorkTree(), "A1"), result.getUpdatedFiles()
126 				.get(0));
127 		checkFile(new File(db.getWorkTree(), "A1"),
128 				b.getString(0, b.size(), false));
129 	}
130 
131 	@Test
132 	public void testAddA2() throws Exception {
133 		ApplyResult result = init("A2", false, true);
134 		assertEquals(1, result.getUpdatedFiles().size());
135 		assertEquals(new File(db.getWorkTree(), "A2"), result.getUpdatedFiles()
136 				.get(0));
137 		checkFile(new File(db.getWorkTree(), "A2"),
138 				b.getString(0, b.size(), false));
139 	}
140 
141 	@Test
142 	public void testAddA3() throws Exception {
143 		ApplyResult result = init("A3", false, true);
144 		assertEquals(1, result.getUpdatedFiles().size());
145 		assertEquals(new File(db.getWorkTree(), "A3"),
146 				result.getUpdatedFiles().get(0));
147 		checkFile(new File(db.getWorkTree(), "A3"),
148 				b.getString(0, b.size(), false));
149 	}
150 
151 	@Test
152 	public void testAddA1Sub() throws Exception {
153 		ApplyResult result = init("A1_sub", false, false);
154 		assertEquals(1, result.getUpdatedFiles().size());
155 		assertEquals(new File(db.getWorkTree(), "sub/A1"), result
156 				.getUpdatedFiles().get(0));
157 	}
158 
159 	@Test
160 	public void testDeleteD() throws Exception {
161 		ApplyResult result = init("D", true, false);
162 		assertEquals(1, result.getUpdatedFiles().size());
163 		assertEquals(new File(db.getWorkTree(), "D"), result.getUpdatedFiles()
164 				.get(0));
165 		assertFalse(new File(db.getWorkTree(), "D").exists());
166 	}
167 
168 	@Test(expected = PatchFormatException.class)
169 	public void testFailureF1() throws Exception {
170 		init("F1", true, false);
171 	}
172 
173 	@Test(expected = PatchApplyException.class)
174 	public void testFailureF2() throws Exception {
175 		init("F2", true, false);
176 	}
177 
178 	@Test
179 	public void testModifyE() throws Exception {
180 		ApplyResult result = init("E");
181 		assertEquals(1, result.getUpdatedFiles().size());
182 		assertEquals(new File(db.getWorkTree(), "E"), result.getUpdatedFiles()
183 				.get(0));
184 		checkFile(new File(db.getWorkTree(), "E"),
185 				b.getString(0, b.size(), false));
186 	}
187 
188 	@Test
189 	public void testModifyW() throws Exception {
190 		ApplyResult result = init("W");
191 		assertEquals(1, result.getUpdatedFiles().size());
192 		assertEquals(new File(db.getWorkTree(), "W"),
193 				result.getUpdatedFiles().get(0));
194 		checkFile(new File(db.getWorkTree(), "W"),
195 				b.getString(0, b.size(), false));
196 	}
197 
198 	@Test
199 	public void testAddM1() throws Exception {
200 		ApplyResult result = init("M1", false, true);
201 		assertEquals(1, result.getUpdatedFiles().size());
202 		if (FS.DETECTED.supportsExecute()) {
203 			assertTrue(FS.DETECTED.canExecute(result.getUpdatedFiles().get(0)));
204 		}
205 		checkFile(new File(db.getWorkTree(), "M1"),
206 				b.getString(0, b.size(), false));
207 	}
208 
209 	private static byte[] readFile(String patchFile) throws IOException {
210 		final InputStream in = getTestResource(patchFile);
211 		if (in == null) {
212 			fail("No " + patchFile + " test vector");
213 			return null; // Never happens
214 		}
215 		try {
216 			final byte[] buf = new byte[1024];
217 			final ByteArrayOutputStream temp = new ByteArrayOutputStream();
218 			int n;
219 			while ((n = in.read(buf)) > 0)
220 				temp.write(buf, 0, n);
221 			return temp.toByteArray();
222 		} finally {
223 			in.close();
224 		}
225 	}
226 
227 	private static InputStream getTestResource(String patchFile) {
228 		return ApplyCommandTest.class.getClassLoader()
229 				.getResourceAsStream("org/eclipse/jgit/diff/" + patchFile);
230 	}
231 }