Skip to content

Commit 0ff4399

Browse files
dfa1claude
andcommitted
test(reader): full coverage for Dict*Array families
Extend DictRecordSmokeTest to 100% line + branch across DictLong/Int/Double/Float: - exercise getter, forEach, fold, and materialize for all four code widths (U8/U16/U32/U64), not just U8 - cover the defensive invalid-codes-type default arm on each bulk op via a direct (of()-bypassing) construction Reuses PTypeIO.LE_* layouts instead of redefining little-endian constants. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 819a8e3 commit 0ff4399

1 file changed

Lines changed: 184 additions & 0 deletions

File tree

reader/src/test/java/io/github/dfa1/vortex/reader/array/DictRecordSmokeTest.java

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
import io.github.dfa1.vortex.core.DType;
44
import io.github.dfa1.vortex.core.PType;
55
import io.github.dfa1.vortex.core.VortexException;
6+
import io.github.dfa1.vortex.encoding.PTypeIO;
67
import org.junit.jupiter.api.Nested;
78
import org.junit.jupiter.api.Test;
89

910
import java.lang.foreign.Arena;
1011
import java.lang.foreign.MemorySegment;
1112
import java.lang.foreign.ValueLayout;
1213
import java.util.ArrayList;
14+
import java.util.List;
1315

1416
import static org.assertj.core.api.Assertions.assertThat;
1517
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -155,6 +157,58 @@ void foldSumsThroughCodes() {
155157
assertThat(total).isEqualTo(6L);
156158
}
157159
}
160+
161+
@Test
162+
void allCodeTypes_getForEachFoldMaterialize() {
163+
try (Arena arena = Arena.ofConfined()) {
164+
// Given — same selection [2,0,1] expressed as U8/U16/U32/U64 codes
165+
LongArray values = longArray(arena, 100L, 200L, 300L);
166+
long[] expected = {300L, 100L, 200L};
167+
List<Array> codeVariants = List.of(
168+
byteArray(arena, (byte) 2, (byte) 0, (byte) 1),
169+
shortArray(arena, U16, (short) 2, (short) 0, (short) 1),
170+
intArray(arena, U32, 2, 0, 1),
171+
longArray(arena, U64, 2L, 0L, 1L));
172+
173+
for (Array codes : codeVariants) {
174+
DictLongArray sut = DictLongArray.of(I64, 3, values, codes);
175+
String label = codes.getClass().getSimpleName();
176+
177+
// getter
178+
for (int i = 0; i < 3; i++) {
179+
assertThat(sut.getLong(i)).as(label).isEqualTo(expected[i]);
180+
}
181+
// forEach
182+
var seen = new ArrayList<Long>();
183+
sut.forEachLong(seen::add);
184+
assertThat(seen).as(label).containsExactly(300L, 100L, 200L);
185+
// fold
186+
assertThat(sut.fold(0L, Long::sum)).as(label).isEqualTo(600L);
187+
// materialize
188+
MemorySegment m = sut.materialize(arena);
189+
for (int i = 0; i < 3; i++) {
190+
assertThat(m.getAtIndex(PTypeIO.LE_LONG, i)).as(label).isEqualTo(expected[i]);
191+
}
192+
}
193+
}
194+
}
195+
196+
@Test
197+
void bulkOps_invalidCodesType_throw() {
198+
// Given — a record built directly (bypassing of()) with a non-int codes array
199+
try (Arena arena = Arena.ofConfined()) {
200+
LongArray values = longArray(arena, 1L);
201+
DictLongArray sut = new DictLongArray(I64, 1, values, floatArray(arena, 0f));
202+
203+
// When / Then — every bulk path hits the defensive default arm
204+
assertThatThrownBy(() -> sut.materialize(arena))
205+
.isInstanceOf(VortexException.class).hasMessageContaining("invalid codes");
206+
assertThatThrownBy(() -> sut.forEachLong(v -> { }))
207+
.isInstanceOf(VortexException.class);
208+
assertThatThrownBy(() -> sut.fold(0L, Long::sum))
209+
.isInstanceOf(VortexException.class);
210+
}
211+
}
158212
}
159213

160214
@Nested
@@ -198,6 +252,51 @@ void foldThroughCodes() {
198252
assertThat(total).isEqualTo(11);
199253
}
200254
}
255+
256+
@Test
257+
void allCodeTypes_getForEachFoldMaterialize() {
258+
try (Arena arena = Arena.ofConfined()) {
259+
IntArray values = intArray(arena, I32, 100, 200, 300);
260+
int[] expected = {300, 100, 200};
261+
List<Array> codeVariants = List.of(
262+
byteArray(arena, (byte) 2, (byte) 0, (byte) 1),
263+
shortArray(arena, U16, (short) 2, (short) 0, (short) 1),
264+
intArray(arena, U32, 2, 0, 1),
265+
longArray(arena, U64, 2L, 0L, 1L));
266+
267+
for (Array codes : codeVariants) {
268+
DictIntArray sut = DictIntArray.of(I32, 3, values, codes);
269+
String label = codes.getClass().getSimpleName();
270+
271+
for (int i = 0; i < 3; i++) {
272+
assertThat(sut.getInt(i)).as(label).isEqualTo(expected[i]);
273+
}
274+
var seen = new ArrayList<Integer>();
275+
sut.forEachInt(seen::add);
276+
assertThat(seen).as(label).containsExactly(300, 100, 200);
277+
assertThat(sut.fold(0, Integer::sum)).as(label).isEqualTo(600);
278+
MemorySegment m = sut.materialize(arena);
279+
for (int i = 0; i < 3; i++) {
280+
assertThat(m.getAtIndex(PTypeIO.LE_INT, i)).as(label).isEqualTo(expected[i]);
281+
}
282+
}
283+
}
284+
}
285+
286+
@Test
287+
void bulkOps_invalidCodesType_throw() {
288+
try (Arena arena = Arena.ofConfined()) {
289+
IntArray values = intArray(arena, I32, 1);
290+
DictIntArray sut = new DictIntArray(I32, 1, values, floatArray(arena, 0f));
291+
292+
assertThatThrownBy(() -> sut.materialize(arena))
293+
.isInstanceOf(VortexException.class).hasMessageContaining("invalid codes");
294+
assertThatThrownBy(() -> sut.forEachInt(v -> { }))
295+
.isInstanceOf(VortexException.class);
296+
assertThatThrownBy(() -> sut.fold(0, Integer::sum))
297+
.isInstanceOf(VortexException.class);
298+
}
299+
}
201300
}
202301

203302
@Nested
@@ -241,6 +340,51 @@ void foldThroughCodes() {
241340
assertThat(total).isEqualTo(5.0);
242341
}
243342
}
343+
344+
@Test
345+
void allCodeTypes_getForEachFoldMaterialize() {
346+
try (Arena arena = Arena.ofConfined()) {
347+
DoubleArray values = doubleArray(arena, 1.5, 2.5, 3.5);
348+
double[] expected = {3.5, 1.5, 2.5};
349+
List<Array> codeVariants = List.of(
350+
byteArray(arena, (byte) 2, (byte) 0, (byte) 1),
351+
shortArray(arena, U16, (short) 2, (short) 0, (short) 1),
352+
intArray(arena, U32, 2, 0, 1),
353+
longArray(arena, U64, 2L, 0L, 1L));
354+
355+
for (Array codes : codeVariants) {
356+
DictDoubleArray sut = DictDoubleArray.of(F64, 3, values, codes);
357+
String label = codes.getClass().getSimpleName();
358+
359+
for (int i = 0; i < 3; i++) {
360+
assertThat(sut.getDouble(i)).as(label).isEqualTo(expected[i]);
361+
}
362+
var seen = new ArrayList<Double>();
363+
sut.forEachDouble(seen::add);
364+
assertThat(seen).as(label).containsExactly(3.5, 1.5, 2.5);
365+
assertThat(sut.fold(0.0, Double::sum)).as(label).isEqualTo(7.5);
366+
MemorySegment m = sut.materialize(arena);
367+
for (int i = 0; i < 3; i++) {
368+
assertThat(m.getAtIndex(PTypeIO.LE_DOUBLE, i)).as(label).isEqualTo(expected[i]);
369+
}
370+
}
371+
}
372+
}
373+
374+
@Test
375+
void bulkOps_invalidCodesType_throw() {
376+
try (Arena arena = Arena.ofConfined()) {
377+
DoubleArray values = doubleArray(arena, 1.0);
378+
DictDoubleArray sut = new DictDoubleArray(F64, 1, values, floatArray(arena, 0f));
379+
380+
assertThatThrownBy(() -> sut.materialize(arena))
381+
.isInstanceOf(VortexException.class).hasMessageContaining("invalid codes");
382+
assertThatThrownBy(() -> sut.forEachDouble(v -> { }))
383+
.isInstanceOf(VortexException.class);
384+
assertThatThrownBy(() -> sut.fold(0.0, Double::sum))
385+
.isInstanceOf(VortexException.class);
386+
}
387+
}
244388
}
245389

246390
@Nested
@@ -270,6 +414,46 @@ void foldThroughCodes() {
270414
assertThat(total).isEqualTo(3.5);
271415
}
272416
}
417+
418+
@Test
419+
void allCodeTypes_getFoldMaterialize() {
420+
try (Arena arena = Arena.ofConfined()) {
421+
FloatArray values = floatArray(arena, 1.5f, 2.5f, 3.5f);
422+
float[] expected = {3.5f, 1.5f, 2.5f};
423+
List<Array> codeVariants = List.of(
424+
byteArray(arena, (byte) 2, (byte) 0, (byte) 1),
425+
shortArray(arena, U16, (short) 2, (short) 0, (short) 1),
426+
intArray(arena, U32, 2, 0, 1),
427+
longArray(arena, U64, 2L, 0L, 1L));
428+
429+
for (Array codes : codeVariants) {
430+
DictFloatArray sut = DictFloatArray.of(F32, 3, values, codes);
431+
String label = codes.getClass().getSimpleName();
432+
433+
for (int i = 0; i < 3; i++) {
434+
assertThat(sut.getFloat(i)).as(label).isEqualTo(expected[i]);
435+
}
436+
assertThat(sut.fold(0.0, Double::sum)).as(label).isEqualTo(7.5);
437+
MemorySegment m = sut.materialize(arena);
438+
for (int i = 0; i < 3; i++) {
439+
assertThat(m.getAtIndex(PTypeIO.LE_FLOAT, i)).as(label).isEqualTo(expected[i]);
440+
}
441+
}
442+
}
443+
}
444+
445+
@Test
446+
void bulkOps_invalidCodesType_throw() {
447+
try (Arena arena = Arena.ofConfined()) {
448+
FloatArray values = floatArray(arena, 1.0f);
449+
DictFloatArray sut = new DictFloatArray(F32, 1, values, doubleArray(arena, 0.0));
450+
451+
assertThatThrownBy(() -> sut.materialize(arena))
452+
.isInstanceOf(VortexException.class).hasMessageContaining("invalid codes");
453+
assertThatThrownBy(() -> sut.fold(0.0, Double::sum))
454+
.isInstanceOf(VortexException.class);
455+
}
456+
}
273457
}
274458

275459
@Nested

0 commit comments

Comments
 (0)