Files
improvise/tests/folder_import_views.rs
T
Claude (agent-lpzu) c43ee72402 fix(import): a header-only or measureless file keeps its identity and a view of its own (improvise-lpzu, improvise-8jk6.13, improvise-8jk6.12)
ImportPipeline::from_merge seeds the File items and every file's columns
from Merged::sources, so a header-only CSV keeps its File item and its
columns (unseen columns are proposed as Labels, as an all-null column
is). A file with no measure column gets a records view filtered to it
instead of paging onto another file's hidden measure. Four per-file-view
rules the review found untested now each have a test that fails when
the rule is broken.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:47:11 -07:00

66 lines
2.3 KiB
Rust

//! A folder import's per-file views, saved and reloaded, as both front ends
//! project them (improvise-lpzu). Evidence: `context/test-evidence/cli.md`.
use improvise::import::csv_parser::merge_csvs_from;
use improvise::import::wizard::ImportPipeline;
use improvise::persistence::{format_md, parse_md};
use improvise::ui::app::App;
use improvise_command::ui::project::{Viewport, grid_in};
use improvise_io::storage::{MemoryFs, Storage};
fn reloaded_folder_import() -> App {
let fs = MemoryFs::new();
let files = [
(
"maat/age.csv",
"entity,age-months\nsrc/a.rs,2\nsrc/c.rs,7\n",
),
(
"maat/coupling.csv",
"entity,coupled,degree,average-revs\nsrc/a.rs,src/b.rs,80,5\nsrc/b.rs,src/c.rs,40,3\n",
),
("maat/soc.csv", "entity,soc\n"),
];
for (path, body) in files {
fs.write(std::path::Path::new(path), body.as_bytes())
.unwrap();
}
let merged = merge_csvs_from(&fs, &files.map(|(p, _)| p)).unwrap();
let (wb, _) = ImportPipeline::from_merge(merged)
.build_model_with_warnings()
.unwrap();
App::new(parse_md(&format_md(&wb)).unwrap(), None)
}
/// Evidence: `context/test-evidence/cli.md`.
#[test]
fn a_saved_per_file_view_projects_only_its_file() {
let app = reloaded_folder_import();
let whole = Viewport {
row_offset: 0,
col_offset: 0,
rows: 100,
cols: 100,
};
for (view, texts) in [("age", ["2.00", "7.00"]), ("coupling", ["5.00", "3.00"])] {
let grid = grid_in(&app, view, whole);
let file = grid.page_coords.iter().find(|p| p.cat == "File").unwrap();
assert_eq!((file.selected.as_str(), &file.items), (view, &None));
let drawn: Vec<&str> = grid
.cells
.iter()
.flatten()
.map(|c| c.text.as_str())
.filter(|t| !t.is_empty())
.collect();
assert_eq!(drawn, texts, "{view}");
}
// A header-only file: its item exists, and its view has nothing editable.
let soc = grid_in(&app, "soc", whole);
let file = soc.page_coords.iter().find(|p| p.cat == "File").unwrap();
assert_eq!(file.selected, "soc");
assert!(soc.records, "a file with no measure opens in records mode");
assert_eq!(soc.extent.rows, 0, "{soc:?}");
}