View Javadoc
1   /*
2    * Copyright (C) 2008-2009, Google Inc. 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.util;
12  
13  import static org.eclipse.jgit.junit.JGitTestUtil.getName;
14  import static org.junit.Assert.assertArrayEquals;
15  import static org.junit.Assert.assertEquals;
16  import static org.junit.Assert.assertNotNull;
17  import static org.junit.Assert.fail;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  
24  import org.eclipse.jgit.junit.TestRng;
25  import org.eclipse.jgit.util.TemporaryBuffer.Block;
26  import org.junit.Test;
27  
28  public class TemporaryBufferTest {
29  	@Test
30  	public void testEmpty() throws IOException {
31  		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
32  		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
33  		try {
34  			b.close();
35  			assertEquals(0, b.length());
36  			final byte[] r = b.toByteArray();
37  			assertNotNull(r);
38  			assertEquals(0, r.length);
39  		} finally {
40  			b.destroy();
41  		}
42  	}
43  
44  	@Test
45  	public void testOneByte() throws IOException {
46  		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
47  		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
48  		final byte test = (byte) new TestRng(getName()).nextInt();
49  		try {
50  			b.write(test);
51  			b.close();
52  			assertEquals(1, b.length());
53  			{
54  				final byte[] r = b.toByteArray();
55  				assertNotNull(r);
56  				assertEquals(1, r.length);
57  				assertEquals(test, r[0]);
58  			}
59  			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
60  				b.writeTo(o, null);
61  				final byte[] r = o.toByteArray();
62  				assertEquals(1, r.length);
63  				assertEquals(test, r[0]);
64  			}
65  		} finally {
66  			b.destroy();
67  		}
68  	}
69  
70  	@Test
71  	public void testOneBlock_BulkWrite() throws IOException {
72  		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
73  		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
74  		final byte[] test = new TestRng(getName())
75  				.nextBytes(TemporaryBuffer.Block.SZ);
76  		try {
77  			b.write(test, 0, 2);
78  			b.write(test, 2, 4);
79  			b.write(test, 6, test.length - 6 - 2);
80  			b.write(test, test.length - 2, 2);
81  			b.close();
82  			assertEquals(test.length, b.length());
83  			{
84  				final byte[] r = b.toByteArray();
85  				assertNotNull(r);
86  				assertEquals(test.length, r.length);
87  				assertArrayEquals(test, r);
88  			}
89  			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
90  				b.writeTo(o, null);
91  				final byte[] r = o.toByteArray();
92  				assertEquals(test.length, r.length);
93  				assertArrayEquals(test, r);
94  			}
95  		} finally {
96  			b.destroy();
97  		}
98  	}
99  
100 	@Test
101 	public void testOneBlockAndHalf_BulkWrite() throws IOException {
102 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
103 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
104 		final byte[] test = new TestRng(getName())
105 				.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
106 		try {
107 			b.write(test, 0, 2);
108 			b.write(test, 2, 4);
109 			b.write(test, 6, test.length - 6 - 2);
110 			b.write(test, test.length - 2, 2);
111 			b.close();
112 			assertEquals(test.length, b.length());
113 			{
114 				final byte[] r = b.toByteArray();
115 				assertNotNull(r);
116 				assertEquals(test.length, r.length);
117 				assertArrayEquals(test, r);
118 			}
119 			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
120 				b.writeTo(o, null);
121 				final byte[] r = o.toByteArray();
122 				assertEquals(test.length, r.length);
123 				assertArrayEquals(test, r);
124 			}
125 		} finally {
126 			b.destroy();
127 		}
128 	}
129 
130 	@Test
131 	public void testOneBlockAndHalf_SingleWrite() throws IOException {
132 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
133 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
134 		final byte[] test = new TestRng(getName())
135 				.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
136 		try {
137 			for (int i = 0; i < test.length; i++)
138 				b.write(test[i]);
139 			b.close();
140 			assertEquals(test.length, b.length());
141 			{
142 				final byte[] r = b.toByteArray();
143 				assertNotNull(r);
144 				assertEquals(test.length, r.length);
145 				assertArrayEquals(test, r);
146 			}
147 			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
148 				b.writeTo(o, null);
149 				final byte[] r = o.toByteArray();
150 				assertEquals(test.length, r.length);
151 				assertArrayEquals(test, r);
152 			}
153 		} finally {
154 			b.destroy();
155 		}
156 	}
157 
158 	@Test
159 	public void testOneBlockAndHalf_Copy() throws IOException {
160 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
161 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
162 		final byte[] test = new TestRng(getName())
163 				.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
164 		try {
165 			final ByteArrayInputStream in = new ByteArrayInputStream(test);
166 			b.write(in.read());
167 			b.copy(in);
168 			b.close();
169 			assertEquals(test.length, b.length());
170 			{
171 				final byte[] r = b.toByteArray();
172 				assertNotNull(r);
173 				assertEquals(test.length, r.length);
174 				assertArrayEquals(test, r);
175 			}
176 			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
177 				b.writeTo(o, null);
178 				final byte[] r = o.toByteArray();
179 				assertEquals(test.length, r.length);
180 				assertArrayEquals(test, r);
181 			}
182 		} finally {
183 			b.destroy();
184 		}
185 	}
186 
187 	@Test
188 	public void testLarge_SingleWrite() throws IOException {
189 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
190 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
191 		final byte[] test = new TestRng(getName())
192 				.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3);
193 		try {
194 			b.write(test);
195 			b.close();
196 			assertEquals(test.length, b.length());
197 			{
198 				final byte[] r = b.toByteArray();
199 				assertNotNull(r);
200 				assertEquals(test.length, r.length);
201 				assertArrayEquals(test, r);
202 			}
203 			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
204 				b.writeTo(o, null);
205 				final byte[] r = o.toByteArray();
206 				assertEquals(test.length, r.length);
207 				assertArrayEquals(test, r);
208 			}
209 		} finally {
210 			b.destroy();
211 		}
212 	}
213 
214 	@Test
215 	public void testInCoreInputStream() throws IOException {
216 		final int cnt = 256;
217 		final byte[] test = new TestRng(getName()).nextBytes(cnt);
218 		try (TemporaryBuffer.Heap b = new TemporaryBuffer.Heap(cnt + 4)) {
219 			b.write(test);
220 			InputStream in = b.openInputStream();
221 			byte[] act = new byte[cnt];
222 			IO.readFully(in, act, 0, cnt);
223 			assertArrayEquals(test, act);
224 		}
225 	}
226 
227 	@Test
228 	public void testInCoreLimit_SwitchOnAppendByte() throws IOException {
229 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
230 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
231 		final byte[] test = new TestRng(getName())
232 				.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT + 1);
233 		try {
234 			b.write(test, 0, test.length - 1);
235 			b.write(test[test.length - 1]);
236 			b.close();
237 			assertEquals(test.length, b.length());
238 			{
239 				final byte[] r = b.toByteArray();
240 				assertNotNull(r);
241 				assertEquals(test.length, r.length);
242 				assertArrayEquals(test, r);
243 			}
244 			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
245 				b.writeTo(o, null);
246 				final byte[] r = o.toByteArray();
247 				assertEquals(test.length, r.length);
248 				assertArrayEquals(test, r);
249 			}
250 		} finally {
251 			b.destroy();
252 		}
253 	}
254 
255 	@Test
256 	public void testInCoreLimit_SwitchBeforeAppendByte() throws IOException {
257 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
258 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
259 		final byte[] test = new TestRng(getName())
260 				.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3);
261 		try {
262 			b.write(test, 0, test.length - 1);
263 			b.write(test[test.length - 1]);
264 			b.close();
265 			assertEquals(test.length, b.length());
266 			{
267 				final byte[] r = b.toByteArray();
268 				assertNotNull(r);
269 				assertEquals(test.length, r.length);
270 				assertArrayEquals(test, r);
271 			}
272 			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
273 				b.writeTo(o, null);
274 				final byte[] r = o.toByteArray();
275 				assertEquals(test.length, r.length);
276 				assertArrayEquals(test, r);
277 			}
278 		} finally {
279 			b.destroy();
280 		}
281 	}
282 
283 	@Test
284 	public void testInCoreLimit_SwitchOnCopy() throws IOException {
285 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
286 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
287 		final byte[] test = new TestRng(getName())
288 				.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2);
289 		try {
290 			final ByteArrayInputStream in = new ByteArrayInputStream(test,
291 					TemporaryBuffer.DEFAULT_IN_CORE_LIMIT, test.length
292 							- TemporaryBuffer.DEFAULT_IN_CORE_LIMIT);
293 			b.write(test, 0, TemporaryBuffer.DEFAULT_IN_CORE_LIMIT);
294 			b.copy(in);
295 			b.close();
296 			assertEquals(test.length, b.length());
297 			{
298 				final byte[] r = b.toByteArray();
299 				assertNotNull(r);
300 				assertEquals(test.length, r.length);
301 				assertArrayEquals(test, r);
302 			}
303 			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
304 				b.writeTo(o, null);
305 				final byte[] r = o.toByteArray();
306 				assertEquals(test.length, r.length);
307 				assertArrayEquals(test, r);
308 			}
309 		} finally {
310 			b.destroy();
311 		}
312 	}
313 
314 	@Test
315 	public void testDestroyWhileOpen() throws IOException {
316 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
317 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
318 		try {
319 			b.write(new TestRng(getName())
320 					.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2));
321 		} finally {
322 			b.destroy();
323 		}
324 	}
325 
326 	@Test
327 	public void testRandomWrites() throws IOException {
328 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
329 		final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
330 		final TestRng rng = new TestRng(getName());
331 		final int max = TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2;
332 		final byte[] expect = new byte[max];
333 		try {
334 			int written = 0;
335 			boolean onebyte = true;
336 			while (written < max) {
337 				if (onebyte) {
338 					final byte v = (byte) rng.nextInt();
339 					b.write(v);
340 					expect[written++] = v;
341 				} else {
342 					final int len = Math
343 							.min(rng.nextInt() & 127, max - written);
344 					final byte[] tmp = rng.nextBytes(len);
345 					b.write(tmp, 0, len);
346 					System.arraycopy(tmp, 0, expect, written, len);
347 					written += len;
348 				}
349 				onebyte = !onebyte;
350 			}
351 			assertEquals(expect.length, written);
352 			b.close();
353 
354 			assertEquals(expect.length, b.length());
355 			{
356 				final byte[] r = b.toByteArray();
357 				assertNotNull(r);
358 				assertEquals(expect.length, r.length);
359 				assertArrayEquals(expect, r);
360 			}
361 			try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
362 				b.writeTo(o, null);
363 				final byte[] r = o.toByteArray();
364 				assertEquals(expect.length, r.length);
365 				assertArrayEquals(expect, r);
366 			}
367 		} finally {
368 			b.destroy();
369 		}
370 	}
371 
372 	@Test
373 	public void testHeap() throws IOException {
374 		try (TemporaryBuffer b = new TemporaryBuffer.Heap(2 * 8 * 1024)) {
375 			final byte[] r = new byte[8 * 1024];
376 			b.write(r);
377 			b.write(r);
378 			try {
379 				b.write(1);
380 				fail("accepted too many bytes of data");
381 			} catch (IOException e) {
382 				assertEquals("In-memory buffer limit exceeded", e.getMessage());
383 			}
384 		}
385 	}
386 
387 	@Test
388 	public void testHeapWithEstimatedSize() throws IOException {
389 		int sz = 2 * Block.SZ;
390 		try (TemporaryBuffer b = new TemporaryBuffer.Heap(sz / 2, sz)) {
391 			for (int i = 0; i < sz; i++) {
392 				b.write('x');
393 			}
394 			try {
395 				b.write(1);
396 				fail("accepted too many bytes of data");
397 			} catch (IOException e) {
398 				assertEquals("In-memory buffer limit exceeded", e.getMessage());
399 			}
400 
401 			try (InputStream in = b.openInputStream()) {
402 				for (int i = 0; i < sz; i++) {
403 					assertEquals('x', in.read());
404 				}
405 				assertEquals(-1, in.read());
406 			}
407 		}
408 	}
409 
410 	@Test
411 	public void testHeapToByteArrayWithLimit() throws IOException {
412 		int sz = 2 * Block.SZ;
413 		try (TemporaryBuffer b = new TemporaryBuffer.Heap(sz / 2, sz)) {
414 			for (int i = 0; i < sz; i++) {
415 				b.write('a' + i % 26);
416 			}
417 			byte[] prefix = b.toByteArray(5);
418 			assertEquals(5, prefix.length);
419 			for (int i = 0; i < prefix.length; i++) {
420 				assertEquals('a' + i % 26, prefix[i]);
421 			}
422 			prefix = b.toByteArray(Block.SZ + 37);
423 			assertEquals(Block.SZ + 37, prefix.length);
424 			for (int i = 0; i < prefix.length; i++) {
425 				assertEquals('a' + i % 26, prefix[i]);
426 			}
427 			prefix = b.toByteArray(sz);
428 			assertEquals(sz, prefix.length);
429 			for (int i = 0; i < prefix.length; i++) {
430 				assertEquals('a' + i % 26, prefix[i]);
431 			}
432 			prefix = b.toByteArray(sz + 37);
433 			assertEquals(sz, prefix.length);
434 			for (int i = 0; i < prefix.length; i++) {
435 				assertEquals('a' + i % 26, prefix[i]);
436 			}
437 		}
438 	}
439 
440 	@Test
441 	public void testFileToByteArrayWithLimit() throws IOException {
442 		@SuppressWarnings("resource") // Buffer is explicitly destroyed in finally block
443 		TemporaryBuffer b = new TemporaryBuffer.LocalFile(null, 2 * Block.SZ);
444 		int sz = 3 * Block.SZ;
445 		try {
446 			for (int i = 0; i < sz; i++) {
447 				b.write('a' + i % 26);
448 			}
449 			b.close();
450 			byte[] prefix = b.toByteArray(5);
451 			assertEquals(5, prefix.length);
452 			for (int i = 0; i < prefix.length; i++) {
453 				assertEquals('a' + i % 26, prefix[i]);
454 			}
455 			prefix = b.toByteArray(Block.SZ + 37);
456 			assertEquals(Block.SZ + 37, prefix.length);
457 			for (int i = 0; i < prefix.length; i++) {
458 				assertEquals('a' + i % 26, prefix[i]);
459 			}
460 			prefix = b.toByteArray(sz);
461 			assertEquals(sz, prefix.length);
462 			for (int i = 0; i < prefix.length; i++) {
463 				assertEquals('a' + i % 26, prefix[i]);
464 			}
465 			prefix = b.toByteArray(sz + 37);
466 			assertEquals(sz, prefix.length);
467 			for (int i = 0; i < prefix.length; i++) {
468 				assertEquals('a' + i % 26, prefix[i]);
469 			}
470 		} finally {
471 			b.destroy();
472 		}
473 	}
474 }