From 4629ff5450e1ab6b2b52b7002a589d38e7997b1c Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sat, 25 Oct 2014 15:07:45 +0400 Subject: [PATCH] Add CharBuffer --- .../teavm/classlib/java/lang/TReadable.java | 27 ++ .../teavm/classlib/java/nio/TCharBuffer.java | 282 ++++++++++++ .../classlib/java/nio/TCharBufferImpl.java | 123 ++++++ .../classlib/java/nio/ByteBufferTest.java | 1 - .../classlib/java/nio/CharBufferTest.java | 415 ++++++++++++++++++ 5 files changed, 847 insertions(+), 1 deletion(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TReadable.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TCharBuffer.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TCharBufferImpl.java create mode 100644 teavm-classlib/src/test/java/org/teavm/classlib/java/nio/CharBufferTest.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TReadable.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TReadable.java new file mode 100644 index 000000000..21920afd8 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TReadable.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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 + * + * http://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.teavm.classlib.java.lang; + +import org.teavm.classlib.java.io.TIOException; +import org.teavm.classlib.java.nio.TCharBuffer; + +/** + * + * @author Alexey Andreev + */ +public interface TReadable { + int read(TCharBuffer cb) throws TIOException; +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TCharBuffer.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TCharBuffer.java new file mode 100644 index 000000000..b0c4c8933 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TCharBuffer.java @@ -0,0 +1,282 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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 + * + * http://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.teavm.classlib.java.nio; + +import org.teavm.classlib.java.io.TIOException; +import org.teavm.classlib.java.lang.TReadable; + +/** + * + * @author Alexey Andreev + */ +public abstract class TCharBuffer extends TBuffer implements Comparable, Appendable, + CharSequence, TReadable { + int start; + char[] array; + + TCharBuffer(int start, int capacity, char[] array, int position, int limit) { + super(capacity); + this.start = start; + this.array = array; + this.position = position; + this.limit = limit; + } + + public static TCharBuffer allocate(int capacity) { + if (capacity < 0) { + throw new IllegalArgumentException("Capacity is negative: " + capacity); + } + return new TCharBufferImpl(capacity); + } + + public static TCharBuffer wrap(char[] array, int offset, int length) { + return new TCharBufferImpl(0, array.length, array, offset, offset + length, false); + } + + public static TCharBuffer wrap(char[] array) { + return wrap(array, 0, array.length); + } + + @Override + public int read(TCharBuffer target) throws TIOException { + if (target == null) { + throw new NullPointerException("Target is null"); + } + if (target.isReadOnly()) { + throw new TReadOnlyBufferException(); + } + if (!hasRemaining()) { + return -1; + } + int sz = Math.min(remaining(), target.remaining()); + target.put(array, start + position, sz); + return sz; + } + + public static TCharBuffer wrap(CharSequence csq, int start, int end) { + return wrap(csq.toString().toCharArray(), start, end - start); + } + + public static TCharBuffer wrap(CharSequence csq) { + return wrap(csq.toString().toCharArray()); + } + + public abstract TCharBuffer slice(); + + public abstract TCharBuffer duplicate(); + + public abstract TCharBuffer asReadOnlyBuffer(); + + public abstract char get(); + + public abstract TCharBuffer put(char c); + + public abstract char get(int index); + + public abstract TCharBuffer put(int index, char c); + + public TCharBuffer get(char[] dst, int offset, int length) { + if (offset < 0 || offset >= dst.length) { + throw new IndexOutOfBoundsException("Offset " + offset + " is outside of range [0;" + dst.length + ")"); + } + if (offset + length > dst.length) { + throw new IndexOutOfBoundsException("The last char in dst " + (offset + length) + " is outside " + + "of array of size " + dst.length); + } + if (remaining() < length) { + throw new TBufferUnderflowException(); + } + if (length < 0) { + throw new IndexOutOfBoundsException("Length " + length + " must be non-negative"); + } + int pos = position + start; + for (int i = 0; i < length; ++i) { + dst[offset++] = array[pos++]; + } + position += length; + return this; + } + + public TCharBuffer get(char[] dst) { + return get(dst, 0, dst.length); + } + + public TCharBuffer put(TCharBuffer src) { + return put(src.array, src.start + src.position, src.remaining()); + } + + public TCharBuffer put(char[] src, int offset, int length) { + if (isReadOnly()) { + throw new TReadOnlyBufferException(); + } + if (remaining() < length) { + throw new TBufferOverflowException(); + } + if (offset < 0 || offset >= src.length) { + throw new IndexOutOfBoundsException("Offset " + offset + " is outside of range [0;" + src.length + ")"); + } + if (offset + length > src.length) { + throw new IndexOutOfBoundsException("The last char in src " + (offset + length) + " is outside " + + "of array of size " + src.length); + } + if (length < 0) { + throw new IndexOutOfBoundsException("Length " + length + " must be non-negative"); + } + int pos = position + start; + for (int i = 0; i < length; ++i) { + array[pos++] = src[offset++]; + } + position += length; + return this; + } + + public final TCharBuffer put(char[] src) { + return put(src, 0, src.length); + } + + public TCharBuffer put(String src, int start, int end) { + if (isReadOnly()) { + throw new TReadOnlyBufferException(); + } + int sz = end - start; + if (remaining() < sz) { + throw new TBufferOverflowException(); + } + if (start < 0 || start >= src.length()) { + throw new IndexOutOfBoundsException("Start " + start + " is outside of range [0;" + src.length() + ")"); + } + if (end > src.length()) { + throw new IndexOutOfBoundsException("The last char in src " + end + " is outside " + + "of string of size " + src.length()); + } + if (start > end) { + throw new IndexOutOfBoundsException("Start " + start + " must be before end " + end); + } + int pos = position + this.start; + while (start < end) { + array[pos++] = src.charAt(start++); + } + position += sz; + return this; + } + + public final TCharBuffer put(String src) { + return put(src, 0, src.length()); + } + + @Override + public final boolean hasArray() { + return true; + } + + @Override + public final char[] array() { + return array; + } + + @Override + public final int arrayOffset() { + return start; + } + + public abstract TCharBuffer compact(); + + @Override + public abstract boolean isDirect(); + + @Override + public int hashCode() { + int hashCode = 0; + int pos = position + start; + for (int i = position; i < limit; ++i) { + hashCode = 31 * hashCode + array[pos++]; + } + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof TCharBuffer)) { + return false; + } + TCharBuffer other = (TCharBuffer)obj; + int sz = remaining(); + if (sz != other.remaining()) { + return false; + } + int a = position + start; + int b = other.position + other.start; + for (int i = 0; i < sz; ++i) { + if (array[a++] != other.array[b++]) { + return false; + } + } + return true; + } + + @Override + public int compareTo(TCharBuffer other) { + if (this == other) { + return 0; + } + int sz = Math.min(remaining(), other.remaining()); + int a = position + start; + int b = other.position + other.start; + for (int i = 0; i < sz; ++i) { + int r = Character.compare(array[a++], other.array[b++]); + if (r != 0) { + return r; + } + } + return Integer.compare(remaining(), other.remaining()); + } + + @Override + public String toString() { + return new String(array, start + position, limit - position); + } + + @Override + public final int length() { + return remaining(); + } + + @Override + public final char charAt(int index) { + return get(index); + } + + @Override + public abstract TCharBuffer subSequence(int start, int end); + + @Override + public TCharBuffer append(CharSequence csq) { + return put(csq.toString()); + } + + @Override + public TCharBuffer append(CharSequence csq, int start, int end) { + return put(csq.subSequence(start, end).toString()); + } + + @Override + public TCharBuffer append(char c) { + return put(c); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TCharBufferImpl.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TCharBufferImpl.java new file mode 100644 index 000000000..f9d4e811b --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/nio/TCharBufferImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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 + * + * http://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.teavm.classlib.java.nio; + +/** + * + * @author Alexey Andreev + */ +class TCharBufferImpl extends TCharBuffer { + private boolean readOnly; + + public TCharBufferImpl(int capacity) { + this(0, capacity, new char[capacity], 0, capacity, false); + } + + public TCharBufferImpl(int start, int capacity, char[] array, int position, int limit, + boolean readOnly) { + super(start, capacity, array, position, limit); + this.readOnly = readOnly; + } + + @Override + public TCharBuffer slice() { + return new TCharBufferImpl(position, limit - position, array, 0, limit - position, readOnly); + } + + @Override + public TCharBuffer duplicate() { + return new TCharBufferImpl(start, capacity, array, position, limit, readOnly); + } + + @Override + public TCharBuffer asReadOnlyBuffer() { + return new TCharBufferImpl(start, capacity, array, position, limit, true); + } + + @Override + public char get() { + if (position >= limit) { + throw new TBufferUnderflowException(); + } + return array[start + position++]; + } + + @Override + public TCharBuffer put(char c) { + if (readOnly) { + throw new TReadOnlyBufferException(); + } + if (position >= limit) { + throw new TBufferOverflowException(); + } + array[start + position++] = c; + return this; + } + + @Override + public char get(int index) { + if (index < 0 || index >= limit) { + throw new IndexOutOfBoundsException("Index " + index + " is outside of range [0;" + limit + ")"); + } + return array[start + index]; + } + + @Override + public TCharBuffer put(int index, char b) { + if (readOnly) { + throw new TReadOnlyBufferException(); + } + if (index < 0 || index >= limit) { + throw new IndexOutOfBoundsException("Index " + index + " is outside of range [0;" + limit + ")"); + } + array[start + index] = b; + return this; + } + + @Override + public TCharBuffer compact() { + if (readOnly) { + throw new TReadOnlyBufferException(); + } + if (position > 0) { + int sz = remaining(); + int dst = start; + int src = start + position; + for (int i = 0; i < sz; ++i) { + array[dst++] = array[src++]; + } + position = sz; + } + limit = capacity; + mark = -1; + return this; + } + + @Override + public boolean isDirect() { + return false; + } + + @Override + public boolean isReadOnly() { + return readOnly; + } + + @Override + public TCharBuffer subSequence(int start, int end) { + return wrap(array, arrayOffset() + start, end - start); + } +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/ByteBufferTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/ByteBufferTest.java index a9e0101a9..9fd2889be 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/ByteBufferTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/ByteBufferTest.java @@ -206,7 +206,6 @@ public class ByteBufferTest { buffer.put((byte)5); fail("Should have thrown error"); } catch (BufferOverflowException e) { - System.out.println(e); assertThat(array[2], is((byte)0)); } } diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/CharBufferTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/CharBufferTest.java new file mode 100644 index 000000000..3e461b04f --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/nio/CharBufferTest.java @@ -0,0 +1,415 @@ +package org.teavm.classlib.java.nio; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import java.io.IOException; +import java.nio.*; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class CharBufferTest { + @Test + public void allocates() { + CharBuffer buffer = CharBuffer.allocate(100); + assertThat(buffer.isDirect(), is(false)); + assertThat(buffer.isReadOnly(), is(false)); + assertThat(buffer.hasArray(), is(true)); + assertThat(buffer.capacity(), is(100)); + assertThat(buffer.position(), is(0)); + assertThat(buffer.limit(), is(100)); + try { + buffer.reset(); + fail("Mark is expected to be undefined"); + } catch (InvalidMarkException e) { + // ok + } + } + + @Test(expected = IllegalArgumentException.class) + public void errorIfAllocatingBufferOfNegativeSize() { + CharBuffer.allocate(-1); + } + + @Test + public void wrapsArray() { + char[] array = new char[100]; + CharBuffer buffer = CharBuffer.wrap(array, 10, 70); + assertThat(buffer.isDirect(), is(false)); + assertThat(buffer.isReadOnly(), is(false)); + assertThat(buffer.hasArray(), is(true)); + assertThat(buffer.array(), is(array)); + assertThat(buffer.arrayOffset(), is(0)); + assertThat(buffer.capacity(), is(100)); + assertThat(buffer.position(), is(10)); + assertThat(buffer.limit(), is(80)); + try { + buffer.reset(); + fail("Mark is expected to be undefined"); + } catch (InvalidMarkException e) { + // ok + } + array[0] = 'A'; + assertThat(buffer.get(0), is('A')); + buffer.put(1, 'B'); + assertThat(array[1], is('B')); + } + + @Test + public void errorWhenWrappingWithWrongParameters() { + char[] array = new char[100]; + try { + CharBuffer.wrap(array, -1, 10); + } catch (IndexOutOfBoundsException e) { + // ok + } + try { + CharBuffer.wrap(array, 101, 10); + } catch (IndexOutOfBoundsException e) { + // ok + } + try { + CharBuffer.wrap(array, 98, 3); + } catch (IndexOutOfBoundsException e) { + // ok + } + try { + CharBuffer.wrap(array, 98, -1); + } catch (IndexOutOfBoundsException e) { + // ok + } + } + + @Test + public void wrapsArrayWithoutOffset() { + char[] array = new char[100]; + CharBuffer buffer = CharBuffer.wrap(array); + assertThat(buffer.position(), is(0)); + assertThat(buffer.limit(), is(100)); + } + + @Test + public void createsSlice() { + CharBuffer buffer = CharBuffer.allocate(100); + buffer.put(new char[60]); + buffer.flip(); + buffer.put(new char[15]); + CharBuffer slice = buffer.slice(); + assertThat(slice.array(), is(buffer.array())); + assertThat(slice.position(), is(0)); + assertThat(slice.capacity(), is(45)); + assertThat(slice.limit(), is(45)); + assertThat(slice.isDirect(), is(false)); + assertThat(slice.isReadOnly(), is(false)); + slice.put(3, 'A'); + assertThat(buffer.get(18), is('A')); + slice.put('B'); + assertThat(buffer.get(15), is('B')); + buffer.put(16, 'C'); + assertThat(slice.get(1), is('C')); + } + + @Test + public void slicePropertiesSameWithOriginal() { + CharBuffer buffer = CharBuffer.allocate(100).asReadOnlyBuffer().slice(); + assertThat(buffer.isReadOnly(), is(true)); + } + + @Test + public void createsDuplicate() { + CharBuffer buffer = CharBuffer.allocate(100); + buffer.put(new char[60]); + buffer.flip(); + buffer.put(new char[15]); + CharBuffer duplicate = buffer.duplicate(); + assertThat(duplicate.array(), is(buffer.array())); + assertThat(duplicate.position(), is(15)); + assertThat(duplicate.capacity(), is(100)); + assertThat(duplicate.limit(), is(60)); + assertThat(duplicate.isDirect(), is(false)); + assertThat(duplicate.isReadOnly(), is(false)); + duplicate.put(3, 'A'); + assertThat(buffer.get(3), is('A')); + duplicate.put('B'); + assertThat(buffer.get(15), is('B')); + buffer.put(1, 'C'); + assertThat(duplicate.get(1), is('C')); + assertThat(duplicate.array(), is(sameInstance(buffer.array()))); + } + + @Test + public void getsChar() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + assertThat(buffer.get(), is('T')); + assertThat(buffer.get(), is('e')); + buffer = buffer.slice(); + assertThat(buffer.get(), is('a')); + assertThat(buffer.get(), is('V')); + } + + @Test + public void gettingCharFromEmptyBufferCausesError() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.limit(2); + buffer.get(); + buffer.get(); + try { + buffer.get(); + fail("Should have thrown error"); + } catch (BufferUnderflowException e) { + // ok + } + } + + @Test + public void putsChar() { + char[] array = new char[5]; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.put('T').put('e').put('a').put('V').put('M'); + assertThat(array, is(new char[] { 'T', 'e', 'a', 'V', 'M' })); + } + + @Test + public void puttingCharToEmptyBufferCausesError() { + char[] array = new char[4]; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.limit(2); + buffer.put('A').put('B'); + try { + buffer.put('C'); + fail("Should have thrown error"); + } catch (BufferOverflowException e) { + assertThat(array[2], is('\0')); + } + } + + @Test(expected = ReadOnlyBufferException.class) + public void puttingCharToReadOnlyBufferCausesError() { + char[] array = new char[4]; + CharBuffer buffer = CharBuffer.wrap(array).asReadOnlyBuffer(); + buffer.put('A'); + } + + @Test + public void getsCharFromGivenLocation() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + assertThat(buffer.get(0), is('T')); + assertThat(buffer.get(1), is('e')); + buffer.get(); + buffer = buffer.slice(); + assertThat(buffer.get(1), is('a')); + assertThat(buffer.get(2), is('V')); + } + + @Test + public void gettingCharFromWrongLocationCausesError() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.limit(3); + try { + buffer.get(-1); + } catch (IndexOutOfBoundsException e) { + // ok + } + try { + buffer.get(3); + } catch (IndexOutOfBoundsException e) { + // ok + } + } + + @Test + public void putsCharToGivenLocation() { + char[] array = new char[5]; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.put(0, 'T'); + buffer.put(1, 'e'); + buffer.get(); + buffer = buffer.slice(); + buffer.put(1, 'a'); + buffer.put(2, 'V'); + buffer.put(3, 'M'); + assertThat(array, is(new char[] { 'T', 'e', 'a', 'V', 'M' })); + } + + @Test + public void puttingCharToWrongLocationCausesError() { + char[] array = new char[4]; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.limit(3); + try { + buffer.put(-1, 'A'); + } catch (IndexOutOfBoundsException e) { + // ok + } + try { + buffer.put(3, 'A'); + } catch (IndexOutOfBoundsException e) { + // ok + } + } + + @Test(expected = ReadOnlyBufferException.class) + public void puttingCharToGivenLocationOfReadOnlyBufferCausesError() { + char[] array = new char[4]; + CharBuffer buffer = CharBuffer.wrap(array).asReadOnlyBuffer(); + buffer.put(0, 'A'); + } + + @Test + public void getsChars() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.get(); + char[] receiver = new char[2]; + buffer.get(receiver, 0, 2); + assertThat(buffer.position(), is(3)); + assertThat(receiver, is(new char[] { 'e', 'a' })); + } + + @Test + public void gettingCharsFromEmptyBufferCausesError() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.limit(3); + char[] receiver = new char[5]; + try { + buffer.get(receiver, 0, 4); + fail("Error expected"); + } catch (BufferUnderflowException e) { + assertThat(receiver, is(new char[5])); + assertThat(buffer.position(), is(0)); + } + } + + @Test + public void gettingCharsWithIllegalArgumentsCausesError() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + char[] receiver = new char[5]; + try { + buffer.get(receiver, 0, 6); + } catch (IndexOutOfBoundsException e) { + assertThat(receiver, is(new char[5])); + assertThat(buffer.position(), is(0)); + } + try { + buffer.get(receiver, -1, 3); + } catch (IndexOutOfBoundsException e) { + assertThat(receiver, is(new char[5])); + assertThat(buffer.position(), is(0)); + } + try { + buffer.get(receiver, 6, 3); + } catch (IndexOutOfBoundsException e) { + assertThat(receiver, is(new char[5])); + assertThat(buffer.position(), is(0)); + } + } + + @Test + public void putsChars() { + char[] array = new char[4]; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.get(); + char[] data = { 'A', 'B' }; + buffer.put(data, 0, 2); + assertThat(buffer.position(), is(3)); + assertThat(array, is(new char[] { '\0', 'A', 'B', '\0' })); + } + + @Test + public void compacts() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.get(); + buffer.mark(); + buffer.compact(); + assertThat(array, is(new char[] { 'e', 'a', 'V', 'M', 'M' })); + assertThat(buffer.position(), is(4)); + assertThat(buffer.limit(), is(5)); + assertThat(buffer.capacity(), is(5)); + try { + buffer.reset(); + fail("Exception expected"); + } catch (InvalidMarkException e) { + // ok + } + } + + @Test + public void marksPosition() { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + buffer.position(1); + buffer.mark(); + buffer.position(2); + buffer.reset(); + assertThat(buffer.position(), is(1)); + } + + @Test + public void readsChars() throws IOException { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + CharBuffer target = CharBuffer.allocate(10); + int charsRead = buffer.read(target); + assertThat(charsRead, is(5)); + assertThat(target.get(0), is('T')); + assertThat(target.get(4), is('M')); + assertThat(target.get(5), is('\0')); + } + + @Test + public void readsCharsToSmallBuffer() throws IOException { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + CharBuffer target = CharBuffer.allocate(2); + int charsRead = buffer.read(target); + assertThat(charsRead, is(2)); + assertThat(target.get(0), is('T')); + assertThat(target.get(1), is('e')); + } + + @Test + public void readsCharsToEmptyBuffer() throws IOException { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + CharBuffer target = CharBuffer.allocate(2); + target.position(2); + int charsRead = buffer.read(target); + assertThat(charsRead, is(0)); + } + + @Test + public void readsCharsFromEmptyBuffer() throws IOException { + char[] array = { 'T', 'e', 'a', 'V', 'M' }; + CharBuffer buffer = CharBuffer.wrap(array); + CharBuffer target = CharBuffer.allocate(2); + buffer.position(5); + int charsRead = buffer.read(target); + assertThat(charsRead, is(-1)); + } + + @Test + public void wrapsCharSequence() { + CharBuffer buffer = CharBuffer.wrap("TeaVM", 2, 4); + assertThat(buffer.capacity(), is(5)); + assertThat(buffer.limit(), is(4)); + assertThat(buffer.position(), is(2)); + } + + @Test + public void putsString() { + CharBuffer buffer = CharBuffer.allocate(100); + buffer.put("TeaVM"); + assertThat(buffer.flip().toString(), is("TeaVM")); + } +}