CharReadBufferTest.java
/*
* 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
*
* https://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 org.apache.commons.geometry.io.core.internal;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.UncheckedIOException;
import java.util.Random;
import org.apache.commons.geometry.core.GeometryTestUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class CharReadBufferTest {
@Test
void testCtor() {
// act/assert
GeometryTestUtils.assertThrowsWithMessage(() -> {
new CharReadBuffer(null, 1, 1);
}, NullPointerException.class, "Reader cannot be null");
GeometryTestUtils.assertThrowsWithMessage(() -> {
new CharReadBuffer(reader("a"), 0, 1);
}, IllegalArgumentException.class, "Initial buffer capacity must be greater than 0; was 0");
GeometryTestUtils.assertThrowsWithMessage(() -> {
new CharReadBuffer(reader("a"), 1, 0);
}, IllegalArgumentException.class, "Min read value must be greater than 0; was 0");
}
@Test
void testHasMoreCharacters() {
// act/assert
for (int s = 1; s < 10; s += 2) {
Assertions.assertFalse(new CharReadBuffer(reader("")).hasMoreCharacters());
Assertions.assertFalse(new CharReadBuffer(reader(""), s).hasMoreCharacters());
Assertions.assertFalse(new CharReadBuffer(reader(""), s, s).hasMoreCharacters());
}
String str;
for (int i = 1; i < 10; ++i) {
str = repeat("a", i);
for (int s = 1; s < 10; s += 2) {
Assertions.assertTrue(new CharReadBuffer(reader(str)).hasMoreCharacters());
Assertions.assertTrue(new CharReadBuffer(reader(str), s).hasMoreCharacters());
Assertions.assertTrue(new CharReadBuffer(reader(str), s, s).hasMoreCharacters());
}
}
}
@Test
void testPeekRead() {
// arrange
final String str = "abcdefg";
final CharReadBuffer buf = new CharReadBuffer(reader(str), 1);
final StringBuilder peek = new StringBuilder();
final StringBuilder read = new StringBuilder();
// act
while (buf.hasMoreCharacters()) {
peek.append((char) buf.peek());
read.append((char) buf.read());
}
// assert
Assertions.assertEquals(str, peek.toString());
Assertions.assertEquals(str, read.toString());
Assertions.assertEquals(-1, buf.peek());
Assertions.assertEquals(-1, buf.read());
}
@Test
void testCharAt() {
// arrange
final String str = "abcdefgh";
final CharReadBuffer buf = new CharReadBuffer(reader(str), 3);
// act/assert
Assertions.assertEquals('a', buf.charAt(0));
Assertions.assertEquals('b', buf.charAt(1));
Assertions.assertEquals('c', buf.charAt(2));
Assertions.assertEquals('d', buf.charAt(3));
Assertions.assertEquals('e', buf.charAt(4));
Assertions.assertEquals('f', buf.charAt(5));
Assertions.assertEquals('g', buf.charAt(6));
Assertions.assertEquals('h', buf.charAt(7));
Assertions.assertEquals(-1, buf.charAt(8));
Assertions.assertEquals(-1, buf.charAt(9));
Assertions.assertEquals(-1, buf.charAt(10));
}
@Test
void testCharAt_invalidArg() {
// arrange
final String str = "abcdefgh";
final CharReadBuffer buf = new CharReadBuffer(reader(str), 3);
// act/assert
GeometryTestUtils.assertThrowsWithMessage(() -> {
buf.charAt(-1);
}, IllegalArgumentException.class, "Character index cannot be negative; was -1");
}
@Test
void testReadPeek_string() {
// arrange
final String str = "abcdefgh";
final CharReadBuffer buf = new CharReadBuffer(reader(str), 50);
// act/assert
Assertions.assertEquals("", buf.peekString(0));
Assertions.assertEquals("", buf.readString(0));
Assertions.assertEquals("abc", buf.peekString(3));
Assertions.assertEquals("abc", buf.readString(3));
Assertions.assertEquals("defgh", buf.peekString(100));
Assertions.assertEquals("defgh", buf.readString(100));
Assertions.assertEquals(null, buf.peekString(1));
Assertions.assertEquals(null, buf.readString(1));
}
@Test
void testReadPeek_tring_zeroLen() {
// act/assert
Assertions.assertNull(new CharReadBuffer(reader("")).peekString(0));
Assertions.assertNull(new CharReadBuffer(reader("")).readString(0));
Assertions.assertEquals("", new CharReadBuffer(reader("a")).peekString(0));
Assertions.assertEquals("", new CharReadBuffer(reader("a")).readString(0));
}
@Test
void testReadPeek_string_invalidArg() {
// arrange
final CharReadBuffer buf = new CharReadBuffer(reader("a"));
final String msg = "Requested string length cannot be negative; was -1";
// act/assert
GeometryTestUtils.assertThrowsWithMessage(() -> {
buf.peekString(-1);
}, IllegalArgumentException.class, msg);
GeometryTestUtils.assertThrowsWithMessage(() -> {
buf.readString(-1);
}, IllegalArgumentException.class, msg);
}
@Test
void testReadPeek_failure() {
// arrange
final CharReadBuffer buf = new CharReadBuffer(failReader());
final String msg = "IOException: read";
// act/assert
GeometryTestUtils.assertThrowsWithMessage(() -> {
buf.peekString(3);
}, UncheckedIOException.class, msg);
GeometryTestUtils.assertThrowsWithMessage(() -> {
buf.readString(3);
}, UncheckedIOException.class, msg);
}
@Test
void testSkip() {
// arrange
final CharReadBuffer buf = new CharReadBuffer(reader("abcdefg"), 3);
buf.peekString(2);
// act/assert
Assertions.assertEquals(0, buf.skip(0));
Assertions.assertEquals("a", buf.peekString(1));
Assertions.assertEquals(1, buf.skip(1));
Assertions.assertEquals("b", buf.peekString(1));
Assertions.assertEquals(4, buf.skip(4));
Assertions.assertEquals("f", buf.peekString(1));
Assertions.assertEquals(1, buf.skip(1));
Assertions.assertEquals("g", buf.peekString(1));
Assertions.assertEquals(1, buf.skip(100));
Assertions.assertNull(buf.peekString(1));
Assertions.assertEquals(0, buf.skip(100));
Assertions.assertNull(buf.peekString(1));
}
@Test
void testSkip_invalidArg() {
// arrange
final CharReadBuffer buf = new CharReadBuffer(reader("a"));
// act/assert
GeometryTestUtils.assertThrowsWithMessage(() -> {
buf.skip(-1);
}, IllegalArgumentException.class, "Character skip count cannot be negative; was -1");
}
@Test
void testSkip_failure() {
// arrange
final CharReadBuffer buf = new CharReadBuffer(failReader());
// act/assert
GeometryTestUtils.assertThrowsWithMessage(() -> {
buf.skip(10);
}, UncheckedIOException.class, "IOException: skip");
}
@Test
void testPushString_emptyReader() {
// arrange
final String a = "abcd";
final String b = "efgh";
final CharReadBuffer buf = new CharReadBuffer(reader(""), 1);
// act
buf.pushString(a);
buf.pushString(b);
// assert
Assertions.assertTrue(buf.hasMoreCharacters());
Assertions.assertEquals("efghabcd", buf.readString(8));
}
@Test
void testPushString_nonEmptyReader() {
// arrange
final String a = "abcd";
final String b = "efgh";
final CharReadBuffer buf = new CharReadBuffer(reader("ABCD"), 1);
// act
buf.pushString(a);
buf.pushString(b);
// assert
Assertions.assertTrue(buf.hasMoreCharacters());
Assertions.assertEquals("efghabcdABCD", buf.readString(12));
}
@Test
void testPush_emptyReader() {
// arrange
final CharReadBuffer buf = new CharReadBuffer(reader("ABCD"), 1);
// act
buf.push('a');
buf.push('b');
buf.push('c');
buf.push('d');
// assert
Assertions.assertTrue(buf.hasMoreCharacters());
Assertions.assertEquals("dcbaABCD", buf.readString(8));
}
@Test
void testAlternatingPushAndRead() {
// arrange
final String str = repeat("abcdefghijlmnopqrstuvwxyz", 10);
final CharReadBuffer buf = new CharReadBuffer(reader(str), 8);
final Random rnd = new Random(1L);
// act
final StringBuilder result = new StringBuilder();
String tmp;
while (buf.hasMoreCharacters()) {
buf.pushString("ABC");
tmp = buf.readString(rnd.nextInt(10) + 4);
result.append(tmp.charAt(3));
buf.pushString(tmp.substring(4));
}
// assert
Assertions.assertEquals(str, result.toString());
}
private static Reader reader(final String content) {
return new StringReader(content);
}
private static Reader failReader() {
return new Reader() {
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
throw new IOException("read");
}
@Override
public long skip(final long skip) throws IOException {
throw new IOException("skip");
}
@Override
public void close() {
// Not used
}
};
}
private static String repeat(final String str, final int count) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; ++i) {
sb.append(str);
}
return sb.toString();
}
}