View Javadoc
1   /*
2    * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
3    *
4    * This program and the accompanying materials are made available
5    * under the terms of the Eclipse Distribution License v1.0 which
6    * accompanies this distribution, is reproduced below, and is
7    * available at http://www.eclipse.org/org/documents/edl-v10.php
8    *
9    * All rights reserved.
10   *
11   * Redistribution and use in source and binary forms, with or
12   * without modification, are permitted provided that the following
13   * conditions are met:
14   *
15   * - Redistributions of source code must retain the above copyright
16   *   notice, this list of conditions and the following disclaimer.
17   *
18   * - Redistributions in binary form must reproduce the above
19   *   copyright notice, this list of conditions and the following
20   *   disclaimer in the documentation and/or other materials provided
21   *   with the distribution.
22   *
23   * - Neither the name of the Eclipse Foundation, Inc. nor the
24   *   names of its contributors may be used to endorse or promote
25   *   products derived from this software without specific prior
26   *   written permission.
27   *
28   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
30   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
33   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
38   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
40   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41   */
42  
43  package org.eclipse.jgit.api;
44  
45  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.AUTO_CRLF;
46  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.AUTO_LF;
47  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.DIRECT;
48  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.TEXT_CRLF;
49  import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.TEXT_LF;
50  import static org.junit.Assert.assertArrayEquals;
51  
52  import java.io.ByteArrayInputStream;
53  import java.io.ByteArrayOutputStream;
54  import java.io.InputStream;
55  import java.io.OutputStream;
56  import java.nio.charset.StandardCharsets;
57  import java.util.Arrays;
58  
59  import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
60  import org.eclipse.jgit.util.IO;
61  import org.eclipse.jgit.util.io.EolStreamTypeUtil;
62  import org.junit.Test;
63  
64  /**
65   * Unit tests for end-of-line conversion streams
66   */
67  public class EolStreamTypeUtilTest {
68  
69  	@Test
70  	public void testCheckoutDirect() throws Exception {
71  		testCheckout(DIRECT, DIRECT, "", "");
72  		testCheckout(DIRECT, DIRECT, "\r", "\r");
73  		testCheckout(DIRECT, DIRECT, "\n", "\n");
74  
75  		testCheckout(DIRECT, DIRECT, "\r\n", "\r\n");
76  		testCheckout(DIRECT, DIRECT, "\n\r", "\n\r");
77  
78  		testCheckout(DIRECT, DIRECT, "\n\r\n", "\n\r\n");
79  		testCheckout(DIRECT, DIRECT, "\r\n\r", "\r\n\r");
80  
81  		testCheckout(DIRECT, DIRECT, "a\nb\n", "a\nb\n");
82  		testCheckout(DIRECT, DIRECT, "a\rb\r", "a\rb\r");
83  		testCheckout(DIRECT, DIRECT, "a\n\rb\n\r", "a\n\rb\n\r");
84  		testCheckout(DIRECT, DIRECT, "a\r\nb\r\n", "a\r\nb\r\n");
85  	}
86  
87  	@Test
88  	public void testCheckoutLF() throws Exception {
89  		testCheckout(TEXT_LF, AUTO_LF, "", "");
90  		testCheckout(TEXT_LF, AUTO_LF, "\r", "\r");
91  		testCheckout(TEXT_LF, AUTO_LF, "\n", "\n");
92  
93  		testCheckout(TEXT_LF, AUTO_LF, "\r\n", "\n");
94  		testCheckout(TEXT_LF, AUTO_LF, "\n\r", "\n\r");
95  
96  		testCheckout(TEXT_LF, AUTO_LF, "\n\r\n", "\n\n");
97  		testCheckout(TEXT_LF, AUTO_LF, "\r\n\r", "\n\r");
98  
99  		testCheckout(TEXT_LF, AUTO_LF, "a\nb\n", "a\nb\n");
100 		testCheckout(TEXT_LF, AUTO_LF, "a\rb\r", "a\rb\r");
101 		testCheckout(TEXT_LF, AUTO_LF, "a\n\rb\n\r", "a\n\rb\n\r");
102 		testCheckout(TEXT_LF, AUTO_LF, "a\r\nb\r\n", "a\nb\n");
103 	}
104 
105 	@Test
106 	public void testCheckoutCRLF() throws Exception {
107 		testCheckout(TEXT_CRLF, AUTO_CRLF, "", "");
108 		testCheckout(TEXT_CRLF, AUTO_CRLF, "\r", "\r");
109 		testCheckout(TEXT_CRLF, AUTO_CRLF, "\n", "\r\n");
110 
111 		testCheckout(TEXT_CRLF, AUTO_CRLF, "\r\n", "\r\n");
112 		testCheckout(TEXT_CRLF, AUTO_CRLF, "\n\r", "\r\n\r");
113 
114 		testCheckout(TEXT_CRLF, AUTO_CRLF, "\n\r\n", "\r\n\r\n");
115 		testCheckout(TEXT_CRLF, AUTO_CRLF, "\r\n\r", "\r\n\r");
116 
117 		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\nb\n", "a\r\nb\r\n");
118 		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\rb\r", "a\rb\r");
119 		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\n\rb\n\r", "a\r\n\rb\r\n\r");
120 		testCheckout(TEXT_CRLF, AUTO_CRLF, "a\r\nb\r\n", "a\r\nb\r\n");
121 	}
122 
123 	/**
124 	 * Test stream type detection based on stream content.
125 	 * <p>
126 	 * Tests three things with the output text:
127 	 * <p>
128 	 * 1) conversion if output was declared as text
129 	 * <p>
130 	 * 2) conversion if output was declared as potentially text (AUTO_...) and
131 	 * is in fact text
132 	 * <p>
133 	 * 3) conversion if modified output (now with binary characters) was
134 	 * declared as potentially text but now contains binary characters
135 	 * <p>
136 	 *
137 	 * @param streamTypeText
138 	 *            is the enum meaning that the output is definitely text (no
139 	 *            binary check at all)
140 	 * @param streamTypeWithBinaryCheck
141 	 *            is the enum meaning that the output may be text (binary check
142 	 *            is done)
143 	 * @param output
144 	 *            is a text output without binary characters
145 	 * @param expectedConversion
146 	 *            is the expected converted output without binary characters
147 	 * @throws Exception
148 	 */
149 	private void testCheckout(EolStreamType streamTypeText,
150 			EolStreamType streamTypeWithBinaryCheck, String output,
151 			String expectedConversion) throws Exception {
152 		ByteArrayOutputStream b;
153 		byte[] outputBytes = output.getBytes(StandardCharsets.UTF_8);
154 		byte[] expectedConversionBytes = expectedConversion
155 				.getBytes(StandardCharsets.UTF_8);
156 
157 		// test using output text and assuming it was declared TEXT
158 		b = new ByteArrayOutputStream();
159 		try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
160 				streamTypeText)) {
161 			out.write(outputBytes);
162 		}
163 		assertArrayEquals(expectedConversionBytes, b.toByteArray());
164 
165 		// test using ouput text and assuming it was declared AUTO, using binary
166 		// detection
167 		b = new ByteArrayOutputStream();
168 		try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
169 				streamTypeWithBinaryCheck)) {
170 			out.write(outputBytes);
171 		}
172 		assertArrayEquals(expectedConversionBytes, b.toByteArray());
173 
174 		// now pollute output text with some binary bytes
175 		outputBytes = extendWithBinaryData(outputBytes);
176 		expectedConversionBytes = extendWithBinaryData(expectedConversionBytes);
177 
178 		// again, test using output text and assuming it was declared TEXT
179 		b = new ByteArrayOutputStream();
180 		try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
181 				streamTypeText)) {
182 			out.write(outputBytes);
183 		}
184 		assertArrayEquals(expectedConversionBytes, b.toByteArray());
185 
186 		// again, test using ouput text and assuming it was declared AUTO, using
187 		// binary
188 		// detection
189 		b = new ByteArrayOutputStream();
190 		try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
191 				streamTypeWithBinaryCheck)) {
192 			out.write(outputBytes);
193 		}
194 		// expect no conversion
195 		assertArrayEquals(outputBytes, b.toByteArray());
196 	}
197 
198 	@Test
199 	public void testCheckinDirect() throws Exception {
200 		testCheckin(DIRECT, DIRECT, "", "");
201 		testCheckin(DIRECT, DIRECT, "\r", "\r");
202 		testCheckin(DIRECT, DIRECT, "\n", "\n");
203 
204 		testCheckin(DIRECT, DIRECT, "\r\n", "\r\n");
205 		testCheckin(DIRECT, DIRECT, "\n\r", "\n\r");
206 
207 		testCheckin(DIRECT, DIRECT, "\n\r\n", "\n\r\n");
208 		testCheckin(DIRECT, DIRECT, "\r\n\r", "\r\n\r");
209 
210 		testCheckin(DIRECT, DIRECT, "a\nb\n", "a\nb\n");
211 		testCheckin(DIRECT, DIRECT, "a\rb\r", "a\rb\r");
212 		testCheckin(DIRECT, DIRECT, "a\n\rb\n\r", "a\n\rb\n\r");
213 		testCheckin(DIRECT, DIRECT, "a\r\nb\r\n", "a\r\nb\r\n");
214 	}
215 
216 	@Test
217 	public void testCheckinLF() throws Exception {
218 		testCheckin(TEXT_LF, AUTO_LF, "", "");
219 		testCheckin(TEXT_LF, AUTO_LF, "\r", "\r");
220 		testCheckin(TEXT_LF, AUTO_LF, "\n", "\n");
221 
222 		testCheckin(TEXT_LF, AUTO_LF, "\r\n", "\n");
223 		testCheckin(TEXT_LF, AUTO_LF, "\n\r", "\n\r");
224 
225 		testCheckin(TEXT_LF, AUTO_LF, "\n\r\n", "\n\n");
226 		testCheckin(TEXT_LF, AUTO_LF, "\r\n\r", "\n\r");
227 
228 		testCheckin(TEXT_LF, AUTO_LF, "a\nb\n", "a\nb\n");
229 		testCheckin(TEXT_LF, AUTO_LF, "a\rb\r", "a\rb\r");
230 		testCheckin(TEXT_LF, AUTO_LF, "a\n\rb\n\r", "a\n\rb\n\r");
231 		testCheckin(TEXT_LF, AUTO_LF, "a\r\nb\r\n", "a\nb\n");
232 	}
233 
234 	@Test
235 	public void testCheckinCRLF() throws Exception {
236 		testCheckin(TEXT_CRLF, AUTO_CRLF, "", "");
237 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r", "\r");
238 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\n", "\r\n");
239 
240 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r\n", "\r\n");
241 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\n\r", "\r\n\r");
242 
243 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\n\r\n", "\r\n\r\n");
244 		testCheckin(TEXT_CRLF, AUTO_CRLF, "\r\n\r", "\r\n\r");
245 
246 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\nb\n", "a\r\nb\r\n");
247 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\rb\r", "a\rb\r");
248 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\n\rb\n\r", "a\r\n\rb\r\n\r");
249 		testCheckin(TEXT_CRLF, AUTO_CRLF, "a\r\nb\r\n", "a\r\nb\r\n");
250 	}
251 
252 	/**
253 	 * Test stream type detection based on stream content.
254 	 * <p>
255 	 * Tests three things with the input text:
256 	 * <p>
257 	 * 1) conversion if input was declared as text
258 	 * <p>
259 	 * 2) conversion if input was declared as potentially text (AUTO_...) and is
260 	 * in fact text
261 	 * <p>
262 	 * 3) conversion if modified input (now with binary characters) was declared
263 	 * as potentially text but now contains binary characters
264 	 * <p>
265 	 *
266 	 * @param streamTypeText
267 	 *            is the enum meaning that the input is definitely text (no
268 	 *            binary check at all)
269 	 * @param streamTypeWithBinaryCheck
270 	 *            is the enum meaning that the input may be text (binary check
271 	 *            is done)
272 	 * @param input
273 	 *            is a text input without binary characters
274 	 * @param expectedConversion
275 	 *            is the expected converted input without binary characters
276 	 * @throws Exception
277 	 */
278 	private void testCheckin(EolStreamType streamTypeText,
279 			EolStreamType streamTypeWithBinaryCheck, String input,
280 			String expectedConversion) throws Exception {
281 		byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
282 		byte[] expectedConversionBytes = expectedConversion
283 				.getBytes(StandardCharsets.UTF_8);
284 
285 		// test using input text and assuming it was declared TEXT
286 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
287 				new ByteArrayInputStream(inputBytes),
288 				streamTypeText)) {
289 			byte[] b = new byte[1024];
290 			int len = IO.readFully(in, b, 0);
291 			assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len));
292 		}
293 
294 		// test using input text and assuming it was declared AUTO, using binary
295 		// detection
296 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
297 				new ByteArrayInputStream(inputBytes),
298 				streamTypeWithBinaryCheck)) {
299 			byte[] b = new byte[1024];
300 			int len = IO.readFully(in, b, 0);
301 			assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len));
302 		}
303 
304 		// now pollute input text with some binary bytes
305 		inputBytes = extendWithBinaryData(inputBytes);
306 		expectedConversionBytes = extendWithBinaryData(expectedConversionBytes);
307 
308 		// again, test using input text and assuming it was declared TEXT
309 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
310 				new ByteArrayInputStream(inputBytes), streamTypeText)) {
311 			byte[] b = new byte[1024];
312 			int len = IO.readFully(in, b, 0);
313 			assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len));
314 		}
315 
316 		// again, test using input text and assuming it was declared AUTO, using
317 		// binary
318 		// detection
319 		try (InputStream in = EolStreamTypeUtil.wrapInputStream(
320 				new ByteArrayInputStream(inputBytes),
321 				streamTypeWithBinaryCheck)) {
322 			byte[] b = new byte[1024];
323 			int len = IO.readFully(in, b, 0);
324 			// expect no conversion
325 			assertArrayEquals(inputBytes, Arrays.copyOf(b, len));
326 		}
327 	}
328 
329 	private byte[] extendWithBinaryData(byte[] data) throws Exception {
330 		int n = 3;
331 		byte[] dataEx = new byte[data.length + n];
332 		System.arraycopy(data, 0, dataEx, 0, data.length);
333 		for (int i = 0; i < n; i++) {
334 			dataEx[data.length + i] = (byte) i;
335 		}
336 		return dataEx;
337 	}
338 
339 }