1 package emissary.core.channels;
2
3 import emissary.test.core.junit5.UnitTest;
4
5 import org.apache.commons.io.IOUtils;
6 import org.junit.jupiter.api.Test;
7
8 import java.io.ByteArrayInputStream;
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.nio.ByteBuffer;
12 import java.nio.channels.SeekableByteChannel;
13 import java.nio.charset.StandardCharsets;
14
15 import static emissary.core.channels.InputStreamChannelFactory.SIZE_IS_UNKNOWN;
16 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
17 import static org.junit.jupiter.api.Assertions.assertEquals;
18 import static org.junit.jupiter.api.Assertions.assertFalse;
19 import static org.junit.jupiter.api.Assertions.assertThrows;
20
21 class InputStreamChannelFactoryTest extends UnitTest {
22 private static class TestInputStreamFactory implements InputStreamFactory {
23 private final byte[] bytes;
24
25 public TestInputStreamFactory(final byte[] bytes) {
26 this.bytes = bytes;
27 }
28
29 @Override
30 public InputStream create() {
31 return new ByteArrayInputStream(bytes);
32 }
33 }
34
35 private static final byte[] testBytes = "0123456789".getBytes(StandardCharsets.UTF_8);
36 private static final byte[] emojiBytes = "😃0123456789".getBytes(StandardCharsets.UTF_16);
37
38
39 @Test
40 void testReadNonUtf8() throws IOException {
41 try (SeekableByteChannel sbc = InputStreamChannelFactory.create(emojiBytes.length, new TestInputStreamFactory(emojiBytes)).create()) {
42 final ByteBuffer byteBuffer = ByteBuffer.allocate(8);
43
44 sbc.position(8);
45 assertEquals(8, IOUtils.read(sbc, byteBuffer));
46 assertEquals("1234", new String(byteBuffer.array(), StandardCharsets.UTF_16));
47
48 byteBuffer.position(0);
49 sbc.position(0);
50 assertEquals(8, IOUtils.read(sbc, byteBuffer));
51 assertEquals("😃0", new String(byteBuffer.array(), StandardCharsets.UTF_16));
52 }
53 }
54
55 @Test
56 void testExhaustively() throws IOException {
57 ChannelTestHelper.checkByteArrayAgainstSbc(testBytes,
58 InputStreamChannelFactory.create(testBytes.length, new TestInputStreamFactory(testBytes)));
59 }
60
61 @Test
62 void testClose() throws IOException {
63 SeekableByteChannel sbc = InputStreamChannelFactory.create(testBytes.length, new TestInputStreamFactory(testBytes)).create();
64
65 sbc.close();
66 assertFalse(sbc.isOpen());
67
68 assertDoesNotThrow(() -> sbc.close());
69 assertFalse(sbc.isOpen());
70 }
71
72 @Test
73 void testRead() throws IOException {
74 try (SeekableByteChannel sbc = InputStreamChannelFactory.create(testBytes.length, new TestInputStreamFactory(testBytes)).create()) {
75 final ByteBuffer byteBuffer = ByteBuffer.allocate(1);
76
77
78 sbc.position(5);
79 assertEquals(1, IOUtils.read(sbc, byteBuffer));
80 assertEquals('5', byteBuffer.get(0));
81
82 byteBuffer.position(0);
83 sbc.position(0);
84 assertEquals(1, IOUtils.read(sbc, byteBuffer));
85 assertEquals('0', byteBuffer.get(0));
86 }
87 }
88
89 @Test
90 void testSize() throws IOException {
91
92 try (SeekableByteChannel sbc = InputStreamChannelFactory.create(testBytes.length, new TestInputStreamFactory(testBytes)).create()) {
93 ByteBuffer buff = ByteBuffer.allocate(32);
94 assertEquals(testBytes.length, sbc.size());
95 assertEquals(testBytes.length, sbc.read(buff));
96 assertEquals(testBytes.length, buff.position());
97 }
98 }
99
100 @Test
101 void testCanWorkOutSize() throws IOException {
102
103 try (SeekableByteChannel sbc = InputStreamChannelFactory.create(-1, new TestInputStreamFactory(testBytes)).create()) {
104 ByteBuffer buff = ByteBuffer.allocate(32);
105 assertEquals(testBytes.length, sbc.size());
106 assertEquals(testBytes.length, sbc.read(buff));
107 assertEquals(testBytes.length, buff.position());
108 }
109 }
110
111 @Test
112 void testReadWithIncorrectSize() throws IOException {
113
114 final int sbcLength = testBytes.length + 8;
115 try (SeekableByteChannel sbc = InputStreamChannelFactory.create(sbcLength, new TestInputStreamFactory(testBytes)).create()) {
116 ByteBuffer buff = ByteBuffer.allocate(32);
117 assertEquals(sbcLength, sbc.size());
118 assertEquals(testBytes.length, sbc.read(buff));
119 assertEquals(testBytes.length, buff.position());
120 }
121 }
122
123 @Test
124 void testReadWithZeroSize() throws IOException {
125
126 try (SeekableByteChannel sbc = InputStreamChannelFactory.create(0, new TestInputStreamFactory(testBytes)).create()) {
127 ByteBuffer buff = ByteBuffer.allocate(1);
128 assertEquals(0, sbc.size());
129 assertEquals(-1, sbc.read(buff));
130 assertEquals(0, buff.position());
131 }
132 }
133
134 @Test
135 void testStartReadBeyondActualData() throws IOException {
136
137 final int sbcLength = testBytes.length + 8;
138 try (SeekableByteChannel sbc = InputStreamChannelFactory.create(sbcLength, new TestInputStreamFactory(testBytes)).create()) {
139 ByteBuffer buff = ByteBuffer.allocate(32);
140 assertEquals(sbcLength, sbc.size());
141
142 sbc.position(testBytes.length + 2);
143 assertThrows(IOException.class, () -> sbc.read(buff));
144 assertEquals(0, buff.position());
145 }
146 }
147
148 @Test
149 void testReadWithLargerThanDefinedSize() throws IOException {
150 final int sbcLength = testBytes.length / 2;
151
152 try (SeekableByteChannel sbc = InputStreamChannelFactory.create(sbcLength, new TestInputStreamFactory(testBytes)).create()) {
153 ByteBuffer buff = ByteBuffer.allocate(32);
154 assertEquals(sbcLength, sbc.size());
155 sbc.read(buff);
156 assertEquals(sbcLength, buff.position());
157 }
158 }
159
160 @Test
161 void testExceptionInputStreamFactory() throws Exception {
162 final InputStreamFactory isf = new InputStreamFactory() {
163 @Override
164 public InputStream create() throws IOException {
165 throw new IOException("This InputStreamFactory only throws IOExceptions!");
166 }
167 };
168 final SeekableByteChannelFactory sbcf = InputStreamChannelFactory.create(SIZE_IS_UNKNOWN, isf);
169 final ByteBuffer byteBuffer = ByteBuffer.allocate(100);
170
171 try (SeekableByteChannel sbc = sbcf.create()) {
172 assertThrows(IOException.class, sbc::size);
173 assertThrows(IOException.class, () -> sbc.read(byteBuffer));
174 }
175 }
176 }