Skip to content

Commit bce47a8

Browse files
dfa1claude
andauthored
test: golden-dictionaries dict interop coverage (#4)
Drive zstd's vendored golden-dictionaries corpus across the FFM/JNI boundary, mirroring zstd's own regression pairing (the dictionary against golden-compression/http): - java compress with dict -> zstd-jni decode with same dict - zstd-jni compress with dict -> java decode with same dict - dict id rides with the frame (ZstdFrame.dictId == dict.id, non-zero) Parameterized over the corpus, submodule-gated like the sibling suites, so shallow clones still build. Covers http-dict-missing-symbols, the adversarial dictionary that omits symbols the entropy tables expect. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 29cd635 commit bce47a8

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

integration-tests/src/test/java/io/github/dfa1/zstd/it/GoldenCorpusTest.java

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

33
import io.github.dfa1.zstd.Zstd;
4+
import io.github.dfa1.zstd.ZstdCompressCtx;
5+
import io.github.dfa1.zstd.ZstdDecompressCtx;
6+
import io.github.dfa1.zstd.ZstdDictionary;
47
import io.github.dfa1.zstd.ZstdException;
8+
import io.github.dfa1.zstd.ZstdFrame;
59
import io.github.dfa1.zstd.ZstdInputStream;
610
import org.junit.jupiter.api.Nested;
711
import org.junit.jupiter.params.ParameterizedTest;
@@ -170,4 +174,81 @@ void javaDecodeThrows(String name, Path file) {
170174
assertThatThrownBy(result).isInstanceOfAny(ZstdException.class, UncheckedIOException.class);
171175
}
172176
}
177+
178+
/// Raw dictionaries the C project ships under `golden-dictionaries/`. These
179+
/// are adversarial dictionaries that surfaced real encoder bugs (e.g.
180+
/// `http-dict-missing-symbols`, where the dictionary omits symbols the entropy
181+
/// tables expect). zstd's own suite pairs them with `golden-compression/http`
182+
/// and asserts a dict round-trip survives, so we drive the same payload across
183+
/// the FFM/JNI boundary in both directions and check the dictionary id rides
184+
/// along with the frame.
185+
@Nested
186+
class GoldenDictionaries {
187+
188+
static Stream<Arguments> dictionaries() {
189+
return filesIn("golden-dictionaries", "");
190+
}
191+
192+
private byte[] payload() {
193+
return read(TESTS.resolve("golden-compression/http"));
194+
}
195+
196+
@ParameterizedTest(name = "{0}")
197+
@MethodSource("dictionaries")
198+
void javaDictCompressJniDictDecompress(String name, Path file) {
199+
// Given
200+
byte[] raw = read(file);
201+
byte[] data = payload();
202+
ZstdDictionary dict = ZstdDictionary.of(raw);
203+
byte[] frame;
204+
try (ZstdCompressCtx ctx = new ZstdCompressCtx()) {
205+
frame = ctx.compress(data, dict);
206+
}
207+
208+
// When
209+
var jniDict = new com.github.luben.zstd.ZstdDictDecompress(raw);
210+
byte[] restored = com.github.luben.zstd.Zstd.decompress(frame, jniDict, data.length);
211+
212+
// Then
213+
assertThat(restored).isEqualTo(data);
214+
}
215+
216+
@ParameterizedTest(name = "{0}")
217+
@MethodSource("dictionaries")
218+
void jniDictCompressJavaDictDecompress(String name, Path file) {
219+
// Given
220+
byte[] raw = read(file);
221+
byte[] data = payload();
222+
var jniDict = new com.github.luben.zstd.ZstdDictCompress(raw, Zstd.defaultCompressionLevel());
223+
byte[] frame = com.github.luben.zstd.Zstd.compress(data, jniDict);
224+
225+
// When
226+
byte[] restored;
227+
try (ZstdDecompressCtx ctx = new ZstdDecompressCtx()) {
228+
restored = ctx.decompress(frame, data.length, ZstdDictionary.of(raw));
229+
}
230+
231+
// Then
232+
assertThat(restored).isEqualTo(data);
233+
}
234+
235+
@ParameterizedTest(name = "{0}")
236+
@MethodSource("dictionaries")
237+
void dictIdRidesWithFrame(String name, Path file) {
238+
// Given
239+
byte[] raw = read(file);
240+
ZstdDictionary dict = ZstdDictionary.of(raw);
241+
byte[] frame;
242+
try (ZstdCompressCtx ctx = new ZstdCompressCtx()) {
243+
frame = ctx.compress(payload(), dict);
244+
}
245+
246+
// When
247+
int frameDictId = ZstdFrame.dictId(frame);
248+
249+
// Then
250+
assertThat(frameDictId).isEqualTo(dict.id());
251+
assertThat(frameDictId).isNotZero();
252+
}
253+
}
173254
}

0 commit comments

Comments
 (0)