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, AUTO_CRLF, "\n\r", "\r\n\r");
85  
86  		testCheckout(TEXT_CRLF, AUTO_CRLF, "\n\r\n", "\r\n\r\n");
87  		testCheckout(TEXT_CRLF, AUTO_CRLF, "\r\n\r", "\r\n\r");
88  
89  		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\nb\n", "a\r\nb\r\n");
90  		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\rb\r", "a\rb\r");
91  		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\n\rb\n\r", "a\r\n\rb\r\n\r");
92  		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\r\nb\r\n", "a\r\nb\r\n");
93  	}
94  
95  	/**
96  	 * Test stream type detection based on stream content.
97  	 * <p>
98  	 * Tests three things with the output text:
99  	 * <p>
100 	 * 1) conversion if output was declared as text
101 	 * <p>
102 	 * 2) conversion if output was declared as potentially text (AUTO_...) and
103 	 * is in fact text
104 	 * <p>
105 	 * 3) conversion if modified output (now with binary characters) was
106 	 * declared as potentially text but now contains binary characters
107 	 * <p>
108 	 *
109 	 * @param streamTypeText
110 	 *            is the enum meaning that the output is definitely text (no
111 	 *            binary check at all)
112 	 * @param streamTypeWithBinaryCheck
113 	 *            is the enum meaning that the output may be text (binary check
114 	 *            is done)
115 	 * @param output
116 	 *            is a text output without binary characters
117 	 * @param expectedConversion
118 	 *            is the expected converted output without binary characters
119 	 * @throws Exception
120 	 */
121 	private void testCheckout(EolStreamType streamTypeText,
122 			EolStreamType streamTypeWithBinaryCheck, String output,
123 			String expectedConversion) throws Exception {
124 		ByteArrayOutputStream b;
125 		byte[] outputBytes = output.getBytes(UTF_8);
126 		byte[] expectedConversionBytes = expectedConversion.getBytes(UTF_8);
127 
128 		if (streamTypeText != null) {
129 			// test using output text and assuming it was declared TEXT
130 			b = new ByteArrayOutputStream();
131 			try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
132 					streamTypeText)) {
133 				out.write(outputBytes);
134 			}
135 			assertArrayEquals(expectedConversionBytes, b.toByteArray());
136 		}
137 		if (streamTypeWithBinaryCheck != null) {
138 			// test using output text and assuming it was declared AUTO, using
139 			// binary detection
140 			b = new ByteArrayOutputStream();
141 			try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
142 					streamTypeWithBinaryCheck)) {
143 				out.write(outputBytes);
144 			}
145 			assertArrayEquals(expectedConversionBytes, b.toByteArray());
146 		}
147 		// now pollute output text with some binary bytes
148 		outputBytes = extendWithBinaryData(outputBytes);
149 		expectedConversionBytes = extendWithBinaryData(expectedConversionBytes);
150 
151 		if (streamTypeText != null) {
152 			// again, test using output text and assuming it was declared TEXT
153 			b = new ByteArrayOutputStream();
154 			try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
155 					streamTypeText)) {
156 				out.write(outputBytes);
157 			}
158 			assertArrayEquals(expectedConversionBytes, b.toByteArray());
159 		}
160 		if (streamTypeWithBinaryCheck != null) {
161 			// again, test using output text and assuming it was declared AUTO,
162 			// using binary detection
163 			b = new ByteArrayOutputStream();
164 			try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
165 					streamTypeWithBinaryCheck)) {
166 				out.write(outputBytes);
167 			}
168 			// expect no conversion
169 			assertArrayEquals(outputBytes, b.toByteArray());
170 		}
171 	}
172 
173 	@Test
174 	public void testCheckinDirect() throws Exception {
175 		testCheckin(DIRECT, DIRECT, "", "");
176 		testCheckin(DIRECT, DIRECT, "\r", "\r");
177 		testCheckin(DIRECT, DIRECT, "\n", "\n");
178 
179 		testCheckin(DIRECT, DIRECT, "\r\n", "\r\n");
180 		testCheckin(DIRECT, DIRECT, "\n\r", "\n\r");
181 
182 		testCheckin(DIRECT, DIRECT, "\n\r\n", "\n\r\n");
183 		testCheckin(DIRECT, DIRECT, "\r\n\r", "\r\n\r");
184 
185 		testCheckin(DIRECT, DIRECT, "a\nb\n", "a\nb\n");
186 		testCheckin(DIRECT, DIRECT, "a\rb\r", "a\rb\r");
187 		testCheckin(DIRECT, DIRECT, "a\n\rb\n\r", "a\n\rb\n\r");
188 		testCheckin(DIRECT, DIRECT, "a\r\nb\r\n", "a\r\nb\r\n");
189 	}
190 
191 	@Test
192 	public void testCheckinLF() throws Exception {
193 		testCheckin(TEXT_LF, AUTO_LF, "", "");
194 		testCheckin(TEXT_LF, AUTO_LF, "\r", "\r");
195 		testCheckin(TEXT_LF, AUTO_LF, "\n", "\n");
196 
197 		testCheckin(TEXT_LF, AUTO_LF, "\r\n", "\n");
198 		testCheckin(TEXT_LF, AUTO_LF, "\n\r", "\n\r");
199 
200 		testCheckin(TEXT_LF, AUTO_LF, "\n\r\n", "\n\n");
201 		testCheckin(TEXT_LF, AUTO_LF, "\r\n\r", "\n\r");
202 
203 		testCheckin(TEXT_LF, AUTO_LF, "a\nb\n", "a\nb\n");
204 		testCheckin(TEXT_LF, AUTO_LF, "a\rb\r", "a\rb\r");
205 		testCheckin(TEXT_LF, AUTO_LF, "a\n\rb\n\r", "a\n\rb\n\r");
206 		testCheckin(TEXT_LF, AUTO_LF, "a\r\nb\r\n", "a\nb\n");
207 	}
208 
209 	@Test
210 	public void testCheckinCRLF() throws Exception {
211 		testCheckin(TEXT_CRLF, AUTO_CRLF, "", "");
212 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r", "\r");
213 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\n", "\r\n");
214 
215 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r\n", "\r\n");
216 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\n\r", "\r\n\r");
217 
218 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\n\r\n", "\r\n\r\n");
219 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r\n\r", "\r\n\r");
220 
221 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\nb\n", "a\r\nb\r\n");
222 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\rb\r", "a\rb\r");
223 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\n\rb\n\r", "a\r\n\rb\r\n\r");
224 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\r\nb\r\n", "a\r\nb\r\n");
225 	}
226 
227 	/**
228 	 * Test stream type detection based on stream content.
229 	 * <p>
230 	 * Tests three things with the input text:
231 	 * <p>
232 	 * 1) conversion if input was declared as text
233 	 * <p>
234 	 * 2) conversion if input was declared as potentially text (AUTO_...) and is
235 	 * in fact text
236 	 * <p>
237 	 * 3) conversion if modified input (now with binary characters) was declared
238 	 * as potentially text but now contains binary characters
239 	 * <p>
240 	 *
241 	 * @param streamTypeText
242 	 *            is the enum meaning that the input is definitely text (no
243 	 *            binary check at all)
244 	 * @param streamTypeWithBinaryCheck
245 	 *            is the enum meaning that the input may be text (binary check
246 	 *            is done)
247 	 * @param input
248 	 *            is a text input without binary characters
249 	 * @param expectedConversion
250 	 *            is the expected converted input without binary characters
251 	 * @throws Exception
252 	 */
253 	private void testCheckin(EolStreamType streamTypeText,
254 			EolStreamType streamTypeWithBinaryCheck, String input,
255 			String expectedConversion) throws Exception {
256 		byte[] inputBytes = input.getBytes(UTF_8);
257 		byte[] expectedConversionBytes = expectedConversion.getBytes(UTF_8);
258 
259 		// test using input text and assuming it was declared TEXT
260 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
261 				new ByteArrayInputStream(inputBytes),
262 				streamTypeText)) {
263 			byte[] b = new byte[1024];
264 			int len = IO.readFully(in, b, 0);
265 			assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len));
266 		}
267 
268 		// test using input text and assuming it was declared AUTO, using binary
269 		// detection
270 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
271 				new ByteArrayInputStream(inputBytes),
272 				streamTypeWithBinaryCheck)) {
273 			byte[] b = new byte[1024];
274 			int len = IO.readFully(in, b, 0);
275 			assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len));
276 		}
277 
278 		// now pollute input text with some binary bytes
279 		inputBytes = extendWithBinaryData(inputBytes);
280 		expectedConversionBytes = extendWithBinaryData(expectedConversionBytes);
281 
282 		// again, test using input text and assuming it was declared TEXT
283 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
284 				new ByteArrayInputStream(inputBytes), streamTypeText)) {
285 			byte[] b = new byte[1024];
286 			int len = IO.readFully(in, b, 0);
287 			assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len));
288 		}
289 
290 		// again, test using input text and assuming it was declared AUTO, using
291 		// binary
292 		// detection
293 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
294 				new ByteArrayInputStream(inputBytes),
295 				streamTypeWithBinaryCheck)) {
296 			byte[] b = new byte[1024];
297 			int len = IO.readFully(in, b, 0);
298 			// expect no conversion
299 			assertArrayEquals(inputBytes, Arrays.copyOf(b, len));
300 		}
301 	}
302 
303 	private byte[] extendWithBinaryData(byte[] data) throws Exception {
304 		int n = 3;
305 		byte[] dataEx = new byte[data.length + n];
306 		System.arraycopy(data, 0, dataEx, 0, data.length);
307 		for (int i = 0; i < n; i++) {
308 			dataEx[data.length + i] = (byte) i;
309 		}
310 		return dataEx;
311 	}
312 
313 }