//! Matrix coverage for `create table T with pk [:[, ...]]` //! (ADR-0005, ADR-0009). use crate::typing_surface::*; use rdbms_playground::input_render::{AmbientHint, InputState}; #[test] fn after_create_expects_table() { let schema = schema_empty(); let a = assess_at_end("create ", &schema); assert!(matches!(a.state, InputState::IncompleteAtEof)); assert_candidate_present(&a, &["table"]); crate::snap!("after_create", a); } #[test] fn after_table_keyword_offers_no_candidates_for_new_name() { // The table-name slot is IdentSource::NewName — the user // invents the name, so no candidates from the schema. The // hint resolver surfaces a ForceProse "Type a name [then ...]" // affordance instead. let schema = schema_empty(); let a = assess_at_end("create table ", &schema); assert!(matches!(a.state, InputState::IncompleteAtEof)); assert!( matches!(&a.hint, Some(AmbientHint::Prose(_))), "expected Prose at NewName slot, got {:?}", a.hint, ); crate::snap!("after_table_keyword", a); } #[test] fn after_new_table_name_expects_with() { let schema = schema_empty(); let a = assess_at_end("create table Customers ", &schema); assert!(matches!(a.state, InputState::IncompleteAtEof)); assert_candidate_present(&a, &["with"]); crate::snap!("after_new_table_name", a); } #[test] fn after_with_expects_pk() { let schema = schema_empty(); let a = assess_at_end("create table Customers with ", &schema); assert!(matches!(a.state, InputState::IncompleteAtEof)); assert_candidate_present(&a, &["pk"]); crate::snap!("after_with", a); } #[test] fn create_table_with_pk_default_parses() { let schema = schema_empty(); let a = assess_at_end("create table Customers with pk", &schema); assert!(matches!(a.state, InputState::Valid)); assert_eq!(a.parse_result.as_deref(), Ok("CreateTable")); crate::snap!("with_pk_default", a); } #[test] fn after_pk_word_does_not_re_offer_pk() { // Handoff-12 regression: at the cursor position right after // `with pk`, the completion engine must NOT re-offer `pk` as // a candidate. The full input parses and the partial-prefix // filter drops it. let schema = schema_empty(); let a = assess_at_end("create table Customers with pk", &schema); let cands = completion_candidate_texts(&a); assert!( !cands.contains(&"pk".to_string()), "should NOT re-suggest `pk` (handoff-12 regression), got: {cands:?}", ); } #[test] fn after_pk_space_with_col_name_typed_expects_colon() { let schema = schema_empty(); let a = assess_at_end("create table Customers with pk Code", &schema); assert!(matches!(a.state, InputState::IncompleteAtEof)); crate::snap!("after_col_name", a); } #[test] fn after_colon_expects_type_candidates() { let schema = schema_empty(); let a = assess_at_end( "create table Customers with pk Code:", &schema, ); assert!(matches!(a.state, InputState::IncompleteAtEof)); assert_candidate_present( &a, &["text", "int", "serial", "shortid", "bool"], ); crate::snap!("after_colon", a); } #[test] fn create_table_with_explicit_pk_parses() { let schema = schema_empty(); let a = assess_at_end( "create table Customers with pk Code:text", &schema, ); assert!(matches!(a.state, InputState::Valid)); crate::snap!("with_explicit_pk", a); } #[test] fn create_table_with_compound_pk_parses() { let schema = schema_empty(); let a = assess_at_end( "create table Memberships with pk UserId:int, GroupId:int", &schema, ); assert!(matches!(a.state, InputState::Valid)); crate::snap!("with_compound_pk", a); } #[test] fn create_table_without_with_pk_is_incomplete() { // Tables need at least one column (parse.custom. // create_table_needs_pk) — submitting `create table T` // alone is rejected. Classification depends on whether the // walker treats `with pk` as required or optional at this // position. let schema = schema_empty(); let a = assess_at_end("create table Customers", &schema); assert!( !matches!(a.state, InputState::Valid), "create table without `with pk` must not be Valid, got {:?}", a.state, ); crate::snap!("no_with_pk", a); }