View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.geometry.io.core.internal;
18  
19  import java.io.IOException;
20  import java.io.Reader;
21  import java.io.StringReader;
22  import java.io.UncheckedIOException;
23  import java.util.Random;
24  
25  import org.apache.commons.geometry.core.GeometryTestUtils;
26  import org.junit.jupiter.api.Assertions;
27  import org.junit.jupiter.api.Test;
28  
29  class CharReadBufferTest {
30  
31      @Test
32      void testCtor() {
33          // act/assert
34          GeometryTestUtils.assertThrowsWithMessage(() -> {
35              new CharReadBuffer(null, 1, 1);
36          }, NullPointerException.class, "Reader cannot be null");
37  
38          GeometryTestUtils.assertThrowsWithMessage(() -> {
39              new CharReadBuffer(reader("a"), 0, 1);
40          }, IllegalArgumentException.class, "Initial buffer capacity must be greater than 0; was 0");
41  
42          GeometryTestUtils.assertThrowsWithMessage(() -> {
43              new CharReadBuffer(reader("a"), 1, 0);
44          }, IllegalArgumentException.class, "Min read value must be greater than 0; was 0");
45      }
46  
47      @Test
48      void testHasMoreCharacters() {
49          // act/assert
50          for (int s = 1; s < 10; s += 2) {
51              Assertions.assertFalse(new CharReadBuffer(reader("")).hasMoreCharacters());
52              Assertions.assertFalse(new CharReadBuffer(reader(""), s).hasMoreCharacters());
53              Assertions.assertFalse(new CharReadBuffer(reader(""), s, s).hasMoreCharacters());
54          }
55  
56          String str;
57          for (int i = 1; i < 10; ++i) {
58              str = repeat("a", i);
59  
60              for (int s = 1; s < 10; s += 2) {
61                  Assertions.assertTrue(new CharReadBuffer(reader(str)).hasMoreCharacters());
62                  Assertions.assertTrue(new CharReadBuffer(reader(str), s).hasMoreCharacters());
63                  Assertions.assertTrue(new CharReadBuffer(reader(str), s, s).hasMoreCharacters());
64              }
65          }
66      }
67  
68      @Test
69      void testPeekRead() {
70          // arrange
71          final String str = "abcdefg";
72          final CharReadBuffer buf = new CharReadBuffer(reader(str), 1);
73  
74          final StringBuilder peek = new StringBuilder();
75          final StringBuilder read = new StringBuilder();
76  
77          // act
78          while (buf.hasMoreCharacters()) {
79              peek.append((char) buf.peek());
80              read.append((char) buf.read());
81          }
82  
83          // assert
84          Assertions.assertEquals(str, peek.toString());
85          Assertions.assertEquals(str, read.toString());
86  
87          Assertions.assertEquals(-1, buf.peek());
88          Assertions.assertEquals(-1, buf.read());
89      }
90  
91      @Test
92      void testCharAt() {
93          // arrange
94          final String str = "abcdefgh";
95          final CharReadBuffer buf = new CharReadBuffer(reader(str), 3);
96  
97          // act/assert
98          Assertions.assertEquals('a', buf.charAt(0));
99          Assertions.assertEquals('b', buf.charAt(1));
100         Assertions.assertEquals('c', buf.charAt(2));
101         Assertions.assertEquals('d', buf.charAt(3));
102         Assertions.assertEquals('e', buf.charAt(4));
103         Assertions.assertEquals('f', buf.charAt(5));
104         Assertions.assertEquals('g', buf.charAt(6));
105         Assertions.assertEquals('h', buf.charAt(7));
106 
107         Assertions.assertEquals(-1, buf.charAt(8));
108         Assertions.assertEquals(-1, buf.charAt(9));
109         Assertions.assertEquals(-1, buf.charAt(10));
110     }
111 
112     @Test
113     void testCharAt_invalidArg() {
114         // arrange
115         final String str = "abcdefgh";
116         final CharReadBuffer buf = new CharReadBuffer(reader(str), 3);
117 
118         // act/assert
119         GeometryTestUtils.assertThrowsWithMessage(() -> {
120             buf.charAt(-1);
121         }, IllegalArgumentException.class, "Character index cannot be negative; was -1");
122     }
123 
124     @Test
125     void testReadPeek_string() {
126         // arrange
127         final String str = "abcdefgh";
128         final CharReadBuffer buf = new CharReadBuffer(reader(str), 50);
129 
130         // act/assert
131         Assertions.assertEquals("", buf.peekString(0));
132         Assertions.assertEquals("", buf.readString(0));
133 
134         Assertions.assertEquals("abc", buf.peekString(3));
135         Assertions.assertEquals("abc", buf.readString(3));
136 
137         Assertions.assertEquals("defgh", buf.peekString(100));
138         Assertions.assertEquals("defgh", buf.readString(100));
139 
140         Assertions.assertEquals(null, buf.peekString(1));
141         Assertions.assertEquals(null, buf.readString(1));
142     }
143 
144     @Test
145     void testReadPeek_tring_zeroLen() {
146         // act/assert
147         Assertions.assertNull(new CharReadBuffer(reader("")).peekString(0));
148         Assertions.assertNull(new CharReadBuffer(reader("")).readString(0));
149 
150         Assertions.assertEquals("", new CharReadBuffer(reader("a")).peekString(0));
151         Assertions.assertEquals("", new CharReadBuffer(reader("a")).readString(0));
152     }
153 
154     @Test
155     void testReadPeek_string_invalidArg() {
156         // arrange
157         final CharReadBuffer buf = new CharReadBuffer(reader("a"));
158         final String msg = "Requested string length cannot be negative; was -1";
159 
160         // act/assert
161         GeometryTestUtils.assertThrowsWithMessage(() -> {
162             buf.peekString(-1);
163         }, IllegalArgumentException.class, msg);
164 
165         GeometryTestUtils.assertThrowsWithMessage(() -> {
166             buf.readString(-1);
167         }, IllegalArgumentException.class, msg);
168     }
169 
170     @Test
171     void testReadPeek_failure() {
172         // arrange
173         final CharReadBuffer buf = new CharReadBuffer(failReader());
174         final String msg = "IOException: read";
175 
176         // act/assert
177         GeometryTestUtils.assertThrowsWithMessage(() -> {
178             buf.peekString(3);
179         }, UncheckedIOException.class, msg);
180 
181         GeometryTestUtils.assertThrowsWithMessage(() -> {
182             buf.readString(3);
183         }, UncheckedIOException.class, msg);
184     }
185 
186     @Test
187     void testSkip() {
188         // arrange
189         final CharReadBuffer buf = new CharReadBuffer(reader("abcdefg"), 3);
190         buf.peekString(2);
191 
192         // act/assert
193         Assertions.assertEquals(0, buf.skip(0));
194         Assertions.assertEquals("a", buf.peekString(1));
195 
196         Assertions.assertEquals(1, buf.skip(1));
197         Assertions.assertEquals("b", buf.peekString(1));
198 
199         Assertions.assertEquals(4, buf.skip(4));
200         Assertions.assertEquals("f", buf.peekString(1));
201 
202         Assertions.assertEquals(1, buf.skip(1));
203         Assertions.assertEquals("g", buf.peekString(1));
204 
205         Assertions.assertEquals(1, buf.skip(100));
206         Assertions.assertNull(buf.peekString(1));
207 
208         Assertions.assertEquals(0, buf.skip(100));
209         Assertions.assertNull(buf.peekString(1));
210     }
211 
212     @Test
213     void testSkip_invalidArg() {
214         // arrange
215         final CharReadBuffer buf = new CharReadBuffer(reader("a"));
216 
217         // act/assert
218         GeometryTestUtils.assertThrowsWithMessage(() -> {
219             buf.skip(-1);
220         }, IllegalArgumentException.class, "Character skip count cannot be negative; was -1");
221     }
222 
223     @Test
224     void testSkip_failure() {
225         // arrange
226         final CharReadBuffer buf = new CharReadBuffer(failReader());
227 
228         // act/assert
229         GeometryTestUtils.assertThrowsWithMessage(() -> {
230             buf.skip(10);
231         }, UncheckedIOException.class, "IOException: skip");
232     }
233 
234     @Test
235     void testPushString_emptyReader() {
236         // arrange
237         final String a = "abcd";
238         final String b = "efgh";
239         final CharReadBuffer buf = new CharReadBuffer(reader(""), 1);
240 
241         // act
242         buf.pushString(a);
243         buf.pushString(b);
244 
245         // assert
246         Assertions.assertTrue(buf.hasMoreCharacters());
247         Assertions.assertEquals("efghabcd", buf.readString(8));
248     }
249 
250     @Test
251     void testPushString_nonEmptyReader() {
252         // arrange
253         final String a = "abcd";
254         final String b = "efgh";
255         final CharReadBuffer buf = new CharReadBuffer(reader("ABCD"), 1);
256 
257         // act
258         buf.pushString(a);
259         buf.pushString(b);
260 
261         // assert
262         Assertions.assertTrue(buf.hasMoreCharacters());
263         Assertions.assertEquals("efghabcdABCD", buf.readString(12));
264     }
265 
266     @Test
267     void testPush_emptyReader() {
268         // arrange
269         final CharReadBuffer buf = new CharReadBuffer(reader("ABCD"), 1);
270 
271         // act
272         buf.push('a');
273         buf.push('b');
274         buf.push('c');
275         buf.push('d');
276 
277         // assert
278         Assertions.assertTrue(buf.hasMoreCharacters());
279         Assertions.assertEquals("dcbaABCD", buf.readString(8));
280     }
281 
282     @Test
283     void testAlternatingPushAndRead() {
284         // arrange
285         final String str = repeat("abcdefghijlmnopqrstuvwxyz", 10);
286 
287         final CharReadBuffer buf = new CharReadBuffer(reader(str), 8);
288 
289         final Random rnd = new Random(1L);
290 
291         // act
292         final StringBuilder result = new StringBuilder();
293         String tmp;
294         while (buf.hasMoreCharacters()) {
295             buf.pushString("ABC");
296 
297             tmp = buf.readString(rnd.nextInt(10) + 4);
298 
299             result.append(tmp.charAt(3));
300 
301             buf.pushString(tmp.substring(4));
302         }
303 
304         // assert
305         Assertions.assertEquals(str, result.toString());
306     }
307 
308     private static Reader reader(final String content) {
309         return new StringReader(content);
310     }
311 
312     private static Reader failReader() {
313         return new Reader() {
314 
315             @Override
316             public int read(char[] cbuf, int off, int len) throws IOException {
317                 throw new IOException("read");
318             }
319 
320             @Override
321             public long skip(final long skip) throws IOException {
322                 throw new IOException("skip");
323             }
324 
325             @Override
326             public void close() {
327             }
328         };
329     }
330 
331     private static String repeat(final String str, final int count) {
332         final StringBuilder sb = new StringBuilder();
333         for (int i = 0; i < count; ++i) {
334             sb.append(str);
335         }
336 
337         return sb.toString();
338     }
339 }