# HG changeset patch # User Jaroslav Tulach # Date 1213429986 -7200 # Node ID 8379bb7c0dff1356ec9c932f4cd0400ff47cb557 # Parent 4db7ceebd2b33ac27bbbb049358aeb4908187dc3 Tests rewritten to new version, just the Writer version 2.0 does not yet implement Appendable diff -r 4db7ceebd2b3 -r 8379bb7c0dff samples/delegatingwriterfinal/build.xml --- a/samples/delegatingwriterfinal/build.xml Sat Jun 14 09:53:06 2008 +0200 +++ b/samples/delegatingwriterfinal/build.xml Sat Jun 14 09:53:06 2008 +0200 @@ -13,20 +13,29 @@ - + + + + + + - + - + + + + + @@ -40,15 +49,34 @@ - + - + - + + + + + + + + + + + + + + + + + + + + diff -r 4db7ceebd2b3 -r 8379bb7c0dff samples/delegatingwriterfinal/nbproject/project.xml --- a/samples/delegatingwriterfinal/nbproject/project.xml Sat Jun 14 09:53:06 2008 +0200 +++ b/samples/delegatingwriterfinal/nbproject/project.xml Sat Jun 14 09:53:06 2008 +0200 @@ -25,7 +25,13 @@ java - src-test + src-test1.0 + UTF-8 + + + + java + src-test2.0 UTF-8 @@ -55,8 +61,12 @@ src-api2.0 - - src-test + + src-test1.0 + + + + src-test2.0 build.xml @@ -80,10 +90,15 @@ 1.5 - src-test + src-test1.0 src-api1.0:../libs/dist/junit-4.4.jar 1.5 + + src-test2.0 + src-api2.0:../libs/dist/junit-4.4.jar + 1.5 + diff -r 4db7ceebd2b3 -r 8379bb7c0dff samples/delegatingwriterfinal/src-api2.0/api/Writer.java --- a/samples/delegatingwriterfinal/src-api2.0/api/Writer.java Sat Jun 14 09:53:06 2008 +0200 +++ b/samples/delegatingwriterfinal/src-api2.0/api/Writer.java Sat Jun 14 09:53:06 2008 +0200 @@ -1,5 +1,6 @@ package api; +import java.io.BufferedWriter; import java.io.IOException; /** Fixing the problem caused by mixing subclassing and delegation in @@ -9,30 +10,124 @@ */ public final class Writer { private final Impl impl; + private final ImplSeq seq; - private Writer(Impl impl) { + private Writer(Impl impl, ImplSeq seq) { this.impl = impl; + this.seq = seq; } public final void write(int c) throws IOException { - impl.write(new CharSeq(c)); + if (impl != null) { + char[] arr = {(char) c}; + impl.write(arr, 0, 1); + } else { + seq.write(new CharSeq(c)); + } } public final void write(char cbuf[]) throws IOException { - impl.write(new CharSeq(cbuf, 0, cbuf.length)); + if (impl != null) { + impl.write(cbuf, 0, cbuf.length); + } else { + seq.write(new CharSeq(cbuf, 0, cbuf.length)); + } } public final void write(char cbuf[], int off, int len) throws IOException { - impl.write(new CharSeq(cbuf, off, len)); + if (impl != null) { + impl.write(cbuf, off, len); + } else { + seq.write(new CharSeq(cbuf, off, len)); + } } public final void write(String str) throws IOException { - impl.write(str); + if (impl != null) { + impl.write(str, 0, str.length()); + } else { + seq.write(str); + } } public final void write(String str, int off, int len) throws IOException { - impl.write(str.subSequence(off, off + len)); + if (impl != null) { + impl.write(str, off, len); + } else { + seq.write(str.subSequence(off, off + len)); + } } + public final void flush() throws IOException { + if (impl != null) { + impl.flush(); + } else { + seq.flush(); + } + } + public final void close() throws IOException { + if (impl != null) { + impl.close(); + } else { + seq.flush(); + } + } + + public static Writer create(Impl impl) { + return new Writer(impl, null); + } + + public static Writer create(ImplSeq impl) { + return new Writer(null, impl); + } + + public static Writer create(final java.io.Writer w) { + return new Writer(new Impl() { + public void write(String str, int off, int len) throws IOException { + w.write(str, off, len); + } + + public void write(char[] arr, int off, int len) throws IOException { + w.write(arr, off, len); + } + + public void close() throws IOException { + w.close(); + } + + public void flush() throws IOException { + w.flush(); + } + }, null); + } + + public static Writer createBuffered(final Writer out) { + class Delegate extends java.io.Writer { + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + out.write(cbuf, off, len); + } + + @Override + public void flush() throws IOException { + out.flush(); + } + + @Override + public void close() throws IOException { + out.close(); + } + + } + return create(new BufferedWriter(new Delegate())); + } public static interface Impl { + public void close() throws IOException; + public void flush() throws IOException; + public void write(String str, int off, int len) throws IOException; + public void write(char[] arr, int off, int len) throws IOException; + } + public static interface ImplSeq { + public void close() throws IOException; + public void flush() throws IOException; public void write(CharSequence seq) throws IOException; } diff -r 4db7ceebd2b3 -r 8379bb7c0dff samples/delegatingwriterfinal/src-test1.0/api/usage/BufferedWriterCryptoTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/src-test1.0/api/usage/BufferedWriterCryptoTest.java Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,37 @@ + +package api.usage; + +import api.Writer; +import java.io.IOException; +import java.io.StringWriter; +import java.io.StringWriter; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +/** Converting the Crypto example to the APIs that split client and provider + * concerns and do not mix delegation and subclassing. + * + * @author Jaroslav Tulach + */ +public class BufferedWriterCryptoTest { + private StringWriter writer; + + + public BufferedWriterCryptoTest() { + } + + @Before + public void setUp() { + writer = new StringWriter(); + } + + @Test + public void testBehaviourOfRealBufferInJDKWorksFine() throws IOException { + Writer bufferedWriter = CryptoWriter.create(Writer.create(writer)); + bufferedWriter.write("VMS"); + bufferedWriter.flush(); + assertEquals("Converted", "WNT", writer.toString()); + } + +} \ No newline at end of file diff -r 4db7ceebd2b3 -r 8379bb7c0dff samples/delegatingwriterfinal/src-test2.0/api/usage/twodotzero/BufferedWriterOnCDImageTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/src-test2.0/api/usage/twodotzero/BufferedWriterOnCDImageTest.java Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,72 @@ + +package api.usage.twodotzero; + +import api.Writer; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Test; +import static org.junit.Assert.*; + +/** Emulates what goes wrong when one wants to process really large character + * sequence. + * + * @author Jaroslav Tulach + */ +public class BufferedWriterOnCDImageTest { + + public BufferedWriterOnCDImageTest() { + } + + @Test + public void testBehaviourOfRealBufferInJDKObviouslyThisIsGoingToThrowOutOfMemoryError() throws IOException { + AtomicInteger cnt = new AtomicInteger(); + Writer writer = CountingWriter.create(cnt); + CDSequence cdImage = new CDSequence(); + Writer bufferedWriter = Writer.createBuffered(writer); + bufferedWriter.append(cdImage); + assertEquals("Correct number of writes delegated", cdImage.length(), cnt.get()); + } + + + /** A "lazy" sequence of characters, for example one that can represent + * content of a CD, read it lazily, do not fit all into memory at once. + */ + private static final class CDSequence implements CharSequence { + private final int start; + private final int end; + + public CDSequence() { + this(0, 647 * 1024 * 1024); + } + + private CDSequence(int start, int end) { + this.start = start; + this.end = end; + } + + + public int length() { + return end - start; + } + + public char charAt(int index) { + int ch = index % ('Z' - 'A' + 1); + return (char) ('A' + ch); + } + + public CharSequence subSequence(int start, int end) { + return new CDSequence(start, end); + } + + @Override + public String toString() { + char[] arr = new char[length()]; + for (int i = 0; i < length(); i++) { + arr[i] = charAt(i); + } + return new String(arr); + } + + + } // end of CharSequence +} \ No newline at end of file diff -r 4db7ceebd2b3 -r 8379bb7c0dff samples/delegatingwriterfinal/src-test2.0/api/usage/twodotzero/CountingWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/delegatingwriterfinal/src-test2.0/api/usage/twodotzero/CountingWriter.java Sat Jun 14 09:53:06 2008 +0200 @@ -0,0 +1,36 @@ + +package api.usage.twodotzero; + +import api.Writer; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +/** Writer that counts the number of written in characters. + * + * @author Jaroslav Tulach + */ +public class CountingWriter implements Writer.ImplSeq { + private final AtomicInteger counter; + + private CountingWriter(AtomicInteger counter) { + this.counter = counter; + } + + public static Writer create(AtomicInteger result) { + return Writer.create(new CountingWriter(result)); + } + + @Override + public void write(CharSequence csq) throws IOException { + counter.addAndGet(csq.length()); + } + + @Override + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + } + +}