### Question:
BrotliDecoder implements AsyncDecoder { @Override public void decode(ByteSource source, ByteSink sink) throws IOException { synchronized (handle.mutex) { if (handle.destroyed) { return; } DecoderJNI.Wrapper brotliNative = handle.brotliNative; if (brotliNative == null) { brotliNative = new DecoderJNI.Wrapper(INPUT_BUFFER_SIZE); handle.brotliNative = brotliNative; } outerLoop: while (true) { switch (brotliNative.getStatus()) { case OK: brotliNative.push(0); break; case NEEDS_MORE_INPUT: if (!source.hasRemaining()) { if (source.finalSource()) { throw new EOFException("unexpected end of brotli stream"); } break outerLoop; } ByteBuffer brotliIn = brotliNative.getInputBuffer(); source.pullBytes(brotliIn.clear()); brotliNative.push(brotliIn.position()); break; case NEEDS_MORE_OUTPUT: do { sink.pushBytes(brotliNative.pull()); } while (brotliNative.hasOutput()); break; case ERROR: throw new IOException("corrupt brotli stream"); case DONE: if (source.hasRemaining()) { throw new IOException("brotli stream finished prematurely"); } while (brotliNative.hasOutput()) { sink.pushBytes(brotliNative.pull()); } break outerLoop; } } } } BrotliDecoder(); @Override String encoding(); @Override void decode(ByteSource source, ByteSink sink); @Override void close();  }### Answer:
@Test void decodesGoodStream() throws IOException { byte[] goodStream = BASE64_DEC.decode(GOOD); for (var so : BuffSizeOption.values()) { byte[] decoded = Decode.decode(new BrotliDecoder(), goodStream, so); assertArrayEquals(brotli(goodStream), decoded); } }
@Test void throwsOnBadStream() { byte[] badStream = BASE64_DEC.decode(BAD); for (var so : BuffSizeOption.values()) { assertThrows(IOException.class, () -> Decode.decode(new BrotliDecoder(), badStream, so)); } }
@Test void throwsOnOverflow() { byte[] goodStream = BASE64_DEC.decode(GOOD); byte[] overflowedStream = Arrays.copyOfRange(goodStream, 0, goodStream.length + 2); for (var so : BuffSizeOption.values()) { var t = assertThrows(IOException.class, () -> Decode.decode(new BrotliDecoder(), overflowedStream, so)); var msg = t.getMessage(); assertTrue(msg.equals("corrupt brotli stream") || msg.equals("brotli stream finished prematurely")); } }
@Test void throwsOnUnderflow() { byte[] goodStream = BASE64_DEC.decode(GOOD); byte[] underflowedStream = Arrays.copyOfRange(goodStream, 0, goodStream.length - 2); for (var so : BuffSizeOption.values()) { assertThrows(EOFException.class, () -> Decode.decode(new BrotliDecoder(), underflowedStream, so)); } }