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.io.TCByteBufferOutputStream.Mark;
009: import com.tc.test.TCTestCase;
010:
011: import java.io.ByteArrayOutputStream;
012: import java.io.IOException;
013: import java.util.ArrayList;
014: import java.util.Arrays;
015: import java.util.List;
016: import java.util.Random;
017:
018: public class TCByteBufferOutputStreamTest extends TCTestCase {
019:
020: final Random random = new Random();
021:
022: public void testMultipleToArray() {
023: for (int i = 0; i < 250; i++) {
024:
025: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream(
026: random.nextInt(100) + 1, false);
027: int bytesToWrite = random.nextInt(75) + 50;
028:
029: for (int n = 0; n < bytesToWrite; n++) {
030: bbos.write(42);
031: }
032:
033: assertEquals(bytesToWrite, bbos.getBytesWritten());
034: TCByteBuffer[] data = bbos.toArray();
035: assertEquals(bytesToWrite, length(data));
036:
037: for (int j = 0; j < 10; j++) {
038: bbos.toArray();
039: }
040: }
041: }
042:
043: public void testMark() {
044: ByteArrayOutputStream baos = new ByteArrayOutputStream();
045: TCByteBufferOutputStream output = new TCByteBufferOutputStream(
046: 32, false);
047: for (int i = 0; i < 30; i++) {
048: output.write(1);
049: baos.write(1);
050: }
051:
052: Mark mark1 = output.mark();
053: for (int i = 0; i < 4; i++) {
054: output.write(0);
055: baos.write(i + 1);
056: }
057:
058: for (int i = 0; i < 30; i++) {
059: output.write(1);
060: baos.write(1);
061: }
062:
063: Mark mark2 = output.mark();
064: output.write(0);
065: int b = random.nextInt();
066: baos.write(b);
067:
068: int written = output.getBytesWritten();
069: mark1.write(new byte[] { 1, 2, 3, 4 }); // should cross the 1st and 2nd buffers in the stream
070: assertEquals(written, output.getBytesWritten());
071: mark2.write(b); // should write to the 3rd buffer exclusively, but start on the 2nd
072: assertEquals(written, output.getBytesWritten());
073:
074: compareData(baos.toByteArray(), output.toArray());
075:
076: // output stream should be closed now due to toArray() above
077: try {
078: mark1.write(1);
079: fail();
080: } catch (IllegalStateException ise) {
081: // expected
082: }
083:
084: try {
085: mark1.write(new byte[2]);
086: fail();
087: } catch (IllegalStateException ise) {
088: // expected
089: }
090:
091: try {
092: output.mark();
093: fail();
094: } catch (IllegalStateException ise) {
095: // expected
096: }
097:
098: }
099:
100: public void testInvalidWriteThroughMark() {
101: TCByteBufferOutputStream output = new TCByteBufferOutputStream();
102: output.write(new byte[30]);
103: Mark mark1 = output.mark();
104:
105: try {
106: mark1.write(0);
107: fail();
108: } catch (IllegalArgumentException iae) {
109: // expected
110: }
111:
112: try {
113: mark1.write(new byte[1]);
114: fail();
115: } catch (IllegalArgumentException iae) {
116: // expected
117: }
118:
119: output.write(1);
120: int written = output.getBytesWritten();
121: mark1.write(1);
122: assertEquals(written, output.getBytesWritten());
123: mark1.write(new byte[0]);
124: assertEquals(written, output.getBytesWritten());
125: mark1.write(new byte[1]);
126: assertEquals(written, output.getBytesWritten());
127:
128: try {
129: mark1.write(new byte[2]);
130: fail();
131: } catch (IllegalArgumentException iae) {
132: // expected
133: }
134:
135: }
136:
137: public void testRandomMark() throws IOException {
138: for (int i = 0; i < 500; i++) {
139: doRandomMark();
140: }
141: }
142:
143: private void doRandomMark() throws IOException {
144: int initial = random.nextInt(10) + 1;
145: int max = initial + random.nextInt(1024) + 1;
146: TCByteBufferOutputStream output = new TCByteBufferOutputStream(
147: initial, max, false);
148: ByteArrayOutputStream baos = new ByteArrayOutputStream();
149: List data = new ArrayList();
150: List marks = new ArrayList();
151:
152: for (int i = 0; i < 1000; i++) {
153: marks.add(output.mark());
154:
155: if (random.nextBoolean()) {
156: byte[] b = new byte[random.nextInt(10)];
157: random.nextBytes(b);
158: baos.write(b);
159: output.write(new byte[b.length]);
160: data.add(b);
161: } else {
162: int b = random.nextInt();
163: output.write(0);
164: baos.write(b);
165: data.add(new byte[] { (byte) b });
166: }
167:
168: if (random.nextInt(10) > 6) {
169: byte[] b = new byte[random.nextInt(5) + 1];
170: random.nextBytes(b);
171: baos.write(b);
172: output.write(b);
173: }
174: }
175:
176: for (int i = 0, n = marks.size(); i < n; i++) {
177: Mark mark = (Mark) marks.get(i);
178: byte[] b = (byte[]) data.get(i);
179: if (b.length == 1) {
180: mark.write(b[0]);
181: } else {
182: mark.write(b);
183: }
184: }
185:
186: compareData(baos.toByteArray(), output.toArray());
187: }
188:
189: public void testArrayWriteZeroLength() {
190: TCByteBufferOutputStream output = new TCByteBufferOutputStream();
191:
192: TCByteBuffer[] bufs = new TCByteBuffer[5];
193: TCByteBuffer bufZeroLen = TCByteBufferFactory.getInstance(
194: false, 0);
195: bufs[0] = bufZeroLen;
196: bufs[1] = TCByteBufferFactory.getInstance(false, 10);
197: bufs[2] = bufZeroLen;
198: bufs[3] = bufZeroLen;
199: bufs[4] = bufZeroLen;
200: long buflength = length(bufs);
201:
202: output.write(bufs);
203: assertEquals(buflength, output.getBytesWritten());
204:
205: TCByteBuffer[] bufsOut = output.toArray();
206: assertTrue(bufsOut.length < bufs.length); // 'coz its consolidated
207: }
208:
209: public void testBytesWritten() {
210: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream();
211: assertEquals(0, bbos.getBytesWritten());
212:
213: bbos.write(42);
214: assertEquals(1, bbos.getBytesWritten());
215:
216: bbos.write(new byte[10]);
217: assertEquals(11, bbos.getBytesWritten());
218:
219: bbos.write(new byte[10], 1, 2);
220: assertEquals(13, bbos.getBytesWritten());
221:
222: // an exception shouldn't mess up the bytes written count
223: try {
224: bbos.write(new byte[10], 10, 1);
225: fail();
226: } catch (IndexOutOfBoundsException ioobe) {
227: // expected
228: }
229: assertEquals(13, bbos.getBytesWritten());
230:
231: bbos.write(new byte[0]);
232: assertEquals(13, bbos.getBytesWritten());
233: }
234:
235: public void testBasic() {
236: int blockSize = 4096;
237: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream(
238: blockSize, false);
239: int num = 10;
240:
241: byte write = 0;
242: for (int i = 0; i < blockSize * num; i++) {
243: bbos.write(write++);
244: }
245:
246: TCByteBuffer[] data = bbos.toArray();
247: assertEquals(data.length, num);
248:
249: for (int i = 0; i < data.length; i++) {
250: assertNotNull(data[i]);
251: assertEquals(0, data[i].position());
252: assertEquals(blockSize, data[i].limit());
253: }
254:
255: byte expect = 0;
256: for (int i = 0; i < data.length; i++) {
257: TCByteBuffer buf = data[i];
258: while (buf.hasRemaining()) {
259: byte read = buf.get();
260: assertEquals(expect++, read);
261: }
262: }
263:
264: }
265:
266: public void testRandom() throws IOException {
267: for (int i = 0; i < 100; i++) {
268: doRandom();
269: }
270: }
271:
272: public void testBasicConsolidation() {
273: TCByteBufferOutputStream os = new TCByteBufferOutputStream(32,
274: 4096, false);
275: ByteArrayOutputStream baos = new ByteArrayOutputStream();
276:
277: for (int i = 0; i < 8192; i++) {
278: byte b = (byte) random.nextInt();
279: baos.write(b);
280: os.write(b);
281: }
282:
283: TCByteBuffer[] bufs = os.toArray();
284: assertEquals(2, bufs.length);
285: assertEquals(4096, bufs[0].limit());
286: assertEquals(4096, bufs[1].limit());
287:
288: compareData(baos.toByteArray(), bufs);
289: }
290:
291: public void doRandom() throws IOException {
292: // this guy will hold the control/compare data
293: ByteArrayOutputStream baos = new ByteArrayOutputStream();
294:
295: final int bufSize = random.nextInt(50) + 1;
296:
297: TCByteBufferOutputStream os = new TCByteBufferOutputStream(
298: bufSize, false);
299:
300: for (int i = 0; i < bufSize * 3; i++) {
301: int streamLen = os.getBytesWritten();
302: int whichWrite = random.nextInt(4);
303: switch (whichWrite) {
304: case 0: { // write(int)
305: byte b = (byte) random.nextInt();
306: baos.write(b);
307: os.write(b);
308: assertEquals(streamLen + 1, os.getBytesWritten());
309: break;
310: }
311: case 1: { // write(byte[])
312: byte b[] = new byte[random.nextInt(bufSize * 2)];
313: random.nextBytes(b);
314: baos.write(b);
315: os.write(b);
316: break;
317: }
318: case 2: { // write(byte[], int, int)
319: byte b[] = new byte[random.nextInt(bufSize * 2)];
320: random.nextBytes(b);
321: int off = b.length == 0 ? 0 : random.nextInt(b.length);
322: int len = b.length == 0 ? 0 : random.nextInt(b.length
323: - off);
324: baos.write(b, off, len);
325: os.write(b, off, len);
326: assertEquals(streamLen + len, os.getBytesWritten());
327: break;
328: }
329: case 3: { // write(TCByteBuffer[])
330: int num = random.nextInt(5);
331: TCByteBuffer[] b = new TCByteBuffer[num];
332: for (int n = 0; n < b.length; n++) {
333: TCByteBuffer buf = TCByteBufferFactory.getInstance(
334: false, random.nextInt(bufSize * 2));
335: byte[] bites = new byte[buf.limit()];
336: random.nextBytes(bites);
337: buf.put(bites);
338: buf.position(0);
339: b[n] = buf;
340: baos.write(bites);
341: }
342: os.write(b);
343: assertEquals(streamLen + length(b), os
344: .getBytesWritten());
345: break;
346: }
347: default: {
348: fail("unknown write: " + whichWrite);
349: }
350: }
351: }
352:
353: TCByteBuffer[] bufsOut = os.toArray();
354: assertNoZeroLength(bufsOut);
355:
356: compareData(baos.toByteArray(), os.toArray());
357: }
358:
359: private void assertNoZeroLength(TCByteBuffer[] bufs) {
360: for (int i = 0; i < bufs.length; i++) {
361: assertTrue("Buffer " + i + " has zero length", bufs[i]
362: .limit() > 0);
363: }
364: }
365:
366: private void compareData(byte[] compare, TCByteBuffer[] test) {
367: if (test.length == 0) {
368: assertEquals(0, compare.length);
369: return;
370: }
371:
372: int index = 0;
373: for (int i = 0; i < compare.length; i++) {
374: byte b = compare[i];
375: while (!test[index].hasRemaining()) {
376: index++;
377: }
378: byte b2 = test[index].get();
379: assertEquals(b, b2);
380: }
381:
382: assertFalse(test[index].hasRemaining());
383: }
384:
385: private int length(TCByteBuffer[] b) {
386: int rv = 0;
387: for (int i = 0; i < b.length; i++) {
388: rv += b[i].limit();
389: }
390: return rv;
391: }
392:
393: public void testWithArrayWrite() {
394: int blockSize = 4096;
395: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream(
396: blockSize, false);
397: int num = 10;
398:
399: byte write = 0;
400: for (int i = 0; i < blockSize * num; i++) {
401: bbos.write(write++);
402: }
403:
404: TCByteBuffer[] b = new TCByteBuffer[1];
405: byte[] s = "Hello Steve".getBytes();
406: b[0] = TCByteBufferFactory.getInstance(false, s.length);
407: b[0].put(s);
408: b[0].flip();
409: bbos.write(b);
410:
411: TCByteBuffer[] data = bbos.toArray();
412: assertEquals(num + 1, data.length);
413:
414: for (int i = 0; i < data.length - 1; i++) {
415: assertNotNull(data[i]);
416: assertEquals(0, data[i].position());
417: assertEquals(blockSize, data[i].limit());
418: }
419:
420: int last = data.length - 1;
421: assertNotNull(data[last]);
422: assertEquals(0, data[last].position());
423:
424: byte expect = 0;
425: for (int i = 0; i < data.length - 1; i++) {
426: TCByteBuffer buf = data[i];
427: while (buf.hasRemaining()) {
428: byte read = buf.get();
429: assertEquals(expect++, read);
430: }
431: }
432: byte[] s2 = new byte[s.length];
433: data[last].get(s2);
434: assertTrue(Arrays.equals(s, s2));
435: assertFalse(data[last].hasRemaining());
436: }
437:
438: public void testExceptions() {
439: try {
440: new TCByteBufferOutputStream(0, false);
441: fail();
442: } catch (IllegalArgumentException iae) {
443: // expected
444: }
445:
446: try {
447: new TCByteBufferOutputStream(-1, false);
448: fail();
449: } catch (IllegalArgumentException iae) {
450: // expected
451: }
452:
453: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream();
454: try {
455: bbos.write((byte[]) null);
456: fail();
457: } catch (NullPointerException npe) {
458: // expected
459: }
460:
461: try {
462: bbos.write((TCByteBuffer[]) null);
463: fail();
464: } catch (NullPointerException npe) {
465: // expected
466: }
467:
468: try {
469: bbos.write(null, 0, 0);
470: fail();
471: } catch (NullPointerException npe) {
472: // expected
473: }
474:
475: try {
476: bbos.write(new byte[10], -10, 0);
477: fail();
478: } catch (IndexOutOfBoundsException ioobe) {
479: // expected
480: }
481:
482: try {
483: bbos.write(new byte[10], 1, -10);
484: fail();
485: } catch (IndexOutOfBoundsException ioobe) {
486: // expected
487: }
488:
489: try {
490: bbos.write(new byte[10], 1, 10);
491: fail();
492: } catch (IndexOutOfBoundsException ioobe) {
493: // expected
494: }
495: }
496:
497: public void testEdgeCase1() {
498: testEdgeCase(10, 5, 1004);
499: }
500:
501: private void testEdgeCase(int bufLength, int byteArrLength,
502: int iterationCount) {
503:
504: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream(
505: bufLength, false);
506: byte data[] = new byte[byteArrLength];
507:
508: int dataWriten = 0;
509: for (int i = 0; i < iterationCount; i++) {
510: bbos.write(data);
511: dataWriten += data.length;
512: }
513:
514: TCByteBuffer[] bufs = bbos.toArray();
515: for (int i = 0; i < bufs.length - 1; i++) {
516: assertEquals(bufs[i].capacity(), bufs[i].limit());
517: dataWriten -= bufs[i].limit();
518: }
519: assertEquals(dataWriten, bufs[bufs.length - 1].limit());
520: }
521:
522: public void testEdgeCase2() {
523: testEdgeCase(3, 37, 10);
524: }
525:
526: public void testEdgeCase3() {
527: testEdgeCase(1, 1, 5000);
528: }
529:
530: public void testEdgeCase4() {
531: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream(
532: 27, false);
533: byte data[] = new byte[370];
534:
535: int written = 0;
536: for (int i = 0; i < 50; i++) {
537: Arrays.fill(data, (byte) 0);
538: Arrays.fill(data, i, i + 50, (byte) 42);
539: bbos.write(data, i, 50);
540: written += 50;
541: }
542:
543: TCByteBuffer[] bufs = bbos.toArray();
544: for (int i = 0; i < bufs.length - 1; i++) {
545: assertEquals(bufs[i].capacity(), bufs[i].limit());
546: written -= bufs[i].limit();
547: }
548: assertEquals(written, bufs[bufs.length - 1].limit());
549:
550: for (int i = 0; i < bufs.length; i++) {
551: while (bufs[i].hasRemaining()) {
552: assertEquals(42, bufs[i].get());
553: }
554: }
555: }
556:
557: public void testEmpty() {
558: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream();
559: bbos.close();
560: TCByteBuffer[] data = bbos.toArray();
561: assertEquals(0, data.length);
562: }
563:
564: public void testClose() {
565: TCByteBufferOutputStream bbos = new TCByteBufferOutputStream();
566:
567: bbos.write(new byte[1234]);
568: for (int i = 0; i < 10; i++) {
569: bbos.close();
570: }
571:
572: try {
573: bbos.write(1);
574: fail();
575: } catch (IllegalStateException ise) {
576: // expected
577: }
578:
579: try {
580: bbos.write(new byte[10]);
581: fail();
582: } catch (IllegalStateException ise) {
583: // expected
584: }
585:
586: try {
587: bbos.write(new byte[10], 2, 5);
588: fail();
589: } catch (IllegalStateException ise) {
590: // expected
591: }
592:
593: try {
594: bbos.write(new TCByteBuffer[] {});
595: fail();
596: } catch (IllegalStateException ise) {
597: // expected
598: }
599:
600: }
601: }
|