Skip to content

Commit 06d1299

Browse files
dfa1claude
andcommitted
test(core): add unit tests for EncodingId and SequenceEncoding
EncodingIdTest: parameterized over all enum values — from() round-trip, unknown-id exception, id() non-blank, toString() == id(). SequenceEncodingTest: decode I64/I32/F64/F32 sequences (linear, constant, negative step, empty), plus error paths: missing metadata, F16, non-primitive dtype, encode() UnsupportedOperationException. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b10fa40 commit 06d1299

2 files changed

Lines changed: 251 additions & 0 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package io.github.dfa1.vortex.encoding;
2+
3+
import io.github.dfa1.vortex.core.VortexException;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.params.ParameterizedTest;
6+
import org.junit.jupiter.params.provider.EnumSource;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
10+
11+
class EncodingIdTest {
12+
13+
@ParameterizedTest
14+
@EnumSource(EncodingId.class)
15+
void from_knownId_roundTrips(EncodingId id) {
16+
// Given / When
17+
EncodingId result = EncodingId.from(id.id());
18+
19+
// Then
20+
assertThat(result).isSameAs(id);
21+
}
22+
23+
@Test
24+
void from_unknownId_throwsVortexException() {
25+
// Given / When / Then
26+
assertThatThrownBy(() -> EncodingId.from("vortex.does.not.exist"))
27+
.isInstanceOf(VortexException.class)
28+
.hasMessageContaining("vortex.does.not.exist");
29+
}
30+
31+
@ParameterizedTest
32+
@EnumSource(EncodingId.class)
33+
void id_isNonBlankString(EncodingId id) {
34+
// Given / When / Then
35+
assertThat(id.id()).isNotBlank();
36+
}
37+
38+
@ParameterizedTest
39+
@EnumSource(EncodingId.class)
40+
void toString_equalsId(EncodingId id) {
41+
// Given / When / Then
42+
assertThat(id.toString()).isEqualTo(id.id());
43+
}
44+
}
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package io.github.dfa1.vortex.encoding;
2+
3+
import dev.vortex.proto.EncodingProtos;
4+
import dev.vortex.proto.ScalarProtos;
5+
import io.github.dfa1.vortex.core.DType;
6+
import io.github.dfa1.vortex.core.PType;
7+
import io.github.dfa1.vortex.core.VortexException;
8+
import io.github.dfa1.vortex.core.array.Array;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.params.ParameterizedTest;
11+
import org.junit.jupiter.params.provider.Arguments;
12+
import org.junit.jupiter.params.provider.MethodSource;
13+
14+
import java.lang.foreign.Arena;
15+
import java.lang.foreign.MemorySegment;
16+
import java.nio.ByteBuffer;
17+
import java.util.stream.Stream;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
21+
22+
class SequenceEncodingTest {
23+
24+
private static final DType I64_DTYPE = new DType.Primitive(PType.I64, false);
25+
private static final DType I32_DTYPE = new DType.Primitive(PType.I32, false);
26+
private static final DType F64_DTYPE = new DType.Primitive(PType.F64, false);
27+
private static final DType F32_DTYPE = new DType.Primitive(PType.F32, false);
28+
29+
private static DecodeContext makeCtx(byte[] meta, DType dtype, long n) {
30+
ArrayNode node = new ArrayNode(
31+
EncodingId.VORTEX_SEQUENCE,
32+
ByteBuffer.wrap(meta),
33+
new ArrayNode[0], new int[0], null);
34+
return new DecodeContext(node, dtype, n, new MemorySegment[0], EncodingRegistry.empty(), Arena.ofAuto());
35+
}
36+
37+
private static byte[] intMeta(long base, long mul) {
38+
return EncodingProtos.SequenceMetadata.newBuilder()
39+
.setBase(ScalarProtos.ScalarValue.newBuilder().setInt64Value(base))
40+
.setMultiplier(ScalarProtos.ScalarValue.newBuilder().setInt64Value(mul))
41+
.build().toByteArray();
42+
}
43+
44+
private static byte[] f64Meta(double base, double mul) {
45+
return EncodingProtos.SequenceMetadata.newBuilder()
46+
.setBase(ScalarProtos.ScalarValue.newBuilder().setF64Value(base))
47+
.setMultiplier(ScalarProtos.ScalarValue.newBuilder().setF64Value(mul))
48+
.build().toByteArray();
49+
}
50+
51+
private static byte[] f32Meta(float base, float mul) {
52+
return EncodingProtos.SequenceMetadata.newBuilder()
53+
.setBase(ScalarProtos.ScalarValue.newBuilder().setF32Value(base))
54+
.setMultiplier(ScalarProtos.ScalarValue.newBuilder().setF32Value(mul))
55+
.build().toByteArray();
56+
}
57+
58+
@Test
59+
void encodingId_isVortexSequence() {
60+
// Given / When / Then
61+
assertThat(new SequenceEncoding().encodingId()).isEqualTo(EncodingId.VORTEX_SEQUENCE);
62+
}
63+
64+
@Test
65+
void encode_throwsUnsupportedOperationException() {
66+
// Given
67+
var sut = new SequenceEncoding();
68+
69+
// When / Then
70+
assertThatThrownBy(() -> sut.encode(I64_DTYPE, new long[]{1L}))
71+
.isInstanceOf(UnsupportedOperationException.class);
72+
}
73+
74+
static Stream<Arguments> i64Sequences() {
75+
return Stream.of(
76+
Arguments.of(0L, 1L, new long[]{0, 1, 2, 3, 4}),
77+
Arguments.of(10L, 2L, new long[]{10, 12, 14, 16}),
78+
Arguments.of(-5L, -1L, new long[]{-5, -6, -7}),
79+
Arguments.of(100L, 0L, new long[]{100, 100, 100}),
80+
Arguments.of(Long.MAX_VALUE, 0L, new long[]{Long.MAX_VALUE})
81+
);
82+
}
83+
84+
@ParameterizedTest
85+
@MethodSource("i64Sequences")
86+
void decode_i64_generatesCorrectSequence(long base, long mul, long[] expected) {
87+
// Given
88+
var sut = new SequenceEncoding();
89+
DecodeContext ctx = makeCtx(intMeta(base, mul), I64_DTYPE, expected.length);
90+
91+
// When
92+
Array result = sut.decode(ctx);
93+
94+
// Then
95+
assertThat(result.length()).isEqualTo(expected.length);
96+
for (int i = 0; i < expected.length; i++) {
97+
assertThat(result.getLong(i)).as("index %d", i).isEqualTo(expected[i]);
98+
}
99+
}
100+
101+
static Stream<Arguments> i32Sequences() {
102+
return Stream.of(
103+
Arguments.of(0L, 1L, new int[]{0, 1, 2, 3}),
104+
Arguments.of(100L, -10L, new int[]{100, 90, 80}),
105+
Arguments.of((long) Integer.MAX_VALUE, 0L, new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE})
106+
);
107+
}
108+
109+
@ParameterizedTest
110+
@MethodSource("i32Sequences")
111+
void decode_i32_generatesCorrectSequence(long base, long mul, int[] expected) {
112+
// Given
113+
var sut = new SequenceEncoding();
114+
DecodeContext ctx = makeCtx(intMeta(base, mul), I32_DTYPE, expected.length);
115+
116+
// When
117+
Array result = sut.decode(ctx);
118+
119+
// Then
120+
assertThat(result.length()).isEqualTo(expected.length);
121+
for (int i = 0; i < expected.length; i++) {
122+
assertThat(result.getInt(i)).as("index %d", i).isEqualTo(expected[i]);
123+
}
124+
}
125+
126+
@Test
127+
void decode_f64_generatesCorrectSequence() {
128+
// Given
129+
var sut = new SequenceEncoding();
130+
DecodeContext ctx = makeCtx(f64Meta(1.0, 0.5), F64_DTYPE, 4);
131+
132+
// When
133+
Array result = sut.decode(ctx);
134+
135+
// Then
136+
assertThat(result.length()).isEqualTo(4);
137+
assertThat(result.getDouble(0)).isEqualTo(1.0);
138+
assertThat(result.getDouble(1)).isEqualTo(1.5);
139+
assertThat(result.getDouble(2)).isEqualTo(2.0);
140+
assertThat(result.getDouble(3)).isEqualTo(2.5);
141+
}
142+
143+
@Test
144+
void decode_f32_generatesCorrectSequence() {
145+
// Given
146+
var sut = new SequenceEncoding();
147+
DecodeContext ctx = makeCtx(f32Meta(0.0f, 1.0f), F32_DTYPE, 3);
148+
149+
// When
150+
Array result = sut.decode(ctx);
151+
152+
// Then
153+
assertThat(result.length()).isEqualTo(3);
154+
assertThat(result.getFloat(0)).isEqualTo(0.0f);
155+
assertThat(result.getFloat(1)).isEqualTo(1.0f);
156+
assertThat(result.getFloat(2)).isEqualTo(2.0f);
157+
}
158+
159+
@Test
160+
void decode_emptySequence_returnsZeroLengthArray() {
161+
// Given
162+
var sut = new SequenceEncoding();
163+
DecodeContext ctx = makeCtx(intMeta(0, 1), I64_DTYPE, 0);
164+
165+
// When
166+
Array result = sut.decode(ctx);
167+
168+
// Then
169+
assertThat(result.length()).isZero();
170+
}
171+
172+
@Test
173+
void decode_missingMetadata_throwsVortexException() {
174+
// Given
175+
var sut = new SequenceEncoding();
176+
ArrayNode node = new ArrayNode(EncodingId.VORTEX_SEQUENCE, null, new ArrayNode[0], new int[0], null);
177+
DecodeContext ctx = new DecodeContext(node, I64_DTYPE, 3, new MemorySegment[0], EncodingRegistry.empty(), Arena.ofAuto());
178+
179+
// When / Then
180+
assertThatThrownBy(() -> sut.decode(ctx))
181+
.isInstanceOf(VortexException.class);
182+
}
183+
184+
@Test
185+
void decode_f16_throwsVortexException() {
186+
// Given
187+
var sut = new SequenceEncoding();
188+
DType f16 = new DType.Primitive(PType.F16, false);
189+
DecodeContext ctx = makeCtx(intMeta(0, 1), f16, 3);
190+
191+
// When / Then
192+
assertThatThrownBy(() -> sut.decode(ctx))
193+
.isInstanceOf(VortexException.class);
194+
}
195+
196+
@Test
197+
void decode_nonPrimitiveDtype_throwsVortexException() {
198+
// Given
199+
var sut = new SequenceEncoding();
200+
DType utf8 = new DType.Utf8(false);
201+
DecodeContext ctx = makeCtx(intMeta(0, 1), utf8, 3);
202+
203+
// When / Then
204+
assertThatThrownBy(() -> sut.decode(ctx))
205+
.isInstanceOf(VortexException.class);
206+
}
207+
}

0 commit comments

Comments
 (0)