• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::description::Description;
16 use crate::matcher::{Matcher, MatcherBase, MatcherResult};
17 use regex::Regex;
18 use std::fmt::Debug;
19 use std::ops::Deref;
20 
21 /// Matches a string containing a substring which matches the given regular
22 /// expression.
23 ///
24 /// Both the actual value and the expected regular expression may be either a
25 /// `String` or a string reference.
26 ///
27 /// ```
28 /// # use googletest::prelude::*;
29 /// # fn should_pass_1() -> Result<()> {
30 /// verify_that!("Some value", contains_regex("S.*e"))?;  // Passes
31 /// #     Ok(())
32 /// # }
33 /// # fn should_fail() -> Result<()> {
34 /// verify_that!("Another value", contains_regex("Some"))?;   // Fails
35 /// #     Ok(())
36 /// # }
37 /// # fn should_pass_2() -> Result<()> {
38 /// verify_that!("Some value".to_string(), contains_regex("v.*e"))?;   // Passes
39 /// verify_that!("Some value", contains_regex("v.*e".to_string()))?;   // Passes
40 /// #     Ok(())
41 /// # }
42 /// # should_pass_1().unwrap();
43 /// # should_fail().unwrap_err();
44 /// # should_pass_2().unwrap();
45 /// ```
46 ///
47 /// Panics if the given `pattern` is not a syntactically valid regular
48 /// expression.
49 #[track_caller]
contains_regex<PatternT: Deref<Target = str>>(pattern: PatternT) -> ContainsRegexMatcher50 pub fn contains_regex<PatternT: Deref<Target = str>>(pattern: PatternT) -> ContainsRegexMatcher {
51     ContainsRegexMatcher { regex: Regex::new(pattern.deref()).unwrap() }
52 }
53 
54 /// A matcher matching a string-like type containing a substring matching a
55 /// given regular expression.
56 ///
57 /// Intended only to be used from the function [`contains_regex`] only.
58 /// Should not be referenced by code outside this library.
59 #[derive(MatcherBase)]
60 pub struct ContainsRegexMatcher {
61     regex: Regex,
62 }
63 
64 impl<ActualT: AsRef<str> + Debug + Copy> Matcher<ActualT> for ContainsRegexMatcher {
matches(&self, actual: ActualT) -> MatcherResult65     fn matches(&self, actual: ActualT) -> MatcherResult {
66         self.regex.is_match(actual.as_ref()).into()
67     }
68 
describe(&self, matcher_result: MatcherResult) -> Description69     fn describe(&self, matcher_result: MatcherResult) -> Description {
70         match matcher_result {
71             MatcherResult::Match => {
72                 format!("contains the regular expression {:#?}", self.regex.as_str()).into()
73             }
74             MatcherResult::NoMatch => {
75                 format!("doesn't contain the regular expression {:#?}", self.regex.as_str()).into()
76             }
77         }
78     }
79 }
80 
81 #[cfg(test)]
82 mod tests {
83     use crate::matcher::MatcherResult;
84     use crate::prelude::*;
85 
86     #[test]
contains_regex_matches_string_reference_with_pattern() -> Result<()>87     fn contains_regex_matches_string_reference_with_pattern() -> Result<()> {
88         let matcher = contains_regex("S.*val");
89 
90         let result = matcher.matches("Some value");
91 
92         verify_that!(result, eq(MatcherResult::Match))
93     }
94 
95     #[test]
contains_regex_does_not_match_string_without_pattern() -> Result<()>96     fn contains_regex_does_not_match_string_without_pattern() -> Result<()> {
97         let matcher = contains_regex("Another");
98 
99         let result = matcher.matches("Some value");
100 
101         verify_that!(result, eq(MatcherResult::NoMatch))
102     }
103 
104     #[test]
contains_regex_matches_owned_string_with_pattern() -> Result<()>105     fn contains_regex_matches_owned_string_with_pattern() -> Result<()> {
106         let matcher = contains_regex("value");
107 
108         let result = matcher.matches(&"Some value".to_string());
109 
110         verify_that!(result, eq(MatcherResult::Match))
111     }
112 
113     #[test]
contains_regex_matches_string_reference_with_owned_string() -> Result<()>114     fn contains_regex_matches_string_reference_with_owned_string() -> Result<()> {
115         let matcher = contains_regex("value");
116 
117         let result = matcher.matches("Some value");
118 
119         verify_that!(result, eq(MatcherResult::Match))
120     }
121 
122     #[test]
verify_that_works_with_owned_string() -> Result<()>123     fn verify_that_works_with_owned_string() -> Result<()> {
124         verify_that!("Some value".to_string(), contains_regex("value"))
125     }
126 
127     #[test]
contains_regex_displays_quoted_debug_of_pattern() -> Result<()>128     fn contains_regex_displays_quoted_debug_of_pattern() -> Result<()> {
129         let matcher = contains_regex("\n");
130 
131         verify_that!(
132             Matcher::<&str>::describe(&matcher, MatcherResult::Match),
133             displays_as(eq("contains the regular expression \"\\n\""))
134         )
135     }
136 }
137