Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,33 @@ static Path writeMultiTypeVortex(Path dir, String name) throws IOException {
return file;
}

/// Writes a single-chunk file with a low-cardinality `label` Utf8 column and an
/// `n` I64 column. The repeated labels trip the global-dictionary encoder, so the
/// `label` column decodes to a `vortex.dict` layout — letting the inspector render
/// its dictionary-preview detail pane (alongside the I64 data-preview pane).
///
/// The global dictionary only forms within a single chunk, so all `rows` are
/// written in one `writeChunk`.
static Path writeRichVortex(Path dir, String name, int rows) throws IOException {
Path file = dir.resolve(name);
DType.Struct schema = new DType.Struct(
List.of("label", "n"),
List.of(new DType.Utf8(false), new DType.Primitive(PType.I64, false)),
false);
String[] labels = {"red", "green", "blue"};
String[] label = new String[rows];
long[] n = new long[rows];
for (int i = 0; i < rows; i++) {
label[i] = labels[i % labels.length];
n[i] = i;
}
try (FileChannel ch = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
VortexWriter writer = VortexWriter.create(ch, schema, WriteOptions.defaults())) {
writer.writeChunk(Map.of("label", label, "n", n));
}
return file;
}

/// Opens `file` on the worker thread and returns the handle. The caller must
/// close the returned handle on the same worker (see [#closeOnWorker]).
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
import io.github.dfa1.vortex.cli.tui.term.Key;
import io.github.dfa1.vortex.cli.tui.term.Terminal;
import io.github.dfa1.vortex.inspect.InspectorTree;
import io.github.dfa1.vortex.reader.VortexHandle;
import io.github.dfa1.vortex.reader.VortexReader;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import static org.assertj.core.api.Assertions.assertThat;

Expand Down Expand Up @@ -67,4 +70,66 @@ void quitsOnEscapeWithoutRenderingDetails() throws Exception {

assertThat(term.output()).contains("vortex-inspect");
}

@Test
void deepExpand_rendersDictAndDataPanes_synchronously() throws Exception {
// Given — a rich fixture (low-cardinality dict column + an I64 column) and a
// script that expands the whole tree, then visits every row so each node's
// detail pane renders. worker == null runs all previews inline.
Path file = TuiTestSupport.writeRichVortex(tmp, "rich.vortex", 200);
FakeTerminal term = new FakeTerminal(new Terminal.Size(40, 120), expandAndVisitAll());

// When
try (VortexReader handle = VortexReader.open(file)) {
InspectorTree tree = InspectorTree.buildShallow(handle);
VortexInspectorTui.run(term, tree, handle, null);
}

// Then — the dictionary-preview and data-preview panes both rendered
String out = term.output();
assertThat(out).contains("Dictionary");
assertThat(out).contains("Data (column");
}

@Test
void deepExpand_overWorker_drivesAsyncPreviews() throws Exception {
// Given — same rich fixture, but a real IoWorker so the async submit branches
// (dict/stats/data load via worker.submit, indexStatsChildrenOnWorker, peek
// prefetch) are exercised instead of the synchronous render-thread path.
Path file = TuiTestSupport.writeRichVortex(tmp, "rich.vortex", 200);
FakeTerminal term = new FakeTerminal(new Terminal.Size(40, 120), expandAndVisitAll(), 3);

// When — handle and tree are built on the worker thread (confined arena)
try (IoWorker worker = new IoWorker("inspect-test-io")) {
VortexHandle handle = TuiTestSupport.openOnWorker(worker, file);
try {
AtomicReference<InspectorTree> tree = new AtomicReference<>();
worker.runAndAwait(() -> tree.set(InspectorTree.buildShallow(handle)));
VortexInspectorTui.run(term, tree.get(), handle, worker);
} finally {
TuiTestSupport.closeOnWorker(worker, handle);
}
}

// Then — completes and rendered the inspector chrome
assertThat(term.output()).contains("vortex-inspect");
}

/// Script: expand every node along the traversal, then return to the top and step
/// through all now-visible rows so each node is selected (and its detail pane
/// rendered) at least once.
private static List<Key> expandAndVisitAll() {
List<Key> script = new ArrayList<>();
script.add(Key.Home.INSTANCE);
for (int i = 0; i < 40; i++) {
script.add(Key.ArrowRight.INSTANCE);
script.add(Key.ArrowDown.INSTANCE);
}
script.add(Key.Home.INSTANCE);
for (int i = 0; i < 80; i++) {
script.add(Key.ArrowDown.INSTANCE);
}
script.add(new Key.Char('q'));
return script;
}
}