001: /*
002: * Regression tests for Circular Buffers.
003: * Copyright (C) 2002 Stephen Ostermiller
004: * http://ostermiller.org/contact.pl?regarding=Java+Utilities
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * See COPYING.TXT for details.
017: */
018: package com.Ostermiller.util;
019:
020: import java.io.*;
021: import java.util.Random;
022:
023: /**
024: * Regression test for circular buffers. When run, this program
025: * should output the Gettysburg Address and quite a few digits of
026: * pi.
027: * More information about this class is available from <a target="_top" href=
028: * "http://ostermiller.org/utils/CircularCharBuffer.html">ostermiller.org</a>.
029: *
030: * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
031: * @since ostermillerutils 1.00.00
032: */
033: class CircularBufferTests {
034:
035: private byte[] pi = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9,
036: 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8,
037: 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0,
038: 9, 7, 4, 9, 4, 4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4, 0, 6, 2, 8,
039: 6, 2, 0, 8, 9, 9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1,
040: 1, 7, 0, 6, 7, 9, 8, 2, 1, 4, 8, 0, 8, 6, 5, 1, 3, 2, 8, 2,
041: 3, 0, 6, 6, 4, 7, 0, 9, 3, 8, 4, 4, 6, 0, 9, 5, 5, 0, 5, 8,
042: 2, 2, 3, 1, 7, 2, 5, 3, 5, 9, 4, 0, 8, 1, 2, 8, 4, 8, 1, 1,
043: 1, 7, 4, 5, 0, 2, 8, 4, 1, 0, 2, 7, 0, 1, 9, 3, 8, 5, 2, 1,
044: 1, 0, 5, 5, 5, 9, 6, 4, 4, 6, 2, 2, 9, 4, 8, 9, 5, 4, 9, 3,
045: 0, 3, 8, 1, 9, 6, 4, 4, 2, 8, 8, 1, 0, 9, 7, 5, 6, 6, 5, 9,
046: 3, 3, 4, 4, 6, 1, 2, 8, 4, 7, 5, 6, 4, 8, 2, 3, 3, 7, 8, 6,
047: 7, 8, 3, 1, 6, 5, 2, 7, 1, 2, 0, 1, 9, 0, 9, 1, 4, 5, 6, 4,
048: 8, 5, 6, 6, 9, 2, 3, 4, 6, 0, 3, 4, 8, 6, 1, 0, 4, 5, 4, 3,
049: 2, 6, 6, 4, 8, 2, 1, 3, 3, 9, 3, 6, 0, 7, 2, 6, 0, 2, 4, 9,
050: 1, 4, 1, 2, 7, 3, 7, 2, 4, 5, 8, 7, 0, 0, 6, 6, 0, 6, 3, 1,
051: 5, 5, 8, 8, 1, 7, 4, 8, 8, 1, 5, 2, 0, 9, 2, 0, 9, 6, 2, 8,
052: 2, 9, 2, 5, 4, 0, 9, 1, 7, 1, 5, 3, 6, 4, 3, 6, 7, 8, 9, 2,
053: 5, 9, 0, 3, 6, 0, 0, 1, 1, 3, 3, 0, 5, 3, 0, 5, 4, 8, 8, 2,
054: 0, 4, 6, 6, 5, 2, 1, 3, 8, 4, 1, 4, 6, 9, 5, 1, 9, 4, 1, 5,
055: 1, 1, 6, 0, 9, 4, 3, 3, 0, 5, 7, 2, 7, 0, 3, 6, 5, 7, 5, 9,
056: 5, 9, 1, 9, 5, 3, 0, 9, 2, 1, 8, 6, 1, 1, 7, 3, 8, 1, 9, 3,
057: 2, 6, 1, 1, 7, 9, 3, 1, 0, 5, 1, 1, 8, 5, 4, 8, 0, 7, 4, 4,
058: 6, 2, 3, 7, 9, 9, 6, 2, 7, 4, 9, 5, 6, 7, 3, 5, 1, 8, 8, 5,
059: 7, 5, 2, 7, 2, 4, 8, 9, 1, 2, 2, 7, 9, 3, 8, 1, 8, 3, 0, 1,
060: 1, 9, 4, 9, 1, 2, 9, 8, 3, 3, 6, 7, 3, 3, 6, 2, 4, 4, 0, 6,
061: 5, 6, 6, 4, 3, 0, 8, 6, 0, 2, 1, 3, 9, 4, 9, 4, 6, 3, 9, 5,
062: 2, 2, 4, 7, 3, 7, 1, 9, 0, 7, 0, 2, 1, 7, 9, 8, 6, 0, 9, 4,
063: 3, 7, 0, 2, 7, 7, 0, 5, 3, 9, 2, 1, 7, 1, 7, 6, 2, 9, 3, 1,
064: 7, 6, 7, 5, 2, 3, 8, 4, 6, 7, 4, 8, 1, 8, 4, 6, 7, 6, 6, 9,
065: 4, 0, 5, 1, 3, 2, 0, 0, 0, 5, 6, 8, 1, 2, 7, 1, 4, 5, 2, 6,
066: 3, 5, 6, 0, 8, 2, 7, 7, 8, 5, 7, 7, 1, 3, 4, 2, 7, 5, 7, 7,
067: 8, 9, 6, 0, 9, 1, 7, 3, 6, 3, 7, 1, 7, 8, 7, 2, 1, 4, 6, 8,
068: 4, 4, 0, 9, 0, 1, 2, 2, 4, 9, 5, 3, 4, 3, 0, 1, 4, 6, 5, 4,
069: 9, 5, 8, 5, 3, 7, 1, 0, 5, 0, 7, 9, 2, 2, 7, 9, 6, 8, 9, 2,
070: 5, 8, 9, 2, 3, 5, 4, 2, 0, 1, 9, 9, 5, 6, 1, 1, 2, 1, 2, 9,
071: 0, 2, 1, 9, 6, 0, 8, 6, 4, 0, 3, 4, 4, 1, 8, 1, 5, 9, 8, 1,
072: 3, 6, 2, 9, 7, 7, 4, 7, 7, 1, 3, 0, 9, 9, 6, 0, 5, 1, 8, 7,
073: 0, 7, 2, 1, 1, 3, 4, 9, 9, 9, 9, 9, 9, 8, 3, 7, 2, 9, 7, 8,
074: 0, 4, 9, 9, 5, 1, };
075:
076: private String theGettysburgAddress = "Four score and seven years ago our fathers brought forth, "
077: + "upon this continent, a new nation, conceived in Liberty, and dedicated "
078: + "to the proposition that all men are created equal.\n"
079: + "Now we are engaged in a great civil war, testing whether that nation, "
080: + "or any nation so conceived, and so dedicated, can long endure. We are "
081: + "met here on a great battlefield of that war. We have come to dedicate "
082: + "a portion of it as a final resting place for those who here gave their "
083: + "lives that that nation might live. It is altogether fitting and proper "
084: + "that we should do this.\n"
085: + "But in a larger sense we can not dedicate -- we can not consecrate -- "
086: + "we can not hallow this ground. The brave men, living and dead, who "
087: + "struggled, here, have consecrated it far above our poor power to add "
088: + "or detract. The world will little note, nor long remember, what we say here, "
089: + "but can never forget what they did here. It is for us, the living, rather "
090: + "to be dedicated here to the unfinished work which they have, thus far, so "
091: + "nobly carried on. It is rather for us to be here dedicated to the great task "
092: + "remaining before us -- that from these honored dead we take increased devotion "
093: + "to that cause for which they here gave the last full measure of devotion -- "
094: + "that we here highly resolve that these dead shall not have died in vain; that "
095: + "this nation shall have a new birth of freedom; and that this government of the "
096: + "people, by the people, for the people, shall not perish from the earth.";
097:
098: private StringWriter tgbaWriter = new StringWriter();
099: private StringWriter tgbaWriter2 = new StringWriter();
100:
101: private ByteArrayOutputStream piOutputStream = new ByteArrayOutputStream();
102:
103: private Random rand = new Random();
104:
105: private CircularCharBuffer ccb = new CircularCharBuffer(20);
106: private Reader ccbin;
107: private Writer ccbout;
108:
109: private CircularByteBuffer cbb = new CircularByteBuffer(20);
110: private InputStream cbbin;
111: private OutputStream cbbout;
112:
113: private CircularObjectBuffer<String> cob = new CircularObjectBuffer<String>(
114: 20);
115:
116: /**
117: * Main test method
118: * @param args command line arguments (ignored)
119: */
120: public static void main(String args[]) {
121: try {
122: new CircularBufferTests();
123: } catch (Exception x) {
124: x.printStackTrace();
125: System.exit(1);
126: }
127: System.exit(0);
128: }
129:
130: private CircularBufferTests() throws Exception {
131:
132: ccbin = ccb.getReader();
133: ccbout = ccb.getWriter();
134: CCBProducer ccbp = new CCBProducer();
135: CCBConsumer ccbc = new CCBConsumer();
136: ccbc.start();
137: ccbp.start();
138: while (ccbc.isAlive() || ccbp.isAlive()) {
139: if (System.in.available() > 0) {
140: ccbc.interrupt();
141: ccbp.interrupt();
142: return;
143: }
144: }
145: String s1 = tgbaWriter.toString();
146: if (!theGettysburgAddress.equals(s1)) {
147: throw new Exception(s1);
148: }
149:
150: cbbin = cbb.getInputStream();
151: cbbout = cbb.getOutputStream();
152: CBBProducer cbbp = new CBBProducer();
153: CBBConsumer cbbc = new CBBConsumer();
154: cbbc.start();
155: cbbp.start();
156: while (cbbc.isAlive() || cbbp.isAlive()) {
157: if (System.in.available() > 0) {
158: cbbc.interrupt();
159: cbbp.interrupt();
160: return;
161: }
162: }
163: assertEqual(pi, piOutputStream.toByteArray());
164:
165: COBProducer cobp = new COBProducer();
166: COBConsumer cobc = new COBConsumer();
167: cobc.start();
168: cobp.start();
169: while (cobc.isAlive() || cobp.isAlive()) {
170: if (System.in.available() > 0) {
171: cobc.interrupt();
172: cobp.interrupt();
173: return;
174: }
175: }
176: String s2 = tgbaWriter2.toString();
177: if (!theGettysburgAddress.equals(s2)) {
178: throw new Exception(s2);
179: }
180: }
181:
182: private static void assertEqual(byte[] b1, byte[] b2)
183: throws Exception {
184: if (b1.length != b2.length)
185: throw new Exception("Length mismatch: " + b1.length + ", "
186: + b2.length);
187: for (int i = 0; i < b1.length; i++) {
188: if (b1[i] != b2[i]) {
189: throw new Exception("Mismatch at position " + i + ": "
190: + b1[i] + ", " + b2[i]);
191: }
192: }
193: }
194:
195: private class CCBProducer extends Thread {
196: /**
197: * @see java.lang.Thread#run()
198: */
199: @Override
200: public void run() {
201: try {
202: for (int position = 0; !isInterrupted()
203: && position < theGettysburgAddress.length(); position++) {
204: int len = rand.nextInt(30);
205: len = Math.min(len, theGettysburgAddress.length()
206: - position);
207: int off = rand.nextInt(10);
208: switch (rand.nextInt(4)) {
209: case 0: {
210: char[] writeBuf = new char[len];
211: for (int i = 0; i < len; i++) {
212: writeBuf[i] = theGettysburgAddress
213: .charAt(position + i);
214: }
215: ccbout.write(writeBuf);
216: }
217: break;
218: case 1: {
219: char[] writeBuf = new char[off + len];
220: for (int i = 0; i < len; i++) {
221: writeBuf[i + off] = theGettysburgAddress
222: .charAt(position + i);
223: }
224: ccbout.write(writeBuf, off, len);
225: }
226: break;
227: case 2: {
228: for (int i = 0; !isInterrupted() && i < len; i++) {
229: ccbout.write(theGettysburgAddress
230: .charAt(position + i));
231: }
232: }
233: break;
234: case 3: {
235: ccbout.write(theGettysburgAddress.substring(
236: position, position + len));
237: }
238: break;
239: case 4: {
240: ccbout.write(theGettysburgAddress, position,
241: len);
242: }
243: break;
244: }
245: position += (len - 1);
246: try {
247: Thread.sleep(50 + rand.nextInt(100));
248: } catch (Exception x) {
249: throw new IOException(
250: "Producer thread interrupted.");
251: }
252: }
253: ccbout.close();
254: } catch (IOException x) {
255: System.err.println(x.getMessage());
256: }
257: }
258: }
259:
260: private class CCBConsumer extends Thread {
261: /**
262: * @see java.lang.Thread#run()
263: */
264: @Override
265: public void run() {
266: try {
267: boolean done = false;
268: while (!isInterrupted() && !done) {
269: int len = rand.nextInt(30);
270: int off = rand.nextInt(10);
271: switch (rand.nextInt(2)) {
272: case 0: {
273: char[] readBuf = new char[len];
274: int read = ccbin.read(readBuf);
275: if (read == -1) {
276: done = true;
277: } else {
278: for (int i = 0; i < read; i++) {
279: tgbaWriter.write(readBuf[i]);
280: }
281: }
282: }
283: break;
284: case 1: {
285: char[] readBuf = new char[off + len];
286: int read = ccbin.read(readBuf, off, len);
287: if (read == -1) {
288: done = true;
289: } else {
290: for (int i = 0; i < read; i++) {
291: tgbaWriter.write(readBuf[i + off]);
292: }
293: }
294: }
295: break;
296: case 2: {
297: for (int i = 0; !isInterrupted() && !done
298: && i < len; i++) {
299: int read;
300: read = ccbin.read();
301: if (read == -1) {
302: done = true;
303: } else {
304: tgbaWriter.write((char) read);
305: }
306: }
307: }
308: break;
309: }
310: try {
311: Thread.sleep(50 + rand.nextInt(100));
312: } catch (Exception x) {
313: throw new IOException(
314: "Consumer thread interrupted.");
315: }
316: }
317: } catch (IOException x) {
318: System.err.println(x.getMessage());
319: }
320: }
321: }
322:
323: private class CBBProducer extends Thread {
324: /**
325: * @see java.lang.Thread#run()
326: */
327: @Override
328: public void run() {
329: try {
330: for (int position = 0; !isInterrupted()
331: && position < pi.length; position++) {
332: int len = rand.nextInt(30);
333: len = Math.min(len, pi.length - position);
334: int off = rand.nextInt(10);
335: switch (rand.nextInt(2)) {
336: case 0: {
337: byte[] writeBuf = new byte[len];
338: for (int i = 0; i < len; i++) {
339: writeBuf[i] = pi[position + i];
340: }
341: cbbout.write(writeBuf);
342: }
343: break;
344: case 1: {
345: byte[] writeBuf = new byte[off + len];
346: for (int i = 0; i < len; i++) {
347: writeBuf[i + off] = pi[position + i];
348: }
349: cbbout.write(writeBuf, off, len);
350: }
351: break;
352: case 2: {
353: for (int i = 0; !isInterrupted() && i < len; i++) {
354: cbbout.write(pi[position + i]);
355: }
356: }
357: break;
358: }
359: position += (len - 1);
360: try {
361: Thread.sleep(50 + rand.nextInt(100));
362: } catch (Exception x) {
363: throw new IOException(
364: "Producer thread interrupted.");
365: }
366: }
367: cbbout.close();
368: } catch (IOException x) {
369: System.err.println(x.getMessage());
370: }
371: }
372: }
373:
374: private class CBBConsumer extends Thread {
375: /**
376: * @see java.lang.Thread#run()
377: */
378: @Override
379: public void run() {
380: try {
381: boolean done = false;
382: while (!isInterrupted() && !done) {
383: int len = rand.nextInt(30);
384: int off = rand.nextInt(10);
385: switch (rand.nextInt(2)) {
386: case 0: {
387: byte[] readBuf = new byte[len];
388: int read = cbbin.read(readBuf);
389: if (read == -1) {
390: done = true;
391: } else {
392: for (int i = 0; i < read; i++) {
393: piOutputStream.write(readBuf[i]);
394: }
395: }
396: }
397: break;
398: case 1: {
399: byte[] readBuf = new byte[off + len];
400: int read = cbbin.read(readBuf, off, len);
401: if (read == -1) {
402: done = true;
403: } else {
404: for (int i = 0; i < read; i++) {
405: piOutputStream.write(readBuf[i + off]);
406: }
407: }
408: }
409: break;
410: case 2: {
411: for (int i = 0; !isInterrupted() && !done
412: && i < len; i++) {
413: int read;
414: read = cbbin.read();
415: if (read == -1) {
416: done = true;
417: } else {
418: piOutputStream.write((byte) read);
419: }
420: }
421: }
422: break;
423: }
424: try {
425: Thread.sleep(50 + rand.nextInt(100));
426: } catch (Exception x) {
427: throw new IOException(
428: "Consumer thread interrupted.");
429: }
430: }
431: } catch (IOException x) {
432: System.err.println(x.getMessage());
433: }
434: }
435: }
436:
437: private class COBProducer extends Thread {
438: /**
439: * @see java.lang.Thread#run()
440: */
441: @Override
442: public void run() {
443: try {
444: for (int position = 0; !isInterrupted()
445: && position < theGettysburgAddress.length(); position++) {
446: int len = rand.nextInt(30);
447: len = Math.min(len, theGettysburgAddress.length()
448: - position);
449: int off = rand.nextInt(10);
450: switch (rand.nextInt(2)) {
451: case 0: {
452: String[] writeBuf = new String[len];
453: for (int i = 0; i < len; i++) {
454: writeBuf[i] = Character
455: .toString(theGettysburgAddress
456: .charAt(position + i));
457: }
458: cob.write(writeBuf);
459: }
460: break;
461: case 1: {
462: String[] writeBuf = new String[off + len];
463: for (int i = 0; i < len; i++) {
464: writeBuf[i + off] = Character
465: .toString(theGettysburgAddress
466: .charAt(position + i));
467: }
468: cob.write(writeBuf, off, len);
469: }
470: break;
471: case 2: {
472: for (int i = 0; !isInterrupted() && i < len; i++) {
473: cob.write(Character
474: .toString(theGettysburgAddress
475: .charAt(position + i)));
476: }
477: }
478: break;
479: }
480: position += (len - 1);
481: try {
482: Thread.sleep(50 + rand.nextInt(100));
483: } catch (Exception x) {
484: throw new IOException(
485: "Producer thread interrupted.");
486: }
487: }
488: cob.done();
489: } catch (Exception x) {
490: System.err.println(x.getMessage());
491: }
492: }
493: }
494:
495: private class COBConsumer extends Thread {
496: /**
497: * @see java.lang.Thread#run()
498: */
499: @Override
500: public void run() {
501: try {
502: boolean done = false;
503: while (!isInterrupted() && !done) {
504: int len = rand.nextInt(30);
505: int off = rand.nextInt(10);
506: switch (rand.nextInt(2)) {
507: case 0: {
508: String[] readBuf = new String[len];
509: int read = cob.read(readBuf);
510: if (read == -1) {
511: done = true;
512: } else {
513: for (int i = 0; i < read; i++) {
514: tgbaWriter2.write(readBuf[i]);
515: }
516: }
517: }
518: break;
519: case 1: {
520: String[] readBuf = new String[off + len];
521: int read = cob.read(readBuf, off, len);
522: if (read == -1) {
523: done = true;
524: } else {
525: for (int i = 0; i < read; i++) {
526: tgbaWriter2.write(readBuf[i + off]);
527: }
528: }
529: }
530: break;
531: case 2: {
532: for (int i = 0; !isInterrupted() && !done
533: && i < len; i++) {
534: String read;
535: read = cob.read();
536: if (read == null) {
537: done = true;
538: } else {
539: tgbaWriter2.write(read);
540: }
541: }
542: }
543: break;
544: }
545: try {
546: Thread.sleep(50 + rand.nextInt(100));
547: } catch (Exception x) {
548: throw new IOException(
549: "Consumer thread interrupted.");
550: }
551: }
552: } catch (Exception x) {
553: System.err.println(x.getMessage());
554: }
555: }
556: }
557: }
|