Added emulation for FilterInputStream and FilterOutputStream
Added emulation for the following Java IO classes based
on the Android libcode implementation:
- FilterInputStream
- FilterOutputStream
Added corresponding unit tests.
Change-Id: I563d9fa3d4397457dff63ca8974fd93cf2541fe0
Review-Link: https://gwt-review.googlesource.com/#/c/13450/
diff --git a/user/super/com/google/gwt/emul/java/io/ByteArrayInputStream.java b/user/super/com/google/gwt/emul/java/io/ByteArrayInputStream.java
index 4093b38..6bdebc0 100644
--- a/user/super/com/google/gwt/emul/java/io/ByteArrayInputStream.java
+++ b/user/super/com/google/gwt/emul/java/io/ByteArrayInputStream.java
@@ -85,7 +85,7 @@
* @return {@code count - pos}
*/
@Override
- public synchronized int available() {
+ public int available() {
return count - pos;
}
@@ -111,7 +111,7 @@
* @see #reset()
*/
@Override
- public synchronized void mark(int readlimit) {
+ public void mark(int readlimit) {
mark = pos;
}
@@ -137,11 +137,11 @@
* @return the byte read or -1 if the end of this stream has been reached.
*/
@Override
- public synchronized int read() {
+ public int read() {
return pos < count ? buf[pos++] & 0xFF : -1;
}
- @Override public synchronized int read(byte[] buffer, int byteOffset, int byteCount) {
+ @Override public int read(byte[] buffer, int byteOffset, int byteCount) {
IOUtils.checkOffsetAndCount(buffer, byteOffset, byteCount);
// Are there any bytes available?
@@ -166,7 +166,7 @@
* @see #mark(int)
*/
@Override
- public synchronized void reset() {
+ public void reset() {
pos = mark;
}
@@ -179,7 +179,7 @@
* @return the number of bytes actually skipped.
*/
@Override
- public synchronized long skip(long byteCount) {
+ public long skip(long byteCount) {
if (byteCount <= 0) {
return 0;
}
diff --git a/user/super/com/google/gwt/emul/java/io/FilterInputStream.java b/user/super/com/google/gwt/emul/java/io/FilterInputStream.java
new file mode 100644
index 0000000..172a67c
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/io/FilterInputStream.java
@@ -0,0 +1,156 @@
+// CHECKSTYLE_OFF: Copyrighted to the Android Open Source Project.
+/*
+ * 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.
+ */
+// CHECKSTYLE_ON
+
+package java.io;
+
+/**
+ * Wraps an existing {@link InputStream} and performs some transformation on
+ * the input data while it is being read. Transformations can be anything from a
+ * simple byte-wise filtering input data to an on-the-fly compression or
+ * decompression of the underlying stream. Input streams that wrap another input
+ * stream and provide some additional functionality on top of it usually inherit
+ * from this class.
+ *
+ * @see FilterOutputStream
+ */
+public class FilterInputStream extends InputStream {
+
+ /**
+ * The source input stream that is filtered.
+ */
+ protected volatile InputStream in;
+
+ /**
+ * Constructs a new {@code FilterInputStream} with the specified input
+ * stream as source.
+ *
+ * <p><strong>Warning:</strong> passing a null source creates an invalid
+ * {@code FilterInputStream}, that fails on every method that is not
+ * overridden. Subclasses should check for null in their constructors.
+ *
+ * @param in the input stream to filter reads on.
+ */
+ protected FilterInputStream(InputStream in) {
+ this.in = in;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return in.available();
+ }
+
+ /**
+ * Closes this stream. This implementation closes the filtered stream.
+ *
+ * @throws IOException
+ * if an error occurs while closing this stream.
+ */
+ @Override
+ public void close() throws IOException {
+ in.close();
+ }
+
+ /**
+ * Sets a mark position in this stream. The parameter {@code readlimit}
+ * indicates how many bytes can be read before the mark is invalidated.
+ * Sending {@code reset()} will reposition this stream back to the marked
+ * position, provided that {@code readlimit} has not been surpassed.
+ * <p>
+ * This implementation sets a mark in the filtered stream.
+ *
+ * @param readlimit
+ * the number of bytes that can be read from this stream before
+ * the mark is invalidated.
+ * @see #markSupported()
+ * @see #reset()
+ */
+ @Override
+ public void mark(int readlimit) {
+ in.mark(readlimit);
+ }
+
+ /**
+ * Indicates whether this stream supports {@code mark()} and {@code reset()}.
+ * This implementation returns whether or not the filtered stream supports
+ * marking.
+ *
+ * @return {@code true} if {@code mark()} and {@code reset()} are supported,
+ * {@code false} otherwise.
+ * @see #mark(int)
+ * @see #reset()
+ * @see #skip(long)
+ */
+ @Override
+ public boolean markSupported() {
+ return in.markSupported();
+ }
+
+ /**
+ * Reads a single byte from the filtered stream and returns it as an integer
+ * in the range from 0 to 255. Returns -1 if the end of this stream has been
+ * reached.
+ *
+ * @return the byte read or -1 if the end of the filtered stream has been
+ * reached.
+ * @throws IOException
+ * if the stream is closed or another IOException occurs.
+ */
+ @Override
+ public int read() throws IOException {
+ return in.read();
+ }
+
+ @Override
+ public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
+ return in.read(buffer, byteOffset, byteCount);
+ }
+
+ /**
+ * Resets this stream to the last marked location. This implementation
+ * resets the target stream.
+ *
+ * @throws IOException
+ * if this stream is already closed, no mark has been set or the
+ * mark is no longer valid because more than {@code readlimit}
+ * bytes have been read since setting the mark.
+ * @see #mark(int)
+ * @see #markSupported()
+ */
+ @Override
+ public void reset() throws IOException {
+ in.reset();
+ }
+
+ /**
+ * Skips {@code byteCount} bytes in this stream. Subsequent
+ * calls to {@code read} will not return these bytes unless {@code reset} is
+ * used. This implementation skips {@code byteCount} bytes in the
+ * filtered stream.
+ *
+ * @return the number of bytes actually skipped.
+ * @throws IOException
+ * if this stream is closed or another IOException occurs.
+ * @see #mark(int)
+ * @see #reset()
+ */
+ @Override
+ public long skip(long byteCount) throws IOException {
+ return in.skip(byteCount);
+ }
+}
diff --git a/user/super/com/google/gwt/emul/java/io/FilterOutputStream.java b/user/super/com/google/gwt/emul/java/io/FilterOutputStream.java
index e185e60..86008c0 100644
--- a/user/super/com/google/gwt/emul/java/io/FilterOutputStream.java
+++ b/user/super/com/google/gwt/emul/java/io/FilterOutputStream.java
@@ -1,29 +1,130 @@
+// CHECKSTYLE_OFF: Copyrighted to the Android Open Source Project.
/*
- * Copyright 2006 Google Inc.
- *
- * Licensed 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.
+ * 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.
*/
+// CHECKSTYLE_ON
+
package java.io;
/**
- * @skip
+ * Wraps an existing {@link OutputStream} and performs some transformation on
+ * the output data while it is being written. Transformations can be anything
+ * from a simple byte-wise filtering output data to an on-the-fly compression or
+ * decompression of the underlying stream. Output streams that wrap another
+ * output stream and provide some additional functionality on top of it usually
+ * inherit from this class.
+ *
+ * @see FilterOutputStream
*/
public class FilterOutputStream extends OutputStream {
- public FilterOutputStream(OutputStream out) {
- }
+ /**
+ * The target output stream for this filter stream.
+ */
+ protected OutputStream out;
- @Override
- public void write(int oneByte) throws IOException {
- }
+ /**
+ * Constructs a new {@code FilterOutputStream} with {@code out} as its
+ * target stream.
+ *
+ * @param out
+ * the target stream that this stream writes to.
+ */
+ public FilterOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ /**
+ * Closes this stream. This implementation closes the target stream.
+ *
+ * @throws IOException
+ * if an error occurs attempting to close this stream.
+ */
+ @Override
+ public void close() throws IOException {
+ Throwable thrown = null;
+ try {
+ flush();
+ } catch (Throwable e) {
+ thrown = e;
+ }
+
+ try {
+ out.close();
+ } catch (Throwable e) {
+ if (thrown == null) {
+ thrown = e;
+ }
+ }
+
+ if (thrown != null) {
+ throw new IOException(thrown);
+ }
+ }
+
+ /**
+ * Ensures that all pending data is sent out to the target stream. This
+ * implementation flushes the target stream.
+ *
+ * @throws IOException
+ * if an error occurs attempting to flush this stream.
+ */
+ @Override
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Writes {@code count} bytes from the byte array {@code buffer} starting at
+ * {@code offset} to the target stream.
+ *
+ * @param buffer
+ * the buffer to write.
+ * @param offset
+ * the index of the first byte in {@code buffer} to write.
+ * @param length
+ * the number of bytes in {@code buffer} to write.
+ * @throws IndexOutOfBoundsException
+ * if {@code offset < 0} or {@code count < 0}, or if
+ * {@code offset + count} is bigger than the length of
+ * {@code buffer}.
+ * @throws IOException
+ * if an I/O error occurs while writing to this stream.
+ */
+ @Override
+ public void write(byte[] buffer, int offset, int length) throws IOException {
+ IOUtils.checkOffsetAndCount(buffer, offset, length);
+ for (int i = 0; i < length; i++) {
+ // Call write() instead of out.write() since subclasses could
+ // override the write() method.
+ write(buffer[offset + i]);
+ }
+ }
+
+ /**
+ * Writes one byte to the target stream. Only the low order byte of the
+ * integer {@code oneByte} is written.
+ *
+ * @param oneByte
+ * the byte to be written.
+ * @throws IOException
+ * if an I/O error occurs while writing to this stream.
+ */
+ @Override
+ public void write(int oneByte) throws IOException {
+ out.write(oneByte);
+ }
}
diff --git a/user/super/com/google/gwt/emul/java/io/InputStream.java b/user/super/com/google/gwt/emul/java/io/InputStream.java
index 6979c52..5d25c9e 100644
--- a/user/super/com/google/gwt/emul/java/io/InputStream.java
+++ b/user/super/com/google/gwt/emul/java/io/InputStream.java
@@ -215,7 +215,7 @@
* @throws IOException
* if this stream is closed or another IOException occurs.
*/
- public synchronized void reset() throws IOException {
+ public void reset() throws IOException {
throw new IOException();
}
diff --git a/user/test/com/google/gwt/emultest/EmulSuite.java b/user/test/com/google/gwt/emultest/EmulSuite.java
index 9a59baa..1e9e2f0 100644
--- a/user/test/com/google/gwt/emultest/EmulSuite.java
+++ b/user/test/com/google/gwt/emultest/EmulSuite.java
@@ -18,6 +18,8 @@
import com.google.gwt.emultest.java.internal.CoercionsTest;
import com.google.gwt.emultest.java.io.ByteArrayInputStreamTest;
import com.google.gwt.emultest.java.io.ByteArrayOutputStreamTest;
+import com.google.gwt.emultest.java.io.FilterInputStreamTest;
+import com.google.gwt.emultest.java.io.FilterOutputStreamTest;
import com.google.gwt.emultest.java.io.InputStreamTest;
import com.google.gwt.emultest.java.io.OutputStreamTest;
import com.google.gwt.emultest.java.lang.BooleanTest;
@@ -64,6 +66,8 @@
//-- java.io
suite.addTestSuite(ByteArrayInputStreamTest.class);
suite.addTestSuite(ByteArrayOutputStreamTest.class);
+ suite.addTestSuite(FilterInputStreamTest.class);
+ suite.addTestSuite(FilterOutputStreamTest.class);
suite.addTestSuite(InputStreamTest.class);
suite.addTestSuite(OutputStreamTest.class);
//-- java.lang
diff --git a/user/test/com/google/gwt/emultest/java/io/FilterInputStreamTest.java b/user/test/com/google/gwt/emultest/java/io/FilterInputStreamTest.java
new file mode 100644
index 0000000..a71cf81
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/io/FilterInputStreamTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed 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 com.google.gwt.emultest.java.io;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Unit test for the {@link java.io.FilterInputStream} emulated class.
+ */
+public class FilterInputStreamTest extends GWTTestCase {
+
+ /**
+ * Mock for {@link InputStream}.
+ */
+ private static class MockInputStream extends InputStream {
+ public static final int RETURNED_VALUE_FOR_AVAILABLE = 100;
+ public static final int RETURNED_VALUE_FOR_READ_BYTE = 150;
+ public static final int RETURNED_VALUE_FOR_READ_BYTES = 200;
+ public static final boolean RETURNED_VALUE_FOR_MARK_SUPPORTED = true;
+ public static final long RETURNED_VALUE_FOR_SKIP = 250;
+
+ // Flags for knowing whether or not the underlying stream methods have been called.
+ private boolean availableCalled;
+ private boolean closeCalled;
+ private boolean markCalled;
+ private boolean markSupportedCalled;
+ private boolean readByteCalled;
+ private boolean readBytesCalled;
+ private boolean resetCalled;
+ private boolean skipCalled;
+
+ // Input parameters to ensure the filter passes the right arguments to the stream.
+ private int requestedReadLimit;
+ private long requestedSkipBytes;
+ private byte[] requestedReadBuffer;
+ private int requestedReadOffset;
+ private int requestedReadLength;
+
+ public MockInputStream() {
+ availableCalled = false;
+ closeCalled = false;
+ markCalled = false;
+ markSupportedCalled = false;
+ readByteCalled = false;
+ readBytesCalled = false;
+ resetCalled = false;
+ skipCalled = false;
+
+ requestedReadLimit = 0;
+ requestedSkipBytes = 0L;
+ requestedReadBuffer = null;
+ requestedReadOffset = 0;
+ requestedReadLength = 0;
+ }
+
+ @Override
+ public int available() {
+ availableCalled = true;
+ return RETURNED_VALUE_FOR_AVAILABLE;
+ }
+
+ @Override
+ public void close() {
+ closeCalled = true;
+ }
+
+ @Override
+ public void mark(int readLimit) {
+ markCalled = true;
+ requestedReadLimit = readLimit;
+ }
+
+ @Override
+ public boolean markSupported() {
+ markSupportedCalled = true;
+ return RETURNED_VALUE_FOR_MARK_SUPPORTED;
+ }
+
+ @Override
+ public int read() {
+ readByteCalled = true;
+ return RETURNED_VALUE_FOR_READ_BYTE;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) {
+ readBytesCalled = true;
+ requestedReadBuffer = b;
+ requestedReadOffset = off;
+ requestedReadLength = len;
+ return RETURNED_VALUE_FOR_READ_BYTES;
+ }
+
+ @Override
+ public void reset() {
+ resetCalled = true;
+ }
+
+ @Override
+ public long skip(long n) {
+ skipCalled = true;
+ requestedSkipBytes = n;
+ return RETURNED_VALUE_FOR_SKIP;
+ }
+
+ public boolean getAvailableCalled() {
+ return availableCalled;
+ }
+
+ public boolean getCloseCalled() {
+ return closeCalled;
+ }
+
+ public boolean getMarkCalled() {
+ return markCalled;
+ }
+
+ public int getMarkReadLimit() {
+ return requestedReadLimit;
+ }
+
+ public boolean getMarkSupportedCalled() {
+ return markSupportedCalled;
+ }
+
+ public boolean getReadByteCalled() {
+ return readByteCalled;
+ }
+
+ public boolean getReadBytesCalled() {
+ return readBytesCalled;
+ }
+
+ public boolean getResetCalled() {
+ return resetCalled;
+ }
+
+ public boolean getSkipCalled() {
+ return skipCalled;
+ }
+
+ public int getRequestedReadLimit() {
+ return requestedReadLimit;
+ }
+
+ public long getRequestedSkipBytes() {
+ return requestedSkipBytes;
+ }
+
+ public byte[] getRequestedReadBuffer() {
+ return requestedReadBuffer;
+ }
+
+ public int getRequestedReadOffset() {
+ return requestedReadOffset;
+ }
+
+ public int getRequestedReadLength() {
+ return requestedReadLength;
+ }
+ }
+
+ /**
+ * The constructor of {@link java.io.FilterInputStream} is protected. This class provides a public
+ * constructor so that it can be instantiated.
+ */
+ private static class InstantiableFilterInputStream extends FilterInputStream {
+ public InstantiableFilterInputStream(InputStream inputStream) {
+ super(inputStream);
+ }
+ }
+
+ private FilterInputStream filter;
+
+ protected MockInputStream mockInputStream;
+
+ /**
+ * Sets module name so that javascript compiler can operate.
+ */
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.emultest.EmulSuite";
+ }
+
+ @Override
+ protected void gwtSetUp() throws Exception {
+ super.gwtSetUp();
+ mockInputStream = new MockInputStream();
+ filter = new InstantiableFilterInputStream(mockInputStream);
+ }
+
+ public void testAvailable() throws IOException {
+ int available = filter.available();
+ assertTrue(mockInputStream.getAvailableCalled());
+ assertEquals(available, MockInputStream.RETURNED_VALUE_FOR_AVAILABLE);
+ }
+
+ public void testClose() throws IOException {
+ filter.close();
+ assertTrue(mockInputStream.getCloseCalled());
+ }
+
+ public void testMark() {
+ int readLimit = 12;
+ filter.mark(readLimit);
+ assertTrue(mockInputStream.getMarkCalled());
+ assertEquals(readLimit, mockInputStream.getMarkReadLimit());
+ }
+
+ public void testMarkSupported() {
+ boolean markSupported = filter.markSupported();
+ assertTrue(mockInputStream.getMarkSupportedCalled());
+ assertEquals(markSupported, MockInputStream.RETURNED_VALUE_FOR_MARK_SUPPORTED);
+ }
+
+ public void testReadValue() throws IOException {
+ int value = filter.read();
+ assertTrue(mockInputStream.getReadByteCalled());
+ assertEquals(value, MockInputStream.RETURNED_VALUE_FOR_READ_BYTE);
+ }
+
+ public void testReadArray() throws IOException {
+ byte[] b = new byte[500];
+ int bytesRead = filter.read(b);
+ assertTrue(mockInputStream.getReadBytesCalled());
+ assertEquals(b, mockInputStream.getRequestedReadBuffer());
+ assertEquals(0, mockInputStream.getRequestedReadOffset());
+ assertEquals(b.length, mockInputStream.getRequestedReadLength());
+ assertEquals(bytesRead, MockInputStream.RETURNED_VALUE_FOR_READ_BYTES);
+ }
+
+ public void testReadArrayRange() throws IOException {
+ byte[] b = new byte[500];
+ int offset = 100;
+ int length = 300;
+ int bytesRead = filter.read(b, offset, length);
+ assertTrue(mockInputStream.getReadBytesCalled());
+ assertEquals(b, mockInputStream.getRequestedReadBuffer());
+ assertEquals(offset, mockInputStream.getRequestedReadOffset());
+ assertEquals(length, mockInputStream.getRequestedReadLength());
+ assertEquals(bytesRead, MockInputStream.RETURNED_VALUE_FOR_READ_BYTES);
+ }
+
+ public void testReset() throws IOException {
+ filter.reset();
+ assertTrue(mockInputStream.getResetCalled());
+ }
+
+ public void testSkip() throws IOException {
+ long bytesToSkip = MockInputStream.RETURNED_VALUE_FOR_SKIP * 3;
+ long skippedBytes = filter.skip(bytesToSkip);
+ assertTrue(mockInputStream.getSkipCalled());
+ assertEquals(bytesToSkip, mockInputStream.getRequestedSkipBytes());
+ assertEquals(skippedBytes, mockInputStream.RETURNED_VALUE_FOR_SKIP);
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java/io/FilterOutputStreamTest.java b/user/test/com/google/gwt/emultest/java/io/FilterOutputStreamTest.java
new file mode 100644
index 0000000..ff9c9bf
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/io/FilterOutputStreamTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed 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 com.google.gwt.emultest.java.io;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.LinkedList;
+
+/**
+ * Unit test class for the {@link java.io.FilterOutputStream} emulated class.
+ */
+public class FilterOutputStreamTest extends GWTTestCase {
+
+ private static final byte[] BYTES_TO_WRITE = {
+ (byte) 0x10, (byte) 0x20, (byte) 0x30, (byte) 0x40, (byte) 0x50, (byte) 0x60
+ };
+
+ /**
+ * Mock for {@link OutputStream}.
+ */
+ private static class MockOutputStream extends OutputStream {
+
+ // Flags for knowing whether or not the underlying stream methods have been called.
+ private boolean closeCalled;
+ private boolean flushCalled;
+ private boolean writeByteCalled;
+
+ /**
+ * Stores all the values written with {@code write(int b)}.
+ */
+ private LinkedList<Byte> writtenBytes;
+
+ private MockOutputStream() {
+ closeCalled = false;
+ flushCalled = false;
+ writeByteCalled = false;
+
+ writtenBytes = new LinkedList<>();
+ }
+
+ @Override
+ public void close() {
+ closeCalled = true;
+ }
+
+ @Override
+ public void flush() {
+ flushCalled = true;
+ }
+
+ @Override
+ public void write(int b) {
+ writeByteCalled = true;
+ writtenBytes.add((byte) b);
+ }
+
+ public boolean getCloseCalled() {
+ return closeCalled;
+ }
+
+ public boolean getFlushCalled() {
+ return flushCalled;
+ }
+
+ public boolean getWriteByteCalled() {
+ return writeByteCalled;
+ }
+
+ public int getLastRequestedByteToWrite() {
+ return (int) writtenBytes.get(writtenBytes.size() - 1);
+ }
+
+ public byte[] getWrittenValues() {
+ int i = 0;
+ byte[] result = new byte[writtenBytes.size()];
+ for (Byte b : writtenBytes) {
+ result[i++] = b.byteValue();
+ }
+ return result;
+ }
+ }
+
+ private FilterOutputStream filter;
+
+ private MockOutputStream mockOutputStream;
+
+ /**
+ * Sets module name so that javascript compiler can operate.
+ */
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.emultest.EmulSuite";
+ }
+
+ @Override
+ public void gwtSetUp() throws Exception {
+ super.gwtSetUp();
+ mockOutputStream = new MockOutputStream();
+ filter = new FilterOutputStream(mockOutputStream);
+ }
+
+ public void testClose() throws IOException {
+ filter.close();
+ assertTrue(mockOutputStream.getCloseCalled());
+ }
+
+ public void testFlush() throws IOException {
+ filter.flush();
+ assertTrue(mockOutputStream.getFlushCalled());
+ }
+
+ public void testWriteValue() throws IOException {
+ int value = 12;
+ filter.write(value);
+ assertTrue(mockOutputStream.getWriteByteCalled());
+ assertEquals(value, mockOutputStream.getLastRequestedByteToWrite());
+ }
+
+ public void testWriteArray() throws IOException {
+ filter.write(BYTES_TO_WRITE);
+ assertTrue(Arrays.equals(BYTES_TO_WRITE, mockOutputStream.getWrittenValues()));
+ }
+
+ public void testWriteArrayRange() throws IOException {
+ int offset = 1;
+ int length = 2;
+ byte[] expectedWrittenValues = new byte[length];
+ System.arraycopy(BYTES_TO_WRITE, offset, expectedWrittenValues, 0, length);
+ filter.write(BYTES_TO_WRITE, offset, length);
+ assertTrue(Arrays.equals(expectedWrittenValues, mockOutputStream.getWrittenValues()));
+ }
+}