Matrix: pin natural candidate ordering
8 tests covering completion-candidate order: connective keywords in reading order (`to`/`from`/`in` before `table`), and command-part keywords before schema identifiers. The ordering already held via declaration-order preservation + keywords-first sectioning in candidates_at_cursor; nothing pinned it until now, so a future grammar or sort change could silently break the hint panel's left-to-right reading.
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
//! Matrix coverage for completion-candidate *ordering*.
|
||||
//!
|
||||
//! The order candidates appear in is load-bearing for the hint
|
||||
//! panel: it reads left-to-right, so the sequence must match
|
||||
//! how the command is spoken. Two invariants the user called
|
||||
//! out (handoff-14 ranker discussion):
|
||||
//!
|
||||
//! 1. Connective keywords appear in grammar-declaration / reading
|
||||
//! order — `to` before `table` so `add column to table T`
|
||||
//! reads correctly, never the jarring `table` / `to`.
|
||||
//! 2. Command-part keywords appear before schema identifiers
|
||||
//! (table / column names) — grammar parts are read before
|
||||
//! the content that fills them.
|
||||
//!
|
||||
//! These hold today via declaration-order preservation +
|
||||
//! keywords-first sectioning in `candidates_at_cursor`. Nothing
|
||||
//! pinned them until now, so a future grammar/sort change could
|
||||
//! silently break the reading order.
|
||||
|
||||
use crate::typing_surface::*;
|
||||
|
||||
/// Index of `needle` in the ordered completion candidate list,
|
||||
/// or panic with the full list for diagnosis.
|
||||
fn pos(a: &Assessment, needle: &str) -> usize {
|
||||
let cands = completion_candidate_texts(a);
|
||||
cands
|
||||
.iter()
|
||||
.position(|c| c == needle)
|
||||
.unwrap_or_else(|| panic!("{needle:?} not in candidates: {cands:?}"))
|
||||
}
|
||||
|
||||
/// Assert `first` appears before `second` in the candidate list.
|
||||
fn assert_before(a: &Assessment, first: &str, second: &str) {
|
||||
let pf = pos(a, first);
|
||||
let ps = pos(a, second);
|
||||
assert!(
|
||||
pf < ps,
|
||||
"expected {first:?} (idx {pf}) before {second:?} (idx {ps}): {:?}",
|
||||
completion_candidate_texts(a),
|
||||
);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Connective ordering: the `[connective] [table] <T>` shape
|
||||
// shared by the DDL commands.
|
||||
// =========================================================
|
||||
|
||||
#[test]
|
||||
fn add_column_lists_to_before_table() {
|
||||
let schema = schema_multi_table();
|
||||
let a = assess_at_end("add column ", &schema);
|
||||
assert_before(&a, "to", "table");
|
||||
crate::snap!("add_column_connectives", a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_column_lists_from_before_table() {
|
||||
let schema = schema_multi_table();
|
||||
let a = assess_at_end("drop column ", &schema);
|
||||
assert_before(&a, "from", "table");
|
||||
crate::snap!("drop_column_connectives", a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_column_lists_in_before_table() {
|
||||
let schema = schema_multi_table();
|
||||
let a = assess_at_end("rename column ", &schema);
|
||||
assert_before(&a, "in", "table");
|
||||
crate::snap!("rename_column_connectives", a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_column_lists_in_before_table() {
|
||||
let schema = schema_multi_table();
|
||||
let a = assess_at_end("change column ", &schema);
|
||||
assert_before(&a, "in", "table");
|
||||
crate::snap!("change_column_connectives", a);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Keywords-before-identifiers: at a position where both a
|
||||
// connective keyword and schema table names are valid, the
|
||||
// keyword comes first.
|
||||
// =========================================================
|
||||
|
||||
#[test]
|
||||
fn add_column_keyword_precedes_table_identifiers() {
|
||||
let schema = schema_multi_table();
|
||||
let a = assess_at_end("add column ", &schema);
|
||||
// `to` / `table` are command parts; Customers / Orders are
|
||||
// schema identifiers — every keyword precedes every ident.
|
||||
assert_before(&a, "table", "Customers");
|
||||
assert_before(&a, "to", "Customers");
|
||||
assert_before(&a, "to", "Orders");
|
||||
crate::snap!("add_column_keyword_then_idents", a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_column_keyword_precedes_table_identifiers() {
|
||||
let schema = schema_multi_table();
|
||||
let a = assess_at_end("drop column ", &schema);
|
||||
assert_before(&a, "table", "Customers");
|
||||
assert_before(&a, "from", "Orders");
|
||||
crate::snap!("drop_column_keyword_then_idents", a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_into_table_keyword_precedes_nothing_when_only_idents() {
|
||||
// Sanity: at `insert into ` only table identifiers are
|
||||
// valid — no keyword to precede them, but the ordering must
|
||||
// still be deterministic (alphabetical among idents).
|
||||
let schema = schema_multi_table();
|
||||
let a = assess_at_end("insert into ", &schema);
|
||||
assert_before(&a, "Customers", "Orders");
|
||||
crate::snap!("insert_into_idents_only", a);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// After consuming the first connective, the second still
|
||||
// surfaces ahead of identifiers.
|
||||
// =========================================================
|
||||
|
||||
#[test]
|
||||
fn add_column_after_to_lists_table_before_identifiers() {
|
||||
let schema = schema_multi_table();
|
||||
let a = assess_at_end("add column to ", &schema);
|
||||
assert_before(&a, "table", "Customers");
|
||||
crate::snap!("add_column_after_to", a);
|
||||
}
|
||||
Reference in New Issue
Block a user