d0c8f9d5d2
New app-level `copy` / `copy all` / `copy last` command (ADR-0041). Delivery is OSC 52 *and* a best-effort native write (arboard), always both — OSC 52 acceptance is undetectable, so a true fallback can't be built. Payload is the panel's plain text exactly as rendered (tags, ✓/✗, box-drawing), drift-locked to render_output_line. arboard added --no-default-features (X11-only; OSC 52 covers Wayland). Amends ADR-0003's command registry; requirements V6.
192 lines
5.8 KiB
Rust
192 lines
5.8 KiB
Rust
//! Matrix coverage for app-lifecycle commands (ADR-0003):
|
|
//! quit, help, rebuild, save / save as, new, load, export,
|
|
//! import, mode, messages.
|
|
//!
|
|
//! App commands don't touch the schema, so the empty schema is
|
|
//! sufficient.
|
|
|
|
use crate::typing_surface::*;
|
|
use rdbms_playground::input_render::InputState;
|
|
|
|
#[test]
|
|
fn quit_parses() {
|
|
let a = assess_at_end("quit", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
assert_eq!(a.parse_result.as_deref(), Ok("App(Quit)"));
|
|
crate::snap!("quit", a);
|
|
}
|
|
|
|
#[test]
|
|
fn help_parses() {
|
|
let a = assess_at_end("help", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
assert_eq!(a.parse_result.as_deref(), Ok("App(Help)"));
|
|
crate::snap!("help", a);
|
|
}
|
|
|
|
#[test]
|
|
fn rebuild_parses() {
|
|
let a = assess_at_end("rebuild", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("rebuild", a);
|
|
}
|
|
|
|
#[test]
|
|
fn save_parses() {
|
|
let a = assess_at_end("save", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
assert_eq!(a.parse_result.as_deref(), Ok("App(Save)"));
|
|
crate::snap!("save", a);
|
|
}
|
|
|
|
#[test]
|
|
fn save_space_offers_as_keyword() {
|
|
// Handoff-12 §3 smoke item: `save ` then Tab offers `as`.
|
|
let a = assess_at_end("save ", &schema_empty());
|
|
assert_candidate_present(&a, &["as"]);
|
|
crate::snap!("save_space", a);
|
|
}
|
|
|
|
#[test]
|
|
fn save_as_parses() {
|
|
let a = assess_at_end("save as", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
assert_eq!(a.parse_result.as_deref(), Ok("App(SaveAs)"));
|
|
crate::snap!("save_as", a);
|
|
}
|
|
|
|
#[test]
|
|
fn new_parses() {
|
|
let a = assess_at_end("new", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("new", a);
|
|
}
|
|
|
|
#[test]
|
|
fn load_parses() {
|
|
let a = assess_at_end("load", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("load", a);
|
|
}
|
|
|
|
#[test]
|
|
fn export_with_no_path_parses() {
|
|
// Export path is optional — `export` alone opens the modal.
|
|
let a = assess_at_end("export", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("export_no_path", a);
|
|
}
|
|
|
|
#[test]
|
|
fn export_with_path_parses() {
|
|
let a = assess_at_end("export myproject.zip", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("export_with_path", a);
|
|
}
|
|
|
|
#[test]
|
|
fn import_with_path_parses() {
|
|
let a = assess_at_end("import bundle.zip", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("import_with_path", a);
|
|
}
|
|
|
|
#[test]
|
|
fn mode_with_value_parses() {
|
|
let a = assess_at_end("mode advanced", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("mode_advanced", a);
|
|
}
|
|
|
|
#[test]
|
|
fn mode_space_offers_simple_and_advanced() {
|
|
let a = assess_at_end("mode ", &schema_empty());
|
|
assert!(matches!(a.state, InputState::IncompleteAtEof));
|
|
assert_candidate_present(&a, &["simple", "advanced"]);
|
|
crate::snap!("mode_space", a);
|
|
}
|
|
|
|
#[test]
|
|
fn messages_with_no_value_parses() {
|
|
// Messages value is optional — `messages` alone shows the
|
|
// current verbosity.
|
|
let a = assess_at_end("messages", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("messages_no_value", a);
|
|
}
|
|
|
|
#[test]
|
|
fn messages_space_offers_short_and_verbose() {
|
|
let a = assess_at_end("messages ", &schema_empty());
|
|
assert_candidate_present(&a, &["short", "verbose"]);
|
|
crate::snap!("messages_space", a);
|
|
}
|
|
|
|
#[test]
|
|
fn messages_with_value_parses() {
|
|
let a = assess_at_end("messages verbose", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
crate::snap!("messages_verbose", a);
|
|
}
|
|
|
|
#[test]
|
|
fn copy_with_no_value_parses() {
|
|
// Copy scope is optional — bare `copy` copies the whole panel.
|
|
let a = assess_at_end("copy", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
assert_eq!(a.parse_result.as_deref(), Ok("App(Copy)"));
|
|
crate::snap!("copy_no_value", a);
|
|
}
|
|
|
|
#[test]
|
|
fn copy_all_parses() {
|
|
let a = assess_at_end("copy all", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
assert_eq!(a.parse_result.as_deref(), Ok("App(Copy)"));
|
|
crate::snap!("copy_all", a);
|
|
}
|
|
|
|
#[test]
|
|
fn copy_last_parses() {
|
|
let a = assess_at_end("copy last", &schema_empty());
|
|
assert!(matches!(a.state, InputState::Valid));
|
|
assert_eq!(a.parse_result.as_deref(), Ok("App(Copy)"));
|
|
crate::snap!("copy_last", a);
|
|
}
|
|
|
|
#[test]
|
|
fn copy_space_offers_all_and_last() {
|
|
let a = assess_at_end("copy ", &schema_empty());
|
|
assert_candidate_present(&a, &["all", "last"]);
|
|
crate::snap!("copy_space", a);
|
|
}
|
|
|
|
#[test]
|
|
fn partial_entry_word_classifies_as_definite_error_but_completes() {
|
|
// `qu` — mid-typing the `quit` entry word.
|
|
//
|
|
// KNOWN UX WRINKLE (handoff-13 finding): a partial entry
|
|
// word is currently classified `DefiniteErrorAt(0)` — the
|
|
// same as a genuinely unknown command (`frobulate`). The
|
|
// walker only engages once a *complete* registered entry
|
|
// word is present; until then `try_walker_route` returns
|
|
// None and the router emits the synthetic unknown-command
|
|
// error. So the input pane shows `qu` in error-red even
|
|
// though it is a valid prefix of `quit`.
|
|
//
|
|
// Completion still works (Tab at `qu` → `quit`), so the
|
|
// user can recover, but the red overlay while typing the
|
|
// first word is jarring. This test documents the current
|
|
// behaviour; flagged to the user for a decision rather
|
|
// than silently asserting it as correct.
|
|
let a = assess_at_end("qu", &schema_empty());
|
|
assert!(
|
|
matches!(a.state, InputState::DefiniteErrorAt(_)),
|
|
"documents current behaviour, got {:?}",
|
|
a.state,
|
|
);
|
|
// Completion recovers — `quit` is offered.
|
|
assert_candidate_present(&a, &["quit"]);
|
|
crate::snap!("partial_quit", a);
|
|
}
|