feat: module application avec render_service et file_service

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:09:08 +02:00
parent 7d2f56a364
commit 9eae97f1d8
4 changed files with 129 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
use crate::infrastructure::file_repository;
use std::path::Path;
#[allow(dead_code)]
pub fn list_markdown_files(dir: &str) -> Result<Vec<String>, String> {
let path = Path::new(dir);
if !path.is_dir() {
return Err(format!("{dir} n'est pas un dossier"));
}
let mut files = Vec::new();
file_repository::collect_md_files(path, &mut files).map_err(|e| e.to_string())?;
files.sort();
Ok(files)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
fn tmpdir(name: &str) -> std::path::PathBuf {
std::env::temp_dir().join(name)
}
#[test]
fn list_markdown_files_sorted() {
let dir = tmpdir("pena_fs_sorted");
fs::create_dir_all(&dir).unwrap();
fs::write(dir.join("z.md"), "").unwrap();
fs::write(dir.join("a.md"), "").unwrap();
fs::write(dir.join("m.md"), "").unwrap();
let result = list_markdown_files(dir.to_str().unwrap()).unwrap();
fs::remove_dir_all(&dir).unwrap();
assert_eq!(result.len(), 3);
assert!(result[0] < result[1] && result[1] < result[2]);
assert!(result[0].ends_with("a.md"));
assert!(result[2].ends_with("z.md"));
}
#[test]
fn list_markdown_files_ignores_non_md() {
let dir = tmpdir("pena_fs_non_md");
fs::create_dir_all(&dir).unwrap();
fs::write(dir.join("doc.md"), "").unwrap();
fs::write(dir.join("notes.txt"), "").unwrap();
let result = list_markdown_files(dir.to_str().unwrap()).unwrap();
fs::remove_dir_all(&dir).unwrap();
assert_eq!(result.len(), 1);
assert!(result[0].ends_with("doc.md"));
}
#[test]
fn list_markdown_files_not_a_dir() {
let result = list_markdown_files("/nonexistent/pena_fs_dir");
assert!(result.is_err());
}
#[test]
fn list_markdown_files_empty_dir() {
let dir = tmpdir("pena_fs_empty");
fs::create_dir_all(&dir).unwrap();
let result = list_markdown_files(dir.to_str().unwrap()).unwrap();
fs::remove_dir_all(&dir).unwrap();
assert_eq!(result.len(), 0);
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod file_service;
pub mod render_service;
@@ -0,0 +1,60 @@
use crate::domain::MarkdownRenderer;
use crate::infrastructure::file_repository;
#[allow(dead_code)]
pub fn render_string(renderer: &dyn MarkdownRenderer, content: &str) -> String {
renderer.render(content)
}
#[allow(dead_code)]
pub fn render_file(renderer: &dyn MarkdownRenderer, path: &str) -> Result<String, String> {
let content = file_repository::read_file(path)?;
Ok(renderer.render(&content))
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
struct MockRenderer;
impl MarkdownRenderer for MockRenderer {
fn render(&self, content: &str) -> String {
format!("<mock>{content}</mock>")
}
}
#[test]
fn render_string_delegates_to_renderer() {
let renderer = MockRenderer;
let result = render_string(&renderer, "hello");
assert_eq!(result, "<mock>hello</mock>");
}
#[test]
fn render_string_empty_content() {
let renderer = MockRenderer;
let result = render_string(&renderer, "");
assert_eq!(result, "<mock></mock>");
}
#[test]
fn render_file_success() {
let dir = std::env::temp_dir().join("pena_rs_render_file");
fs::create_dir_all(&dir).unwrap();
let file = dir.join("test.md");
fs::write(&file, "world").unwrap();
let renderer = MockRenderer;
let result = render_file(&renderer, file.to_str().unwrap());
fs::remove_dir_all(&dir).unwrap();
assert_eq!(result.unwrap(), "<mock>world</mock>");
}
#[test]
fn render_file_not_found() {
let renderer = MockRenderer;
let result = render_file(&renderer, "/nonexistent/pena_rs_file.md");
assert!(result.is_err());
}
}
+1
View File
@@ -1,3 +1,4 @@
mod application;
mod core;
mod domain;
mod infrastructure;