You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2006/08/26 13:39:22 UTC

svn commit: r437146 [2/2] - in /db/derby/code/branches/10.2/java: engine/org/apache/derby/iapi/services/io/ engine/org/apache/derby/iapi/types/ engine/org/apache/derby/impl/jdbc/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/...

Added: db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/ByteAlphabet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/ByteAlphabet.java?rev=437146&view=auto
==============================================================================
--- db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/ByteAlphabet.java (added)
+++ db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/ByteAlphabet.java Sat Aug 26 04:39:20 2006
@@ -0,0 +1,208 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.util.streams.ByteAlphabet
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.util.streams;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * A looping alphabet, returning bytes in a specified encoding.
+ *
+ * The alphabet loops over a list of bytes representing characters. The
+ * alphabet-object is used by looping stream, which in turn is used for testing
+ * methods requiring streaming inputs.
+ *
+ * The following alphabets have been defined:
+ * <ul><li><em>Modern latin, lowercase</em> ; letters a - z (26)
+ *     <li><em>Norwegian/Danish, lowercase</em> ; letters a - z, plus three
+ *         additional letters (29)
+ *     <li><em>Tamil</em> ; 46 Tamil letters from UNICODE U0B80
+ *     <li><em>CJK subset</em> ; 12 letter from UNICODE CJK U4E00 
+ * </ul>
+ */
+public class ByteAlphabet {
+
+    /** The name of the alphabet. */
+    private final String name;
+    /** The encoding used to represent characters as bytes. */
+    private final String encoding;
+    /** The bytes representing the characters in the alphabet. */
+    private final byte[] bytes;
+    /** The number of characters in the alphabet. */
+    private final int charCount;
+    /** The number of byes in the alphabet. */
+    private final int byteCount;
+    /** Offset into the byte array. */
+    private int boff = 0;
+
+    /**
+     * Create an alphabet returning bytes representing the lowercase letters
+     * a-z in the "US-ASCII" encoding.
+     */
+    public static ByteAlphabet modernLatinLowercase() {
+        return new ByteAlphabet("Modern latin lowercase, US-ASCII",
+                            CharAlphabet.MODERNLATINLOWER,
+                            "US-ASCII");
+    }
+
+    /**
+     * Create an alphabet returning bytes representing the 29 lowercase
+     * letters in the Norwegian/Danish alphabet in the "ISO-8859-1" encoding.
+     */
+    public static ByteAlphabet norwegianLowercase() {
+        return new ByteAlphabet("Norwegian/Danish lowercase, ISO-8859-1",
+                        CharAlphabet.NO_DK_LOWER,
+                        "ISO-8859-1");
+    }
+
+    /**
+     * Create an alphabet returning bytes representing a subset of the Tamil
+     * alphabet in the UTF-8 encoding.
+     */
+    public static ByteAlphabet tamilUTF8() {
+        return new ByteAlphabet("Tamil, UTF-8",
+                        CharAlphabet.TAMIL,
+                        "UTF8");
+    }
+
+    /**
+     * Create an alphabet returning bytes representing a subset of the Tamil
+     * alphabet in the UTF-16BE encoding.
+     */
+    public static ByteAlphabet tamilUTF16BE() {
+        return new ByteAlphabet("Tamil, UTF-16BE",
+                        CharAlphabet.TAMIL,
+                        "UTF-16BE");
+    }
+
+    /**
+     * Create an alphabet returning bytes representing a subset of the CJK
+     * alphabet in the UTF-8 encoding.
+     */
+    public static ByteAlphabet cjkSubsetUTF8() {
+        return new ByteAlphabet("CJK subset, UTF-8",
+                        CharAlphabet.CJKSUBSET,
+                        "UTF8");
+    }
+
+    /**
+     * Create an alphabet returning bytes representing a subset of the CJK
+     * alphabet in the UTF-16BE encoding.
+     */
+    public static ByteAlphabet cjkSubsetUTF16BE() {
+        return new ByteAlphabet("CJK subset, UTF-16BE",
+                        CharAlphabet.CJKSUBSET,
+                        "UTF-16BE");
+    }
+
+    /**
+     * Create an alphabet with the given name, the given characters and using
+     * the specified encoding to represent the characters as bytes.
+     *
+     * @param name the name of the alphabet
+     * @param chars the characters in the alphabet
+     * @param encoding the encoding to use to represent characters as bytes
+     */
+    private ByteAlphabet(String name, char[] chars, String encoding) {
+        this.name = name;
+        this.encoding = encoding;
+        this.charCount = chars.length;
+        String tmpStr = new String(chars);
+        byte[] tmpBytes;
+        int tmpByteCount;
+        try {
+            tmpBytes = tmpStr.getBytes(encoding);
+            tmpByteCount = tmpBytes.length;
+        } catch (UnsupportedEncodingException uee) {
+            // We are nasty and ignore this...
+            tmpBytes = new byte[] {0};
+            tmpByteCount = 1;
+        }
+        this.bytes = tmpBytes;
+        this.byteCount = tmpByteCount;
+    }
+
+    /**
+     * Return the name of the alphabet.
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Return the encoding used to represent characters as bytes.
+     */
+    public String getEncoding() {
+        return this.encoding;
+    }
+
+    /**
+     * Return the number of characters in the alphabet.
+     */
+    public int charCount() {
+        return charCount;
+    }
+
+    /**
+     * Return the number of bytes in the alphabet.
+     *
+     * The number of bytes in the alphabet is noramlly different from the
+     * number of characters in the alphabet, but it depends on the
+     * characters in the alphabet and encoding used to represent them as
+     * bytes.
+     */
+    public int byteCount() {
+        return byteCount;
+    }
+
+    /**
+     * Return the next byte in the alphabet.
+     */
+    public byte nextByte() {
+        if (boff >= byteCount) {
+            boff = 0;
+        }
+        return bytes[boff++]; 
+    }
+    
+    /**
+     * Reset the alphabet, the next byte returned is the first byte in the
+     * alphabet, which might not be a complete character.
+     */
+    public void reset() {
+        boff = 0;
+    }
+
+    /**
+     * Compute the next byte to read after reading the specified number
+     * of bytes. 
+     *
+     * Besides from returning the index, the internal state of
+     * the alphabet is updated.
+     *
+     * @param bytesRead the number of bytes read
+     * @return the index of the next byte
+     */
+    public int nextByteToRead(int bytesRead) {
+        boff = (boff + (bytesRead % byteCount)) % byteCount;
+        return boff;
+    }
+} // End class ByteAlphabet

Propchange: db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/ByteAlphabet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java?rev=437146&view=auto
==============================================================================
--- db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java (added)
+++ db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java Sat Aug 26 04:39:20 2006
@@ -0,0 +1,169 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.util.streams.CharAlphabet
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.util.streams;
+
+/**
+ * A looping alphabet, returning characters.
+ *
+ * The alphabet loops over a list of characters. The alphabet-object is used
+ * by looping readers, which in turn is used for testing methods requiring
+ * streaming inputs.
+ *
+ * The following alphabets have been defined:
+ * <ul><li><em>Modern latin, lowercase</em> ; letters a - z (26)
+ *     <li><em>Norwegian/Danish, lowercase</em> ; letters a - z, plus three
+ *         additional letters (29)
+ *     <li><em>Tamil</em> ; 46 Tamil letters from UNICODE U0B80
+ *     <li><em>CJK subset</em> ; 12 letter from UNICODE CJK U4E00 
+ * </ul>
+ */
+public class CharAlphabet {
+    
+    /** Modern latin, lowercase; a - z, 26 letters */
+    public static char[] MODERNLATINLOWER = {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
+        };
+
+    /** Norwegian/Danish alphabet, lowercase; 29 letters */
+    public static char[] NO_DK_LOWER = {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '\u00E6', '\u00F8', '\u00E5'
+        };
+
+    /** Subset of Tamil alphabet; 46 letters, UNICODE U0B80 */
+    public static char[] TAMIL = {
+            '\u0B85', '\u0B86', '\u0B87', '\u0B88', '\u0B89', '\u0B8A',
+            '\u0B8E', '\u0B8F', '\u0B90', '\u0B92', '\u0B93', '\u0B94',
+            '\u0B95', '\u0B99', '\u0B9A', '\u0B9C', '\u0B9E', '\u0B9F',
+            '\u0BA3', '\u0BA4', '\u0BA8', '\u0BA9', '\u0BAA', '\u0BAE',
+            '\u0BAF', '\u0BB0', '\u0BB1', '\u0BB2', '\u0BB3', '\u0BB4',
+            '\u0BB5', '\u0BB6', '\u0BB7', '\u0BB8', '\u0BB9', '\u0BBE',
+            '\u0BBF', '\u0BC0', '\u0BC1', '\u0BC2', '\u0BC6', '\u0BC7',
+            '\u0BC8', '\u0BCA', '\u0BCB', '\u0BCC'
+        };
+
+    /** CJK subset; 12 letters, UNICODE U4E00 */
+    public static char[] CJKSUBSET = {
+            '\u4E00', '\u4E01', '\u4E02', '\u4E03', '\u4E04', '\u4E05',
+            '\u4E06', '\u4E07', '\u4E08', '\u4E09', '\u4E0A', '\u4E0B'
+        };
+
+    /**
+     * Get a modern latin lowercase alphabet.
+     */
+    public static CharAlphabet modernLatinLowercase() {
+        return new CharAlphabet("Modern latin lowercase",
+                                CharAlphabet.MODERNLATINLOWER);
+    }
+
+    /**
+     * Get a CJK subset alphabet.
+     */
+    public static CharAlphabet cjkSubset() {
+        return new CharAlphabet("CJK subset",
+                                CharAlphabet.CJKSUBSET);
+    }
+
+    /** Name of the alphabet. */
+    private final String name;
+    /** Characters in the alphabet. */
+    private final char[] chars;
+    /** Number of characters in the alphabet. */
+    private final int charCount;
+    /** Current offset into the alphabet/character array. */
+    private int off = 0;
+    
+    /**
+     * Create an alphabet with the given name and characters.
+     *
+     * @param name name of the alphabet
+     * @param chars characters in the alphabet.
+     */
+    private CharAlphabet(String name, char[] chars) {
+        this.name = name;
+        this.chars = chars;
+        this.charCount = chars.length;
+    }
+
+    /**
+     * Return the name of the alphabet.
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Return the number of characters in the alphabet.
+     */
+    public int charCount() {
+        return this.charCount;
+    }
+
+    /**
+     * Return the next char as an <code>integer</code>.
+     *
+     * @return the next character in the alphabet as an <code>integer</code>
+     */
+    public int nextCharAsInt() {
+        if (off >= charCount) {
+            off = 0;
+        }
+        return (int)chars[off++];
+    }
+
+    /**
+     * Return the next char.
+     *
+     * @return the next character in the alphabet
+     */
+    public char nextChar() {
+        if (off >= charCount) {
+            off = 0;
+        }
+        return chars[off++];
+    }
+
+    /**
+     * Compute the next character to read after reading the specified number
+     * of characters. 
+     *
+     * Besides from returning the index, the internal state of
+     * the alphabet is updated.
+     *
+     * @param charsRead the number of characters read
+     * @return the index of the next character
+     */
+    public int nextCharToRead(int charsRead) {
+        off = (off + (charsRead % charCount)) % charCount;
+        return off;
+    }
+
+    /**
+     * Reset the alphabet, the next character returned will be the first
+     * character in the alphabet.
+     */
+    public void reset() {
+        off = 0;
+    }
+} // Enc class CharAlphabet

Propchange: db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/CharAlphabet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java?rev=437146&view=auto
==============================================================================
--- db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java (added)
+++ db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java Sat Aug 26 04:39:20 2006
@@ -0,0 +1,249 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetReader
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.util.streams;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A stream returning characters by looping over an alphabet.
+ */
+public class LoopingAlphabetReader
+    extends Reader {
+
+    /**
+     * Maximum size of buffer.
+     * Balance between size and memory usage.
+     */
+    private static final int MAX_BUF_SIZE = 32*1024;
+    /** The character used for blanks (SPACE). */
+    private static final int SPACE = ' ';
+
+    /** Number of characters in the reader. */
+    private final long length;
+    /** Number of blanks at the end of stream. */
+    private final int trailingBlanks;
+    /** Remaining non-blank characters. */
+    private long remainingNonBlanks;
+    /** Remaining blanks. */
+    private long remainingBlanks;
+    /** 
+     * Internal buffer of characters. 
+     * Used by the read-methods with a char[] argument. 
+     */
+    private char[] buffer = new char[0];
+    /** The alphabet to draw letters from. */
+    private final CharAlphabet alphabet;
+    /** Tell if the reader is closed or not. */
+    private boolean closed = false;
+
+    /**
+     * Create a looping modern latin alphabet reader of the specified length.
+     *
+     * @param length the number of characters
+     */
+    public LoopingAlphabetReader(long length) {
+        this(length, 0);
+    }
+
+    /**
+     * Create a looping modern latin alphabet of the specified length, with
+     * the specified number of trailing blanks.
+     *
+     * The number of non-blank characters is
+     * <code>length - trailingBlanks</code>.
+     *
+     * @param length total number of characters
+     * @param trailingBlanks number of blank characters at the end
+     */
+    public LoopingAlphabetReader(long length, int trailingBlanks) {
+        this.length = length;
+        this.trailingBlanks = trailingBlanks;
+        this.remainingNonBlanks = length - trailingBlanks;
+        this.remainingBlanks = trailingBlanks;
+        this.alphabet = CharAlphabet.modernLatinLowercase();
+        fillBuffer(alphabet.charCount());
+    }
+
+    /**
+     * Create a looping alphabet of the specified type and length.
+     *
+     * @param length the number of chars in the reader
+     * @param alphabet the alphabet to loop over
+     */
+    public LoopingAlphabetReader(long length, CharAlphabet alphabet) {
+        this(length, alphabet, 0);
+    }
+
+    /**
+     * Create a looping alphabet of the specified type and length, with
+     * the specified number of trailing blanks.
+     *
+     * The number of non-blank characters is
+     * <code>length - trailingBlanks</code>.
+     *
+     * @param length total number of characters
+     * @param alphabet the alphabet to draw characters from
+     * @param trailingBlanks number of blank characters at the end
+     */
+    public LoopingAlphabetReader(long length,
+                                 CharAlphabet alphabet,
+                                 int trailingBlanks) {
+        this.length = length;
+        this.trailingBlanks = trailingBlanks;
+        this.remainingNonBlanks = length - trailingBlanks;
+        this.remainingBlanks = trailingBlanks;
+        this.alphabet = alphabet;
+        fillBuffer(alphabet.charCount());
+    }
+
+    public int read()
+            throws IOException {
+        ensureOpen();
+        if (remainingBlanks <= 0 && remainingNonBlanks <= 0) {
+            return -1;
+        }
+        if (remainingNonBlanks <= 0) {
+            remainingBlanks--;
+            return SPACE;
+        }
+        remainingNonBlanks--;
+        return alphabet.nextCharAsInt();
+    }
+
+    public int read(char[] buf, int off, int length)
+            throws IOException {
+        ensureOpen();
+        if (remainingBlanks <= 0 && remainingNonBlanks <= 0) {
+            return -1;
+        }
+        // We can only read as many chars as there are in the stream.
+        int nonBlankLength = Math.min((int)remainingNonBlanks, length);
+        fillBuffer(nonBlankLength);
+        int read = 0;
+        // Find position of next char in the buffer.
+        int cOff = alphabet.nextCharToRead(0);
+        if (nonBlankLength <= (buffer.length - cOff)) {
+            System.arraycopy(buffer, cOff, buf, off, nonBlankLength);
+            remainingNonBlanks -= nonBlankLength;
+            read = nonBlankLength;
+            alphabet.nextCharToRead(nonBlankLength);
+        } else {
+            // Must read several times from the buffer.
+            int toRead = 0;
+            while (remainingNonBlanks > 0 && read < nonBlankLength) {
+                cOff = alphabet.nextCharToRead(toRead);
+                toRead = Math.min(buffer.length - cOff, nonBlankLength - read);
+                System.arraycopy(buffer, cOff, buf, off + read, toRead);
+                remainingNonBlanks -= toRead;
+                read += toRead;
+            }
+            cOff = alphabet.nextCharToRead(toRead);
+        }
+        if (read < length && remainingBlanks > 0) {
+            read += fillBlanks(buf, off + read, length - read);
+        }
+        return read;
+    }
+
+    /**
+     * Reset the stream.
+     */
+    public void reset()
+            throws IOException {
+        ensureOpen();
+        remainingNonBlanks = length - trailingBlanks;
+        remainingBlanks = trailingBlanks;
+        alphabet.reset();
+    }
+
+    /**
+     * Return remaining characters in the stream.
+     */
+    public int available() {
+        return (int)(remainingNonBlanks + remainingBlanks);
+    }
+
+    /**
+     * Close the reader.
+     */
+    public void close() {
+        this.closed = true;
+    }
+
+    /**
+     * Fill internal buffer of character sequence.
+     *
+     * @param bufSize the wanted size, might be ignored if too big
+     */
+    private void fillBuffer(int bufSize) {
+        if (bufSize > MAX_BUF_SIZE) {
+            bufSize = MAX_BUF_SIZE;
+        }
+        if (bufSize <= buffer.length) {
+            return;
+        }
+        int curOff = alphabet.nextCharToRead(0);
+        // First letter in buffer is always the first letter in the alphabet.
+        alphabet.reset();
+        buffer = new char[bufSize];
+        for (int i=0; i < bufSize; i++) {
+            buffer[i] = alphabet.nextChar();
+        }
+        // Must reset internal state of the alphabet, as we have not yet
+        // delivered any bytes.
+        alphabet.reset();
+        alphabet.nextCharToRead(curOff);
+    }
+
+    /**
+     * Fill array with blanks (SPACE).
+     *
+     * @param buf array to fill
+     * @param off starting offset
+     * @param length maximum number of blanks to fill in
+     */
+    private int fillBlanks(char[] buf, int off, int length) {
+        int i=0;
+        for (; i < length; i++) {
+            if (remainingBlanks > 0) {
+                buf[off+i] = SPACE;
+                remainingBlanks--;
+            } else {
+                break;
+            }
+        }
+        return i;
+    }
+
+    /**
+     * Ensure reader is open.
+     *
+     * @throws IOException if reader is closed
+     */
+    private final void ensureOpen()
+            throws IOException {
+        if (closed) {
+            throw new IOException("Reader closed");
+        }
+    }
+} // End class LoopingAlphabetReader

Propchange: db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetStream.java?rev=437146&view=auto
==============================================================================
--- db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetStream.java (added)
+++ db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetStream.java Sat Aug 26 04:39:20 2006
@@ -0,0 +1,187 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetStream
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.util.streams;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * A stream returning a cycle of the 26 lowercase letters of the modern Latin
+ * alphabet.
+ */
+public class LoopingAlphabetStream
+    extends InputStream {
+
+    /**
+     * Maximum size of buffer.
+     * Balance between size and memory usage.
+     */
+    private static final int MAX_BUF_SIZE = 32*1024;
+    private static final byte SPACE = (byte)' ';
+
+    /** Length of the stream. */
+    private final long length;
+    private final int trailingBlanks; 
+    /** Remaining bytes in the stream. */
+    private long remainingBlanks;
+    private long remainingNonBlanks;
+    private byte[] buffer = new byte[0];
+    private final ByteAlphabet alphabet;
+
+    /**
+     * Create a looping modern latin alphabet stream of the specified length.
+     *
+     * @param length the number of characters (and also the number of bytes)
+     */
+    public LoopingAlphabetStream(long length) {
+        this(length, 0);
+    }
+
+    public LoopingAlphabetStream(long length, int trailingBlanks) {
+        this.length = length;
+        this.trailingBlanks = trailingBlanks;
+        this.remainingNonBlanks = length - trailingBlanks;
+        this.remainingBlanks = trailingBlanks;
+        this.alphabet = ByteAlphabet.modernLatinLowercase();
+        fillBuffer(alphabet.byteCount());
+    }
+
+    /**
+     * Create a looping alphabet of the specified type and length.
+     *
+     * @param length the number of bytes in the stream
+     * @param alphabet the alphabet to loop over
+     */
+    public LoopingAlphabetStream(long length, ByteAlphabet alphabet) {
+        this(length, alphabet, 0);
+    }
+
+    public LoopingAlphabetStream(long length,
+                                 ByteAlphabet alphabet,
+                                 int trailingBlanks) {
+        this.length = length;
+        this.trailingBlanks = trailingBlanks;
+        this.remainingNonBlanks = length - trailingBlanks;
+        this.remainingBlanks = trailingBlanks;
+        this.alphabet = alphabet;
+        fillBuffer(alphabet.byteCount());
+    }
+
+    public int read() {
+        if (remainingBlanks <= 0 && remainingNonBlanks <= 0) {
+            return -1;
+        }
+        if (remainingNonBlanks <= 0) {
+            remainingBlanks--;
+            return SPACE;
+        }
+        remainingNonBlanks--;
+        return alphabet.nextByte();
+    }
+
+    public int read(byte[] buf, int off, int length) {
+        if (remainingBlanks <= 0 && remainingNonBlanks <= 0) {
+            return -1;
+        }
+        // We can only read as many bytes as there are in the stream.
+        int nonBlankLength = Math.min((int)remainingNonBlanks, length);
+        fillBuffer(nonBlankLength);
+        int read = 0;
+        // Find position of next letter in the buffer.
+        int bOff = alphabet.nextByteToRead(0);
+        if (nonBlankLength <= (buffer.length - bOff)) {
+            System.arraycopy(buffer, bOff, buf, off, nonBlankLength);
+            remainingNonBlanks -= nonBlankLength;
+            read = nonBlankLength;
+            alphabet.nextByteToRead(nonBlankLength);
+        } else {
+            // Must read several times from the buffer.
+            int toRead = 0;
+            while (remainingNonBlanks > 0 && read < nonBlankLength) {
+                bOff = alphabet.nextByteToRead(toRead);
+                toRead = Math.min(buffer.length - bOff, nonBlankLength - read);
+                System.arraycopy(buffer, bOff, buf, off + read, toRead);
+                remainingNonBlanks -= toRead;
+                read += toRead;
+            }
+            bOff = alphabet.nextByteToRead(toRead);
+        }
+        if (read < length && remainingBlanks > 0) {
+            read += fillBlanks(buf, off + read, length - read);
+        }
+        return read;
+    }
+
+    /**
+     * Reset the stream.
+     */
+    public void reset() {
+        remainingNonBlanks = length - trailingBlanks;
+        remainingBlanks = trailingBlanks;
+        alphabet.reset();
+    }
+
+    /**
+     * Return remaining bytes in the stream.
+     */
+    public int available() {
+        return (int)(remainingNonBlanks + remainingBlanks);
+    }
+
+    /**
+     * Fill internal buffer of bytes (from character sequence).
+     *
+     * @param bufSize the wanted size, might be ignored if too big
+     */
+    private void fillBuffer(int bufSize) {
+        if (bufSize > MAX_BUF_SIZE) {
+            bufSize = MAX_BUF_SIZE;
+        }
+        if (bufSize <= buffer.length) {
+            return;
+        }
+        int curOff = alphabet.nextByteToRead(0);
+        // First letter in buffer is always the first letter in the alphabet.
+        alphabet.reset();
+        buffer = new byte[bufSize];
+        for (int i=0; i < bufSize; i++) {
+            buffer[i] = alphabet.nextByte();
+        }
+        // Must reset internal state of the alphabet, as we have not yet
+        // delivered any bytes.
+        alphabet.reset();
+        alphabet.nextByteToRead(curOff);
+    }
+
+    private int fillBlanks(byte[] buf, int off, int length) {
+        int i=0;
+        for (; i < length; i++) {
+            if (remainingBlanks > 0) {
+                buf[off+i] = SPACE;
+                remainingBlanks--;
+            } else {
+                break;
+            }
+        }
+        return i;
+    }
+} // End class LoopingAlphabetStream

Propchange: db/derby/code/branches/10.2/java/testing/org/apache/derbyTesting/functionTests/util/streams/LoopingAlphabetStream.java
------------------------------------------------------------------------------
    svn:eol-style = native