2115N/A/*
2362N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2115N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2115N/A *
2115N/A * This code is free software; you can redistribute it and/or modify it
2115N/A * under the terms of the GNU General Public License version 2 only, as
2115N/A * published by the Free Software Foundation.
2115N/A *
2115N/A * This code is distributed in the hope that it will be useful, but WITHOUT
2115N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2115N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2115N/A * version 2 for more details (a copy is included in the LICENSE file that
2115N/A * accompanied this code).
2115N/A *
2115N/A * You should have received a copy of the GNU General Public License version
2115N/A * 2 along with this work; if not, write to the Free Software Foundation,
2115N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2115N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
2115N/A */
2115N/A
2115N/A/* @test
2115N/A * @summary Stochastic test of charset-based streams
2115N/A */
2115N/A
2115N/Aimport java.io.*;
2115N/Aimport java.util.*;
2115N/Aimport java.nio.*;
2115N/Aimport java.nio.channels.*;
2115N/Aimport java.nio.charset.*;
2115N/A
2115N/A
2115N/Apublic class BashStreams {
2115N/A
2115N/A static final PrintStream log = System.err;
2115N/A
2115N/A
2115N/A static class CharacterGenerator {
2115N/A
2115N/A private final Random rand;
2115N/A private final int max;
2115N/A private final int limit;
2115N/A private int count = 0;
2115N/A
2115N/A CharacterGenerator(long seed, String csn, int limit) {
2115N/A rand = new Random(seed);
2562N/A this.max = Character.MAX_CODE_POINT + 1;
2115N/A this.limit = limit;
2115N/A }
2115N/A
2115N/A private char[] saved = new char[10];
2115N/A private int savedCount = 0;
2115N/A
2115N/A void push(char c) {
2115N/A saved[savedCount++] = c;
2115N/A count--;
2115N/A }
2115N/A
2115N/A int count() {
2115N/A return count;
2115N/A }
2115N/A
2115N/A boolean hasNext() {
2115N/A return count < limit;
2115N/A }
2115N/A
2115N/A char next() {
2115N/A if (count >= limit)
2115N/A throw new RuntimeException("EOF");
2115N/A if (savedCount > 0) {
2115N/A savedCount--;
2115N/A count++;
2115N/A return saved[savedCount];
2115N/A }
2115N/A int c;
2115N/A for (;;) {
2115N/A c = rand.nextInt(max);
2562N/A if ((Character.isBmpCodePoint(c)
2562N/A && (Character.isSurrogate((char) c)
2562N/A || (c == 0xfffe) || (c == 0xffff))))
2115N/A continue;
2562N/A if (Character.isSupplementaryCodePoint(c)
2562N/A && (count == limit - 1))
2115N/A continue;
2115N/A break;
2115N/A }
2115N/A count++;
2562N/A if (Character.isSupplementaryCodePoint(c)) {
2115N/A count++;
2567N/A push(Character.lowSurrogate(c));
2567N/A return Character.highSurrogate(c);
2115N/A }
2115N/A return (char)c;
2115N/A }
2115N/A
2115N/A }
2115N/A
2115N/A
2115N/A static void mismatch(String csn, int count, char c, char d) {
2115N/A throw new RuntimeException(csn + ": Mismatch at count "
2115N/A + count
2115N/A + ": " + Integer.toHexString(c)
2115N/A + " != "
2115N/A + Integer.toHexString(d));
2115N/A }
2115N/A
2115N/A static void mismatchedEOF(String csn, int count, int cgCount) {
2115N/A throw new RuntimeException(csn + ": Mismatched EOFs: "
2115N/A + count
2115N/A + " != "
2115N/A + cgCount);
2115N/A }
2115N/A
2115N/A
2115N/A static class Sink // One abomination...
2115N/A extends OutputStream
2115N/A implements WritableByteChannel
2115N/A {
2115N/A
2115N/A private final String csn;
2115N/A private final CharacterGenerator cg;
2115N/A private int count = 0;
2115N/A
2115N/A Sink(String csn, long seed) {
2115N/A this.csn = csn;
2115N/A this.cg = new CharacterGenerator(seed, csn, Integer.MAX_VALUE);
2115N/A }
2115N/A
2115N/A public void write(int b) throws IOException {
2115N/A write (new byte[] { (byte)b }, 0, 1);
2115N/A }
2115N/A
2115N/A private int check(byte[] ba, int off, int len) throws IOException {
2115N/A String s = new String(ba, off, len, csn);
2115N/A int n = s.length();
2115N/A for (int i = 0; i < n; i++) {
2115N/A char c = s.charAt(i);
2115N/A char d = cg.next();
2115N/A if (c != d) {
2115N/A if (c == '?') {
2562N/A if (Character.isHighSurrogate(d))
2115N/A cg.next();
2115N/A continue;
2115N/A }
2115N/A mismatch(csn, count + i, c, d);
2115N/A }
2115N/A }
2115N/A count += n;
2115N/A return len;
2115N/A }
2115N/A
2115N/A public void write(byte[] ba, int off, int len) throws IOException {
2115N/A check(ba, off, len);
2115N/A }
2115N/A
2115N/A public int write(ByteBuffer bb) throws IOException {
2115N/A int n = check(bb.array(),
2115N/A bb.arrayOffset() + bb.position(),
2115N/A bb.remaining());
2115N/A bb.position(bb.position() + n);
2115N/A return n;
2115N/A }
2115N/A
2115N/A public void close() {
2115N/A count = -1;
2115N/A }
2115N/A
2115N/A public boolean isOpen() {
2115N/A return count >= 0;
2115N/A }
2115N/A
2115N/A }
2115N/A
2115N/A static void testWrite(String csn, int limit, long seed, Writer w)
2115N/A throws IOException
2115N/A {
2115N/A Random rand = new Random(seed);
2115N/A CharacterGenerator cg = new CharacterGenerator(seed, csn,
2115N/A Integer.MAX_VALUE);
2115N/A int count = 0;
2115N/A char[] ca = new char[16384];
2115N/A
2115N/A int n = 0;
2115N/A while (count < limit) {
2115N/A n = rand.nextInt(ca.length);
2115N/A for (int i = 0; i < n; i++)
2115N/A ca[i] = cg.next();
2115N/A w.write(ca, 0, n);
2115N/A count += n;
2115N/A }
2562N/A if (Character.isHighSurrogate(ca[n - 1]))
2115N/A w.write(cg.next());
2115N/A w.close();
2115N/A }
2115N/A
2115N/A static void testStreamWrite(String csn, int limit, long seed)
2115N/A throws IOException
2115N/A {
2115N/A log.println(" write stream");
2115N/A testWrite(csn, limit, seed,
2115N/A new OutputStreamWriter(new Sink(csn, seed), csn));
2115N/A }
2115N/A
2115N/A static void testChannelWrite(String csn, int limit, long seed)
2115N/A throws IOException
2115N/A {
2115N/A log.println(" write channel");
2115N/A testWrite(csn, limit, seed,
2115N/A Channels.newWriter(new Sink(csn, seed),
2115N/A Charset.forName(csn)
2115N/A .newEncoder()
2115N/A .onMalformedInput(CodingErrorAction.REPLACE)
2115N/A .onUnmappableCharacter(CodingErrorAction.REPLACE),
2115N/A 8192));
2115N/A }
2115N/A
2115N/A
2115N/A static class Source // ... and another
2115N/A extends InputStream
2115N/A implements ReadableByteChannel
2115N/A {
2115N/A
2115N/A private final String csn;
2115N/A private final CharsetEncoder enc;
2115N/A private final CharacterGenerator cg;
2115N/A private int count = 0;
2115N/A
2115N/A Source(String csn, long seed, int limit) {
2115N/A this.csn = csn.startsWith("\1") ? csn.substring(1) : csn;
2115N/A this.enc = Charset.forName(this.csn).newEncoder()
2115N/A .onMalformedInput(CodingErrorAction.REPLACE)
2115N/A .onUnmappableCharacter(CodingErrorAction.REPLACE);
2115N/A this.cg = new CharacterGenerator(seed, csn, limit);
2115N/A }
2115N/A
2115N/A public int read() throws IOException {
2115N/A byte[] b = new byte[1];
2115N/A read(b);
2115N/A return b[0];
2115N/A }
2115N/A
2115N/A private CharBuffer cb = CharBuffer.allocate(8192);
2115N/A private ByteBuffer bb = null;
2115N/A
2115N/A public int read(byte[] ba, int off, int len) throws IOException {
2115N/A if (!cg.hasNext())
2115N/A return -1;
2115N/A int end = off + len;
2115N/A int i = off;
2115N/A while (i < end) {
2115N/A if ((bb == null) || !bb.hasRemaining()) {
2115N/A cb.clear();
2115N/A while (cb.hasRemaining()) {
2115N/A if (!cg.hasNext())
2115N/A break;
2115N/A char c = cg.next();
2562N/A if (Character.isHighSurrogate(c)
2562N/A && cb.remaining() == 1) {
2115N/A cg.push(c);
2115N/A break;
2115N/A }
2115N/A cb.put(c);
2115N/A }
2115N/A cb.flip();
2115N/A if (!cb.hasRemaining())
2115N/A break;
2115N/A bb = enc.encode(cb);
2115N/A }
2115N/A int d = Math.min(bb.remaining(), end - i);
2115N/A bb.get(ba, i, d);
2115N/A i += d;
2115N/A }
2115N/A return i - off;
2115N/A }
2115N/A
2115N/A public int read(ByteBuffer bb) throws IOException {
2115N/A int n = read(bb.array(),
2115N/A bb.arrayOffset() + bb.position(),
2115N/A bb.remaining());
2115N/A if (n >= 0)
2115N/A bb.position(bb.position() + n);
2115N/A return n;
2115N/A }
2115N/A
2115N/A public void close() {
2115N/A count = -1;
2115N/A }
2115N/A
2115N/A public boolean isOpen() {
2115N/A return count != -1;
2115N/A }
2115N/A
2115N/A }
2115N/A
2115N/A static void testRead(String csn, int limit, long seed, int max,
2115N/A Reader rd)
2115N/A throws IOException
2115N/A {
2115N/A Random rand = new Random(seed);
2115N/A CharacterGenerator cg = new CharacterGenerator(seed, csn, limit);
2115N/A int count = 0;
2115N/A char[] ca = new char[16384];
2115N/A
2115N/A int n = 0;
2115N/A while (count < limit) {
2115N/A int rn = rand.nextInt(ca.length);
2115N/A n = rd.read(ca, 0, rn);
2115N/A if (n < 0)
2115N/A break;
2115N/A for (int i = 0; i < n; i++) {
2115N/A char c = ca[i];
2115N/A if (!cg.hasNext())
2115N/A mismatchedEOF(csn, count + i, cg.count());
2115N/A char d = cg.next();
2115N/A if (c == '?') {
2562N/A if (Character.isHighSurrogate(d)) {
2115N/A cg.next();
2115N/A continue;
2115N/A }
2115N/A if (d > max)
2115N/A continue;
2115N/A }
2115N/A if (c != d)
2115N/A mismatch(csn, count + i, c, d);
2115N/A }
2115N/A count += n;
2115N/A }
2115N/A if (cg.hasNext())
2115N/A mismatchedEOF(csn, count, cg.count());
2115N/A rd.close();
2115N/A }
2115N/A
2115N/A static void testStreamRead(String csn, int limit, long seed, int max)
2115N/A throws IOException
2115N/A {
2115N/A log.println(" read stream");
2115N/A testRead(csn, limit, seed, max,
2115N/A new InputStreamReader(new Source(csn, seed, limit), csn));
2115N/A }
2115N/A
2115N/A static void testChannelRead(String csn, int limit, long seed, int max)
2115N/A throws IOException
2115N/A {
2115N/A log.println(" read channel");
2115N/A testRead(csn, limit, seed, max,
2115N/A Channels.newReader(new Source(csn, seed, limit), csn));
2115N/A }
2115N/A
2115N/A
2115N/A static final int LIMIT = 1 << 21;
2115N/A
2115N/A static void test(String csn, int limit, long seed, int max)
2115N/A throws Exception
2115N/A {
2115N/A log.println();
2115N/A log.println(csn);
2115N/A
2115N/A testStreamWrite(csn, limit, seed);
2115N/A testChannelWrite(csn, limit, seed);
2115N/A testStreamRead(csn, limit, seed, max);
2115N/A testChannelRead(csn, limit, seed, max);
2115N/A }
2115N/A
2115N/A public static void main(String[] args) throws Exception {
2115N/A
2115N/A if (System.getProperty("os.arch").equals("ia64")) {
2115N/A // This test requires 54 minutes on an Itanium-1 processor
2115N/A return;
2115N/A }
2115N/A
2115N/A int ai = 0, an = args.length;
2115N/A
2115N/A int limit;
2115N/A if (ai < an)
2115N/A limit = 1 << Integer.parseInt(args[ai++]);
2115N/A else
2115N/A limit = LIMIT;
2115N/A log.println("limit = " + limit);
2115N/A
2115N/A long seed;
2115N/A if (ai < an)
2115N/A seed = Long.parseLong(args[ai++]);
2115N/A else
2115N/A seed = System.currentTimeMillis();
2115N/A log.println("seed = " + seed);
2115N/A
2115N/A test("UTF-8", limit, seed, Integer.MAX_VALUE);
2115N/A test("US-ASCII", limit, seed, 0x7f);
2115N/A test("ISO-8859-1", limit, seed, 0xff);
2115N/A
2115N/A }
2115N/A
2115N/A}