// tests/m8_5_acceptance.rs --- T M8.5 magit-class foldable section view. //! Acceptance for the M8.5 deliverable: a foldable section view //! built on the two-buffer projection pattern (Plan A from the //! M8.5 architecture decision). The package source-of-record is //! the in-tree fixture at `tests/fixtures/pmacs-magit/`. //! //! The four spec acceptance bullets: //! //! 1. Section rendering: a buffer with three top-level sections, //! each containing nested subsections, renders correctly. //! 2. Folding state survives buffer redraw and view repaint. //! 3. Folding does not modify the rope; the underlying text is //! unchanged regardless of fold state. //! 4. Cursor navigation respects fold state (folded sections //! skipped on `C-n` / `C-p`). //! //! Plus regressions: //! //! * Visible buffer rejects user edits (intercept). //! * Toggle-fold via TAB binding through the dispatch path. //! * fold-all / unfold-all commands. //! * Nested fold: collapsing a parent hides every descendant. //! * Re-open is reload-safe (`on_unload` hook drops handles + //! commands cleanly). use std::path::PathBuf; use std::time::{Duration, Instant}; use pmacs::editor::EditorState; use pmacs::lua_bindings::PackageInstallOverride; use tempfile::TempDir; fn magit_package_path() -> PathBuf { let here = PathBuf::from(env!("CARGO_MANIFEST_DIR")); here.join("tests").join("fixtures").join("pmacs-magit") } #[allow(dead_code)] fn pump_until bool>(state: &mut EditorState, predicate: F) { let deadline = Instant::now() + Duration::from_secs(5); while !predicate(state) { assert!( Instant::now() < deadline, "async pump deadline exceeded after 5s" ); state.tick_async(); std::thread::sleep(Duration::from_millis(2)); } } fn editor_with_magit() -> (EditorState, TempDir, TempDir) { let cache = tempfile::tempdir().expect("cache tempdir"); let user_root = tempfile::tempdir().expect("user-root tempdir"); let mut state = EditorState::new_with_roots(&crate::iso::roots()); state.lua_host.reopen_init_phase_for_testing(); state.lua_host.set_package_install_override( PackageInstallOverride::new() .with_cache_dir(cache.path().to_path_buf()) .with_user_install_root(user_root.path().to_path_buf()), ); let pkg = magit_package_path(); let pkg_str = pkg.display().to_string(); let install = format!( r#" pmacs.packages.install_local("{pkg_str}") require("pmacs-magit") "# ); state .lua_host .eval(Some("magit-install"), &install) .unwrap_or_else(|e| panic!("install_local + require failed: {e}")); (state, cache, user_root) } /// Standard test spec: three top-level sections, each with two /// nested subsections. Used by most of the acceptance tests. const STANDARD_SPEC: &str = r#" require("pmacs-magit").open { { id = "a", title = "Section A", body = "a-body-1\na-body-2", children = { { id = "a1", title = "Subsection A1", body = "a1-body" }, { id = "a2", title = "Subsection A2", body = "a2-body" }, }, }, { id = "b", title = "Section B", body = "b-body", children = { { id = "b1", title = "Subsection B1", body = "b1-body" }, { id = "b2", title = "Subsection B2", body = "b2-body" }, }, }, { id = "c", title = "Section C", body = "c-body", children = { { id = "c1", title = "Subsection C1", body = "c1-body" }, { id = "c2", title = "Subsection C2", body = "c2-body" }, }, }, } "#; fn open_standard(state: &mut EditorState) { state .lua_host .eval(Some("magit-open-standard"), STANDARD_SPEC) .unwrap_or_else(|e| panic!("magit.open failed: {e}")); } fn active_buffer_text(state: &mut EditorState) -> String { state .lua_host .lua() .load( r" local buf = pmacs.window.buffer() return buf:slice(0, buf:len()) ", ) .eval::() .expect("read active buffer") } fn source_text(state: &mut EditorState) -> String { state .lua_host .lua() .load( r#" local te = require("pmacs-magit").__pmacs_magit_test_seam_DO_NOT_USE local h = te.active_handle() return h.source:slice(0, h.source:len()) "#, ) .eval::() .expect("read source buffer text") } // --------------------------------------------------------------------------- // Bullet 1 --- section rendering // --------------------------------------------------------------------------- #[test] fn magit_three_top_level_with_nested_subsections_render_correctly() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); let text = active_buffer_text(&mut state); let lines: Vec<&str> = text.lines().collect(); // Default: everything expanded. Each top-level section has: // 1 header + 1-or-2 body lines + (2 children * (1 header + 1 body)). // Three top-levels with the standard spec produces 21 lines: // A header (1) + 2 body + A1 header + a1 body + A2 header + a2 body // = 7 lines for A (and same for B/C). // But B and C have 1 body each (not 2), so they're 6 lines each. // Total: 7 + 6 + 6 = 19. assert_eq!( lines.len(), 19, "expected 19 lines (7 + 6 + 6); got {}: {}", lines.len(), text ); // Top-level headers (depth 0) start with the fold marker. assert!( lines[0].starts_with("v Section A") || lines[0].starts_with("> Section A"), "line 0 must be Section A header: {:?}", lines[0] ); // Body indented under header (2 spaces past header indent + 0 marker). assert_eq!(lines[1], " a-body-1"); assert_eq!(lines[2], " a-body-2"); // Subsection header indented 2 spaces. assert!( lines[3].starts_with(" ") && lines[3].contains("Subsection A1"), "line 3 must be Subsection A1: {:?}", lines[3] ); // Subsection body indented 4 spaces (2 levels deep + 1). assert_eq!(lines[4], " a1-body"); } // --------------------------------------------------------------------------- // Bullet 2 --- folding state survives buffer redraw // --------------------------------------------------------------------------- #[test] fn magit_fold_state_survives_explicit_repaint() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); // Collapse section "a" via direct fold-state manipulation (the // test seam exposes the helpers); then call repaint twice and // verify the projection is the same both times. state .lua_host .eval( Some("collapse-and-repaint"), r#" local te = require("pmacs-magit").__pmacs_magit_test_seam_DO_NOT_USE local h = te.active_handle() te.fold.toggle(h.fold_state, "a") te.repaint_visible(h) _G.M8_5_AFTER_FIRST = h.visible:slice(0, h.visible:len()) te.repaint_visible(h) _G.M8_5_AFTER_SECOND = h.visible:slice(0, h.visible:len()) _G.M8_5_FOLD_A = h.fold_state.a "#, ) .expect("collapse + repaint"); let after_first: String = state .lua_host .lua() .globals() .get("M8_5_AFTER_FIRST") .expect("first projection"); let after_second: String = state .lua_host .lua() .globals() .get("M8_5_AFTER_SECOND") .expect("second projection"); let fold_a: String = state .lua_host .lua() .globals() .get("M8_5_FOLD_A") .expect("fold state of a"); assert_eq!(fold_a, "collapsed", "section a must be collapsed"); assert_eq!( after_first, after_second, "two consecutive repaints with the same fold state must be byte-identical" ); // Section A's body and subsections must not appear in the projection. assert!( !after_first.contains("a-body-1") && !after_first.contains("Subsection A1"), "collapsed Section A must hide its body and children: {after_first}" ); // Header line for A is still present (with collapsed marker). assert!( after_first.contains("Section A"), "collapsed Section A must still show its header: {after_first}" ); } // --------------------------------------------------------------------------- // Bullet 3 --- source rope unchanged across fold ops // --------------------------------------------------------------------------- #[test] fn magit_source_rope_unchanged_across_fold_operations() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); let source_before = source_text(&mut state); assert!(!source_before.is_empty(), "source buffer must have content"); // A sequence of fold operations: collapse a few, expand them, // collapse all, expand all. After all of this the source rope // must be byte-for-byte identical to its initial state. state .lua_host .eval( Some("fold-churn"), r#" pmacs.command.invoke("pmacs-magit.fold-all") pmacs.command.invoke("pmacs-magit.unfold-all") local te = require("pmacs-magit").__pmacs_magit_test_seam_DO_NOT_USE local h = te.active_handle() te.fold.toggle(h.fold_state, "b1") te.repaint_visible(h) te.fold.toggle(h.fold_state, "b1") te.repaint_visible(h) te.fold.toggle(h.fold_state, "a") te.repaint_visible(h) "#, ) .expect("fold churn"); let source_after = source_text(&mut state); assert_eq!( source_before, source_after, "source rope must be byte-for-byte unchanged after fold churn" ); } // --------------------------------------------------------------------------- // Bullet 4 --- cursor navigation respects fold state // --------------------------------------------------------------------------- // // In Plan A, "respects fold state" is a structural property of the // visible buffer: folded content isn't in it at all, so any cursor // movement (`C-n` / `C-p`, page-down, word-skip, ...) within the // visible buffer cannot land on a folded line. The strongest // version of this test verifies that no byte position in the // visible buffer corresponds to text that the source contains // inside a folded section. #[test] fn magit_visible_buffer_excludes_folded_content_after_collapse() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); // Collapse Section B. state .lua_host .eval( Some("collapse-b"), r#" local te = require("pmacs-magit").__pmacs_magit_test_seam_DO_NOT_USE local h = te.active_handle() te.fold.toggle(h.fold_state, "b") te.repaint_visible(h) "#, ) .expect("collapse b"); let visible = active_buffer_text(&mut state); let source = source_text(&mut state); // Source still has every body line. assert!(source.contains("b-body")); assert!(source.contains("b1-body")); assert!(source.contains("b2-body")); assert!(source.contains("Subsection B1")); assert!(source.contains("Subsection B2")); // Visible buffer omits B's body and all of B's descendants. assert!( !visible.contains("b-body"), "collapsed Section B's body must not be in visible: {visible}" ); assert!( !visible.contains("Subsection B1"), "collapsed Section B's child header must be hidden: {visible}" ); assert!( !visible.contains("b1-body") && !visible.contains("b2-body"), "collapsed Section B's grandchildren bodies must be hidden: {visible}" ); // B's own header is still visible (collapsed marker, not its body). assert!( visible.contains("Section B"), "Section B's header must still be in visible: {visible}" ); // Cursor in visible buffer: the line count after Section B's // header is the start of Section C. C-n / C-p respect this // because there's nothing in between. let visible_lines: Vec<&str> = visible.lines().collect(); let b_idx = visible_lines .iter() .position(|l| l.contains("Section B")) .expect("Section B header in visible"); let c_idx = visible_lines .iter() .position(|l| l.contains("Section C")) .expect("Section C header in visible"); assert_eq!( c_idx, b_idx + 1, "with B collapsed, C must be the line immediately after B's header in the visible buffer" ); } // --------------------------------------------------------------------------- // Regression: visible buffer rejects user edits // --------------------------------------------------------------------------- #[test] fn magit_visible_buffer_rejects_user_edits() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); let msg: String = state .lua_host .lua() .load( r#" local buf = pmacs.window.buffer() local ok, err = pcall(function() buf:insert(0, "x") end) assert(not ok, "user edit must be rejected by intercept") return tostring(err) "#, ) .eval() .expect("user-edit eval"); assert!( msg.contains("section view") && msg.contains("not supported"), "rejection must explain why; got: {msg}" ); } // --------------------------------------------------------------------------- // Regression: TAB binding invokes toggle-fold // --------------------------------------------------------------------------- #[test] fn magit_tab_binding_toggles_fold_at_cursor() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); // Cursor lands at byte 0 by default → line 0 = Section A header. // Invoke the bound TAB command: this is a buffer-scope keymap // entry that resolves to pmacs-magit.toggle-fold. // // Since we don't have a clean dispatch_key seam in tests yet, // we exercise the same code path by invoking the command // directly (M8.4 finding 4: `pmacs.editor.move_cursor` and // friends will let us drive through the actual keymap path). state .lua_host .eval( Some("toggle-via-command"), r#"pmacs.command.invoke("pmacs-magit.toggle-fold")"#, ) .expect("toggle-fold invoke"); let after = active_buffer_text(&mut state); assert!( !after.contains("a-body-1"), "after toggling Section A, its body must be hidden: {after}" ); } // --------------------------------------------------------------------------- // Regression: fold-all / unfold-all // --------------------------------------------------------------------------- #[test] fn magit_fold_all_collapses_every_section() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); state .lua_host .eval( Some("fold-all"), r#"pmacs.command.invoke("pmacs-magit.fold-all")"#, ) .expect("fold-all"); let visible = active_buffer_text(&mut state); // No body lines should be visible. for body in [ "a-body-1", "a-body-2", "a1-body", "a2-body", "b-body", "b1-body", "b2-body", "c-body", "c1-body", "c2-body", ] { assert!( !visible.contains(body), "fold-all: body {body} must not be in visible: {visible}" ); } // Three top-level headers still show. assert!(visible.contains("Section A")); assert!(visible.contains("Section B")); assert!(visible.contains("Section C")); // Subsection headers are hidden because their parents are folded. assert!(!visible.contains("Subsection A1")); assert!(!visible.contains("Subsection B2")); } #[test] fn magit_unfold_all_after_fold_all_restores_full_view() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); let before = active_buffer_text(&mut state); state .lua_host .eval( Some("fold-then-unfold"), r#" pmacs.command.invoke("pmacs-magit.fold-all") pmacs.command.invoke("pmacs-magit.unfold-all") "#, ) .expect("fold-then-unfold"); let after = active_buffer_text(&mut state); assert_eq!( before, after, "unfold-all after fold-all must restore the original view" ); } // --------------------------------------------------------------------------- // Regression: nested fold cascade // --------------------------------------------------------------------------- #[test] fn magit_collapsing_parent_hides_descendant_subtree() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); state .lua_host .eval( Some("collapse-a-only"), r#" local te = require("pmacs-magit").__pmacs_magit_test_seam_DO_NOT_USE local h = te.active_handle() te.fold.toggle(h.fold_state, "a") te.repaint_visible(h) "#, ) .expect("collapse a"); let v = active_buffer_text(&mut state); // Collapsing A hides every descendant: A's body, A's children's // headers, A's children's bodies. None of "a-body-1", "a-body-2", // "Subsection A1", "a1-body", "Subsection A2", "a2-body" should appear. for hidden in [ "a-body-1", "a-body-2", "Subsection A1", "Subsection A2", "a1-body", "a2-body", ] { assert!( !v.contains(hidden), "collapsed A must hide descendant {hidden}: {v}" ); } // B and C are unaffected. assert!(v.contains("Subsection B1")); assert!(v.contains("Subsection C2")); assert!(v.contains("c2-body")); } // --------------------------------------------------------------------------- // Regression: parse errors surface usefully // --------------------------------------------------------------------------- #[test] fn magit_open_with_duplicate_id_errors() { let (state, _c, _u) = editor_with_magit(); let msg: String = state .lua_host .lua() .load( r#" local ok, err = pcall(function() require("pmacs-magit").open { { id = "x", title = "X", body = "" }, { id = "x", title = "X-again", body = "" }, } end) assert(not ok, "duplicate id must error") return tostring(err) "#, ) .eval() .expect("dup-id eval"); assert!( msg.contains("duplicate section id"), "error must name the duplicate-id problem: {msg}" ); } #[test] fn magit_open_with_no_sections_errors() { let (state, _c, _u) = editor_with_magit(); let msg: String = state .lua_host .lua() .load( r#" local ok, err = pcall(function() require("pmacs-magit").open {} end) assert(not ok, "empty spec must error") return tostring(err) "#, ) .eval() .expect("empty-spec eval"); assert!( msg.contains("at least one"), "error must explain the empty-spec problem: {msg}" ); } // --------------------------------------------------------------------------- // Regression: section-at lookup via test seam // --------------------------------------------------------------------------- #[test] fn magit_section_at_lookup_resolves_header_and_body_lines() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); let answers: String = state .lua_host .lua() .load( r#" local te = require("pmacs-magit").__pmacs_magit_test_seam_DO_NOT_USE local h = te.active_handle() local proj = h.projection -- Line 0: A header. Line 1: a-body-1 (belongs to A). -- Line 3: A1 header. Line 4: a1-body (belongs to A1). local s0 = te.fold.section_at(proj, 0) local s1 = te.fold.section_at(proj, 1) local s3 = te.fold.section_at(proj, 3) local s4 = te.fold.section_at(proj, 4) return s0 .. "|" .. s1 .. "|" .. s3 .. "|" .. s4 "#, ) .eval() .expect("section_at eval"); assert_eq!(answers, "a|a|a1|a1"); } // --------------------------------------------------------------------------- // Pass-2 review High1 --- source-of-truth is read-only // --------------------------------------------------------------------------- // // Earlier draft created a leading-space-named source buffer; pmacs's // listing / cycling does not filter leading-space names, so the // canonical source rope was reachable via C-x / C-x C-b / // pmacs.window.switch_buffer(source). Plan A's invariant requires // the source-of-truth to be unwritable by the user. Fix: keep the // source as a real rope-backed buffer, but attach a read-only // intercept to reject direct edits. #[test] fn magit_source_of_truth_is_a_readonly_buffer() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); let source_names: Vec = state .lua_host .lua() .load( r" local out = {} for _, id in ipairs(pmacs.buffer.list()) do local d = pmacs.describe.buffer(id) if d ~= nil and d.name:find('magit%-source') then out[#out + 1] = d.name end end return out ", ) .eval::>() .expect("buffer list eval"); assert_eq!( source_names.len(), 1, "source rope must be present as exactly one buffer; got: {source_names:?}" ); let msg: String = state .lua_host .lua() .load( r#" local te = require("pmacs-magit").__pmacs_magit_test_seam_DO_NOT_USE local h = te.active_handle() local before = h.source:slice(0, h.source:len()) local ok, err = pcall(function() h.source:insert(0, "x") end) assert(not ok, "source edit must be rejected") assert(h.source:slice(0, h.source:len()) == before, "rejected source edit must leave source rope unchanged") return tostring(err) "#, ) .eval() .expect("source edit eval"); assert!( msg.contains("magit source view") && msg.contains("not supported"), "source rejection must explain why; got: {msg}" ); } // --------------------------------------------------------------------------- // Pass-2 review Med2 --- body-only sections show fold marker // --------------------------------------------------------------------------- // // Earlier draft considered a section foldable only if it had // children, so a body-only leaf could be collapsed (body hidden) // while its header rendered with a blank " " marker, visually // indistinguishable from a never-foldable leaf. Fix: foldable = // body OR children. The marker shows whenever folding has any // effect. #[test] fn magit_body_only_section_shows_fold_marker() { let (mut state, _c, _u) = editor_with_magit(); state .lua_host .eval( Some("body-only-spec"), r#" require("pmacs-magit").open { { id = "leaf", title = "Leaf", body = "single body line" }, } "#, ) .expect("open body-only"); let initial = active_buffer_text(&mut state); let lines: Vec<&str> = initial.lines().collect(); // Default expanded -> "v Leaf" header. assert!( lines[0].starts_with("v Leaf"), "body-only section must render with expanded marker; got: {:?}", lines[0] ); assert_eq!(lines[1], " single body line"); // Collapse via toggle-fold. state .lua_host .eval( Some("collapse-leaf"), r#"pmacs.command.invoke("pmacs-magit.toggle-fold")"#, ) .expect("toggle"); let after = active_buffer_text(&mut state); let after_lines: Vec<&str> = after.lines().collect(); assert_eq!(after_lines.len(), 1, "body must be hidden: {after}"); assert!( after_lines[0].starts_with("> Leaf"), "collapsed body-only section must render with collapsed marker; \ got: {:?}", after_lines[0] ); } // True leaves (no body, no children) still get no marker. #[test] fn magit_true_leaf_section_renders_without_fold_marker() { let (mut state, _c, _u) = editor_with_magit(); state .lua_host .eval( Some("leaf-spec"), r#" require("pmacs-magit").open { { id = "empty", title = "Empty Section" }, } "#, ) .expect("open leaf"); let text = active_buffer_text(&mut state); let lines: Vec<&str> = text.lines().collect(); assert_eq!(lines.len(), 1, "leaf must render exactly one line"); // " " (no marker) prefix. assert!( lines[0].starts_with(" Empty Section"), "true-leaf must render with no fold marker; got: {:?}", lines[0] ); } // --------------------------------------------------------------------------- // Pass-2 review Med3 --- cursor reseats to same section after repaint // --------------------------------------------------------------------------- // // Wholesale `:replace` of the visible buffer leaves the engine's // window cursor at a stale byte offset. After a fold-all or a // body-line toggle, the cursor would land on whatever happened to // be at the same byte index in the new projection. Fix: // repaint_visible captures the section under cursor first, then // after repaint walks the cursor (via move_up/move_down, the same // pattern builtin/commands/default.lua's buffer-list refresh uses) // to that section's new header line. #[test] fn magit_cursor_stays_on_same_section_across_fold_all_unfold_all() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); // Move the cursor onto Section B's header (line 7 in the // default projection: line 0=A, 1-2=A body, 3=A1 hdr, 4=a1 body, // 5=A2 hdr, 6=a2 body, 7=B hdr). state .lua_host .eval( Some("seek-to-b"), r" for _ = 1, 7 do pmacs.editor.move_down() end ", ) .expect("seek to B"); let line_at_b: i64 = state .lua_host .lua() .load("return pmacs.editor.cursor_line()") .eval() .expect("cursor at B"); assert_eq!(line_at_b, 7, "setup: cursor must be on Section B header"); // fold-all + unfold-all. After this churn the projection is the // same as the start (per the existing unfold-after-fold-all // test); cursor should be back on Section B's header. state .lua_host .eval( Some("fold-then-unfold"), r#" pmacs.command.invoke("pmacs-magit.fold-all") pmacs.command.invoke("pmacs-magit.unfold-all") "#, ) .expect("fold-then-unfold"); let line_after: i64 = state .lua_host .lua() .load("return pmacs.editor.cursor_line()") .eval() .expect("cursor after"); assert_eq!( line_after, 7, "cursor must be back on Section B header after fold-all + unfold-all" ); } // Cursor on a body line should also follow the section: after the // section's body is collapsed, cursor goes to the section's header. #[test] fn magit_cursor_from_body_line_reseats_to_header_after_collapse() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); // Move cursor to line 1 (Section A, body line 1). state .lua_host .eval(Some("to-a-body"), "pmacs.editor.move_down()") .expect("to A body"); let baseline_line: i64 = state .lua_host .lua() .load("return pmacs.editor.cursor_line()") .eval() .expect("baseline"); assert_eq!(baseline_line, 1, "setup: cursor on A's first body line"); // Toggle Section A collapsed (cursor on body -> belongs to A). state .lua_host .eval( Some("toggle-from-body"), r#"pmacs.command.invoke("pmacs-magit.toggle-fold")"#, ) .expect("toggle"); let after_line: i64 = state .lua_host .lua() .load("return pmacs.editor.cursor_line()") .eval() .expect("after"); assert_eq!( after_line, 0, "cursor must reseat onto A's header (line 0) after A collapses" ); } // Cursor on a section that gets hidden by a parent fold reseats to // the nearest visible ancestor, not to byte 0. #[test] fn magit_cursor_on_hidden_descendant_reseats_to_visible_ancestor() { let (mut state, _c, _u) = editor_with_magit(); open_standard(&mut state); // Move cursor onto Subsection A1's header (line 3). state .lua_host .eval( Some("to-a1-hdr"), r"for _ = 1, 3 do pmacs.editor.move_down() end", ) .expect("to A1"); let on_a1: i64 = state .lua_host .lua() .load("return pmacs.editor.cursor_line()") .eval() .expect("on A1"); assert_eq!(on_a1, 3, "setup: cursor on A1 header"); // Collapse Section A (the parent of A1). A1 is no longer in the // projection. Cursor should reseat onto A's header (line 0), // not stay at byte offset 3 / line 3 (which would now be the // start of Section B's body region). state .lua_host .eval( Some("collapse-a"), r#" local te = require("pmacs-magit").__pmacs_magit_test_seam_DO_NOT_USE local h = te.active_handle() te.fold.toggle(h.fold_state, "a") te.repaint_visible(h) "#, ) .expect("collapse a"); let after: i64 = state .lua_host .lua() .load("return pmacs.editor.cursor_line()") .eval() .expect("after"); assert_eq!( after, 0, "cursor on hidden A1 must reseat to A's header (line 0)" ); } // Isolated bootstrap storage roots (see the module docs): an // integration test is compiled without `cfg(test)`, so a raw // `EditorState::new()` would read the developer's real `init.lua` and // write into their real data root. #[path = "common/iso.rs"] mod iso;