View Javadoc
1   /*
2    * Copyright (C) 2015, 2020 Ivan Motsch <ivan.motsch@bsiag.com> 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  
11  package org.eclipse.jgit.api;
12  
13  import static java.nio.charset.StandardCharsets.UTF_8;
14  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.AUTO_CRLF;
15  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.AUTO_LF;
16  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.DIRECT;
17  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.TEXT_CRLF;
18  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.TEXT_LF;
19  import static org.junit.Assert.assertArrayEquals;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.util.Arrays;
26  
27  import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
28  import org.eclipse.jgit.util.IO;
29  import org.eclipse.jgit.util.io.EolStreamTypeUtil;
30  import org.junit.Test;
31  
32  /**
33   * Unit tests for end-of-line conversion streams
34   */
35  public class EolStreamTypeUtilTest {
36  
37  	@Test
38  	public void testCheckoutDirect() throws Exception {
39  		testCheckout(DIRECT, DIRECT, "", "");
40  		testCheckout(DIRECT, DIRECT, "\r", "\r");
41  		testCheckout(DIRECT, DIRECT, "\n", "\n");
42  
43  		testCheckout(DIRECT, DIRECT, "\r\n", "\r\n");
44  		testCheckout(DIRECT, DIRECT, "\n\r", "\n\r");
45  
46  		testCheckout(DIRECT, DIRECT, "\n\r\n", "\n\r\n");
47  		testCheckout(DIRECT, DIRECT, "\r\n\r", "\r\n\r");
48  
49  		testCheckout(DIRECT, DIRECT, "a\nb\n", "a\nb\n");
50  		testCheckout(DIRECT, DIRECT, "a\rb\r", "a\rb\r");
51  		testCheckout(DIRECT, DIRECT, "a\n\rb\n\r", "a\n\rb\n\r");
52  		testCheckout(DIRECT, DIRECT, "a\r\nb\r\n", "a\r\nb\r\n");
53  	}
54  
55  	@Test
56  	public void testCheckoutLF() throws Exception {
57  		testCheckout(TEXT_LF, AUTO_LF, "", "");
58  		testCheckout(TEXT_LF, AUTO_LF, "\r", "\r");
59  		testCheckout(TEXT_LF, AUTO_LF, "\n", "\n");
60  
61  		testCheckout(TEXT_LF, null, "\r\n", "\n");
62  		testCheckout(null, AUTO_LF, "\r\n", "\r\n");
63  		testCheckout(TEXT_LF, AUTO_LF, "\n\r", "\n\r");
64  
65  		testCheckout(TEXT_LF, null, "\n\r\n", "\n\n");
66  		testCheckout(null, AUTO_LF, "\n\r\n", "\n\r\n");
67  		testCheckout(TEXT_LF, null, "\r\n\r", "\n\r");
68  		testCheckout(null, AUTO_LF, "\r\n\r", "\r\n\r");
69  
70  		testCheckout(TEXT_LF, AUTO_LF, "a\nb\n", "a\nb\n");
71  		testCheckout(TEXT_LF, AUTO_LF, "a\rb\r", "a\rb\r");
72  		testCheckout(TEXT_LF, AUTO_LF, "a\n\rb\n\r", "a\n\rb\n\r");
73  		testCheckout(TEXT_LF, null, "a\r\nb\r\n", "a\nb\n");
74  		testCheckout(null, AUTO_LF, "a\r\nb\r\n", "a\r\nb\r\n");
75  	}
76  
77  	@Test
78  	public void testCheckoutCRLF() throws Exception {
79  		testCheckout(TEXT_CRLF, AUTO_CRLF, "", "");
80  		testCheckout(TEXT_CRLF, AUTO_CRLF, "\r", "\r");
81  		testCheckout(TEXT_CRLF, AUTO_CRLF, "\n", "\r\n");
82  
83  		testCheckout(TEXT_CRLF, AUTO_CRLF, "\r\n", "\r\n");
84  		testCheckout(TEXT_CRLF, null, "\n\r", "\r\n\r");
85  		testCheckout(null, AUTO_CRLF, "\n\r", "\n\r"); // Lone CR
86  
87  		testCheckout(null, AUTO_CRLF, "\n\r\n", "\n\r\n");
88  		testCheckout(TEXT_CRLF, null, "\n\r\n", "\r\n\r\n");
89  		testCheckout(TEXT_CRLF, AUTO_CRLF, "\r\n\r", "\r\n\r");
90  
91  		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\nb\n", "a\r\nb\r\n");
92  		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\rb\r", "a\rb\r");
93  		testCheckout(TEXT_CRLF, null, "a\n\rb\n\r", "a\r\n\rb\r\n\r");
94  		testCheckout(null, AUTO_CRLF, "a\n\rb\n\r", "a\n\rb\n\r"); // Lone CR
95  		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\r\nb\r\n", "a\r\nb\r\n");
96  	}
97  
98  	/**
99  	 * Test stream type detection based on stream content.
100 	 * <p>
101 	 * Tests three things with the output text:
102 	 * <p>
103 	 * 1) conversion if output was declared as text
104 	 * <p>
105 	 * 2) conversion if output was declared as potentially text (AUTO_...) and
106 	 * is in fact text
107 	 * <p>
108 	 * 3) conversion if modified output (now with binary characters) was
109 	 * declared as potentially text but now contains binary characters
110 	 * <p>
111 	 *
112 	 * @param streamTypeText
113 	 *            is the enum meaning that the output is definitely text (no
114 	 *            binary check at all)
115 	 * @param streamTypeWithBinaryCheck
116 	 *            is the enum meaning that the output may be text (binary check
117 	 *            is done)
118 	 * @param output
119 	 *            is a text output without binary characters
120 	 * @param expectedConversion
121 	 *            is the expected converted output without binary characters
122 	 * @throws Exception
123 	 */
124 	private void testCheckout(EolStreamType streamTypeText,
125 			EolStreamType streamTypeWithBinaryCheck, String output,
126 			String expectedConversion) throws Exception {
127 		ByteArrayOutputStream b;
128 		byte[] outputBytes = output.getBytes(UTF_8);
129 		byte[] expectedConversionBytes = expectedConversion.getBytes(UTF_8);
130 
131 		if (streamTypeText != null) {
132 			// test using output text and assuming it was declared TEXT
133 			b = new ByteArrayOutputStream();
134 			try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
135 					streamTypeText)) {
136 				out.write(outputBytes);
137 			}
138 			assertArrayEquals(expectedConversionBytes, b.toByteArray());
139 		}
140 		if (streamTypeWithBinaryCheck != null) {
141 			// test using output text and assuming it was declared AUTO, using
142 			// binary detection
143 			b = new ByteArrayOutputStream();
144 			try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
145 					streamTypeWithBinaryCheck)) {
146 				out.write(outputBytes);
147 			}
148 			assertArrayEquals(expectedConversionBytes, b.toByteArray());
149 		}
150 		// now pollute output text with some binary bytes
151 		outputBytes = extendWithBinaryData(outputBytes);
152 		expectedConversionBytes = extendWithBinaryData(expectedConversionBytes);
153 
154 		if (streamTypeText != null) {
155 			// again, test using output text and assuming it was declared TEXT
156 			b = new ByteArrayOutputStream();
157 			try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
158 					streamTypeText)) {
159 				out.write(outputBytes);
160 			}
161 			assertArrayEquals(expectedConversionBytes, b.toByteArray());
162 		}
163 		if (streamTypeWithBinaryCheck != null) {
164 			// again, test using output text and assuming it was declared AUTO,
165 			// using binary detection
166 			b = new ByteArrayOutputStream();
167 			try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
168 					streamTypeWithBinaryCheck)) {
169 				out.write(outputBytes);
170 			}
171 			// expect no conversion
172 			assertArrayEquals(outputBytes, b.toByteArray());
173 		}
174 	}
175 
176 	@Test
177 	public void testCheckinDirect() throws Exception {
178 		testCheckin(DIRECT, DIRECT, "", "");
179 		testCheckin(DIRECT, DIRECT, "\r", "\r");
180 		testCheckin(DIRECT, DIRECT, "\n", "\n");
181 
182 		testCheckin(DIRECT, DIRECT, "\r\n", "\r\n");
183 		testCheckin(DIRECT, DIRECT, "\n\r", "\n\r");
184 
185 		testCheckin(DIRECT, DIRECT, "\n\r\n", "\n\r\n");
186 		testCheckin(DIRECT, DIRECT, "\r\n\r", "\r\n\r");
187 
188 		testCheckin(DIRECT, DIRECT, "a\nb\n", "a\nb\n");
189 		testCheckin(DIRECT, DIRECT, "a\rb\r", "a\rb\r");
190 		testCheckin(DIRECT, DIRECT, "a\n\rb\n\r", "a\n\rb\n\r");
191 		testCheckin(DIRECT, DIRECT, "a\r\nb\r\n", "a\r\nb\r\n");
192 	}
193 
194 	@Test
195 	public void testCheckinLF() throws Exception {
196 		testCheckin(TEXT_LF, AUTO_LF, "", "");
197 		testCheckin(TEXT_LF, AUTO_LF, "\r", "\r");
198 		testCheckin(TEXT_LF, AUTO_LF, "\n", "\n");
199 
200 		testCheckin(TEXT_LF, AUTO_LF, "\r\n", "\n");
201 		testCheckin(TEXT_LF, AUTO_LF, "\n\r", "\n\r");
202 
203 		testCheckin(TEXT_LF, AUTO_LF, "\n\r\n", "\n\n");
204 		testCheckin(TEXT_LF, null, "\r\n\r", "\n\r");
205 		testCheckin(null, AUTO_LF, "\r\n\r", "\r\n\r"); // Lone CR
206 
207 		testCheckin(TEXT_LF, AUTO_LF, "a\nb\n", "a\nb\n");
208 		testCheckin(TEXT_LF, AUTO_LF, "a\rb\r", "a\rb\r");
209 		testCheckin(TEXT_LF, AUTO_LF, "a\n\rb\n\r", "a\n\rb\n\r");
210 		testCheckin(TEXT_LF, AUTO_LF, "a\r\nb\r\n", "a\nb\n");
211 	}
212 
213 	@Test
214 	public void testCheckinCRLF() throws Exception {
215 		testCheckin(TEXT_CRLF, AUTO_CRLF, "", "");
216 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r", "\r");
217 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\n", "\r\n");
218 
219 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r\n", "\r\n");
220 		testCheckin(TEXT_CRLF, null, "\n\r", "\r\n\r");
221 		testCheckin(null, AUTO_CRLF, "\n\r", "\n\r"); // Lone CR
222 
223 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\n\r\n", "\r\n\r\n");
224 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r\n\r", "\r\n\r");
225 
226 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\nb\n", "a\r\nb\r\n");
227 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\rb\r", "a\rb\r");
228 		testCheckin(TEXT_CRLF, null, "a\n\rb\n\r", "a\r\n\rb\r\n\r");
229 		testCheckin(null, AUTO_CRLF, "a\n\rb\n\r", "a\n\rb\n\r"); // Lone CR
230 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\r\nb\r\n", "a\r\nb\r\n");
231 	}
232 
233 	/**
234 	 * Test stream type detection based on stream content.
235 	 * <p>
236 	 * Tests three things with the input text:
237 	 * <p>
238 	 * 1) conversion if input was declared as text
239 	 * <p>
240 	 * 2) conversion if input was declared as potentially text (AUTO_...) and is
241 	 * in fact text
242 	 * <p>
243 	 * 3) conversion if modified input (now with binary characters) was declared
244 	 * as potentially text but now contains binary characters
245 	 * <p>
246 	 *
247 	 * @param streamTypeText
248 	 *            is the enum meaning that the input is definitely text (no
249 	 *            binary check at all)
250 	 * @param streamTypeWithBinaryCheck
251 	 *            is the enum meaning that the input may be text (binary check
252 	 *            is done)
253 	 * @param input
254 	 *            is a text input without binary characters
255 	 * @param expectedConversion
256 	 *            is the expected converted input without binary characters
257 	 * @throws Exception
258 	 */
259 	private void testCheckin(EolStreamType streamTypeText,
260 			EolStreamType streamTypeWithBinaryCheck, String input,
261 			String expectedConversion) throws Exception {
262 		byte[] inputBytes = input.getBytes(UTF_8);
263 		byte[] expectedConversionBytes = expectedConversion.getBytes(UTF_8);
264 
265 		if (streamTypeText != null) {
266 			// test using input text and assuming it was declared TEXT
267 			try (InputStream in = EolStreamTypeUtil.wrapInputStream(
268 					new ByteArrayInputStream(inputBytes), streamTypeText)) {
269 				byte[] b = new byte[1024];
270 				int len = IO.readFully(in, b, 0);
271 				assertArrayEquals(expectedConversionBytes,
272 						Arrays.copyOf(b, len));
273 			}
274 		}
275 
276 		if (streamTypeWithBinaryCheck != null) {
277 			// test using input text and assuming it was declared AUTO, using
278 			// binary detection
279 			try (InputStream in = EolStreamTypeUtil.wrapInputStream(
280 					new ByteArrayInputStream(inputBytes),
281 					streamTypeWithBinaryCheck)) {
282 				byte[] b = new byte[1024];
283 				int len = IO.readFully(in, b, 0);
284 				assertArrayEquals(expectedConversionBytes,
285 						Arrays.copyOf(b, len));
286 			}
287 		}
288 		// now pollute input text with some binary bytes
289 		inputBytes = extendWithBinaryData(inputBytes);
290 		expectedConversionBytes = extendWithBinaryData(expectedConversionBytes);
291 
292 		if (streamTypeText != null) {
293 			// again, test using input text and assuming it was declared TEXT
294 			try (InputStream in = EolStreamTypeUtil.wrapInputStream(
295 					new ByteArrayInputStream(inputBytes), streamTypeText)) {
296 				byte[] b = new byte[1024];
297 				int len = IO.readFully(in, b, 0);
298 				assertArrayEquals(expectedConversionBytes,
299 						Arrays.copyOf(b, len));
300 			}
301 		}
302 
303 		if (streamTypeWithBinaryCheck != null) {
304 			// again, test using input text and assuming it was declared AUTO,
305 			// using binary detection
306 			try (InputStream in = EolStreamTypeUtil.wrapInputStream(
307 					new ByteArrayInputStream(inputBytes),
308 					streamTypeWithBinaryCheck)) {
309 				byte[] b = new byte[1024];
310 				int len = IO.readFully(in, b, 0);
311 				// expect no conversion
312 				assertArrayEquals(inputBytes, Arrays.copyOf(b, len));
313 			}
314 		}
315 	}
316 
317 	private byte[] extendWithBinaryData(byte[] data) throws Exception {
318 		int n = 3;
319 		byte[] dataEx = new byte[data.length + n];
320 		System.arraycopy(data, 0, dataEx, 0, data.length);
321 		for (int i = 0; i < n; i++) {
322 			dataEx[data.length + i] = (byte) i;
323 		}
324 		return dataEx;
325 	}
326 
327 }