Skip to main content

aviso_validators/
string.rs

1// (C) Copyright 2024- ECMWF and individual contributors.
2//
3// This software is licensed under the terms of the Apache Licence Version 2.0
4// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5// In applying this licence, ECMWF does not waive the privileges and immunities
6// granted to it by virtue of its status as an intergovernmental organisation nor
7// does it submit to any jurisdiction.
8
9//! String validation and canonicalization
10//!
11//! Provides validation for string fields with configurable length constraints.
12//! Ensures strings are non-empty and within specified length limits.
13
14use anyhow::{Result, bail};
15
16/// String validation handler
17///
18/// Validates string fields according to the following rules:
19/// - Must not be empty (required for all string fields)
20/// - Must not exceed maximum length if specified
21/// - Returns the original string if valid (no canonicalization needed)
22pub struct StringHandler;
23
24impl StringHandler {
25    /// Validate and canonicalize a string value
26    ///
27    /// # Arguments
28    /// * `value` - The string value to validate
29    /// * `max_length` - Optional maximum length constraint
30    /// * `field_name` - Name of the field (for error messages)
31    ///
32    /// # Returns
33    /// * `Ok(String)` - The validated string (unchanged)
34    /// * `Err(anyhow::Error)` - Validation failed with detailed error
35    pub fn validate_and_canonicalize(
36        value: &str,
37        max_length: Option<usize>,
38        field_name: &str,
39    ) -> Result<String> {
40        // Check for empty strings (not allowed)
41        if value.is_empty() {
42            bail!("Field '{}' cannot be empty", field_name);
43        }
44
45        // Check maximum length constraint if specified
46        if let Some(max_len) = max_length
47            && value.len() > max_len
48        {
49            bail!(
50                "Field '{}' exceeds maximum length of {} characters, got: {}",
51                field_name,
52                max_len,
53                value.len()
54            );
55        }
56
57        // String is valid, return as-is (no canonicalization needed)
58        Ok(value.to_string())
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_valid_string() {
68        let result = StringHandler::validate_and_canonicalize("test", Some(10), "field");
69        assert!(result.is_ok());
70        assert_eq!(result.unwrap(), "test");
71    }
72
73    #[test]
74    fn test_empty_string_fails() {
75        let result = StringHandler::validate_and_canonicalize("", Some(10), "field");
76        assert!(result.is_err());
77        assert!(result.unwrap_err().to_string().contains("cannot be empty"));
78    }
79
80    #[test]
81    fn test_too_long_string_fails() {
82        let result = StringHandler::validate_and_canonicalize("toolong", Some(5), "field");
83        assert!(result.is_err());
84        assert!(
85            result
86                .unwrap_err()
87                .to_string()
88                .contains("exceeds maximum length")
89        );
90    }
91
92    #[test]
93    fn test_no_length_limit() {
94        let result = StringHandler::validate_and_canonicalize("very long string", None, "field");
95        assert!(result.is_ok());
96    }
97}