#![allow(dead_code)]
use crate::io::file_buffer::{FileBuffer, FileBufferError};
use crate::io::file_system::FileSystemTrait;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct FileBufferManager<F: FileSystemTrait> {
buffers: HashMap<PathBuf, FileBuffer<F>>,
filesystem: F,
}
impl<F: FileSystemTrait + Clone> FileBufferManager<F> {
pub fn new(filesystem: F) -> Self {
Self {
buffers: HashMap::new(),
filesystem,
}
}
pub fn get_buffer(
&mut self,
path: impl AsRef<Path>,
) -> Result<&mut FileBuffer<F>, FileBufferError> {
let path_buf = path.as_ref().to_path_buf();
if !self.buffers.contains_key(&path_buf) {
let buffer = FileBuffer::new_with_filesystem(&path_buf, self.filesystem.clone())?;
self.buffers.insert(path_buf.clone(), buffer);
}
Ok(self.buffers.get_mut(&path_buf).unwrap())
}
pub fn clear_cache(&mut self) {
self.buffers.clear();
}
}
use crate::io::file_system::RealFileSystem;
pub type RealFileBufferManager = FileBufferManager<RealFileSystem>;
impl RealFileBufferManager {
pub fn new_real() -> Self {
Self::new(RealFileSystem)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::io::file_buffer::FilePosition;
use crate::io::file_system::TestFileSystem;
use std::time::{Duration, UNIX_EPOCH};
use tempfile::tempdir;
#[cfg(feature = "test-logging")]
#[ctor::ctor]
fn init_test_logging() {
crate::test_utils::logging::init();
}
#[test]
fn test_file_buffer_manager_caching() {
let filesystem = TestFileSystem::new();
let test_path = PathBuf::from("/test/cached.txt");
let content = "Cached content";
let time = UNIX_EPOCH + Duration::from_secs(1000);
filesystem.set_file_content(&test_path, content, time);
let mut manager = FileBufferManager::new(filesystem);
{
let buffer1 = manager.get_buffer(&test_path).unwrap();
let start = FilePosition::new(0, 0);
let end = FilePosition::new(0, 6);
let result = buffer1.text_between(start, end).unwrap();
assert_eq!(result, "Cached");
}
{
let buffer2 = manager.get_buffer(&test_path).unwrap();
let start = FilePosition::new(0, 0);
let end = FilePosition::new(0, 6);
let result = buffer2.text_between(start, end).unwrap();
assert_eq!(result, "Cached");
}
}
#[test]
fn test_file_buffer_manager_cache_operations() {
let filesystem = TestFileSystem::new();
let mut manager = FileBufferManager::new(filesystem.clone());
let path1 = PathBuf::from("/test/file1.txt");
let path2 = PathBuf::from("/test/file2.txt");
let time = UNIX_EPOCH + Duration::from_secs(1000);
filesystem.set_file_content(&path1, "Content 1", time);
filesystem.set_file_content(&path2, "Content 2", time);
{
let buffer1 = manager.get_buffer(&path1).unwrap();
let start = FilePosition::new(0, 0);
let end = FilePosition::new(0, 7);
let result = buffer1.text_between(start, end).unwrap();
assert_eq!(result, "Content");
}
{
let buffer2 = manager.get_buffer(&path2).unwrap();
let start = FilePosition::new(0, 0);
let end = FilePosition::new(0, 7);
let result = buffer2.text_between(start, end).unwrap();
assert_eq!(result, "Content");
}
manager.clear_cache();
{
let buffer1 = manager.get_buffer(&path1).unwrap();
let start = FilePosition::new(0, 0);
let end = FilePosition::new(0, 7);
let result = buffer1.text_between(start, end).unwrap();
assert_eq!(result, "Content");
}
}
#[test]
fn test_file_buffer_manager_with_real_filesystem() {
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("test.txt");
let content = "Real filesystem content\nSecond line";
std::fs::write(&file_path, content).unwrap();
let mut manager = RealFileBufferManager::new_real();
{
let buffer = manager.get_buffer(&file_path).unwrap();
let start = FilePosition::new(0, 0);
let end = FilePosition::new(0, 4);
let result = buffer.text_between(start, end).unwrap();
assert_eq!(result, "Real");
let start = FilePosition::new(1, 0);
let end = FilePosition::new(1, 6);
let result = buffer.text_between(start, end).unwrap();
assert_eq!(result, "Second");
}
}
#[test]
fn test_filemanager_concurrent_access_simulation() {
let filesystem = TestFileSystem::new();
let test_path = PathBuf::from("/test/concurrent.txt");
let time = UNIX_EPOCH + Duration::from_secs(1000);
filesystem.set_file_content(&test_path, "Initial content", time);
let mut manager1 = FileBufferManager::new(filesystem.clone());
let mut manager2 = FileBufferManager::new(filesystem.clone());
let buffer1 = manager1.get_buffer(&test_path).unwrap();
let buffer2 = manager2.get_buffer(&test_path).unwrap();
assert!(!std::ptr::eq(buffer1, buffer2));
let start = FilePosition::new(0, 0);
let end = FilePosition::new(0, 7);
let result1 = buffer1.text_between(start, end).unwrap();
let result2 = buffer2.text_between(start, end).unwrap();
assert_eq!(result1, "Initial");
assert_eq!(result2, "Initial");
let updated_time = time + Duration::from_secs(1000);
filesystem.update_file_content(&test_path, "Updated content", updated_time);
let result1 = buffer1.text_between(start, end).unwrap();
let result2 = buffer2.text_between(start, end).unwrap();
assert_eq!(result1, "Updated");
assert_eq!(result2, "Updated");
}
}