001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.io;
005:
006: import com.tc.bytes.TCByteBuffer;
007: import com.tc.bytes.TCByteBufferFactory;
008: import com.tc.test.TCTestCase;
009:
010: import java.io.IOException;
011: import java.security.SecureRandom;
012: import java.util.Arrays;
013: import java.util.Date;
014: import java.util.Random;
015:
016: public class TCByteBufferInputStreamTest extends TCTestCase {
017:
018: private Random random = new SecureRandom();
019:
020: public void testExceptions() {
021: try {
022: new TCByteBufferInputStream((TCByteBuffer) null);
023: fail();
024: } catch (NullPointerException npe) {
025: // expected
026: }
027:
028: try {
029: new TCByteBufferInputStream((TCByteBuffer[]) null);
030: fail();
031: } catch (NullPointerException npe) {
032: // expected
033: }
034:
035: try {
036: new TCByteBufferInputStream(new TCByteBuffer[] {
037: TCByteBufferFactory.getInstance(false, 5), null });
038: fail();
039: } catch (NullPointerException npe) {
040: // expected
041: }
042:
043: try {
044: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
045: TCByteBufferFactory.getInstance(false, 10));
046: bbis.read(null);
047: fail();
048: } catch (NullPointerException npe) {
049: // expected
050: }
051:
052: try {
053: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
054: TCByteBufferFactory.getInstance(false, 10));
055: bbis.read(null, 1, 10);
056: fail();
057: } catch (NullPointerException npe) {
058: // expected
059: }
060:
061: try {
062: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
063: TCByteBufferFactory.getInstance(false, 10));
064: bbis.read(new byte[10], 10, 1);
065: fail();
066: } catch (IndexOutOfBoundsException ioobe) {
067: // expected
068: }
069:
070: try {
071: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
072: TCByteBufferFactory.getInstance(false, 10));
073: bbis.read(new byte[10], -1, 1);
074: fail();
075: } catch (IndexOutOfBoundsException ioobe) {
076: // expected
077: }
078:
079: try {
080: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
081: TCByteBufferFactory.getInstance(false, 10));
082: bbis.read(new byte[10], 1, -1);
083: fail();
084: } catch (IndexOutOfBoundsException ioobe) {
085: // expected
086: }
087:
088: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
089: TCByteBufferFactory.getInstance(false, 10));
090: for (int i = 0; i < 10; i++) {
091: bbis.close();
092: }
093:
094: try {
095: bbis.read();
096: fail();
097: } catch (IllegalStateException ise) {
098: // expected
099: }
100:
101: try {
102: bbis.read(new byte[1]);
103: fail();
104: } catch (IllegalStateException ise) {
105: // expected
106: }
107:
108: try {
109: bbis.read(new byte[1], 0, 1);
110: fail();
111: } catch (IllegalStateException ise) {
112: // expected
113: }
114: }
115:
116: public void testToArray() {
117: for (int i = 0; i < 250; i++) {
118: TCByteBuffer[] data = getRandomDataNonZeroLength();
119: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
120: data);
121:
122: int read = random.nextInt(bbis.available());
123: for (int r = 0; r < read; r++) {
124: bbis.read();
125: }
126:
127: TCByteBufferInputStream compare = new TCByteBufferInputStream(
128: bbis.toArray());
129: while (compare.available() > 0) {
130: int orig = bbis.read();
131: int comp = compare.read();
132: assertEquals(orig, comp);
133: }
134:
135: assertEquals(0, compare.available());
136: assertEquals(0, bbis.available());
137: }
138: }
139:
140: public void testLimit() {
141: for (int i = 0; i < 250; i++) {
142: TCByteBuffer[] data = getRandomDataNonZeroLength();
143: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
144: data);
145:
146: int read = random.nextInt(bbis.available());
147: for (int r = 0; r < read; r++) {
148: bbis.read();
149: }
150:
151: int which = random.nextInt(3);
152: switch (which) {
153: case 0: {
154: bbis.limit(0);
155: assertEquals(0, bbis.available());
156: break;
157: }
158: case 1: {
159: int before = bbis.available();
160: bbis.limit(bbis.available());
161: assertEquals(before, bbis.available());
162: break;
163: }
164: case 2: {
165: bbis.limit(random.nextInt(bbis.available()));
166: break;
167: }
168: default: {
169: throw new RuntimeException("" + which);
170: }
171: }
172:
173: TCByteBufferInputStream compare = new TCByteBufferInputStream(
174: bbis.toArray());
175: while (compare.available() > 0) {
176: int orig = bbis.read();
177: int comp = compare.read();
178: assertEquals(orig, comp);
179: }
180:
181: assertEquals(0, compare.available());
182: assertEquals(0, bbis.available());
183: }
184: }
185:
186: public void testDuplicateAndLimitZeroLen() {
187: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
188: new TCByteBuffer[] {});
189:
190: assertEquals(0, bbis.available());
191: assertEquals(0, bbis.duplicateAndLimit(0).available());
192: }
193:
194: public void testDuplicateAndLimit() {
195: for (int i = 0; i < 50; i++) {
196: TCByteBuffer[] data = getRandomDataNonZeroLength();
197: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
198: data);
199:
200: int length = bbis.available();
201: assertTrue(length > 0);
202: int start = random.nextInt(length);
203: bbis.skip(start);
204: int limit = random.nextInt(bbis.available());
205:
206: TCByteBufferInput dupe = bbis.duplicateAndLimit(limit);
207: for (int n = 0; n < limit; n++) {
208: int dupeByte = dupe.read();
209: int origByte = bbis.read();
210:
211: assertTrue(dupeByte != -1);
212: assertTrue(origByte != -1);
213:
214: assertEquals(origByte, dupeByte);
215: }
216:
217: assertEquals(0, dupe.available());
218: }
219: }
220:
221: public void testDuplicate() {
222: for (int i = 0; i < 250; i++) {
223: TCByteBuffer[] data = getRandomData();
224: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
225: data);
226: bbis.read();
227: TCByteBufferInput dupe = bbis.duplicate();
228: assertEquals(bbis.available(), dupe.available());
229: int read = bbis.read();
230: if (read != -1) {
231: // reading from one stream doesn't affect the other
232: assertEquals(dupe.available() - 1, bbis.available());
233: int dupeRead = dupe.read();
234: assertEquals(read, dupeRead);
235: }
236:
237: bbis = new TCByteBufferInputStream(
238: getRandomDataNonZeroLength());
239: int dupeStart = random.nextInt(bbis.getTotalLength());
240: for (int n = 0; n < dupeStart; n++) {
241: int b = bbis.read();
242: assertTrue(b >= 0);
243: }
244: dupe = bbis.duplicate();
245: while (bbis.available() > 0) {
246: int n1 = bbis.read();
247: int n2 = dupe.read();
248: assertEquals(n1, n2);
249: }
250: assertEquals(0, dupe.available());
251: assertEquals(0, bbis.available());
252: }
253: }
254:
255: public void testOffsetReadArray() {
256: for (int i = 0; i < 25; i++) {
257: testOffsetReadArray(getRandomData());
258: }
259: }
260:
261: private void testOffsetReadArray(TCByteBuffer[] data) {
262: final int numBufs = data.length == 0 ? 0 : data.length - 1;
263:
264: reportLengths(data);
265: final long totalLength = length(data);
266: TCByteBufferInputStream bbis = new TCByteBufferInputStream(data);
267: assertEquals(totalLength, bbis.available());
268: assertEquals(totalLength, bbis.getTotalLength());
269:
270: int index = 0;
271: int bytesRead = 0;
272: while (bbis.available() > 0) {
273: byte[] buffer = new byte[random.nextInt(50) + 1];
274: byte fill = (byte) random.nextInt();
275: Arrays.fill(buffer, fill);
276:
277: final int offset = random.nextInt(buffer.length);
278: final int length = random.nextInt(buffer.length - offset);
279: final int read = bbis.read(buffer, offset, length);
280: if (read == -1) {
281: break;
282: }
283: bytesRead += read;
284:
285: for (int i = 0; i < offset; i++) {
286: assertEquals(fill, buffer[i]);
287: }
288:
289: for (int i = offset + length + 1; i < buffer.length; i++) {
290: assertEquals(fill, buffer[i]);
291: }
292:
293: for (int i = 0; i < read; i++) {
294: for (; !data[index].hasRemaining() && index < numBufs; index++) {
295: //
296: }
297:
298: assertEquals(data[index].get(), buffer[offset + i]);
299: }
300: }
301:
302: if (index < numBufs) {
303: for (; index < numBufs; index++) {
304: assertEquals(0, data[index + 1].limit());
305: }
306: }
307:
308: assertEquals(index, numBufs);
309: if (numBufs > 0) {
310: assertEquals(0, data[numBufs].remaining());
311: }
312:
313: assertEquals(bytesRead, totalLength);
314: assertEquals(0, bbis.available());
315: assertEquals(-1, bbis.read());
316: assertEquals(-1, bbis.read(new byte[10]));
317: assertEquals(-1, bbis.read(new byte[10], 0, 3));
318: }
319:
320: public void testReadBasics() {
321: for (int i = 0; i < 250; i++) {
322: testReadBasics(getRandomData());
323: }
324: }
325:
326: public void testBasic() {
327: for (int i = 0; i < 250; i++) {
328: TCByteBuffer[] data = getRandomDataNonZeroLength();
329: TCByteBufferInputStream bbis = new TCByteBufferInputStream(
330: data);
331:
332: assertTrue(bbis.available() > 0);
333:
334: final byte b = data[0].get(0);
335: int read = bbis.read();
336: assertEquals(b, (byte) read);
337:
338: byte[] readArray = new byte[1];
339: bbis = new TCByteBufferInputStream(data);
340: bbis.read(readArray);
341: assertEquals(b, readArray[0]);
342:
343: bbis = new TCByteBufferInputStream(data);
344: bbis.read(readArray, 0, 1);
345: assertEquals(b, readArray[0]);
346:
347: bbis = new TCByteBufferInputStream(data);
348: int avail = bbis.available();
349: bbis.read(new byte[0]);
350: assertEquals(avail, bbis.available());
351: bbis.read(new byte[0], 0, 0);
352: assertEquals(avail, bbis.available());
353: bbis.read(new byte[10], 0, 0);
354: assertEquals(avail, bbis.available());
355: }
356: }
357:
358: public void testMarkReset() throws IOException {
359: TCByteBuffer[] data = createBuffersWithRandomData(4, 10);
360: TCByteBufferInputStream bbis = new TCByteBufferInputStream(data);
361:
362: bbis.readInt();
363: bbis.readInt();
364: bbis.readInt(); // should be 2 bytes into 2nd buffer by now
365:
366: try {
367: bbis.tcReset();
368: fail();
369: } catch (IllegalStateException ise) {
370: // expected
371: }
372:
373: int avail = bbis.available();
374: bbis.mark();
375:
376: int i1 = bbis.readInt();
377: int i2 = bbis.readInt();
378: int i3 = bbis.readInt(); // should be 4 bytes into 3rd buffer now
379:
380: bbis.tcReset();
381:
382: assertEquals(avail, bbis.available());
383: assertEquals(i1, bbis.readInt());
384: assertEquals(i2, bbis.readInt());
385: assertEquals(i3, bbis.readInt());
386:
387: try {
388: bbis.tcReset();
389: fail();
390: } catch (IllegalStateException ise) {
391: // expected
392: }
393: }
394:
395: public void testMarkReset2() throws IOException {
396: // This one stays on the same buffer between mark and reset
397: TCByteBuffer[] data = createBuffersWithRandomData(1, 10);
398: TCByteBufferInputStream bbis = new TCByteBufferInputStream(data);
399:
400: bbis.readInt();
401: int avail = bbis.available();
402: bbis.mark();
403:
404: int i1 = bbis.readInt();
405:
406: bbis.tcReset();
407:
408: assertEquals(avail, bbis.available());
409: assertEquals(i1, bbis.readInt());
410: }
411:
412: private void testReadBasics(TCByteBuffer[] data) {
413: final int numBufs = data.length == 0 ? 0 : data.length - 1;
414:
415: reportLengths(data);
416: final long len = length(data);
417: TCByteBufferInputStream bbis = new TCByteBufferInputStream(data);
418: assertEquals(len, bbis.available());
419: assertEquals(len, bbis.getTotalLength());
420:
421: int index = 0;
422: for (int i = 0; i < len; i++) {
423: for (; !data[index].hasRemaining() && index < numBufs; index++) {
424: //
425: }
426:
427: assertEquals(len - i, bbis.available());
428: int fromStream = bbis.read();
429: assertFalse(fromStream < 0);
430:
431: byte original = data[index].get();
432:
433: assertEquals(original, (byte) fromStream);
434: }
435:
436: if (index < numBufs) {
437: for (; index < numBufs; index++) {
438: assertEquals(0, data[index + 1].limit());
439: }
440: }
441:
442: assertEquals(index, numBufs);
443: if (numBufs > 0) {
444: assertEquals(0, data[numBufs].remaining());
445: }
446:
447: assertEquals(0, bbis.available());
448: assertEquals(-1, bbis.read());
449: assertEquals(-1, bbis.read(new byte[10]));
450: assertEquals(-1, bbis.read(new byte[10], 0, 3));
451: }
452:
453: private void reportLengths(TCByteBuffer[] data) {
454: // comment this if tests are failing
455: if (true)
456: return;
457:
458: System.err.print(data.length + " buffers with lengths: ");
459: for (int i = 0; i < data.length; i++) {
460: System.err.print(data[i].limit() + " ");
461: }
462: System.err.println();
463: }
464:
465: public void testTrailingZeroLength() {
466: TCByteBuffer[] data = getRandomData();
467: TCByteBuffer zeroLen = TCByteBufferFactory
468: .getInstance(false, 0);
469:
470: for (int i = 0; i < Math.min(10, data.length); i++) {
471: data[data.length - i - 1] = zeroLen;
472: rewindBuffers(data);
473: testReadArrayBasics(data);
474:
475: rewindBuffers(data);
476: testOffsetReadArray(data);
477: }
478: }
479:
480: public void testRandomZeroLength() {
481: TCByteBuffer[] data = getRandomDataNonZeroLength();
482:
483: TCByteBuffer zeroLen = TCByteBufferFactory
484: .getInstance(false, 0);
485:
486: int num = Math.min(25, data.length);
487:
488: for (int i = 0; i < num; i++) {
489: data[random.nextInt(data.length)] = zeroLen;
490: rewindBuffers(data);
491: testReadArrayBasics(data);
492:
493: rewindBuffers(data);
494: testOffsetReadArray(data);
495: }
496: }
497:
498: private TCByteBuffer[] getRandomDataNonZeroLength() {
499: TCByteBuffer[] data;
500: do {
501: data = getRandomData();
502: } while ((data.length == 0) || (data[0].limit() == 0));
503:
504: return data;
505: }
506:
507: public void testReadArrayBasics() {
508: for (int i = 0; i < 50; i++) {
509: testReadArrayBasics(getRandomData());
510: }
511: }
512:
513: private void rewindBuffers(TCByteBuffer[] data) {
514: for (int i = 0; i < data.length; i++) {
515: data[i].rewind();
516: }
517: }
518:
519: private void testReadArrayBasics(TCByteBuffer[] data) {
520: final int numBufs = data.length == 0 ? 0 : data.length - 1;
521:
522: reportLengths(data);
523: final long len = length(data);
524: TCByteBufferInputStream bbis = new TCByteBufferInputStream(data);
525: assertEquals(len, bbis.available());
526: assertEquals(len, bbis.getTotalLength());
527:
528: int counter = 0;
529: int index = 0;
530: while (bbis.available() > 0) {
531: byte[] buffer = new byte[random.nextInt(10) + 1];
532: int read = bbis.read(buffer);
533:
534: if (read <= 0) {
535: assertEquals(0, bbis.available());
536: break;
537: }
538:
539: counter += read;
540: assertEquals(len - counter, bbis.available());
541:
542: for (int i = 0; i < read; i++) {
543: for (; !data[index].hasRemaining() && index < numBufs; index++) {
544: //
545: }
546: assertEquals(data[index].get(), buffer[i]);
547: }
548: }
549:
550: if (index < numBufs) {
551: for (; index < numBufs; index++) {
552: assertEquals(0, data[index + 1].limit());
553: }
554: }
555:
556: assertEquals(numBufs, index);
557: if (numBufs > 0) {
558: assertEquals(0, data[numBufs].remaining());
559: }
560:
561: assertEquals(0, bbis.available());
562: assertEquals(-1, bbis.read());
563: assertEquals(-1, bbis.read(new byte[10]));
564: assertEquals(-1, bbis.read(new byte[10], 0, 3));
565: }
566:
567: public void testSkip() {
568: for (int i = 0; i < 250; i++) {
569: TCByteBuffer[] data = getRandomDataNonZeroLength();
570: TCByteBufferInputStream is = new TCByteBufferInputStream(
571: data);
572:
573: assertEquals(0, is.skip(0));
574: assertEquals(0, is.skip(-1));
575:
576: int len = is.getTotalLength();
577: assertEquals(len, is.available());
578: long skipped = is.skip(len - 1);
579: assertEquals(len - 1, skipped);
580: assertEquals(1, is.available());
581: is.read();
582: assertEquals(0, is.available());
583: int read = is.read();
584: assertEquals(-1, read);
585:
586: try {
587: is.skip(Integer.MAX_VALUE + 1L);
588: fail();
589: } catch (IllegalArgumentException iae) {
590: // expected
591: }
592: }
593: }
594:
595: private void log(String msg) {
596: System.err.println(new Date() + " - " + msg);
597: }
598:
599: public void testZeroLength() {
600: TCByteBuffer[] data = new TCByteBuffer[] {};
601: long len = length(data);
602: assertEquals(0, len);
603: TCByteBufferInputStream bbis = new TCByteBufferInputStream(data);
604: assertEquals(0, bbis.available());
605: assertEquals(0, bbis.getTotalLength());
606: assertEquals(-1, bbis.read());
607: assertEquals(-1, bbis.read(new byte[10]));
608: assertEquals(-1, bbis.read(new byte[10], 1, 3));
609: assertEquals(0, bbis.read(new byte[10], 1, 0));
610:
611: testReadArrayBasics(data);
612: testReadBasics(data);
613: testOffsetReadArray(data);
614:
615: TCByteBuffer[] toArray = bbis.toArray();
616: assertEquals(0, toArray.length);
617: }
618:
619: private long length(TCByteBuffer[] data) {
620: long rv = 0;
621: for (int i = 0; i < data.length; i++) {
622: rv += data[i].limit();
623: }
624: return rv;
625: }
626:
627: private TCByteBuffer[] createBuffersWithRandomData(int number,
628: int size) {
629: TCByteBuffer[] rv = new TCByteBuffer[number];
630: for (int i = 0; i < rv.length; i++) {
631: rv[i] = TCByteBufferFactory.getInstance(false, size);
632: byte[] bites = new byte[size];
633: random.nextBytes(bites);
634: rv[i].put(bites);
635: rv[i].flip();
636: }
637:
638: return rv;
639: }
640:
641: private TCByteBuffer[] getRandomData() {
642: final int num = random.nextInt(20);
643: final int maxSize = random.nextInt(200);
644:
645: TCByteBuffer[] rv = new TCByteBuffer[num];
646:
647: for (int i = 0; i < num; i++) {
648: rv[i] = TCByteBufferFactory.getInstance(false,
649: maxSize > 0 ? random.nextInt(maxSize) : 0);
650: random.nextBytes(rv[i].array());
651: }
652:
653: return rv;
654: }
655:
656: }
|