|
@@ -0,0 +1,268 @@
|
|
|
|
|
+/*
|
|
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
|
|
+ * @license WTFPL
|
|
|
|
|
+ * @url http://ranides.net/projects/assira
|
|
|
|
|
+ */
|
|
|
|
|
+package net.ranides.assira.io;
|
|
|
|
|
+
|
|
|
|
|
+import java.io.IOException;
|
|
|
|
|
+import java.io.InputStream;
|
|
|
|
|
+import java.io.OutputStream;
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.Arrays;
|
|
|
|
|
+import java.util.Collections;
|
|
|
|
|
+import java.util.HashSet;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Set;
|
|
|
|
|
+import java.util.concurrent.ConcurrentLinkedQueue;
|
|
|
|
|
+import net.ranides.assira.collection.SetUtils;
|
|
|
|
|
+import net.ranides.assira.events.Event;
|
|
|
|
|
+import net.ranides.assira.events.EventListener;
|
|
|
|
|
+import net.ranides.assira.text.TextEncoding;
|
|
|
|
|
+import net.ranides.assira.text.TextInputStream;
|
|
|
|
|
+import net.ranides.assira.text.TextOutputStream;
|
|
|
|
|
+import net.ranides.assira.time.TimeUtils;
|
|
|
|
|
+import org.junit.Test;
|
|
|
|
|
+import static org.junit.Assert.*;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
|
|
+ */
|
|
|
|
|
+public class AsyncStreamTest {
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void testWriter() throws IOException {
|
|
|
|
|
+ OutputStream ostream = CheckedStream.wrap(new TextOutputStream());
|
|
|
|
|
+ AsyncStream.OStream astream = AsyncStream.wrap(ostream);
|
|
|
|
|
+ EventCollector<IOEvent> events1 = new EventCollector<>();
|
|
|
|
|
+ EventCollector<IORequest> events2 = new EventCollector<>();
|
|
|
|
|
+
|
|
|
|
|
+ astream.addEventListener(IOEvent.class, events1);
|
|
|
|
|
+ astream.addEventListener(IORequest.class, events2);
|
|
|
|
|
+
|
|
|
|
|
+ astream.write('H');
|
|
|
|
|
+ astream.write("ello ".getBytes(TextEncoding.NIO_UTF8));
|
|
|
|
|
+ astream.write("...world!...".getBytes(TextEncoding.NIO_UTF8), 3, 6);
|
|
|
|
|
+ astream.write("???".getBytes(TextEncoding.NIO_UTF8), 100, 100);
|
|
|
|
|
+ astream.flush();
|
|
|
|
|
+ astream.close();
|
|
|
|
|
+
|
|
|
|
|
+ // @todo (assira # 8) issue: exception will be lost
|
|
|
|
|
+ // CStream won't write anything but exception will be lost
|
|
|
|
|
+ astream.write('?');
|
|
|
|
|
+
|
|
|
|
|
+ TimeUtils.sleep(250);
|
|
|
|
|
+ assertEquals("Hello world!",ostream.toString());
|
|
|
|
|
+
|
|
|
|
|
+ // @todo (assira # 8) issue: exception will be lost
|
|
|
|
|
+ astream.close();
|
|
|
|
|
+
|
|
|
|
|
+ TimeUtils.sleep(250);
|
|
|
|
|
+ assertEquals("Hello world!",ostream.toString());
|
|
|
|
|
+
|
|
|
|
|
+ assertTrue(events1.eq(SetUtils.asHashSet(
|
|
|
|
|
+ "IOEvent.WriteByte: 72",
|
|
|
|
|
+ "IOEvent.WriteByteArray: 5",
|
|
|
|
|
+ "IOEvent.WriteByteArray: 6",
|
|
|
|
|
+ "IOEvent.Failure: java.io.IOException: java.lang.ArrayIndexOutOfBoundsException",
|
|
|
|
|
+ "IOEvent.Flush",
|
|
|
|
|
+ "IOEvent.Close"
|
|
|
|
|
+ )));
|
|
|
|
|
+ assertTrue(events2.eq(Arrays.asList(
|
|
|
|
|
+ "IORequest.WriteByte: 72",
|
|
|
|
|
+ "IORequest.WriteByteArray: 5",
|
|
|
|
|
+ "IORequest.WriteByteArray: 6",
|
|
|
|
|
+ "IORequest.Flush",
|
|
|
|
|
+ "IORequest.Close",
|
|
|
|
|
+ "IORequest.WriteByte: 63"
|
|
|
|
|
+ )));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void testWriterDispose() throws IOException {
|
|
|
|
|
+
|
|
|
|
|
+ OutputStream ostream = CheckedStream.wrap(new TextOutputStream());
|
|
|
|
|
+ AsyncStream.OStream astream = AsyncStream.wrap(ostream);
|
|
|
|
|
+ EventCollector<IOEvent> events1 = new EventCollector<>();
|
|
|
|
|
+ EventCollector<IORequest> events2 = new EventCollector<>();
|
|
|
|
|
+
|
|
|
|
|
+ astream.addEventListener(IOEvent.class, events1);
|
|
|
|
|
+ astream.addEventListener(IORequest.class, events2);
|
|
|
|
|
+
|
|
|
|
|
+ astream.dispose();
|
|
|
|
|
+
|
|
|
|
|
+ // @todo (assira # 8) issue: exception will be lost
|
|
|
|
|
+ TimeUtils.sleep(250);
|
|
|
|
|
+ astream.dispose();
|
|
|
|
|
+
|
|
|
|
|
+ TimeUtils.sleep(250);
|
|
|
|
|
+
|
|
|
|
|
+ assertTrue(events1.eq(SetUtils.asHashSet(
|
|
|
|
|
+ "IOEvent.Close"
|
|
|
|
|
+ )));
|
|
|
|
|
+ assertTrue(events2.eq(Collections.<String>emptyList()));
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void testWriterRouter() throws IOException {
|
|
|
|
|
+
|
|
|
|
|
+ OutputStream ostream = CheckedStream.wrap(new TextOutputStream());
|
|
|
|
|
+ AsyncStream.OStream astream = AsyncStream.wrap(ostream);
|
|
|
|
|
+ EventListener<Event> e1 = new EventCollector<>();
|
|
|
|
|
+ EventListener<Event> e2 = new EventCollector<>();
|
|
|
|
|
+
|
|
|
|
|
+ int prev = astream.getEventListenersCount();
|
|
|
|
|
+
|
|
|
|
|
+ astream.addEventListener(IOEvent.class, e1);
|
|
|
|
|
+ astream.addEventListener(IORequest.class, e2);
|
|
|
|
|
+ assertEquals(prev+2, astream.getEventListenersCount());
|
|
|
|
|
+
|
|
|
|
|
+ astream.removeEventListener(IOEvent.class, e2);
|
|
|
|
|
+ astream.removeEventListener(IORequest.class, e1);
|
|
|
|
|
+ assertEquals(prev+2, astream.getEventListenersCount());
|
|
|
|
|
+
|
|
|
|
|
+ astream.removeEventListener(IOEvent.class, e1);
|
|
|
|
|
+ assertEquals(prev+1, astream.getEventListenersCount());
|
|
|
|
|
+ astream.removeEventListener(IORequest.class, e2);
|
|
|
|
|
+ assertEquals(prev+0, astream.getEventListenersCount());
|
|
|
|
|
+
|
|
|
|
|
+ // @todo (assira # 8) issue: AsyncStream will be broken
|
|
|
|
|
+ // "hidden" listener is required to implement functionality
|
|
|
|
|
+ astream.removeAllEventListeners();
|
|
|
|
|
+ assertEquals(0, astream.getEventListenersCount());
|
|
|
|
|
+
|
|
|
|
|
+ astream.close();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void testReader() throws IOException {
|
|
|
|
|
+ InputStream istream = CheckedStream.wrap(new TextInputStream("Hello world"));
|
|
|
|
|
+ AsyncStream.IStream astream = AsyncStream.wrap(istream);
|
|
|
|
|
+ EventCollector<IOEvent> events1 = new EventCollector<>();
|
|
|
|
|
+
|
|
|
|
|
+ astream.addEventListener(IOEvent.class, events1);
|
|
|
|
|
+
|
|
|
|
|
+ assertEquals(11, astream.available());
|
|
|
|
|
+ assertTrue(astream.markSupported());
|
|
|
|
|
+ astream.mark(8);
|
|
|
|
|
+ assertEquals('H', astream.read());
|
|
|
|
|
+ astream.reset();
|
|
|
|
|
+
|
|
|
|
|
+ byte[] target= new byte[6];
|
|
|
|
|
+ assertEquals(6, astream.read(target));
|
|
|
|
|
+ assertArrayEquals("Hello ".getBytes(), target);
|
|
|
|
|
+
|
|
|
|
|
+ assertEquals(2, astream.skip(2));
|
|
|
|
|
+ assertEquals(2, astream.read(target, 1, 2));
|
|
|
|
|
+ assertArrayEquals("Hrllo ".getBytes(), target);
|
|
|
|
|
+
|
|
|
|
|
+ astream.close();
|
|
|
|
|
+ // @todo (assira # 8) issue: exceptions will be lost
|
|
|
|
|
+ try {
|
|
|
|
|
+ astream.close();
|
|
|
|
|
+ fail("IOException expected");
|
|
|
|
|
+ } catch(IOException ex) { assertTrue(true); }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ astream.read();
|
|
|
|
|
+ fail("IOException expected");
|
|
|
|
|
+ } catch(IOException ex) { assertTrue(true); }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ astream.read(target);
|
|
|
|
|
+ fail("IOException expected");
|
|
|
|
|
+ } catch(IOException ex) { assertTrue(true); }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ astream.read(target,1,2);
|
|
|
|
|
+ fail("IOException expected");
|
|
|
|
|
+ } catch(IOException ex) { assertTrue(true); }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ astream.reset();
|
|
|
|
|
+ fail("IOException expected");
|
|
|
|
|
+ } catch(IOException ex) { assertTrue(true); }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ astream.skip(5);
|
|
|
|
|
+ fail("IOException expected");
|
|
|
|
|
+ } catch(IOException ex) { assertTrue(true); }
|
|
|
|
|
+
|
|
|
|
|
+ assertTrue(events1.eq(Arrays.asList(
|
|
|
|
|
+ "IOEvent.Mark",
|
|
|
|
|
+ "IOEvent.ReadByte: 72",
|
|
|
|
|
+ "IOEvent.Reset",
|
|
|
|
|
+ "IOEvent.ReadByteArray: 6:48 65 6C 6C 6F 20",
|
|
|
|
|
+ "IOEvent.Skip",
|
|
|
|
|
+ "IOEvent.ReadByteArray: 2:72 6C",
|
|
|
|
|
+ "IOEvent.Close"
|
|
|
|
|
+ )));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void testReaderDispose() throws IOException {
|
|
|
|
|
+ InputStream istream = CheckedStream.wrap(new TextInputStream("Hello world"));
|
|
|
|
|
+ AsyncStream.IStream astream = AsyncStream.wrap(istream);
|
|
|
|
|
+ EventCollector<IOEvent> events1 = new EventCollector<>();
|
|
|
|
|
+
|
|
|
|
|
+ astream.addEventListener(IOEvent.class, events1);
|
|
|
|
|
+
|
|
|
|
|
+ astream.dispose();
|
|
|
|
|
+ astream.dispose();
|
|
|
|
|
+ TimeUtils.sleep(250);
|
|
|
|
|
+
|
|
|
|
|
+ assertTrue(events1.eq(SetUtils.asHashSet(
|
|
|
|
|
+ "IOEvent.Close"
|
|
|
|
|
+ )));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void testReaderRouter() throws IOException {
|
|
|
|
|
+ InputStream istream = CheckedStream.wrap(new TextInputStream("Hello world"));
|
|
|
|
|
+ AsyncStream.IStream astream = AsyncStream.wrap(istream);
|
|
|
|
|
+ EventCollector<IOEvent> e1 = new EventCollector<>();
|
|
|
|
|
+ EventCollector<IOEvent> e2 = new EventCollector<>();
|
|
|
|
|
+
|
|
|
|
|
+ astream.addEventListener(IOEvent.Close.class, e1);
|
|
|
|
|
+ astream.addEventListener(IOEvent.Read.class, e2);
|
|
|
|
|
+ assertEquals(2, astream.getEventListenersCount());
|
|
|
|
|
+
|
|
|
|
|
+ astream.removeEventListener(IOEvent.Read.class, e1);
|
|
|
|
|
+ astream.removeEventListener(IOEvent.Close.class, e2);
|
|
|
|
|
+ assertEquals(2, astream.getEventListenersCount());
|
|
|
|
|
+
|
|
|
|
|
+ astream.removeEventListener(IOEvent.Close.class, e1);
|
|
|
|
|
+ assertEquals(1, astream.getEventListenersCount());
|
|
|
|
|
+ astream.removeEventListener(IOEvent.Read.class, e2);
|
|
|
|
|
+ assertEquals(0, astream.getEventListenersCount());
|
|
|
|
|
+
|
|
|
|
|
+ astream.removeAllEventListeners();
|
|
|
|
|
+ assertEquals(0, astream.getEventListenersCount());
|
|
|
|
|
+
|
|
|
|
|
+ astream.close();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static final class EventCollector<E extends Event> implements EventListener<E> {
|
|
|
|
|
+
|
|
|
|
|
+ private final ConcurrentLinkedQueue<String> events = new ConcurrentLinkedQueue<>();
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void handleEvent(E event) {
|
|
|
|
|
+ events.add(event.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public boolean eq(Set<String> collection) {
|
|
|
|
|
+ return collection.equals(new HashSet<>(events));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public boolean eq(List<String> collection) {
|
|
|
|
|
+ return collection.equals(new ArrayList<>(events));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+}
|