Skip to content

Commit 9358d18

Browse files
dfa1claude
andauthored
refactor(test): extract shared ZstdTestSupport, dedup helpers (#40)
Pull duplicated unit-test helpers into a package-private ZstdTestSupport: segmentOf(Arena,byte[]), bytesOf(MemorySegment,long/int), and trainDictionary(int) (one sample schema, caller-chosen count). Hoist the byte-for-byte nativeDict(...) duplicate in ZstdDictionaryTest up to the outer class. Update ZstdSegment/SegmentStream/RefPrefix/Stream/Frame/Memory tests to use it. Test-only: no production change, no assertions changed, counts preserved (3000/2000). 261 tests pass, checkstyle clean. ~67 lines removed. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2689697 commit 9358d18

8 files changed

Lines changed: 103 additions & 119 deletions

File tree

zstd/src/test/java/io/github/dfa1/zstd/RefPrefixTest.java

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.dfa1.zstd;
22

3-
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
3+
import static io.github.dfa1.zstd.ZstdTestSupport.bytesOf;
4+
import static io.github.dfa1.zstd.ZstdTestSupport.segmentOf;
45
import static org.assertj.core.api.Assertions.assertThat;
56
import static org.assertj.core.api.Assertions.assertThatThrownBy;
67

@@ -21,8 +22,8 @@ void roundTripsWithMatchingPrefix() {
2122
try (Arena arena = Arena.ofConfined();
2223
ZstdCompressCtx cctx = new ZstdCompressCtx();
2324
ZstdDecompressCtx dctx = new ZstdDecompressCtx()) {
24-
MemorySegment prefix = copy(arena, prefixBytes);
25-
MemorySegment src = copy(arena, dataBytes);
25+
MemorySegment prefix = segmentOf(arena, prefixBytes);
26+
MemorySegment src = segmentOf(arena, dataBytes);
2627
MemorySegment frame = arena.allocate(Zstd.compressBound(dataBytes.length));
2728
MemorySegment out = arena.allocate(dataBytes.length);
2829

@@ -34,7 +35,7 @@ void roundTripsWithMatchingPrefix() {
3435

3536
// Then
3637
assertThat(m).isEqualTo(dataBytes.length);
37-
assertThat(bytes(out, (int) m)).isEqualTo(dataBytes);
38+
assertThat(bytesOf(out, (int) m)).isEqualTo(dataBytes);
3839
}
3940
}
4041

@@ -47,8 +48,8 @@ void prefixIsAppliedAndRequiredToDecode() {
4748
// for random content.)
4849
byte[] random = randomBytes(0xBEEF, 16384);
4950
try (Arena arena = Arena.ofConfined()) {
50-
MemorySegment prefix = copy(arena, random);
51-
MemorySegment src = copy(arena, random);
51+
MemorySegment prefix = segmentOf(arena, random);
52+
MemorySegment src = segmentOf(arena, random);
5253

5354
long baseline;
5455
try (ZstdCompressCtx cctx = new ZstdCompressCtx().level(19)) {
@@ -58,7 +59,7 @@ void prefixIsAppliedAndRequiredToDecode() {
5859
try (ZstdCompressCtx cctx = new ZstdCompressCtx().level(19)) {
5960
cctx.refPrefix(prefix);
6061
MemorySegment f = cctx.compress(arena, src);
61-
frame = bytes(f, (int) f.byteSize());
62+
frame = bytesOf(f, (int) f.byteSize());
6263
}
6364

6465
// Then — the prefix slashes the frame (16 KiB random → tens of bytes)
@@ -68,16 +69,16 @@ void prefixIsAppliedAndRequiredToDecode() {
6869
try (ZstdDecompressCtx dctx = new ZstdDecompressCtx()) {
6970
MemorySegment out = arena.allocate(random.length);
7071
dctx.refPrefix(prefix);
71-
long m = dctx.decompress(out, copy(arena, frame));
72-
assertThat(bytes(out, (int) m)).isEqualTo(random);
72+
long m = dctx.decompress(out, segmentOf(arena, frame));
73+
assertThat(bytesOf(out, (int) m)).isEqualTo(random);
7374
}
7475

7576
// But — it cannot be recovered without the prefix
7677
boolean reproduced;
7778
try (ZstdDecompressCtx dctx = new ZstdDecompressCtx()) {
7879
MemorySegment out = arena.allocate(random.length);
79-
long m = dctx.decompress(out, copy(arena, frame));
80-
reproduced = Arrays.equals(bytes(out, (int) m), random);
80+
long m = dctx.decompress(out, segmentOf(arena, frame));
81+
reproduced = Arrays.equals(bytesOf(out, (int) m), random);
8182
} catch (ZstdException e) {
8283
reproduced = false;
8384
}
@@ -91,8 +92,8 @@ void clearingPrefixWithNullCompressesPlainly() {
9192
byte[] dataBytes = "the quick brown fox".getBytes();
9293
try (Arena arena = Arena.ofConfined();
9394
ZstdCompressCtx cctx = new ZstdCompressCtx()) {
94-
MemorySegment prefix = copy(arena, "a prior version of the text".getBytes());
95-
MemorySegment src = copy(arena, dataBytes);
95+
MemorySegment prefix = segmentOf(arena, "a prior version of the text".getBytes());
96+
MemorySegment src = segmentOf(arena, dataBytes);
9697
MemorySegment frame = arena.allocate(Zstd.compressBound(dataBytes.length));
9798

9899
// When — set then clear the prefix before compressing
@@ -105,7 +106,7 @@ void clearingPrefixWithNullCompressesPlainly() {
105106
try (ZstdDecompressCtx dctx = new ZstdDecompressCtx()) {
106107
MemorySegment out = arena.allocate(dataBytes.length);
107108
long m = dctx.decompress(out, frame.asSlice(0, n));
108-
restored = bytes(out, (int) m);
109+
restored = bytesOf(out, (int) m);
109110
}
110111
assertThat(restored).isEqualTo(dataBytes);
111112
}
@@ -118,8 +119,8 @@ void prefixIsSingleUseAndDoesNotStickAcrossFrames() {
118119
byte[] random = randomBytes(0xCAFE, 16384);
119120
try (Arena arena = Arena.ofConfined();
120121
ZstdCompressCtx cctx = new ZstdCompressCtx().level(19)) {
121-
MemorySegment prefix = copy(arena, random);
122-
MemorySegment src = copy(arena, random);
122+
MemorySegment prefix = segmentOf(arena, random);
123+
MemorySegment src = segmentOf(arena, random);
123124
MemorySegment first = arena.allocate(Zstd.compressBound(random.length));
124125
MemorySegment second = arena.allocate(Zstd.compressBound(random.length));
125126

@@ -137,7 +138,7 @@ void prefixIsSingleUseAndDoesNotStickAcrossFrames() {
137138
try (ZstdDecompressCtx dctx = new ZstdDecompressCtx()) {
138139
MemorySegment out = arena.allocate(random.length);
139140
long m = dctx.decompress(out, second.asSlice(0, n2));
140-
restored = bytes(out, (int) m);
141+
restored = bytesOf(out, (int) m);
141142
}
142143
assertThat(restored).isEqualTo(random);
143144
}
@@ -221,7 +222,7 @@ void refPrefixReturnsTheSameContextForChaining() {
221222
try (Arena arena = Arena.ofConfined();
222223
ZstdCompressCtx cctx = new ZstdCompressCtx();
223224
ZstdDecompressCtx dctx = new ZstdDecompressCtx()) {
224-
MemorySegment prefix = copy(arena, "a prior version".getBytes());
225+
MemorySegment prefix = segmentOf(arena, "a prior version".getBytes());
225226

226227
// When setting and then clearing a prefix on both contexts
227228
ZstdCompressCtx cSet = cctx.refPrefix(prefix);
@@ -243,7 +244,7 @@ void loadDictionaryFromSegmentReturnsTheSameContextForChaining() {
243244
try (Arena arena = Arena.ofConfined();
244245
ZstdCompressCtx cctx = new ZstdCompressCtx();
245246
ZstdDecompressCtx dctx = new ZstdDecompressCtx()) {
246-
MemorySegment dict = copy(arena, "dictionary sample payload ".repeat(64).getBytes());
247+
MemorySegment dict = segmentOf(arena, "dictionary sample payload ".repeat(64).getBytes());
247248

248249
// When loading and then clearing a segment dictionary on both contexts
249250
ZstdCompressCtx cSet = cctx.loadDictionary(dict);
@@ -259,18 +260,6 @@ void loadDictionaryFromSegmentReturnsTheSameContextForChaining() {
259260
}
260261
}
261262

262-
private static MemorySegment copy(Arena arena, byte[] src) {
263-
MemorySegment seg = arena.allocate(src.length);
264-
MemorySegment.copy(src, 0, seg, JAVA_BYTE, 0, src.length);
265-
return seg;
266-
}
267-
268-
private static byte[] bytes(MemorySegment seg, int len) {
269-
byte[] out = new byte[len];
270-
MemorySegment.copy(seg, JAVA_BYTE, 0, out, 0, len);
271-
return out;
272-
}
273-
274263
private static byte[] randomBytes(long seed, int n) {
275264
byte[] b = new byte[n];
276265
new Random(seed).nextBytes(b);

zstd/src/test/java/io/github/dfa1/zstd/ZstdDictionaryTest.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -429,12 +429,6 @@ void rejectsHeapCompressDictSegment() {
429429
// Then it fails fast
430430
assertThatThrownBy(result).isInstanceOf(IllegalArgumentException.class);
431431
}
432-
433-
private MemorySegment nativeDict(Arena arena, byte[] raw) {
434-
MemorySegment seg = arena.allocate(raw.length);
435-
MemorySegment.copy(raw, 0, seg, ValueLayout.JAVA_BYTE, 0, raw.length);
436-
return seg;
437-
}
438432
}
439433

440434
@Nested
@@ -614,12 +608,6 @@ void loadAndRefReturnTheSameDecompressContext() {
614608
assertThat(dctx.refDictionary(null)).isSameAs(dctx);
615609
}
616610
}
617-
618-
private MemorySegment nativeDict(Arena arena, byte[] raw) {
619-
MemorySegment seg = arena.allocate(raw.length);
620-
MemorySegment.copy(raw, 0, seg, ValueLayout.JAVA_BYTE, 0, raw.length);
621-
return seg;
622-
}
623611
}
624612

625613
private static byte[] record(int i) {
@@ -629,4 +617,10 @@ private static byte[] record(int i) {
629617
+ ",\"score\":" + (i * 7 % 1000)
630618
+ ",\"tag\":\"event\"}").getBytes(StandardCharsets.UTF_8);
631619
}
620+
621+
private static MemorySegment nativeDict(Arena arena, byte[] raw) {
622+
MemorySegment seg = arena.allocate(raw.length);
623+
MemorySegment.copy(raw, 0, seg, ValueLayout.JAVA_BYTE, 0, raw.length);
624+
return seg;
625+
}
632626
}

zstd/src/test/java/io/github/dfa1/zstd/ZstdFrameTest.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@
99
import java.lang.foreign.MemorySegment;
1010
import java.lang.foreign.ValueLayout;
1111
import java.nio.charset.StandardCharsets;
12-
import java.util.ArrayList;
1312
import java.util.Arrays;
14-
import java.util.List;
1513

14+
import static io.github.dfa1.zstd.ZstdTestSupport.trainDictionary;
1615
import static org.assertj.core.api.Assertions.assertThat;
1716
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1817

@@ -409,11 +408,7 @@ void matchesThroughTheSegmentOverload() {
409408
}
410409

411410
private ZstdDictionary trainDict() {
412-
List<byte[]> samples = new ArrayList<>();
413-
for (int i = 0; i < 3000; i++) {
414-
samples.add(("{\"id\":" + i + ",\"k\":\"v" + (i % 30) + "\"}").getBytes(StandardCharsets.UTF_8));
415-
}
416-
return ZstdDictionary.train(samples, 8 * 1024);
411+
return trainDictionary(3000);
417412
}
418413
}
419414

zstd/src/test/java/io/github/dfa1/zstd/ZstdMemoryTest.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
import org.junit.jupiter.api.Test;
55

66
import java.nio.charset.StandardCharsets;
7-
import java.util.ArrayList;
8-
import java.util.List;
97

8+
import static io.github.dfa1.zstd.ZstdTestSupport.trainDictionary;
109
import static org.assertj.core.api.Assertions.assertThat;
1110

1211
class ZstdMemoryTest {
@@ -76,11 +75,7 @@ void streamsReportContextSize() {
7675
}
7776

7877
private ZstdDictionary trainDict() {
79-
List<byte[]> samples = new ArrayList<>();
80-
for (int i = 0; i < 2000; i++) {
81-
samples.add(("{\"id\":" + i + ",\"k\":\"v" + (i % 20) + "\"}").getBytes(StandardCharsets.UTF_8));
82-
}
83-
return ZstdDictionary.train(samples, 8 * 1024);
78+
return trainDictionary(2000);
8479
}
8580
}
8681
}

zstd/src/test/java/io/github/dfa1/zstd/ZstdSegmentStreamTest.java

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
import java.lang.foreign.Arena;
88
import java.lang.foreign.MemorySegment;
99
import java.nio.charset.StandardCharsets;
10-
import java.util.ArrayList;
11-
import java.util.List;
1210
import java.util.Random;
1311

14-
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
12+
import static io.github.dfa1.zstd.ZstdTestSupport.bytesOf;
13+
import static io.github.dfa1.zstd.ZstdTestSupport.segmentOf;
14+
import static io.github.dfa1.zstd.ZstdTestSupport.trainDictionary;
1515
import static org.assertj.core.api.Assertions.assertThat;
1616

1717
class ZstdSegmentStreamTest {
@@ -26,7 +26,7 @@ void roundTripsInOneCallEach() {
2626
ZstdCompressStream cs = new ZstdCompressStream();
2727
ZstdDecompressStream ds = new ZstdDecompressStream()) {
2828

29-
MemorySegment src = segment(arena, original);
29+
MemorySegment src = segmentOf(arena, original);
3030
MemorySegment dst = arena.allocate(Zstd.compressBound(original.length));
3131

3232
// When compressed in one END step
@@ -42,7 +42,7 @@ void roundTripsInOneCallEach() {
4242

4343
assertThat(d.isComplete()).isTrue();
4444
assertThat(d.bytesProduced()).isEqualTo(original.length);
45-
assertThat(bytes(out, d.bytesProduced())).isEqualTo(original);
45+
assertThat(bytesOf(out, d.bytesProduced())).isEqualTo(original);
4646
}
4747
}
4848
}
@@ -71,7 +71,7 @@ private byte[] drive(byte[] input, int chunk, boolean compress) {
7171
ZstdCompressStream cs = compress ? new ZstdCompressStream() : null;
7272
ZstdDecompressStream ds = compress ? null : new ZstdDecompressStream()) {
7373

74-
MemorySegment src = segment(arena, input);
74+
MemorySegment src = segmentOf(arena, input);
7575
MemorySegment dst = arena.allocate(chunk);
7676
long srcOff = 0;
7777
ZstdStreamResult r;
@@ -81,7 +81,7 @@ private byte[] drive(byte[] input, int chunk, boolean compress) {
8181
? cs.compress(dst, srcSlice, ZstdEndDirective.END)
8282
: ds.decompress(dst, srcSlice);
8383
srcOff += r.bytesConsumed();
84-
collected.writeBytes(bytes(dst, r.bytesProduced()));
84+
collected.writeBytes(bytesOf(dst, r.bytesProduced()));
8585
} while (!r.isComplete());
8686
return collected.toByteArray();
8787
}
@@ -97,7 +97,7 @@ void tracksByteCounters() {
9797
try (Arena arena = Arena.ofConfined();
9898
ZstdCompressStream cs = new ZstdCompressStream()) {
9999

100-
MemorySegment src = segment(arena, original);
100+
MemorySegment src = segmentOf(arena, original);
101101
MemorySegment dst = arena.allocate(Zstd.compressBound(original.length));
102102

103103
// fresh stream: nothing moved yet
@@ -127,35 +127,18 @@ void roundTripsAgainstDictionary() {
127127
ZstdCompressStream cs = new ZstdCompressStream(3, dict);
128128
ZstdDecompressStream ds = new ZstdDecompressStream(dict)) {
129129

130-
MemorySegment src = segment(arena, record);
130+
MemorySegment src = segmentOf(arena, record);
131131
MemorySegment dst = arena.allocate(Zstd.compressBound(record.length));
132132
ZstdStreamResult c = cs.compress(dst, src, ZstdEndDirective.END);
133133

134134
MemorySegment out = arena.allocate(record.length);
135135
ds.decompress(out, dst.asSlice(0, c.bytesProduced()));
136-
assertThat(bytes(out, record.length)).isEqualTo(record);
136+
assertThat(bytesOf(out, record.length)).isEqualTo(record);
137137
}
138138
}
139139

140140
private ZstdDictionary trainDict() {
141-
List<byte[]> samples = new ArrayList<>();
142-
for (int i = 0; i < 3000; i++) {
143-
samples.add(("{\"id\":" + i + ",\"user\":\"u" + (i % 30) + "\",\"event\":\"x\"}")
144-
.getBytes(StandardCharsets.UTF_8));
145-
}
146-
return ZstdDictionary.train(samples, 8 * 1024);
141+
return trainDictionary(3000);
147142
}
148143
}
149-
150-
private static MemorySegment segment(Arena arena, byte[] bytes) {
151-
MemorySegment seg = arena.allocate(Math.max(bytes.length, 1));
152-
MemorySegment.copy(bytes, 0, seg, JAVA_BYTE, 0, bytes.length);
153-
return seg;
154-
}
155-
156-
private static byte[] bytes(MemorySegment seg, long len) {
157-
byte[] out = new byte[Math.toIntExact(len)];
158-
MemorySegment.copy(seg, JAVA_BYTE, 0, out, 0, out.length);
159-
return out;
160-
}
161144
}

0 commit comments

Comments
 (0)