gglib_core/utils/
validation.rs

1//! File validation utilities for GGUF model files.
2//!
3//! This module provides validation functions to ensure files are
4//! valid GGUF format and can be safely processed by the parser.
5
6use crate::ports::{GgufMetadata, GgufParserPort};
7use anyhow::{Result, anyhow};
8use std::path::Path;
9
10/// Validates that a file exists and has a .gguf extension.
11///
12/// # Arguments
13/// * `file_path` - Path to the file to validate
14///
15/// # Returns
16/// * `Ok(())` if valid, `Err` if file doesn't exist or has wrong extension
17///
18/// # Examples
19///
20/// ```rust
21/// use gglib_core::utils::validation::validate_file;
22/// use std::fs::File;
23/// use tempfile::tempdir;
24///
25/// // Create a temporary .gguf file
26/// let temp_dir = tempdir().unwrap();
27/// let file_path = temp_dir.path().join("model.gguf");
28/// File::create(&file_path).unwrap();
29///
30/// // Validate the file
31/// let result = validate_file(file_path.to_str().unwrap());
32/// assert!(result.is_ok());
33/// ```
34///
35/// ```rust
36/// use gglib_core::utils::validation::validate_file;
37///
38/// // Non-existent file should fail
39/// let result = validate_file("/nonexistent/model.gguf");
40/// assert!(result.is_err());
41/// ```
42pub fn validate_file(file_path: &str) -> Result<()> {
43    let path: &Path = Path::new(file_path);
44
45    if !path.exists() {
46        return Err(anyhow!("File does not exist: {file_path}"));
47    }
48    match path.extension() {
49        Some(ext) if ext == "gguf" => Ok(()),
50        Some(_) => Err(anyhow!("Wrong extension.")),
51        None => Err(anyhow!("File has no extension.")),
52    }
53}
54
55/// Validates a GGUF file and extracts its metadata using the provided parser.
56///
57/// This function performs both file validation (existence and extension) and
58/// GGUF format parsing to extract model metadata.
59///
60/// # Arguments
61/// * `parser` - The GGUF parser to use (injected via port)
62/// * `file_path` - Path to the GGUF file to validate and parse
63///
64/// # Returns
65/// * `Ok(GgufMetadata)` with extracted metadata if valid
66/// * `Err` if file doesn't exist, has wrong extension, or can't be parsed
67pub fn validate_and_parse_gguf(
68    parser: &dyn GgufParserPort,
69    file_path: &str,
70) -> Result<GgufMetadata> {
71    // First validate the file exists and has correct extension
72    validate_file(file_path)?;
73
74    // Then parse the GGUF metadata using the injected parser
75    let path = Path::new(file_path);
76    let metadata = parser.parse(path)?;
77
78    Ok(metadata)
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84    use std::fs::File;
85    use tempfile::tempdir;
86
87    #[test]
88    fn test_validate_file_success() {
89        let temp_dir = tempdir().unwrap();
90        let file_path = temp_dir.path().join("test.gguf");
91        File::create(&file_path).unwrap();
92
93        let result = validate_file(file_path.to_str().unwrap());
94        assert!(result.is_ok());
95    }
96
97    #[test]
98    fn test_validate_file_not_exists() {
99        let result = validate_file("/nonexistent/path/model.gguf");
100        assert!(result.is_err());
101        assert!(
102            result
103                .unwrap_err()
104                .to_string()
105                .contains("File does not exist")
106        );
107    }
108
109    #[test]
110    fn test_validate_file_wrong_extension() {
111        let temp_dir = tempdir().unwrap();
112        let file_path = temp_dir.path().join("test.txt");
113        File::create(&file_path).unwrap();
114
115        let result = validate_file(file_path.to_str().unwrap());
116        assert!(result.is_err());
117        assert!(result.unwrap_err().to_string().contains("Wrong extension"));
118    }
119
120    #[test]
121    fn test_validate_file_no_extension() {
122        let temp_dir = tempdir().unwrap();
123        let file_path = temp_dir.path().join("test_no_ext");
124        File::create(&file_path).unwrap();
125
126        let result = validate_file(file_path.to_str().unwrap());
127        assert!(result.is_err());
128        assert!(
129            result
130                .unwrap_err()
131                .to_string()
132                .contains("File has no extension")
133        );
134    }
135
136    // Note: validate_and_parse_gguf tests would require mock GGUF files
137    // These are better suited for integration tests with actual GGUF samples
138}