distant_protocol/common/
search.rs

1use std::borrow::Cow;
2use std::collections::HashSet;
3use std::path::PathBuf;
4use std::str::FromStr;
5
6use serde::{Deserialize, Serialize};
7
8use crate::common::FileType;
9use crate::utils;
10
11/// Id associated with a search
12pub type SearchId = u32;
13
14/// Represents a query to perform against the filesystem
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub struct SearchQuery {
17    /// Kind of data to examine using condition
18    pub target: SearchQueryTarget,
19
20    /// Condition to meet to be considered a match
21    pub condition: SearchQueryCondition,
22
23    /// Paths in which to perform the query
24    pub paths: Vec<PathBuf>,
25
26    /// Options to apply to the query
27    #[serde(default)]
28    pub options: SearchQueryOptions,
29}
30
31impl SearchQuery {
32    /// Creates a search query targeting the contents of files.
33    pub fn contents<I, T>(
34        condition: SearchQueryCondition,
35        paths: I,
36        options: SearchQueryOptions,
37    ) -> Self
38    where
39        I: IntoIterator<Item = T>,
40        T: Into<PathBuf>,
41    {
42        Self {
43            target: SearchQueryTarget::Contents,
44            condition,
45            paths: paths.into_iter().map(Into::into).collect(),
46            options,
47        }
48    }
49
50    /// Creates a search query targeting the paths of files, directories, and symlinks.
51    pub fn path<I, T>(
52        condition: SearchQueryCondition,
53        paths: I,
54        options: SearchQueryOptions,
55    ) -> Self
56    where
57        I: IntoIterator<Item = T>,
58        T: Into<PathBuf>,
59    {
60        Self {
61            target: SearchQueryTarget::Path,
62            condition,
63            paths: paths.into_iter().map(Into::into).collect(),
64            options,
65        }
66    }
67}
68
69/// Kind of data to examine using conditions
70#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
71#[serde(rename_all = "snake_case")]
72pub enum SearchQueryTarget {
73    /// Checks path of file, directory, or symlink
74    Path,
75
76    /// Checks contents of files
77    Contents,
78}
79
80/// Condition used to find a match in a search query
81#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
82#[serde(rename_all = "snake_case", deny_unknown_fields, tag = "type")]
83pub enum SearchQueryCondition {
84    /// Text is found anywhere (all regex patterns are escaped)
85    Contains { value: String },
86
87    /// Begins with some text (all regex patterns are escaped)
88    EndsWith { value: String },
89
90    /// Matches some text exactly (all regex patterns are escaped)
91    Equals { value: String },
92
93    /// Any of the conditions match
94    Or { value: Vec<SearchQueryCondition> },
95
96    /// Matches some regex
97    Regex { value: String },
98
99    /// Begins with some text (all regex patterns are escaped)
100    StartsWith { value: String },
101}
102
103impl SearchQueryCondition {
104    /// Creates a new instance with `Contains` variant
105    pub fn contains(value: impl Into<String>) -> Self {
106        Self::Contains {
107            value: value.into(),
108        }
109    }
110
111    /// Creates a new instance with `EndsWith` variant
112    pub fn ends_with(value: impl Into<String>) -> Self {
113        Self::EndsWith {
114            value: value.into(),
115        }
116    }
117
118    /// Creates a new instance with `Equals` variant
119    pub fn equals(value: impl Into<String>) -> Self {
120        Self::Equals {
121            value: value.into(),
122        }
123    }
124
125    /// Creates a new instance with `Or` variant
126    pub fn or<I, C>(value: I) -> Self
127    where
128        I: IntoIterator<Item = C>,
129        C: Into<SearchQueryCondition>,
130    {
131        Self::Or {
132            value: value.into_iter().map(|s| s.into()).collect(),
133        }
134    }
135
136    /// Creates a new instance with `Regex` variant
137    pub fn regex(value: impl Into<String>) -> Self {
138        Self::Regex {
139            value: value.into(),
140        }
141    }
142
143    /// Creates a new instance with `StartsWith` variant
144    pub fn starts_with(value: impl Into<String>) -> Self {
145        Self::StartsWith {
146            value: value.into(),
147        }
148    }
149
150    /// Converts the condition in a regex string
151    pub fn to_regex_string(&self) -> String {
152        match self {
153            Self::Contains { value } => regex::escape(value),
154            Self::EndsWith { value } => format!(r"{}$", regex::escape(value)),
155            Self::Equals { value } => format!(r"^{}$", regex::escape(value)),
156            Self::Regex { value } => value.to_string(),
157            Self::StartsWith { value } => format!(r"^{}", regex::escape(value)),
158            Self::Or { value } => {
159                let mut s = String::new();
160                for (i, condition) in value.iter().enumerate() {
161                    if i > 0 {
162                        s.push('|');
163                    }
164                    s.push_str(&condition.to_regex_string());
165                }
166                s
167            }
168        }
169    }
170}
171
172impl FromStr for SearchQueryCondition {
173    type Err = std::convert::Infallible;
174
175    /// Parses search query from a JSON string
176    fn from_str(s: &str) -> Result<Self, Self::Err> {
177        Ok(Self::regex(s))
178    }
179}
180
181/// Options associated with a search query
182#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
183#[serde(default)]
184pub struct SearchQueryOptions {
185    /// Restrict search to only these file types (otherwise all are allowed).
186    #[serde(skip_serializing_if = "HashSet::is_empty")]
187    pub allowed_file_types: HashSet<FileType>,
188
189    /// Regex to use to filter paths being searched to only those that match the include condition.
190    #[serde(skip_serializing_if = "Option::is_none")]
191    pub include: Option<SearchQueryCondition>,
192
193    /// Regex to use to filter paths being searched to only those that do not match the exclude.
194    /// condition
195    #[serde(skip_serializing_if = "Option::is_none")]
196    pub exclude: Option<SearchQueryCondition>,
197
198    /// If true, will search upward through parent directories rather than the traditional downward
199    /// search that recurses through all children directories.
200    ///
201    /// Note that this will use maximum depth to apply to the reverse direction, and will only look
202    /// through each ancestor directory's immediate entries. In other words, this will not result
203    /// in recursing through sibling directories.
204    ///
205    /// An upward search will ALWAYS search the contents of a directory, so this means providing a
206    /// path to a directory will search its entries EVEN if the max_depth is 0.
207    #[serde(skip_serializing_if = "utils::is_false")]
208    pub upward: bool,
209
210    /// Search should follow symbolic links.
211    #[serde(skip_serializing_if = "utils::is_false")]
212    pub follow_symbolic_links: bool,
213
214    /// Maximum results to return before stopping the query.
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub limit: Option<u64>,
217
218    /// Maximum depth (directories) to search
219    ///
220    /// The smallest depth is 0 and always corresponds to the path given to the new function on
221    /// this type. Its direct descendents have depth 1, and their descendents have depth 2, and so
222    /// on.
223    ///
224    /// Note that this will not simply filter the entries of the iterator, but it will actually
225    /// avoid descending into directories when the depth is exceeded.
226    #[serde(skip_serializing_if = "Option::is_none")]
227    pub max_depth: Option<u64>,
228
229    /// Amount of results to batch before sending back excluding final submission that will always
230    /// include the remaining results even if less than pagination request.
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub pagination: Option<u64>,
233
234    /// If true, will skip searching hidden files.
235    #[serde(skip_serializing_if = "utils::is_false")]
236    pub ignore_hidden: bool,
237
238    /// If true, will read `.ignore` files that are used by `ripgrep` and `The Silver Searcher`
239    /// to determine which files and directories to not search.
240    #[serde(skip_serializing_if = "utils::is_false")]
241    pub use_ignore_files: bool,
242
243    /// If true, will read `.ignore` files from parent directories that are used by `ripgrep` and
244    /// `The Silver Searcher` to determine which files and directories to not search.
245    #[serde(skip_serializing_if = "utils::is_false")]
246    pub use_parent_ignore_files: bool,
247
248    /// If true, will read `.gitignore` files to determine which files and directories to not
249    /// search.
250    #[serde(skip_serializing_if = "utils::is_false")]
251    pub use_git_ignore_files: bool,
252
253    /// If true, will read global `.gitignore` files to determine which files and directories to
254    /// not search.
255    #[serde(skip_serializing_if = "utils::is_false")]
256    pub use_global_git_ignore_files: bool,
257
258    /// If true, will read `.git/info/exclude` files to determine which files and directories to
259    /// not search.
260    #[serde(skip_serializing_if = "utils::is_false")]
261    pub use_git_exclude_files: bool,
262}
263
264/// Represents a match for a search query
265#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
266#[serde(rename_all = "snake_case", deny_unknown_fields, tag = "type")]
267pub enum SearchQueryMatch {
268    /// Matches part of a file's path
269    Path(SearchQueryPathMatch),
270
271    /// Matches part of a file's contents
272    Contents(SearchQueryContentsMatch),
273}
274
275impl SearchQueryMatch {
276    pub fn into_path_match(self) -> Option<SearchQueryPathMatch> {
277        match self {
278            Self::Path(x) => Some(x),
279            _ => None,
280        }
281    }
282
283    pub fn into_contents_match(self) -> Option<SearchQueryContentsMatch> {
284        match self {
285            Self::Contents(x) => Some(x),
286            _ => None,
287        }
288    }
289}
290
291/// Represents details for a match on a path
292#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
293pub struct SearchQueryPathMatch {
294    /// Path associated with the match
295    pub path: PathBuf,
296
297    /// Collection of matches tied to `path` where each submatch's byte offset is relative to
298    /// `path`
299    pub submatches: Vec<SearchQuerySubmatch>,
300}
301
302/// Represents details for a match on a file's contents
303#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
304pub struct SearchQueryContentsMatch {
305    /// Path to file whose contents match
306    pub path: PathBuf,
307
308    /// Line(s) that matched
309    pub lines: SearchQueryMatchData,
310
311    /// Line number where match starts (base index 1)
312    pub line_number: u64,
313
314    /// Absolute byte offset corresponding to the start of `lines` in the data being searched
315    pub absolute_offset: u64,
316
317    /// Collection of matches tied to `lines` where each submatch's byte offset is relative to
318    /// `lines` and not the overall content
319    pub submatches: Vec<SearchQuerySubmatch>,
320}
321
322#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
323pub struct SearchQuerySubmatch {
324    /// Content matched by query
325    pub r#match: SearchQueryMatchData,
326
327    /// Byte offset representing start of submatch (inclusive)
328    pub start: u64,
329
330    /// Byte offset representing end of submatch (exclusive)
331    pub end: u64,
332}
333
334impl SearchQuerySubmatch {
335    /// Creates a new submatch using the given `match` data, `start`, and `end`.
336    pub fn new(r#match: impl Into<SearchQueryMatchData>, start: u64, end: u64) -> Self {
337        Self {
338            r#match: r#match.into(),
339            start,
340            end,
341        }
342    }
343}
344
345#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
346#[serde(untagged)]
347pub enum SearchQueryMatchData {
348    /// Match represented as bytes
349    Bytes(Vec<u8>),
350
351    /// Match represented as UTF-8 text
352    Text(String),
353}
354
355impl SearchQueryMatchData {
356    /// Creates a new instance with `Text` variant
357    pub fn text(value: impl Into<String>) -> Self {
358        Self::Text(value.into())
359    }
360
361    /// Creates a new instance with `Bytes` variant
362    pub fn bytes(value: impl Into<Vec<u8>>) -> Self {
363        Self::Bytes(value.into())
364    }
365
366    /// Returns the UTF-8 str reference to the data, if is valid UTF-8
367    pub fn to_str(&self) -> Option<&str> {
368        match self {
369            Self::Text(x) => Some(x),
370            Self::Bytes(x) => std::str::from_utf8(x).ok(),
371        }
372    }
373
374    /// Converts data to a UTF-8 string, replacing any invalid UTF-8 sequences with
375    /// [`U+FFFD REPLACEMENT CHARACTER`](https://doc.rust-lang.org/nightly/core/char/const.REPLACEMENT_CHARACTER.html)
376    pub fn to_string_lossy(&self) -> Cow<'_, str> {
377        match self {
378            Self::Text(x) => Cow::Borrowed(x),
379            Self::Bytes(x) => String::from_utf8_lossy(x),
380        }
381    }
382}
383
384impl From<Vec<u8>> for SearchQueryMatchData {
385    fn from(bytes: Vec<u8>) -> Self {
386        Self::Bytes(bytes)
387    }
388}
389
390impl<'a> From<&'a [u8]> for SearchQueryMatchData {
391    fn from(bytes: &'a [u8]) -> Self {
392        Self::Bytes(bytes.to_vec())
393    }
394}
395
396impl From<String> for SearchQueryMatchData {
397    fn from(text: String) -> Self {
398        Self::Text(text)
399    }
400}
401
402impl<'a> From<&'a str> for SearchQueryMatchData {
403    fn from(text: &'a str) -> Self {
404        Self::Text(text.to_string())
405    }
406}
407
408#[cfg(test)]
409mod tests {
410    use super::*;
411
412    mod search_query {
413        use super::*;
414
415        #[test]
416        fn should_be_able_to_serialize_to_json() {
417            let query = SearchQuery {
418                target: SearchQueryTarget::Contents,
419                condition: SearchQueryCondition::equals("hello world"),
420                paths: vec![PathBuf::from("path1"), PathBuf::from("path2")],
421                options: SearchQueryOptions::default(),
422            };
423
424            let value = serde_json::to_value(query).unwrap();
425            assert_eq!(
426                value,
427                serde_json::json!({
428                    "target": "contents",
429                    "condition": {
430                        "type": "equals",
431                        "value": "hello world",
432                    },
433                    "paths": ["path1", "path2"],
434                    "options": {},
435                })
436            );
437        }
438
439        #[test]
440        fn should_be_able_to_deserialize_from_json() {
441            let value = serde_json::json!({
442                "target": "contents",
443                "condition": {
444                    "type": "equals",
445                    "value": "hello world",
446                },
447                "paths": ["path1", "path2"],
448            });
449
450            let query: SearchQuery = serde_json::from_value(value).unwrap();
451            assert_eq!(
452                query,
453                SearchQuery {
454                    target: SearchQueryTarget::Contents,
455                    condition: SearchQueryCondition::equals("hello world"),
456                    paths: vec![PathBuf::from("path1"), PathBuf::from("path2")],
457                    options: SearchQueryOptions::default(),
458                }
459            );
460        }
461
462        #[test]
463        fn should_be_able_to_serialize_to_msgpack() {
464            let query = SearchQuery {
465                target: SearchQueryTarget::Contents,
466                condition: SearchQueryCondition::equals("hello world"),
467                paths: vec![PathBuf::from("path1"), PathBuf::from("path2")],
468                options: SearchQueryOptions::default(),
469            };
470
471            // NOTE: We don't actually check the output here because it's an implementation detail
472            // and could change as we change how serialization is done. This is merely to verify
473            // that we can serialize since there are times when serde fails to serialize at
474            // runtime.
475            let _ = rmp_serde::encode::to_vec_named(&query).unwrap();
476        }
477
478        #[test]
479        fn should_be_able_to_deserialize_from_msgpack() {
480            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
481            // verify that we are not corrupting or causing issues when serializing on a
482            // client/server and then trying to deserialize on the other side. This has happened
483            // enough times with minor changes that we need tests to verify.
484            let buf = rmp_serde::encode::to_vec_named(&SearchQuery {
485                target: SearchQueryTarget::Contents,
486                condition: SearchQueryCondition::equals("hello world"),
487                paths: vec![PathBuf::from("path1"), PathBuf::from("path2")],
488                options: SearchQueryOptions::default(),
489            })
490            .unwrap();
491
492            let query: SearchQuery = rmp_serde::decode::from_slice(&buf).unwrap();
493            assert_eq!(
494                query,
495                SearchQuery {
496                    target: SearchQueryTarget::Contents,
497                    condition: SearchQueryCondition::equals("hello world"),
498                    paths: vec![PathBuf::from("path1"), PathBuf::from("path2")],
499                    options: SearchQueryOptions::default(),
500                }
501            );
502        }
503    }
504
505    mod search_query_target {
506        use super::*;
507
508        #[test]
509        fn should_be_able_to_serialize_to_json() {
510            let target = SearchQueryTarget::Contents;
511            let value = serde_json::to_value(target).unwrap();
512            assert_eq!(value, serde_json::json!("contents"));
513
514            let target = SearchQueryTarget::Path;
515            let value = serde_json::to_value(target).unwrap();
516            assert_eq!(value, serde_json::json!("path"));
517        }
518
519        #[test]
520        fn should_be_able_to_deserialize_from_json() {
521            let value = serde_json::json!("contents");
522            let target: SearchQueryTarget = serde_json::from_value(value).unwrap();
523            assert_eq!(target, SearchQueryTarget::Contents);
524
525            let value = serde_json::json!("path");
526            let target: SearchQueryTarget = serde_json::from_value(value).unwrap();
527            assert_eq!(target, SearchQueryTarget::Path);
528        }
529
530        #[test]
531        fn should_be_able_to_serialize_to_msgpack() {
532            // NOTE: We don't actually check the output here because it's an implementation detail
533            // and could change as we change how serialization is done. This is merely to verify
534            // that we can serialize since there are times when serde fails to serialize at
535            // runtime.
536            let target = SearchQueryTarget::Contents;
537            let _ = rmp_serde::encode::to_vec_named(&target).unwrap();
538
539            let target = SearchQueryTarget::Path;
540            let _ = rmp_serde::encode::to_vec_named(&target).unwrap();
541        }
542
543        #[test]
544        fn should_be_able_to_deserialize_from_msgpack() {
545            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
546            // verify that we are not corrupting or causing issues when serializing on a
547            // client/server and then trying to deserialize on the other side. This has happened
548            // enough times with minor changes that we need tests to verify.
549            let buf = rmp_serde::encode::to_vec_named(&SearchQueryTarget::Contents).unwrap();
550            let target: SearchQueryTarget = rmp_serde::decode::from_slice(&buf).unwrap();
551            assert_eq!(target, SearchQueryTarget::Contents);
552
553            let buf = rmp_serde::encode::to_vec_named(&SearchQueryTarget::Path).unwrap();
554            let target: SearchQueryTarget = rmp_serde::decode::from_slice(&buf).unwrap();
555            assert_eq!(target, SearchQueryTarget::Path);
556        }
557    }
558
559    mod search_query_condition {
560        use super::*;
561
562        #[test]
563        fn to_regex_string_should_convert_to_appropriate_regex_and_escape_as_needed() {
564            assert_eq!(
565                SearchQueryCondition::contains("t^es$t").to_regex_string(),
566                r"t\^es\$t"
567            );
568            assert_eq!(
569                SearchQueryCondition::ends_with("t^es$t").to_regex_string(),
570                r"t\^es\$t$"
571            );
572            assert_eq!(
573                SearchQueryCondition::equals("t^es$t").to_regex_string(),
574                r"^t\^es\$t$"
575            );
576            assert_eq!(
577                SearchQueryCondition::or([
578                    SearchQueryCondition::contains("t^es$t"),
579                    SearchQueryCondition::equals("t^es$t"),
580                    SearchQueryCondition::regex("^test$"),
581                ])
582                .to_regex_string(),
583                r"t\^es\$t|^t\^es\$t$|^test$"
584            );
585            assert_eq!(
586                SearchQueryCondition::regex("test").to_regex_string(),
587                "test"
588            );
589            assert_eq!(
590                SearchQueryCondition::starts_with("t^es$t").to_regex_string(),
591                r"^t\^es\$t"
592            );
593        }
594
595        mod contains {
596            use super::*;
597
598            #[test]
599            fn should_be_able_to_serialize_to_json() {
600                let condition = SearchQueryCondition::contains("some text");
601
602                let value = serde_json::to_value(condition).unwrap();
603                assert_eq!(
604                    value,
605                    serde_json::json!({
606                        "type": "contains",
607                        "value": "some text",
608                    })
609                );
610            }
611
612            #[test]
613            fn should_be_able_to_deserialize_from_json() {
614                let value = serde_json::json!({
615                    "type": "contains",
616                    "value": "some text",
617                });
618
619                let condition: SearchQueryCondition = serde_json::from_value(value).unwrap();
620                assert_eq!(condition, SearchQueryCondition::contains("some text"));
621            }
622
623            #[test]
624            fn should_be_able_to_serialize_to_msgpack() {
625                let condition = SearchQueryCondition::contains("some text");
626
627                // NOTE: We don't actually check the output here because it's an implementation detail
628                // and could change as we change how serialization is done. This is merely to verify
629                // that we can serialize since there are times when serde fails to serialize at
630                // runtime.
631                let _ = rmp_serde::encode::to_vec_named(&condition).unwrap();
632            }
633
634            #[test]
635            fn should_be_able_to_deserialize_from_msgpack() {
636                // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
637                // verify that we are not corrupting or causing issues when serializing on a
638                // client/server and then trying to deserialize on the other side. This has happened
639                // enough times with minor changes that we need tests to verify.
640                let buf =
641                    rmp_serde::encode::to_vec_named(&SearchQueryCondition::contains("some text"))
642                        .unwrap();
643
644                let condition: SearchQueryCondition = rmp_serde::decode::from_slice(&buf).unwrap();
645                assert_eq!(condition, SearchQueryCondition::contains("some text"));
646            }
647        }
648
649        mod ends_with {
650            use super::*;
651
652            #[test]
653            fn should_be_able_to_serialize_to_json() {
654                let condition = SearchQueryCondition::ends_with("some text");
655
656                let value = serde_json::to_value(condition).unwrap();
657                assert_eq!(
658                    value,
659                    serde_json::json!({
660                        "type": "ends_with",
661                        "value": "some text",
662                    })
663                );
664            }
665
666            #[test]
667            fn should_be_able_to_deserialize_from_json() {
668                let value = serde_json::json!({
669                    "type": "ends_with",
670                    "value": "some text",
671                });
672
673                let condition: SearchQueryCondition = serde_json::from_value(value).unwrap();
674                assert_eq!(condition, SearchQueryCondition::ends_with("some text"));
675            }
676
677            #[test]
678            fn should_be_able_to_serialize_to_msgpack() {
679                let condition = SearchQueryCondition::ends_with("some text");
680
681                // NOTE: We don't actually check the output here because it's an implementation detail
682                // and could change as we change how serialization is done. This is merely to verify
683                // that we can serialize since there are times when serde fails to serialize at
684                // runtime.
685                let _ = rmp_serde::encode::to_vec_named(&condition).unwrap();
686            }
687
688            #[test]
689            fn should_be_able_to_deserialize_from_msgpack() {
690                // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
691                // verify that we are not corrupting or causing issues when serializing on a
692                // client/server and then trying to deserialize on the other side. This has happened
693                // enough times with minor changes that we need tests to verify.
694                let buf =
695                    rmp_serde::encode::to_vec_named(&SearchQueryCondition::ends_with("some text"))
696                        .unwrap();
697
698                let condition: SearchQueryCondition = rmp_serde::decode::from_slice(&buf).unwrap();
699                assert_eq!(condition, SearchQueryCondition::ends_with("some text"));
700            }
701        }
702
703        mod equals {
704            use super::*;
705
706            #[test]
707            fn should_be_able_to_serialize_to_json() {
708                let condition = SearchQueryCondition::equals("some text");
709
710                let value = serde_json::to_value(condition).unwrap();
711                assert_eq!(
712                    value,
713                    serde_json::json!({
714                        "type": "equals",
715                        "value": "some text",
716                    })
717                );
718            }
719
720            #[test]
721            fn should_be_able_to_deserialize_from_json() {
722                let value = serde_json::json!({
723                    "type": "equals",
724                    "value": "some text",
725                });
726
727                let condition: SearchQueryCondition = serde_json::from_value(value).unwrap();
728                assert_eq!(condition, SearchQueryCondition::equals("some text"));
729            }
730
731            #[test]
732            fn should_be_able_to_serialize_to_msgpack() {
733                let condition = SearchQueryCondition::equals("some text");
734
735                // NOTE: We don't actually check the output here because it's an implementation detail
736                // and could change as we change how serialization is done. This is merely to verify
737                // that we can serialize since there are times when serde fails to serialize at
738                // runtime.
739                let _ = rmp_serde::encode::to_vec_named(&condition).unwrap();
740            }
741
742            #[test]
743            fn should_be_able_to_deserialize_from_msgpack() {
744                // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
745                // verify that we are not corrupting or causing issues when serializing on a
746                // client/server and then trying to deserialize on the other side. This has happened
747                // enough times with minor changes that we need tests to verify.
748                let buf =
749                    rmp_serde::encode::to_vec_named(&SearchQueryCondition::equals("some text"))
750                        .unwrap();
751
752                let condition: SearchQueryCondition = rmp_serde::decode::from_slice(&buf).unwrap();
753                assert_eq!(condition, SearchQueryCondition::equals("some text"));
754            }
755        }
756
757        mod or {
758            use super::*;
759
760            #[test]
761            fn should_be_able_to_serialize_to_json() {
762                let condition = SearchQueryCondition::or([
763                    SearchQueryCondition::starts_with("start text"),
764                    SearchQueryCondition::ends_with("end text"),
765                ]);
766
767                let value = serde_json::to_value(condition).unwrap();
768                assert_eq!(
769                    value,
770                    serde_json::json!({
771                        "type": "or",
772                        "value": [
773                            { "type": "starts_with", "value": "start text" },
774                            { "type": "ends_with", "value": "end text" },
775                        ],
776                    })
777                );
778            }
779
780            #[test]
781            fn should_be_able_to_deserialize_from_json() {
782                let value = serde_json::json!({
783                    "type": "or",
784                    "value": [
785                        { "type": "starts_with", "value": "start text" },
786                        { "type": "ends_with", "value": "end text" },
787                    ],
788                });
789
790                let condition: SearchQueryCondition = serde_json::from_value(value).unwrap();
791                assert_eq!(
792                    condition,
793                    SearchQueryCondition::or([
794                        SearchQueryCondition::starts_with("start text"),
795                        SearchQueryCondition::ends_with("end text"),
796                    ])
797                );
798            }
799
800            #[test]
801            fn should_be_able_to_serialize_to_msgpack() {
802                let condition = SearchQueryCondition::or([
803                    SearchQueryCondition::starts_with("start text"),
804                    SearchQueryCondition::ends_with("end text"),
805                ]);
806
807                // NOTE: We don't actually check the output here because it's an implementation detail
808                // and could change as we change how serialization is done. This is merely to verify
809                // that we can serialize since there are times when serde fails to serialize at
810                // runtime.
811                let _ = rmp_serde::encode::to_vec_named(&condition).unwrap();
812            }
813
814            #[test]
815            fn should_be_able_to_deserialize_from_msgpack() {
816                // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
817                // verify that we are not corrupting or causing issues when serializing on a
818                // client/server and then trying to deserialize on the other side. This has happened
819                // enough times with minor changes that we need tests to verify.
820                let buf = rmp_serde::encode::to_vec_named(&SearchQueryCondition::or([
821                    SearchQueryCondition::starts_with("start text"),
822                    SearchQueryCondition::ends_with("end text"),
823                ]))
824                .unwrap();
825
826                let condition: SearchQueryCondition = rmp_serde::decode::from_slice(&buf).unwrap();
827                assert_eq!(
828                    condition,
829                    SearchQueryCondition::or([
830                        SearchQueryCondition::starts_with("start text"),
831                        SearchQueryCondition::ends_with("end text"),
832                    ])
833                );
834            }
835        }
836
837        mod regex {
838            use super::*;
839
840            #[test]
841            fn should_be_able_to_serialize_to_json() {
842                let condition = SearchQueryCondition::regex("some text");
843
844                let value = serde_json::to_value(condition).unwrap();
845                assert_eq!(
846                    value,
847                    serde_json::json!({
848                        "type": "regex",
849                        "value": "some text",
850                    })
851                );
852            }
853
854            #[test]
855            fn should_be_able_to_deserialize_from_json() {
856                let value = serde_json::json!({
857                    "type": "regex",
858                    "value": "some text",
859                });
860
861                let condition: SearchQueryCondition = serde_json::from_value(value).unwrap();
862                assert_eq!(condition, SearchQueryCondition::regex("some text"));
863            }
864
865            #[test]
866            fn should_be_able_to_serialize_to_msgpack() {
867                let condition = SearchQueryCondition::regex("some text");
868
869                // NOTE: We don't actually check the output here because it's an implementation detail
870                // and could change as we change how serialization is done. This is merely to verify
871                // that we can serialize since there are times when serde fails to serialize at
872                // runtime.
873                let _ = rmp_serde::encode::to_vec_named(&condition).unwrap();
874            }
875
876            #[test]
877            fn should_be_able_to_deserialize_from_msgpack() {
878                // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
879                // verify that we are not corrupting or causing issues when serializing on a
880                // client/server and then trying to deserialize on the other side. This has happened
881                // enough times with minor changes that we need tests to verify.
882                let buf =
883                    rmp_serde::encode::to_vec_named(&SearchQueryCondition::regex("some text"))
884                        .unwrap();
885
886                let condition: SearchQueryCondition = rmp_serde::decode::from_slice(&buf).unwrap();
887                assert_eq!(condition, SearchQueryCondition::regex("some text"));
888            }
889        }
890
891        mod starts_with {
892            use super::*;
893
894            #[test]
895            fn should_be_able_to_serialize_to_json() {
896                let condition = SearchQueryCondition::starts_with("some text");
897
898                let value = serde_json::to_value(condition).unwrap();
899                assert_eq!(
900                    value,
901                    serde_json::json!({
902                        "type": "starts_with",
903                        "value": "some text",
904                    })
905                );
906            }
907
908            #[test]
909            fn should_be_able_to_deserialize_from_json() {
910                let value = serde_json::json!({
911                    "type": "starts_with",
912                    "value": "some text",
913                });
914
915                let condition: SearchQueryCondition = serde_json::from_value(value).unwrap();
916                assert_eq!(condition, SearchQueryCondition::starts_with("some text"));
917            }
918
919            #[test]
920            fn should_be_able_to_serialize_to_msgpack() {
921                let condition = SearchQueryCondition::starts_with("some text");
922
923                // NOTE: We don't actually check the output here because it's an implementation detail
924                // and could change as we change how serialization is done. This is merely to verify
925                // that we can serialize since there are times when serde fails to serialize at
926                // runtime.
927                let _ = rmp_serde::encode::to_vec_named(&condition).unwrap();
928            }
929
930            #[test]
931            fn should_be_able_to_deserialize_from_msgpack() {
932                // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
933                // verify that we are not corrupting or causing issues when serializing on a
934                // client/server and then trying to deserialize on the other side. This has happened
935                // enough times with minor changes that we need tests to verify.
936                let buf = rmp_serde::encode::to_vec_named(&SearchQueryCondition::starts_with(
937                    "some text",
938                ))
939                .unwrap();
940
941                let condition: SearchQueryCondition = rmp_serde::decode::from_slice(&buf).unwrap();
942                assert_eq!(condition, SearchQueryCondition::starts_with("some text"));
943            }
944        }
945    }
946
947    mod search_query_options {
948        use super::*;
949
950        #[test]
951        fn should_be_able_to_serialize_minimal_options_to_json() {
952            let options = SearchQueryOptions {
953                allowed_file_types: [].into_iter().collect(),
954                include: None,
955                exclude: None,
956                upward: false,
957                follow_symbolic_links: false,
958                limit: None,
959                max_depth: None,
960                pagination: None,
961                ignore_hidden: false,
962                use_ignore_files: false,
963                use_parent_ignore_files: false,
964                use_git_ignore_files: false,
965                use_global_git_ignore_files: false,
966                use_git_exclude_files: false,
967            };
968
969            let value = serde_json::to_value(options).unwrap();
970            assert_eq!(value, serde_json::json!({}));
971        }
972
973        #[test]
974        fn should_be_able_to_serialize_full_options_to_json() {
975            let options = SearchQueryOptions {
976                allowed_file_types: [FileType::File].into_iter().collect(),
977                include: Some(SearchQueryCondition::Equals {
978                    value: String::from("hello"),
979                }),
980                exclude: Some(SearchQueryCondition::Contains {
981                    value: String::from("world"),
982                }),
983                upward: true,
984                follow_symbolic_links: true,
985                limit: Some(u64::MAX),
986                max_depth: Some(u64::MAX),
987                pagination: Some(u64::MAX),
988                ignore_hidden: true,
989                use_ignore_files: true,
990                use_parent_ignore_files: true,
991                use_git_ignore_files: true,
992                use_global_git_ignore_files: true,
993                use_git_exclude_files: true,
994            };
995
996            let value = serde_json::to_value(options).unwrap();
997            assert_eq!(
998                value,
999                serde_json::json!({
1000                    "allowed_file_types": ["file"],
1001                    "include": {
1002                        "type": "equals",
1003                        "value": "hello",
1004                    },
1005                    "exclude": {
1006                        "type": "contains",
1007                        "value": "world",
1008                    },
1009                    "upward": true,
1010                    "follow_symbolic_links": true,
1011                    "limit": u64::MAX,
1012                    "max_depth": u64::MAX,
1013                    "pagination": u64::MAX,
1014                    "ignore_hidden": true,
1015                    "use_ignore_files": true,
1016                    "use_parent_ignore_files": true,
1017                    "use_git_ignore_files": true,
1018                    "use_global_git_ignore_files": true,
1019                    "use_git_exclude_files": true,
1020                })
1021            );
1022        }
1023
1024        #[test]
1025        fn should_be_able_to_deserialize_minimal_options_from_json() {
1026            let value = serde_json::json!({});
1027
1028            let options: SearchQueryOptions = serde_json::from_value(value).unwrap();
1029            assert_eq!(
1030                options,
1031                SearchQueryOptions {
1032                    allowed_file_types: [].into_iter().collect(),
1033                    include: None,
1034                    exclude: None,
1035                    upward: false,
1036                    follow_symbolic_links: false,
1037                    limit: None,
1038                    max_depth: None,
1039                    pagination: None,
1040                    ignore_hidden: false,
1041                    use_ignore_files: false,
1042                    use_parent_ignore_files: false,
1043                    use_git_ignore_files: false,
1044                    use_global_git_ignore_files: false,
1045                    use_git_exclude_files: false,
1046                }
1047            );
1048        }
1049
1050        #[test]
1051        fn should_be_able_to_deserialize_full_options_from_json() {
1052            let value = serde_json::json!({
1053                "allowed_file_types": ["file"],
1054                "include": {
1055                    "type": "equals",
1056                    "value": "hello",
1057                },
1058                "exclude": {
1059                    "type": "contains",
1060                    "value": "world",
1061                },
1062                "upward": true,
1063                "follow_symbolic_links": true,
1064                "limit": u64::MAX,
1065                "max_depth": u64::MAX,
1066                "pagination": u64::MAX,
1067                "ignore_hidden": true,
1068                "use_ignore_files": true,
1069                "use_parent_ignore_files": true,
1070                "use_git_ignore_files": true,
1071                "use_global_git_ignore_files": true,
1072                "use_git_exclude_files": true,
1073            });
1074
1075            let options: SearchQueryOptions = serde_json::from_value(value).unwrap();
1076            assert_eq!(
1077                options,
1078                SearchQueryOptions {
1079                    allowed_file_types: [FileType::File].into_iter().collect(),
1080                    include: Some(SearchQueryCondition::Equals {
1081                        value: String::from("hello"),
1082                    }),
1083                    exclude: Some(SearchQueryCondition::Contains {
1084                        value: String::from("world"),
1085                    }),
1086                    upward: true,
1087                    follow_symbolic_links: true,
1088                    limit: Some(u64::MAX),
1089                    max_depth: Some(u64::MAX),
1090                    pagination: Some(u64::MAX),
1091                    ignore_hidden: true,
1092                    use_ignore_files: true,
1093                    use_parent_ignore_files: true,
1094                    use_git_ignore_files: true,
1095                    use_global_git_ignore_files: true,
1096                    use_git_exclude_files: true,
1097                }
1098            );
1099        }
1100
1101        #[test]
1102        fn should_be_able_to_serialize_minimal_options_to_msgpack() {
1103            let options = SearchQueryOptions {
1104                allowed_file_types: [].into_iter().collect(),
1105                include: None,
1106                exclude: None,
1107                upward: false,
1108                follow_symbolic_links: false,
1109                limit: None,
1110                max_depth: None,
1111                pagination: None,
1112                ignore_hidden: false,
1113                use_ignore_files: false,
1114                use_parent_ignore_files: false,
1115                use_git_ignore_files: false,
1116                use_global_git_ignore_files: false,
1117                use_git_exclude_files: false,
1118            };
1119
1120            // NOTE: We don't actually check the output here because it's an implementation detail
1121            // and could change as we change how serialization is done. This is merely to verify
1122            // that we can serialize since there are times when serde fails to serialize at
1123            // runtime.
1124            let _ = rmp_serde::encode::to_vec_named(&options).unwrap();
1125        }
1126
1127        #[test]
1128        fn should_be_able_to_serialize_full_options_to_msgpack() {
1129            let options = SearchQueryOptions {
1130                allowed_file_types: [FileType::File].into_iter().collect(),
1131                include: Some(SearchQueryCondition::Equals {
1132                    value: String::from("hello"),
1133                }),
1134                exclude: Some(SearchQueryCondition::Contains {
1135                    value: String::from("world"),
1136                }),
1137                upward: true,
1138                follow_symbolic_links: true,
1139                limit: Some(u64::MAX),
1140                max_depth: Some(u64::MAX),
1141                pagination: Some(u64::MAX),
1142                ignore_hidden: true,
1143                use_ignore_files: true,
1144                use_parent_ignore_files: true,
1145                use_git_ignore_files: true,
1146                use_global_git_ignore_files: true,
1147                use_git_exclude_files: true,
1148            };
1149
1150            // NOTE: We don't actually check the output here because it's an implementation detail
1151            // and could change as we change how serialization is done. This is merely to verify
1152            // that we can serialize since there are times when serde fails to serialize at
1153            // runtime.
1154            let _ = rmp_serde::encode::to_vec_named(&options).unwrap();
1155        }
1156
1157        #[test]
1158        fn should_be_able_to_deserialize_minimal_options_from_msgpack() {
1159            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
1160            // verify that we are not corrupting or causing issues when serializing on a
1161            // client/server and then trying to deserialize on the other side. This has happened
1162            // enough times with minor changes that we need tests to verify.
1163            let buf = rmp_serde::encode::to_vec_named(&SearchQueryOptions {
1164                allowed_file_types: [].into_iter().collect(),
1165                include: None,
1166                exclude: None,
1167                upward: false,
1168                follow_symbolic_links: false,
1169                limit: None,
1170                max_depth: None,
1171                pagination: None,
1172                ignore_hidden: false,
1173                use_ignore_files: false,
1174                use_parent_ignore_files: false,
1175                use_git_ignore_files: false,
1176                use_global_git_ignore_files: false,
1177                use_git_exclude_files: false,
1178            })
1179            .unwrap();
1180
1181            let options: SearchQueryOptions = rmp_serde::decode::from_slice(&buf).unwrap();
1182            assert_eq!(
1183                options,
1184                SearchQueryOptions {
1185                    allowed_file_types: [].into_iter().collect(),
1186                    include: None,
1187                    exclude: None,
1188                    upward: false,
1189                    follow_symbolic_links: false,
1190                    limit: None,
1191                    max_depth: None,
1192                    pagination: None,
1193                    ignore_hidden: false,
1194                    use_ignore_files: false,
1195                    use_parent_ignore_files: false,
1196                    use_git_ignore_files: false,
1197                    use_global_git_ignore_files: false,
1198                    use_git_exclude_files: false,
1199                }
1200            );
1201        }
1202
1203        #[test]
1204        fn should_be_able_to_deserialize_full_options_from_msgpack() {
1205            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
1206            // verify that we are not corrupting or causing issues when serializing on a
1207            // client/server and then trying to deserialize on the other side. This has happened
1208            // enough times with minor changes that we need tests to verify.
1209            let buf = rmp_serde::encode::to_vec_named(&SearchQueryOptions {
1210                allowed_file_types: [FileType::File].into_iter().collect(),
1211                include: Some(SearchQueryCondition::Equals {
1212                    value: String::from("hello"),
1213                }),
1214                exclude: Some(SearchQueryCondition::Contains {
1215                    value: String::from("world"),
1216                }),
1217                upward: true,
1218                follow_symbolic_links: true,
1219                limit: Some(u64::MAX),
1220                max_depth: Some(u64::MAX),
1221                pagination: Some(u64::MAX),
1222                ignore_hidden: true,
1223                use_ignore_files: true,
1224                use_parent_ignore_files: true,
1225                use_git_ignore_files: true,
1226                use_global_git_ignore_files: true,
1227                use_git_exclude_files: true,
1228            })
1229            .unwrap();
1230
1231            let options: SearchQueryOptions = rmp_serde::decode::from_slice(&buf).unwrap();
1232            assert_eq!(
1233                options,
1234                SearchQueryOptions {
1235                    allowed_file_types: [FileType::File].into_iter().collect(),
1236                    include: Some(SearchQueryCondition::Equals {
1237                        value: String::from("hello"),
1238                    }),
1239                    exclude: Some(SearchQueryCondition::Contains {
1240                        value: String::from("world"),
1241                    }),
1242                    upward: true,
1243                    follow_symbolic_links: true,
1244                    limit: Some(u64::MAX),
1245                    max_depth: Some(u64::MAX),
1246                    pagination: Some(u64::MAX),
1247                    ignore_hidden: true,
1248                    use_ignore_files: true,
1249                    use_parent_ignore_files: true,
1250                    use_git_ignore_files: true,
1251                    use_global_git_ignore_files: true,
1252                    use_git_exclude_files: true,
1253                }
1254            );
1255        }
1256    }
1257
1258    mod search_query_match {
1259        use super::*;
1260
1261        mod for_path {
1262            use super::*;
1263
1264            #[test]
1265            fn should_be_able_to_serialize_to_json() {
1266                let r#match = SearchQueryMatch::Path(SearchQueryPathMatch {
1267                    path: PathBuf::from("path"),
1268                    submatches: vec![SearchQuerySubmatch {
1269                        r#match: SearchQueryMatchData::Text(String::from("text")),
1270                        start: 8,
1271                        end: 13,
1272                    }],
1273                });
1274
1275                let value = serde_json::to_value(r#match).unwrap();
1276                assert_eq!(
1277                    value,
1278                    serde_json::json!({
1279                        "type": "path",
1280                        "path": "path",
1281                        "submatches": [{
1282                            "match": "text",
1283                            "start": 8,
1284                            "end": 13,
1285                        }],
1286                    })
1287                );
1288            }
1289
1290            #[test]
1291            fn should_be_able_to_deserialize_from_json() {
1292                let value = serde_json::json!({
1293                    "type": "path",
1294                    "path": "path",
1295                    "submatches": [{
1296                        "match": "text",
1297                        "start": 8,
1298                        "end": 13,
1299                    }],
1300                });
1301
1302                let r#match: SearchQueryMatch = serde_json::from_value(value).unwrap();
1303                assert_eq!(
1304                    r#match,
1305                    SearchQueryMatch::Path(SearchQueryPathMatch {
1306                        path: PathBuf::from("path"),
1307                        submatches: vec![SearchQuerySubmatch {
1308                            r#match: SearchQueryMatchData::Text(String::from("text")),
1309                            start: 8,
1310                            end: 13,
1311                        }],
1312                    })
1313                );
1314            }
1315
1316            #[test]
1317            fn should_be_able_to_serialize_to_msgpack() {
1318                let r#match = SearchQueryMatch::Path(SearchQueryPathMatch {
1319                    path: PathBuf::from("path"),
1320                    submatches: vec![SearchQuerySubmatch {
1321                        r#match: SearchQueryMatchData::Text(String::from("text")),
1322                        start: 8,
1323                        end: 13,
1324                    }],
1325                });
1326
1327                // NOTE: We don't actually check the output here because it's an implementation detail
1328                // and could change as we change how serialization is done. This is merely to verify
1329                // that we can serialize since there are times when serde fails to serialize at
1330                // runtime.
1331                let _ = rmp_serde::encode::to_vec_named(&r#match).unwrap();
1332            }
1333
1334            #[test]
1335            fn should_be_able_to_deserialize_from_msgpack() {
1336                // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
1337                // verify that we are not corrupting or causing issues when serializing on a
1338                // client/server and then trying to deserialize on the other side. This has happened
1339                // enough times with minor changes that we need tests to verify.
1340                let buf = rmp_serde::encode::to_vec_named(&SearchQueryMatch::Path(
1341                    SearchQueryPathMatch {
1342                        path: PathBuf::from("path"),
1343                        submatches: vec![SearchQuerySubmatch {
1344                            r#match: SearchQueryMatchData::Text(String::from("text")),
1345                            start: 8,
1346                            end: 13,
1347                        }],
1348                    },
1349                ))
1350                .unwrap();
1351
1352                let r#match: SearchQueryMatch = rmp_serde::decode::from_slice(&buf).unwrap();
1353                assert_eq!(
1354                    r#match,
1355                    SearchQueryMatch::Path(SearchQueryPathMatch {
1356                        path: PathBuf::from("path"),
1357                        submatches: vec![SearchQuerySubmatch {
1358                            r#match: SearchQueryMatchData::Text(String::from("text")),
1359                            start: 8,
1360                            end: 13,
1361                        }],
1362                    })
1363                );
1364            }
1365        }
1366
1367        mod for_contents {
1368            use super::*;
1369
1370            #[test]
1371            fn should_be_able_to_serialize_to_json() {
1372                let r#match = SearchQueryMatch::Contents(SearchQueryContentsMatch {
1373                    path: PathBuf::from("path"),
1374                    lines: SearchQueryMatchData::Text(String::from("some text")),
1375                    line_number: 12,
1376                    absolute_offset: 24,
1377                    submatches: vec![SearchQuerySubmatch {
1378                        r#match: SearchQueryMatchData::Text(String::from("text")),
1379                        start: 8,
1380                        end: 13,
1381                    }],
1382                });
1383
1384                let value = serde_json::to_value(r#match).unwrap();
1385                assert_eq!(
1386                    value,
1387                    serde_json::json!({
1388                        "type": "contents",
1389                        "path": "path",
1390                        "lines": "some text",
1391                        "line_number": 12,
1392                        "absolute_offset": 24,
1393                        "submatches": [{
1394                            "match": "text",
1395                            "start": 8,
1396                            "end": 13,
1397                        }],
1398                    })
1399                );
1400            }
1401
1402            #[test]
1403            fn should_be_able_to_deserialize_from_json() {
1404                let value = serde_json::json!({
1405                    "type": "contents",
1406                    "path": "path",
1407                    "lines": "some text",
1408                    "line_number": 12,
1409                    "absolute_offset": 24,
1410                    "submatches": [{
1411                        "match": "text",
1412                        "start": 8,
1413                        "end": 13,
1414                    }],
1415                });
1416
1417                let r#match: SearchQueryMatch = serde_json::from_value(value).unwrap();
1418                assert_eq!(
1419                    r#match,
1420                    SearchQueryMatch::Contents(SearchQueryContentsMatch {
1421                        path: PathBuf::from("path"),
1422                        lines: SearchQueryMatchData::Text(String::from("some text")),
1423                        line_number: 12,
1424                        absolute_offset: 24,
1425                        submatches: vec![SearchQuerySubmatch {
1426                            r#match: SearchQueryMatchData::Text(String::from("text")),
1427                            start: 8,
1428                            end: 13,
1429                        }],
1430                    })
1431                );
1432            }
1433
1434            #[test]
1435            fn should_be_able_to_serialize_to_msgpack() {
1436                let r#match = SearchQueryMatch::Contents(SearchQueryContentsMatch {
1437                    path: PathBuf::from("path"),
1438                    lines: SearchQueryMatchData::Text(String::from("some text")),
1439                    line_number: 12,
1440                    absolute_offset: 24,
1441                    submatches: vec![SearchQuerySubmatch {
1442                        r#match: SearchQueryMatchData::Text(String::from("text")),
1443                        start: 8,
1444                        end: 13,
1445                    }],
1446                });
1447
1448                // NOTE: We don't actually check the output here because it's an implementation detail
1449                // and could change as we change how serialization is done. This is merely to verify
1450                // that we can serialize since there are times when serde fails to serialize at
1451                // runtime.
1452                let _ = rmp_serde::encode::to_vec_named(&r#match).unwrap();
1453            }
1454
1455            #[test]
1456            fn should_be_able_to_deserialize_from_msgpack() {
1457                // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
1458                // verify that we are not corrupting or causing issues when serializing on a
1459                // client/server and then trying to deserialize on the other side. This has happened
1460                // enough times with minor changes that we need tests to verify.
1461                let buf = rmp_serde::encode::to_vec_named(&SearchQueryMatch::Contents(
1462                    SearchQueryContentsMatch {
1463                        path: PathBuf::from("path"),
1464                        lines: SearchQueryMatchData::Text(String::from("some text")),
1465                        line_number: 12,
1466                        absolute_offset: 24,
1467                        submatches: vec![SearchQuerySubmatch {
1468                            r#match: SearchQueryMatchData::Text(String::from("text")),
1469                            start: 8,
1470                            end: 13,
1471                        }],
1472                    },
1473                ))
1474                .unwrap();
1475
1476                let r#match: SearchQueryMatch = rmp_serde::decode::from_slice(&buf).unwrap();
1477                assert_eq!(
1478                    r#match,
1479                    SearchQueryMatch::Contents(SearchQueryContentsMatch {
1480                        path: PathBuf::from("path"),
1481                        lines: SearchQueryMatchData::Text(String::from("some text")),
1482                        line_number: 12,
1483                        absolute_offset: 24,
1484                        submatches: vec![SearchQuerySubmatch {
1485                            r#match: SearchQueryMatchData::Text(String::from("text")),
1486                            start: 8,
1487                            end: 13,
1488                        }],
1489                    })
1490                );
1491            }
1492        }
1493    }
1494
1495    mod search_query_path_match {
1496        use super::*;
1497
1498        #[test]
1499        fn should_be_able_to_serialize_to_json() {
1500            let r#match = SearchQueryPathMatch {
1501                path: PathBuf::from("path"),
1502                submatches: vec![SearchQuerySubmatch {
1503                    r#match: SearchQueryMatchData::Text(String::from("text")),
1504                    start: 8,
1505                    end: 13,
1506                }],
1507            };
1508
1509            let value = serde_json::to_value(r#match).unwrap();
1510            assert_eq!(
1511                value,
1512                serde_json::json!({
1513                    "path": "path",
1514                    "submatches": [{
1515                        "match": "text",
1516                        "start": 8,
1517                        "end": 13,
1518                    }],
1519                })
1520            );
1521        }
1522
1523        #[test]
1524        fn should_be_able_to_deserialize_from_json() {
1525            let value = serde_json::json!({
1526                "path": "path",
1527                "submatches": [{
1528                    "match": "text",
1529                    "start": 8,
1530                    "end": 13,
1531                }],
1532            });
1533
1534            let r#match: SearchQueryPathMatch = serde_json::from_value(value).unwrap();
1535            assert_eq!(
1536                r#match,
1537                SearchQueryPathMatch {
1538                    path: PathBuf::from("path"),
1539                    submatches: vec![SearchQuerySubmatch {
1540                        r#match: SearchQueryMatchData::Text(String::from("text")),
1541                        start: 8,
1542                        end: 13,
1543                    }],
1544                }
1545            );
1546        }
1547
1548        #[test]
1549        fn should_be_able_to_serialize_to_msgpack() {
1550            let r#match = SearchQueryPathMatch {
1551                path: PathBuf::from("path"),
1552                submatches: vec![SearchQuerySubmatch {
1553                    r#match: SearchQueryMatchData::Text(String::from("text")),
1554                    start: 8,
1555                    end: 13,
1556                }],
1557            };
1558
1559            // NOTE: We don't actually check the output here because it's an implementation detail
1560            // and could change as we change how serialization is done. This is merely to verify
1561            // that we can serialize since there are times when serde fails to serialize at
1562            // runtime.
1563            let _ = rmp_serde::encode::to_vec_named(&r#match).unwrap();
1564        }
1565
1566        #[test]
1567        fn should_be_able_to_deserialize_from_msgpack() {
1568            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
1569            // verify that we are not corrupting or causing issues when serializing on a
1570            // client/server and then trying to deserialize on the other side. This has happened
1571            // enough times with minor changes that we need tests to verify.
1572            let buf = rmp_serde::encode::to_vec_named(&SearchQueryPathMatch {
1573                path: PathBuf::from("path"),
1574                submatches: vec![SearchQuerySubmatch {
1575                    r#match: SearchQueryMatchData::Text(String::from("text")),
1576                    start: 8,
1577                    end: 13,
1578                }],
1579            })
1580            .unwrap();
1581
1582            let r#match: SearchQueryPathMatch = rmp_serde::decode::from_slice(&buf).unwrap();
1583            assert_eq!(
1584                r#match,
1585                SearchQueryPathMatch {
1586                    path: PathBuf::from("path"),
1587                    submatches: vec![SearchQuerySubmatch {
1588                        r#match: SearchQueryMatchData::Text(String::from("text")),
1589                        start: 8,
1590                        end: 13,
1591                    }],
1592                }
1593            );
1594        }
1595    }
1596
1597    mod search_query_contents_match {
1598        use super::*;
1599
1600        #[test]
1601        fn should_be_able_to_serialize_to_json() {
1602            let r#match = SearchQueryContentsMatch {
1603                path: PathBuf::from("path"),
1604                lines: SearchQueryMatchData::Text(String::from("some text")),
1605                line_number: 12,
1606                absolute_offset: 24,
1607                submatches: vec![SearchQuerySubmatch {
1608                    r#match: SearchQueryMatchData::Text(String::from("text")),
1609                    start: 8,
1610                    end: 13,
1611                }],
1612            };
1613
1614            let value = serde_json::to_value(r#match).unwrap();
1615            assert_eq!(
1616                value,
1617                serde_json::json!({
1618                    "path": "path",
1619                    "lines": "some text",
1620                    "line_number": 12,
1621                    "absolute_offset": 24,
1622                    "submatches": [{
1623                        "match": "text",
1624                        "start": 8,
1625                        "end": 13,
1626                    }],
1627                })
1628            );
1629        }
1630
1631        #[test]
1632        fn should_be_able_to_deserialize_from_json() {
1633            let value = serde_json::json!({
1634                "path": "path",
1635                "lines": "some text",
1636                "line_number": 12,
1637                "absolute_offset": 24,
1638                "submatches": [{
1639                    "match": "text",
1640                    "start": 8,
1641                    "end": 13,
1642                }],
1643            });
1644
1645            let r#match: SearchQueryContentsMatch = serde_json::from_value(value).unwrap();
1646            assert_eq!(
1647                r#match,
1648                SearchQueryContentsMatch {
1649                    path: PathBuf::from("path"),
1650                    lines: SearchQueryMatchData::Text(String::from("some text")),
1651                    line_number: 12,
1652                    absolute_offset: 24,
1653                    submatches: vec![SearchQuerySubmatch {
1654                        r#match: SearchQueryMatchData::Text(String::from("text")),
1655                        start: 8,
1656                        end: 13,
1657                    }],
1658                }
1659            );
1660        }
1661
1662        #[test]
1663        fn should_be_able_to_serialize_to_msgpack() {
1664            let r#match = SearchQueryContentsMatch {
1665                path: PathBuf::from("path"),
1666                lines: SearchQueryMatchData::Text(String::from("some text")),
1667                line_number: 12,
1668                absolute_offset: 24,
1669                submatches: vec![SearchQuerySubmatch {
1670                    r#match: SearchQueryMatchData::Text(String::from("text")),
1671                    start: 8,
1672                    end: 13,
1673                }],
1674            };
1675
1676            // NOTE: We don't actually check the output here because it's an implementation detail
1677            // and could change as we change how serialization is done. This is merely to verify
1678            // that we can serialize since there are times when serde fails to serialize at
1679            // runtime.
1680            let _ = rmp_serde::encode::to_vec_named(&r#match).unwrap();
1681        }
1682
1683        #[test]
1684        fn should_be_able_to_deserialize_from_msgpack() {
1685            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
1686            // verify that we are not corrupting or causing issues when serializing on a
1687            // client/server and then trying to deserialize on the other side. This has happened
1688            // enough times with minor changes that we need tests to verify.
1689            let buf = rmp_serde::encode::to_vec_named(&SearchQueryContentsMatch {
1690                path: PathBuf::from("path"),
1691                lines: SearchQueryMatchData::Text(String::from("some text")),
1692                line_number: 12,
1693                absolute_offset: 24,
1694                submatches: vec![SearchQuerySubmatch {
1695                    r#match: SearchQueryMatchData::Text(String::from("text")),
1696                    start: 8,
1697                    end: 13,
1698                }],
1699            })
1700            .unwrap();
1701
1702            let r#match: SearchQueryContentsMatch = rmp_serde::decode::from_slice(&buf).unwrap();
1703            assert_eq!(
1704                r#match,
1705                SearchQueryContentsMatch {
1706                    path: PathBuf::from("path"),
1707                    lines: SearchQueryMatchData::Text(String::from("some text")),
1708                    line_number: 12,
1709                    absolute_offset: 24,
1710                    submatches: vec![SearchQuerySubmatch {
1711                        r#match: SearchQueryMatchData::Text(String::from("text")),
1712                        start: 8,
1713                        end: 13,
1714                    }],
1715                }
1716            );
1717        }
1718    }
1719
1720    mod search_query_submatch {
1721        use super::*;
1722
1723        #[test]
1724        fn should_be_able_to_serialize_to_json() {
1725            let data = SearchQuerySubmatch {
1726                r#match: SearchQueryMatchData::Text(String::from("some text")),
1727                start: 12,
1728                end: 24,
1729            };
1730
1731            let value = serde_json::to_value(data).unwrap();
1732            assert_eq!(
1733                value,
1734                serde_json::json!({
1735                    "match": "some text",
1736                    "start": 12,
1737                    "end": 24,
1738                })
1739            );
1740
1741            let data = SearchQuerySubmatch {
1742                r#match: SearchQueryMatchData::Bytes(vec![1, 2, 3]),
1743                start: 12,
1744                end: 24,
1745            };
1746
1747            // Do the same for bytes
1748            let value = serde_json::to_value(data).unwrap();
1749            assert_eq!(
1750                value,
1751                serde_json::json!({
1752                    "match": [1, 2, 3],
1753                    "start": 12,
1754                    "end": 24,
1755                })
1756            );
1757        }
1758
1759        #[test]
1760        fn should_be_able_to_deserialize_from_json() {
1761            let value = serde_json::json!({
1762                "match": "some text",
1763                "start": 12,
1764                "end": 24,
1765            });
1766
1767            let submatch: SearchQuerySubmatch = serde_json::from_value(value).unwrap();
1768            assert_eq!(
1769                submatch,
1770                SearchQuerySubmatch {
1771                    r#match: SearchQueryMatchData::Text(String::from("some text")),
1772                    start: 12,
1773                    end: 24,
1774                }
1775            );
1776
1777            // Do the same for bytes
1778            let value = serde_json::json!({
1779                "match": [1, 2, 3],
1780                "start": 12,
1781                "end": 24,
1782            });
1783
1784            let submatch: SearchQuerySubmatch = serde_json::from_value(value).unwrap();
1785            assert_eq!(
1786                submatch,
1787                SearchQuerySubmatch {
1788                    r#match: SearchQueryMatchData::Bytes(vec![1, 2, 3]),
1789                    start: 12,
1790                    end: 24,
1791                }
1792            );
1793        }
1794
1795        #[test]
1796        fn should_be_able_to_serialize_to_msgpack() {
1797            let submatch = SearchQuerySubmatch {
1798                r#match: SearchQueryMatchData::Text(String::from("some text")),
1799                start: 12,
1800                end: 24,
1801            };
1802
1803            // NOTE: We don't actually check the output here because it's an implementation detail
1804            // and could change as we change how serialization is done. This is merely to verify
1805            // that we can serialize since there are times when serde fails to serialize at
1806            // runtime.
1807            let _ = rmp_serde::encode::to_vec_named(&submatch).unwrap();
1808
1809            // Do the same for bytes
1810            let submatch = SearchQuerySubmatch {
1811                r#match: SearchQueryMatchData::Bytes(vec![1, 2, 3]),
1812                start: 12,
1813                end: 24,
1814            };
1815
1816            let _ = rmp_serde::encode::to_vec_named(&submatch).unwrap();
1817        }
1818
1819        #[test]
1820        fn should_be_able_to_deserialize_from_msgpack() {
1821            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
1822            // verify that we are not corrupting or causing issues when serializing on a
1823            // client/server and then trying to deserialize on the other side. This has happened
1824            // enough times with minor changes that we need tests to verify.
1825            let buf = rmp_serde::encode::to_vec_named(&SearchQuerySubmatch {
1826                r#match: SearchQueryMatchData::Text(String::from("some text")),
1827                start: 12,
1828                end: 24,
1829            })
1830            .unwrap();
1831
1832            let submatch: SearchQuerySubmatch = rmp_serde::decode::from_slice(&buf).unwrap();
1833            assert_eq!(
1834                submatch,
1835                SearchQuerySubmatch {
1836                    r#match: SearchQueryMatchData::Text(String::from("some text")),
1837                    start: 12,
1838                    end: 24,
1839                }
1840            );
1841
1842            // Do the same for bytes
1843            let buf = rmp_serde::encode::to_vec_named(&SearchQuerySubmatch {
1844                r#match: SearchQueryMatchData::Bytes(vec![1, 2, 3]),
1845                start: 12,
1846                end: 24,
1847            })
1848            .unwrap();
1849
1850            let submatch: SearchQuerySubmatch = rmp_serde::decode::from_slice(&buf).unwrap();
1851            assert_eq!(
1852                submatch,
1853                SearchQuerySubmatch {
1854                    r#match: SearchQueryMatchData::Bytes(vec![1, 2, 3]),
1855                    start: 12,
1856                    end: 24,
1857                }
1858            );
1859        }
1860    }
1861
1862    mod search_query_match_data {
1863        use super::*;
1864
1865        #[test]
1866        fn should_be_able_to_serialize_to_json() {
1867            let data = SearchQueryMatchData::Text(String::from("some text"));
1868
1869            let value = serde_json::to_value(data).unwrap();
1870            assert_eq!(value, serde_json::json!("some text"));
1871
1872            // Do the same for bytes
1873            let data = SearchQueryMatchData::Bytes(vec![1, 2, 3]);
1874
1875            let value = serde_json::to_value(data).unwrap();
1876            assert_eq!(value, serde_json::json!([1, 2, 3]));
1877        }
1878
1879        #[test]
1880        fn should_be_able_to_deserialize_from_json() {
1881            let value = serde_json::json!("some text");
1882
1883            let data: SearchQueryMatchData = serde_json::from_value(value).unwrap();
1884            assert_eq!(data, SearchQueryMatchData::Text(String::from("some text")));
1885
1886            // Do the same for bytes
1887            let value = serde_json::json!([1, 2, 3]);
1888
1889            let data: SearchQueryMatchData = serde_json::from_value(value).unwrap();
1890            assert_eq!(data, SearchQueryMatchData::Bytes(vec![1, 2, 3]));
1891        }
1892
1893        #[test]
1894        fn should_be_able_to_serialize_to_msgpack() {
1895            let data = SearchQueryMatchData::Text(String::from("some text"));
1896
1897            // NOTE: We don't actually check the output here because it's an implementation detail
1898            // and could change as we change how serialization is done. This is merely to verify
1899            // that we can serialize since there are times when serde fails to serialize at
1900            // runtime.
1901            let _ = rmp_serde::encode::to_vec_named(&data).unwrap();
1902
1903            // Do the same for bytes
1904            let data = SearchQueryMatchData::Bytes(vec![1, 2, 3]);
1905            let _ = rmp_serde::encode::to_vec_named(&data).unwrap();
1906        }
1907
1908        #[test]
1909        fn should_be_able_to_deserialize_from_msgpack() {
1910            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
1911            // verify that we are not corrupting or causing issues when serializing on a
1912            // client/server and then trying to deserialize on the other side. This has happened
1913            // enough times with minor changes that we need tests to verify.
1914            let buf = rmp_serde::encode::to_vec_named(&SearchQueryMatchData::Text(String::from(
1915                "some text",
1916            )))
1917            .unwrap();
1918
1919            let data: SearchQueryMatchData = rmp_serde::decode::from_slice(&buf).unwrap();
1920            assert_eq!(data, SearchQueryMatchData::Text(String::from("some text")));
1921
1922            // Do the same for bytes
1923            let buf = rmp_serde::encode::to_vec_named(&SearchQueryMatchData::Bytes(vec![1, 2, 3]))
1924                .unwrap();
1925
1926            let data: SearchQueryMatchData = rmp_serde::decode::from_slice(&buf).unwrap();
1927            assert_eq!(data, SearchQueryMatchData::Bytes(vec![1, 2, 3]));
1928        }
1929    }
1930}