Skip to content

Commit 6615542

Browse files
dfa1claude
andcommitted
test(varbin): add VarBinArray unit tests
Covers Regular and Dict modes: getBytes, getByteLength, forEachByteLength, empty array, and error cases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3082745 commit 6615542

1 file changed

Lines changed: 210 additions & 0 deletions

File tree

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package io.github.dfa1.vortex.core.array;
2+
3+
import io.github.dfa1.vortex.core.ArrayStats;
4+
import io.github.dfa1.vortex.core.DType;
5+
import io.github.dfa1.vortex.core.PType;
6+
import org.junit.jupiter.api.Nested;
7+
import org.junit.jupiter.api.Test;
8+
9+
import java.lang.foreign.MemorySegment;
10+
import java.nio.ByteBuffer;
11+
import java.nio.ByteOrder;
12+
import java.nio.charset.StandardCharsets;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
16+
import static org.assertj.core.api.Assertions.assertThat;
17+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
18+
19+
class VarBinArrayTest {
20+
21+
private static final DType UTF8 = new DType.Utf8(false);
22+
23+
@Nested
24+
class Regular {
25+
26+
@Test
27+
void length_returnsElementCount() {
28+
// Given
29+
VarBinArray sut = of("a", "bb", "ccc");
30+
31+
// When / Then
32+
assertThat(sut.length()).isEqualTo(3L);
33+
}
34+
35+
@Test
36+
void dtype_returnsConstructedDtype() {
37+
// Given
38+
VarBinArray sut = of("x");
39+
40+
// When / Then
41+
assertThat(sut.dtype()).isEqualTo(UTF8);
42+
}
43+
44+
@Test
45+
void getBytes_returnsCorrectBytes() {
46+
// Given
47+
VarBinArray sut = of("hello", "world");
48+
49+
// When / Then
50+
assertThat(new String(sut.getBytes(0), StandardCharsets.UTF_8)).isEqualTo("hello");
51+
assertThat(new String(sut.getBytes(1), StandardCharsets.UTF_8)).isEqualTo("world");
52+
}
53+
54+
@Test
55+
void getByteLength_returnsCorrectLengths() {
56+
// Given
57+
VarBinArray sut = of("hi", "there", "!");
58+
59+
// When / Then
60+
assertThat(sut.getByteLength(0)).isEqualTo(2);
61+
assertThat(sut.getByteLength(1)).isEqualTo(5);
62+
assertThat(sut.getByteLength(2)).isEqualTo(1);
63+
}
64+
65+
@Test
66+
void forEachByteLength_visitsAllLengths() {
67+
// Given
68+
VarBinArray sut = of("ab", "c", "def");
69+
List<Integer> lengths = new ArrayList<>();
70+
71+
// When
72+
sut.forEachByteLength(lengths::add);
73+
74+
// Then
75+
assertThat(lengths).containsExactly(2, 1, 3);
76+
}
77+
78+
@Test
79+
void getBytes_emptyString_returnsEmptyArray() {
80+
// Given
81+
VarBinArray sut = of("", "x", "");
82+
83+
// When / Then
84+
assertThat(sut.getBytes(0)).isEmpty();
85+
assertThat(sut.getByteLength(0)).isZero();
86+
assertThat(sut.getByteLength(2)).isZero();
87+
}
88+
89+
@Test
90+
void empty_zeroElements() {
91+
// Given
92+
VarBinArray sut = of();
93+
94+
// When / Then
95+
assertThat(sut.length()).isZero();
96+
}
97+
98+
@Test
99+
void buffer_invalidIndex_throws() {
100+
// Given
101+
VarBinArray sut = of("a");
102+
103+
// When / Then
104+
assertThatThrownBy(() -> sut.buffer(1))
105+
.isInstanceOf(IndexOutOfBoundsException.class);
106+
}
107+
108+
@Test
109+
void child_invalidIndex_throws() {
110+
// Given
111+
VarBinArray sut = of("a");
112+
113+
// When / Then
114+
assertThatThrownBy(() -> sut.child(1))
115+
.isInstanceOf(IndexOutOfBoundsException.class);
116+
}
117+
}
118+
119+
@Nested
120+
class Dict {
121+
122+
@Test
123+
void getBytes_resolvesViaDict() {
124+
// Given — dict=["foo","bar"], codes=[1,0,1]
125+
VarBinArray sut = ofDict(new String[]{"foo", "bar"}, new int[]{1, 0, 1});
126+
127+
// When / Then
128+
assertThat(new String(sut.getBytes(0), StandardCharsets.UTF_8)).isEqualTo("bar");
129+
assertThat(new String(sut.getBytes(1), StandardCharsets.UTF_8)).isEqualTo("foo");
130+
assertThat(new String(sut.getBytes(2), StandardCharsets.UTF_8)).isEqualTo("bar");
131+
}
132+
133+
@Test
134+
void getByteLength_resolvesViaDict() {
135+
// Given — dict=["hi","there"], codes=[0,1,0]
136+
VarBinArray sut = ofDict(new String[]{"hi", "there"}, new int[]{0, 1, 0});
137+
138+
// When / Then
139+
assertThat(sut.getByteLength(0)).isEqualTo(2);
140+
assertThat(sut.getByteLength(1)).isEqualTo(5);
141+
assertThat(sut.getByteLength(2)).isEqualTo(2);
142+
}
143+
144+
@Test
145+
void forEachByteLength_resolvesViaDict() {
146+
// Given
147+
VarBinArray sut = ofDict(new String[]{"a", "bbb"}, new int[]{1, 0, 1});
148+
List<Integer> lengths = new ArrayList<>();
149+
150+
// When
151+
sut.forEachByteLength(lengths::add);
152+
153+
// Then
154+
assertThat(lengths).containsExactly(3, 1, 3);
155+
}
156+
157+
@Test
158+
void child_inDictMode_throws() {
159+
// Given
160+
VarBinArray sut = ofDict(new String[]{"x"}, new int[]{0});
161+
162+
// When / Then
163+
assertThatThrownBy(() -> sut.child(0))
164+
.isInstanceOf(IllegalStateException.class);
165+
}
166+
167+
private static VarBinArray ofDict(String[] dictValues, int[] codes) {
168+
byte[] allBytes = String.join("", dictValues).getBytes(StandardCharsets.UTF_8);
169+
MemorySegment dictValBytes = MemorySegment.ofArray(allBytes);
170+
171+
int[] offs = new int[dictValues.length + 1];
172+
for (int i = 0; i < dictValues.length; i++) {
173+
offs[i + 1] = offs[i] + dictValues[i].getBytes(StandardCharsets.UTF_8).length;
174+
}
175+
MemorySegment dictValOffsets = leInts(offs);
176+
177+
MemorySegment dictCodes = leInts(codes);
178+
179+
return VarBinArray.ofDict(UTF8, codes.length,
180+
dictValBytes, dictValOffsets, PType.I32,
181+
dictCodes, PType.I32, ArrayStats.empty());
182+
}
183+
184+
private static MemorySegment leInts(int[] values) {
185+
ByteBuffer bb = ByteBuffer.allocate(values.length * 4).order(ByteOrder.LITTLE_ENDIAN);
186+
for (int v : values) {
187+
bb.putInt(v);
188+
}
189+
return MemorySegment.ofArray(bb.array());
190+
}
191+
}
192+
193+
private static VarBinArray of(String... values) {
194+
byte[] allBytes = String.join("", values).getBytes(StandardCharsets.UTF_8);
195+
MemorySegment bytes = MemorySegment.ofArray(allBytes);
196+
197+
int[] offs = new int[values.length + 1];
198+
for (int i = 0; i < values.length; i++) {
199+
offs[i + 1] = offs[i] + values[i].getBytes(StandardCharsets.UTF_8).length;
200+
}
201+
ByteBuffer bb = ByteBuffer.allocate(offs.length * 4).order(ByteOrder.LITTLE_ENDIAN);
202+
for (int o : offs) {
203+
bb.putInt(o);
204+
}
205+
MemorySegment offsetsSeg = MemorySegment.ofArray(bb.array());
206+
DType i32 = new DType.Primitive(PType.I32, false);
207+
IntArray offsetsArr = new IntArray(i32, offs.length, offsetsSeg, ArrayStats.empty());
208+
return new VarBinArray(UTF8, values.length, bytes, offsetsArr, PType.I32, ArrayStats.empty());
209+
}
210+
}

0 commit comments

Comments
 (0)