Files
improvise/tests/folder_import_views.rs
Claude (agent-headless-import) 8bd4b1a77b fix(import): headless import refuses instead of silently succeeding (improvise-8jk6.4, improvise-8jk6.5, improvise-8jk6.6)
- 8jk6.4: the CSV parser yields source text (CsvRecords), and only the
  role reads it as a number. A forced category keeps 00565796 and
  220944e2 verbatim; measures and analysis read the text through
  csv_parser::number_in. CsvRecords reaches a pipeline only through
  ImportPipeline::from_csv, so handing CSV text to the JSON constructor
  no longer compiles.
- 8jk6.5: an import formula that does not parse is refused by name with
  its parse error: the build refuses (headless exits non-zero and writes
  nothing), and the wizard keeps it out of the list with the text still
  in the buffer.
- 8jk6.6: an import that kept no record refuses and says why, from the
  build and from the wizard's review step. A partial skip stays a
  warning with a count and exit 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:54:39 -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:?}");
}