44import dev .vortex .api .VortexWriter ;
55import dev .vortex .arrow .ArrowAllocation ;
66import dev .vortex .jni .NativeLoader ;
7- import io .github .dfa1 .vortex .core .error .VortexException ;
87import io .github .dfa1 .vortex .reader .VortexReader ;
98import org .apache .arrow .c .ArrowArray ;
109import org .apache .arrow .c .ArrowSchema ;
2928/// Cross-compatibility for column-name edge cases nobody advertises, measured against the
3029/// Rust (JNI) reference:
3130///
32- /// - Blank names (`""`, whitespace-only) are wire-legal — the Rust writer produces them — but
33- /// vortex-java refuses them BOTH ways by policy: the writer never emits them and the reader
34- /// rejects files carrying them with a message pointing at the producing pipeline. Stricter
35- /// than the wire on purpose, like a JSON library refusing a `""` key it could technically
36- /// parse (see `VortexWriterTest` / `DTypeStructBuilderTest` / `PostscriptParserDTypeGuardsTest`).
31+ /// - Blank names (`""`, whitespace-only) are wire-legal — the Rust writer produces them (e.g.
32+ /// `uci-electricityloaddiagrams20112014` has one at field index 0) — and vortex-java accepts
33+ /// them on both the read and write paths. `ColumnName` enforces non-null + no ISO-control
34+ /// characters; blank is explicitly permitted.
3735/// - Duplicate field names are legal in Rust's in-memory `StructFields`
3836/// (`vortex-array/src/dtype/struct_.rs`, first-match name access) but REJECTED by its file
3937/// writer: "StructLayout must have unique field names" — the wire contract both writers
@@ -48,29 +46,22 @@ class ColumnNameEdgeCasesIntegrationTest {
4846 }
4947
5048 @ Test
51- void jniWritesEmptyColumnName_javaRejectsItByPolicy (@ TempDir Path tmp ) throws IOException {
49+ void jniWritesEmptyColumnName_javaAcceptsIt (@ TempDir Path tmp ) throws IOException {
5250 // Given — the Rust (JNI) writer legitimately produces a file whose first column is
53- // named "" (the wire format permits it )
51+ // named "" (blank names are wire-legal and appear in real Raincloud corpus files )
5452 Path file = tmp .resolve ("jni_empty_name.vortex" );
5553 Schema schema = new Schema (List .of (
5654 Field .notNullable ("" , new ArrowType .Int (64 , true )),
5755 Field .notNullable ("x" , new ArrowType .Int (64 , true ))));
5856 writeJni (file , schema , new long [][]{{1 , 2 }, {30 , 40 }});
5957
60- // When
58+ // When / Then — blank names pass through on both paths; ColumnName allows them
6159 Throwable result = catchThrowable (() -> {
6260 try (var reader = VortexReader .open (file )) {
6361 assertThat (reader ).isNotNull ();
6462 }
6563 });
66-
67- // Then — deliberate strictness beyond the wire: a blank name is almost certainly a bug
68- // in the producing pipeline, and rejecting it loudly beats propagating an unusable name
69- // into name-keyed APIs and SQL identifiers
70- assertThat (result )
71- .isInstanceOf (VortexException .class )
72- .hasMessageContaining ("invalid field name in file schema" )
73- .hasMessageContaining ("blank field name" );
64+ assertThat (result ).isNull ();
7465 }
7566
7667 @ Test
0 commit comments