Skip to content

Commit 96a8dd5

Browse files
authored
Merge pull request #280 from scijava/bytebank-tests
Bytebank tests and bugfixes
2 parents fde1871 + 66af2f6 commit 96a8dd5

File tree

7 files changed

+252
-9
lines changed

7 files changed

+252
-9
lines changed

src/main/java/org/scijava/io/ByteArrayByteBank.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public ByteArrayByteBank(final int initialCapacity) {
6868
*/
6969
public ByteArrayByteBank(final ByteArray bytes) {
7070
buffer = bytes;
71-
bytes.size();
71+
maxBufferedPos = bytes.size();
7272
}
7373

7474
/**
@@ -98,12 +98,17 @@ public void setBytes(final long startpos, final byte[] bytes,
9898
// copy the data
9999
System.arraycopy(bytes, offset, buffer.getArray(), (int) startpos, length);
100100
buffer.setSize(neededCapacity);
101-
updateMaxPos(startpos + length);
101+
updateMaxPos(startpos + length - 1);
102102
}
103103

104104
@Override
105105
public void setByte(final long pos, final byte b) {
106106
checkWritePos(pos, pos);
107+
buffer.ensureCapacity((int) pos);
108+
// NB: update the size of the underlying buffer before appending to it
109+
if (pos == buffer.size()) {
110+
buffer.setSize((int) (pos + 1));
111+
}
107112
buffer.setValue((int) pos, b);
108113
updateMaxPos(pos);
109114
}
@@ -131,7 +136,8 @@ public int getBytes(final long startPos, final byte[] b, final int offset,
131136
final int length)
132137
{
133138
checkReadPos(startPos, startPos + length);
134-
final int readLength = (int) Math.min(getMaxPos() - startPos, length);
139+
// ensure we don't try to read data which is not in the buffer
140+
final int readLength = (int) Math.min(getMaxPos() - startPos + 1, length);
135141
System.arraycopy(buffer.getArray(), (int) startPos, b, offset, readLength);
136142
return readLength;
137143
}

src/main/java/org/scijava/io/ByteBank.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,18 @@ default int getBytes(long startPos, byte[] bytes) {
8080
* @param length the number of elements to append from the bytes array
8181
*/
8282
default void appendBytes(byte[] bytes, int length) {
83-
setBytes(getMaxPos() + 1, bytes, 0, length);
83+
appendBytes(bytes, 0, length);
84+
}
85+
86+
/**
87+
* Appends the given bytes to the buffer
88+
*
89+
* @param bytes the array containing the bytes to append to the buffer
90+
* @param offset the offset in the bytes array
91+
* @param length the number of elements to append from the bytes array
92+
*/
93+
default void appendBytes(byte[] bytes, int offset, int length) {
94+
setBytes(getMaxPos() + 1, bytes, offset, length);
8495
}
8596

8697
/**

src/main/java/org/scijava/io/nio/ByteBufferByteBank.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,15 @@ public void setBytes(final long startpos, final byte[] bytes,
9393
buffer.put(bytes, offset, length);
9494

9595
// update the maxpos
96-
updateMaxPos(startpos + length);
96+
updateMaxPos(startpos + length - 1);
9797
}
9898

9999
@Override
100100
public void setByte(final long pos, final byte b) {
101101
checkWritePos(pos, pos);
102+
if (pos == buffer.capacity()) {
103+
ensureCapacity((int) pos + 1);
104+
}
102105
buffer.put((int) pos, b);
103106
updateMaxPos(pos);
104107
}
@@ -127,10 +130,12 @@ public int getBytes(final long startPos, final byte[] b, final int offset,
127130
final int length)
128131
{
129132
checkReadPos(startPos, startPos + length);
133+
// ensure we don't try to read data which is not in the buffer
134+
final int readLength = (int) Math.min(getMaxPos() - startPos + 1, length);
130135
buffer.position((int) startPos);
131-
buffer.get(b, offset, length);
136+
buffer.get(b, offset, readLength);
132137

133-
return length;
138+
return readLength;
134139
}
135140

136141
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2016 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.io;
33+
34+
/**
35+
* Tests {@link ByteArrayByteBank}
36+
*
37+
* @author Gabriel Einsdorf
38+
* @see ByteBankTest
39+
*/
40+
public class ByteArrayByteBankTest extends ByteBankTest {
41+
42+
@Override
43+
public ByteBank createByteBank() {
44+
return new ByteArrayByteBank();
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2016 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.io;
33+
34+
import static org.junit.Assert.assertArrayEquals;
35+
import static org.junit.Assert.assertEquals;
36+
37+
import org.junit.Before;
38+
import org.junit.Test;
39+
40+
/**
41+
* Abstract superclass for testing {@link ByteBank} implementations.
42+
*
43+
* @author Gabriel Einsdorf
44+
*/
45+
public abstract class ByteBankTest {
46+
47+
private static byte[] testBytes = { 0, -1, 2, -3, 4, 120, -128, 127, 32, 42 };
48+
private ByteBank bank;
49+
50+
/**
51+
* @return the ByteBank implementation to test
52+
*/
53+
public abstract ByteBank createByteBank();
54+
55+
@Before
56+
public void setup() {
57+
bank = createByteBank();
58+
}
59+
60+
@Test
61+
public void testSetGetBytesArray() {
62+
// read in full array
63+
bank.setBytes(0l, testBytes.clone(), 0, testBytes.length);
64+
65+
// read out full array
66+
assertEqualRead(testBytes.length, 0);
67+
assertEqualRead(testBytes.length - 4, 2);
68+
}
69+
70+
@Test
71+
public void testSetGetBytesPartialArray() {
72+
// read in the partial array
73+
bank.setBytes(0l, testBytes, 0, testBytes.length - 4);
74+
75+
// read out the partial array
76+
assertEqualRead(testBytes.length - 4, 0);
77+
assertEqualRead(testBytes.length - 4, 2);
78+
}
79+
80+
@Test
81+
public void testSetGetByte() {
82+
final int numElements = 200_000;
83+
for (int i = 0; i < numElements; i++) {
84+
bank.setByte(i, (byte) i);
85+
}
86+
87+
for (int i = 0; i < numElements; i++) {
88+
assertEquals((byte) i, bank.getByte(i));
89+
}
90+
}
91+
92+
@Test
93+
public void testClear() {
94+
bank.setBytes(0, testBytes, 0, testBytes.length);
95+
assertEquals(testBytes.length - 1, bank.getMaxPos());
96+
97+
bank.clear();
98+
assertEquals(0, bank.getMaxPos());
99+
}
100+
101+
@Test
102+
public void testAppendBytes() {
103+
// simple append
104+
bank.appendBytes(testBytes, testBytes.length);
105+
assertEqualRead(testBytes.length, 0);
106+
107+
// append to buffer that already contains data
108+
bank.clear();
109+
bank.setByte(0l, (byte) 42);
110+
bank.setByte(1l, (byte) 43);
111+
bank.appendBytes(testBytes, testBytes.length);
112+
113+
final byte[] expected = new byte[testBytes.length + 2];
114+
expected[0] = 42;
115+
expected[1] = 43;
116+
System.arraycopy(testBytes, 0, expected, 2, testBytes.length);
117+
118+
final byte[] actuals = new byte[expected.length];
119+
bank.getBytes(0, actuals);
120+
121+
assertArrayEquals(expected, actuals);
122+
}
123+
124+
/**
125+
* Asserts that {@link #bank} contains the same bytes as {@link #testBytes},
126+
* allows to specify an offset.
127+
*
128+
* @param length how many bytes (starting from the offset) of
129+
* {@link #testBytes} are tested, this allows to test partial reads.
130+
* @param offset the offset position
131+
*/
132+
private void assertEqualRead(final int length, final int offset) {
133+
// read from offset up to the length of the given array
134+
final byte[] bytes = new byte[length];
135+
final int read = bank.getBytes(offset, bytes);
136+
137+
final byte[] expected = new byte[length];
138+
System.arraycopy(testBytes, offset, expected, 0, read);
139+
assertArrayEquals(expected, bytes);
140+
141+
// read from offset to offset
142+
final byte[] offsetBytes = new byte[testBytes.length];
143+
final int readOffset = bank.getBytes(offset, offsetBytes, offset, length);
144+
145+
final byte[] offsetExpected = new byte[testBytes.length];
146+
System.arraycopy(testBytes, offset, offsetExpected, offset, readOffset);
147+
assertArrayEquals(expected, bytes);
148+
}
149+
}

src/test/java/org/scijava/io/location/BytesLocationTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void testBytesOffsetLength() {
6464

6565
final byte[] testDigits = new byte[digits.length];
6666
loc.getByteBank().getBytes(0, testDigits);
67-
assertEquals(length, loc.getByteBank().getMaxPos());
67+
assertEquals(length - 1, loc.getByteBank().getMaxPos());
6868

6969
final byte[] expectedDigits = new byte[digits.length];
7070
System.arraycopy(digits, offset, expectedDigits, 0, length);

src/test/java/org/scijava/io/nio/ByteBufferByteBankTest.java

+27-1
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,41 @@
3535
import static org.junit.Assert.assertTrue;
3636

3737
import java.nio.ByteBuffer;
38+
import java.util.function.Function;
3839

3940
import org.junit.Test;
41+
import org.junit.runner.RunWith;
42+
import org.junit.runners.Parameterized;
43+
import org.junit.runners.Parameterized.Parameter;
44+
import org.junit.runners.Parameterized.Parameters;
45+
import org.scijava.io.ByteBank;
46+
import org.scijava.io.ByteBankTest;
4047

4148
/**
4249
* Tests {@link ByteBufferByteBank}.
4350
*
4451
* @author Curtis Rueden
52+
* @author Gabriel Einsdorf
53+
* @see ByteBankTest
4554
*/
46-
public class ByteBufferByteBankTest {
55+
@RunWith(Parameterized.class)
56+
public class ByteBufferByteBankTest extends ByteBankTest {
57+
58+
@Parameter
59+
public Function<Integer, ByteBuffer> supplier;
60+
61+
@Parameters
62+
public static Object[] params() {
63+
final Function<Integer, ByteBuffer> alloc = ByteBuffer::allocate;
64+
final Function<Integer, ByteBuffer> allocDirect =
65+
ByteBuffer::allocateDirect;
66+
return new Function[] { alloc, allocDirect };
67+
}
68+
69+
@Override
70+
public ByteBank createByteBank() {
71+
return new ByteBufferByteBank(supplier);
72+
}
4773

4874
@Test
4975
public void testReadOnlyDefault() {

0 commit comments

Comments
 (0)