Skip to main content

ralph/queue/search/
options.rs

1//! Search options for task filtering and searching.
2//!
3//! Responsibilities:
4//! - Define `SearchOptions` struct that unifies parameters for CLI and GUI clients
5//!
6//! Not handled here:
7//! - Actual search/filter implementation (see sibling modules)
8//! - Default value logic for scopes (handled by callers)
9//!
10//! Invariants/assumptions:
11//! - All boolean flags default to false for conservative/safe behavior
12//! - Scopes vec is owned (callers normalize before setting)
13
14/// Options controlling search and filtering behavior.
15///
16/// This struct unifies the parameters used by both CLI and GUI clients for
17/// consistent search semantics across surfaces.
18#[derive(Debug, Clone, PartialEq, Eq, Default)]
19pub struct SearchOptions {
20    /// Use regular expression matching (default: false, use substring).
21    pub use_regex: bool,
22    /// Case-sensitive search (default: false, case-insensitive).
23    pub case_sensitive: bool,
24    /// Use fuzzy matching (default: false, use substring).
25    pub use_fuzzy: bool,
26    /// Scope filter tokens (default: empty, no scope filter).
27    pub scopes: Vec<String>,
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33
34    #[test]
35    fn search_options_default_values() {
36        let opts = SearchOptions::default();
37        assert!(!opts.use_regex, "default: substring search");
38        assert!(!opts.case_sensitive, "default: case-insensitive");
39        assert!(opts.scopes.is_empty(), "default: no scope filter");
40    }
41
42    #[test]
43    fn search_options_regex_enabled() {
44        let opts = SearchOptions {
45            use_regex: true,
46            case_sensitive: false,
47            use_fuzzy: false,
48            scopes: vec![],
49        };
50        assert!(opts.use_regex, "regex enabled");
51        assert!(!opts.case_sensitive, "case-insensitive");
52        assert!(!opts.use_fuzzy, "fuzzy disabled");
53    }
54
55    #[test]
56    fn search_options_case_sensitive_enabled() {
57        let opts = SearchOptions {
58            use_regex: false,
59            case_sensitive: true,
60            use_fuzzy: false,
61            scopes: vec![],
62        };
63        assert!(!opts.use_regex, "substring search");
64        assert!(opts.case_sensitive, "case-sensitive");
65        assert!(!opts.use_fuzzy, "fuzzy disabled");
66    }
67
68    #[test]
69    fn search_options_both_enabled() {
70        let opts = SearchOptions {
71            use_regex: true,
72            case_sensitive: true,
73            use_fuzzy: false,
74            scopes: vec![],
75        };
76        assert!(opts.use_regex, "regex enabled");
77        assert!(opts.case_sensitive, "case-sensitive");
78        assert!(!opts.use_fuzzy, "fuzzy disabled");
79    }
80
81    #[test]
82    fn search_options_with_scopes() {
83        let opts = SearchOptions {
84            use_regex: false,
85            case_sensitive: false,
86            use_fuzzy: false,
87            scopes: vec!["crates/ralph".to_string()],
88        };
89        assert!(!opts.use_regex, "substring search");
90        assert!(!opts.case_sensitive, "case-insensitive");
91        assert!(!opts.use_fuzzy, "fuzzy disabled");
92        assert_eq!(opts.scopes.len(), 1, "one scope filter");
93        assert_eq!(opts.scopes[0], "crates/ralph");
94    }
95
96    #[test]
97    fn search_options_fuzzy_enabled() {
98        let opts = SearchOptions {
99            use_regex: false,
100            case_sensitive: false,
101            use_fuzzy: true,
102            scopes: vec![],
103        };
104        assert!(!opts.use_regex, "substring search");
105        assert!(!opts.case_sensitive, "case-insensitive");
106        assert!(opts.use_fuzzy, "fuzzy enabled");
107    }
108}