//! Typed contract tests for registered lexical and fuzzy query leaves. #![allow(clippy::expect_used)] use context_query::{ FuzzyMode, FuzzyQuery, FuzzySourceName, FuzzyThreshold, LexicalBooleanOperator, LexicalNormalization, LexicalPrefixTerm, LexicalQuery, LexicalRankWeights, LexicalRanker, LexicalSourceName, LexicalText, LexicalWeight, LexicalWeightSet, MAX_LEXICAL_BOOLEAN_CLAUSES, MAX_LEXICAL_NAME_BYTES, MAX_LEXICAL_NORMALIZATION, MAX_LEXICAL_PHRASE_DISTANCE, MAX_LEXICAL_QUERY_DEPTH, MAX_LEXICAL_TEXT_BYTES, QueryError, QueryIr, QueryKind, RegisteredTsQueryName, ScoreOrder, parse_query_plan, }; use serde_json::{Value, json}; fn text(value: &str) -> LexicalText { LexicalText::new(value).expect("bounded lexical text") } fn source() -> LexicalSourceName { LexicalSourceName::new("body").expect("registered lexical source") } #[test] fn registered_identifiers_reject_non_identifier_input() { assert!(LexicalSourceName::new("body").is_ok()); assert!(LexicalSourceName::new("_body_2").is_ok()); assert!(FuzzySourceName::new("body_trgm").is_ok()); assert!(RegisteredTsQueryName::new("saved_query").is_ok()); for rejected in ["", "Body", "body-1", "1body", "body;drop", "body space"] { assert!( LexicalSourceName::new(rejected).is_err(), "identifier {rejected:?} must be rejected" ); } assert!(LexicalSourceName::new("a".repeat(MAX_LEXICAL_NAME_BYTES)).is_ok()); assert!(LexicalSourceName::new("a".repeat(MAX_LEXICAL_NAME_BYTES + 1)).is_err()); } #[test] fn lexical_text_enforces_exact_byte_and_content_bounds() { assert!(LexicalText::new("a".repeat(MAX_LEXICAL_TEXT_BYTES)).is_ok()); assert!(LexicalText::new("a".repeat(MAX_LEXICAL_TEXT_BYTES + 1)).is_err()); assert!(LexicalText::new("").is_err()); assert!(LexicalText::new(" ").is_err()); assert!(LexicalText::new("post\0gres").is_err()); assert!(LexicalText::new("post\u{7}gres").is_err()); assert!(LexicalText::new("multi\nline").is_ok()); } #[test] fn prefix_terms_reject_every_tsquery_metacharacter() { assert!(LexicalPrefixTerm::new("postgre").is_ok()); assert!(LexicalPrefixTerm::new("posts_2").is_ok()); assert!(LexicalPrefixTerm::new("ünicode").is_ok()); for rejected in [ "", "a b", "a&b", "a|b", "a!b", "a:b", "a'b", "a\\b", "a