Skip to main content

options/
validate.rs

1use std::fmt::{Display, Formatter, Result as FormatResult};
2
3/// Represents the result of [`Options`](crate::Options) validation.
4#[derive(Clone, Debug)]
5pub struct ValidateOptionsResult {
6    succeeded: bool,
7    skipped: bool,
8    failed: bool,
9    failures: Vec<String>,
10}
11
12impl ValidateOptionsResult {
13    /// Gets a value indicating whether the validation was successful.
14    pub fn succeeded(&self) -> bool {
15        self.succeeded
16    }
17
18    /// Gets a value indicating whether the validation was skipped.
19    pub fn skipped(&self) -> bool {
20        self.skipped
21    }
22
23    /// Gets a value indicating whether the validation failed.
24    pub fn failed(&self) -> bool {
25        self.failed
26    }
27
28    /// Gets the validation failure description.
29    pub fn failure_message(&self) -> String {
30        if self.failures.is_empty() {
31            String::new()
32        } else {
33            self.failures.join("; ")
34        }
35    }
36
37    /// Gets the full list of validation failures.
38    pub fn failures(&self) -> &[String] {
39        &self.failures
40    }
41
42    /// Creates a result when validation was skipped due to not matching.
43    pub fn skip() -> Self {
44        Self {
45            succeeded: false,
46            skipped: true,
47            failed: false,
48            failures: Vec::with_capacity(0),
49        }
50    }
51
52    /// Creates a result when validation was successful.
53    pub fn success() -> Self {
54        Self {
55            succeeded: true,
56            skipped: false,
57            failed: false,
58            failures: Vec::with_capacity(0),
59        }
60    }
61
62    /// Creates a result when validation failed.
63    ///
64    /// # Arguments
65    ///
66    /// `failure` - The failure message
67    pub fn fail<S: AsRef<str>>(failure: S) -> Self {
68        Self::fail_many([failure].iter())
69    }
70
71    /// Creates a result when validation failed for many reasons.
72    pub fn fail_many<S, I>(failures: I) -> Self
73    where
74        S: AsRef<str>,
75        I: Iterator<Item = S>,
76    {
77        Self {
78            succeeded: false,
79            skipped: false,
80            failed: true,
81            failures: failures.map(|f| f.as_ref().to_owned()).collect(),
82        }
83    }
84}
85
86impl Display for ValidateOptionsResult {
87    fn fmt(&self, formatter: &mut Formatter<'_>) -> FormatResult {
88        formatter.write_str(&self.failure_message())
89    }
90}
91
92/// Defines the behavior of an object that validates configuration options.
93#[cfg_attr(feature = "async", maybe_impl::traits(Send, Sync))]
94pub trait ValidateOptions<T> {
95    /// Validates named options or all options if no name is specified.
96    ///
97    /// # Arguments
98    ///
99    /// * `name` - The optional name of the options to validate
100    /// * `options` - The options to validate
101    fn validate(&self, name: Option<&str>, options: &T) -> ValidateOptionsResult;
102}
103
104#[cfg(test)]
105mod tests {
106
107    use super::*;
108
109    #[test]
110    fn success_should_indicate_succeed() {
111        // arrange
112        let result = ValidateOptionsResult::success();
113
114        // act
115        let succeeded = result.succeeded();
116
117        // assert
118        assert!(succeeded);
119    }
120
121    #[test]
122    fn skip_should_indicate_skipped() {
123        // arrange
124        let result = ValidateOptionsResult::skip();
125
126        // act
127        let skipped = result.skipped();
128
129        // assert
130        assert!(skipped);
131    }
132
133    #[test]
134    fn fail_should_return_failed() {
135        // arrange
136        let result = ValidateOptionsResult::fail("");
137
138        // act
139        let failed = result.failed();
140
141        // assert
142        assert!(failed);
143    }
144
145    #[test]
146    fn fail_should_return_message() {
147        // arrange
148        let result = ValidateOptionsResult::fail("Failed");
149
150        // act
151        let message = result.failure_message();
152
153        // assert
154        assert_eq!(&message, "Failed");
155    }
156
157    #[test]
158    fn fail_many_should_return_joined_message() {
159        // arrange
160        let failures = ["Failure 1", "Failure 2"];
161        let result = ValidateOptionsResult::fail_many(failures.iter());
162
163        // act
164        let message = result.failure_message();
165
166        // assert
167        assert_eq!(&message, "Failure 1; Failure 2");
168    }
169
170    #[test]
171    fn fail_many_should_return_failures() {
172        // arrange
173        let expected = ["Failure 1", "Failure 2"];
174        let result = ValidateOptionsResult::fail_many(expected.iter());
175
176        // act
177        let failures = result.failures();
178
179        // assert
180        assert_eq!(failures, &expected[..]);
181    }
182
183    #[test]
184    fn to_string_should_return_message() {
185        // arrange
186        let result = ValidateOptionsResult::fail("Failed");
187        let message = result.failure_message();
188
189        // act
190        let string = result.to_string();
191
192        // assert
193        assert_eq!(string, message);
194    }
195}