Skip to main content

trueno_rag/loader/
text.rs

1//! Text file loader for `.txt` and `.md` files.
2
3use crate::{Document, Result};
4use std::path::Path;
5
6use super::DocumentLoader;
7
8/// Loads plain text and Markdown files.
9///
10/// Supports `.txt` and `.md` extensions.
11#[derive(Debug, Clone, Copy)]
12pub struct TextLoader;
13
14impl DocumentLoader for TextLoader {
15    fn supported_extensions(&self) -> Vec<&str> {
16        vec!["txt", "md"]
17    }
18
19    fn load(&self, path: &Path) -> Result<Document> {
20        let content = std::fs::read_to_string(path).map_err(crate::Error::Io)?;
21        let title = path.file_stem().and_then(|s| s.to_str()).unwrap_or("Untitled").to_string();
22
23        Ok(Document::new(content).with_title(title).with_source(path.to_string_lossy()))
24    }
25}
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30
31    #[test]
32    fn test_text_loader_extensions() {
33        let loader = TextLoader;
34        let exts = loader.supported_extensions();
35        assert!(exts.contains(&"txt"));
36        assert!(exts.contains(&"md"));
37    }
38
39    #[test]
40    fn test_text_loader_can_load() {
41        let loader = TextLoader;
42        assert!(loader.can_load(Path::new("readme.txt")));
43        assert!(loader.can_load(Path::new("README.MD")));
44        assert!(!loader.can_load(Path::new("video.mp4")));
45        assert!(!loader.can_load(Path::new("Makefile")));
46    }
47
48    #[test]
49    fn test_text_loader_load() {
50        let dir = std::env::temp_dir().join("trueno_rag_test_text_loader");
51        let _ = std::fs::create_dir_all(&dir);
52        let file = dir.join("hello.txt");
53        std::fs::write(&file, "Hello, world!").unwrap();
54
55        let loader = TextLoader;
56        let doc = loader.load(&file).unwrap();
57        assert_eq!(doc.content, "Hello, world!");
58        assert_eq!(doc.title.as_deref(), Some("hello"));
59        assert!(doc.source.is_some());
60
61        let _ = std::fs::remove_dir_all(&dir);
62    }
63
64    #[test]
65    fn test_text_loader_missing_file() {
66        let loader = TextLoader;
67        let result = loader.load(Path::new("/nonexistent/file.txt"));
68        assert!(result.is_err());
69    }
70
71    #[test]
72    fn test_text_loader_title_from_stem() {
73        let dir = std::env::temp_dir().join("trueno_rag_test_text_title");
74        let _ = std::fs::create_dir_all(&dir);
75        let file = dir.join("my-document.md");
76        std::fs::write(&file, "# Header").unwrap();
77
78        let loader = TextLoader;
79        let doc = loader.load(&file).unwrap();
80        assert_eq!(doc.title.as_deref(), Some("my-document"));
81
82        let _ = std::fs::remove_dir_all(&dir);
83    }
84}