snippy 0.1.1

A command-line tool for that makes using LLMs for code generation a breeze
Documentation
use snippy::content_extractor::ContentApplier;
use snippy::content_extractor::{BlockType, ParsedBlock};
use snippy::content_extractor::{ContentExtractor, MarkdownExtractor};
use tempfile::tempdir;
use tokio::fs;
use tracing::debug;

#[tokio::test]
async fn test_concurrent_diff_application() {
    let dir = tempdir().unwrap();
    let base_path = dir.path().to_path_buf();
    let logs_path = base_path.clone();
    let applier = ContentApplier::new(base_path.clone(), logs_path);

    let initial_content = "fn main() { println!(\"Hello, world!\"); }\n";
    let mut handles = Vec::new();

    for i in 0..10 {
        let file_path = base_path.join(format!("test{}.rs", i));
        fs::write(&file_path, initial_content)
            .await
            .unwrap_or_else(|e| panic!("Failed to write initial content: {:?}", e));

        let block = ParsedBlock {
            filename: format!("test{}.rs", i),
            content: format!(
                r#"--- test{0}.rs
+++ test{0}.rs
@@ -1 +1 @@
-fn main() {{ println!("Hello, world!"); }}
+fn main() {{ println!("Hello, Rust!"); }}
"#,
                i
            ),
            block_type: BlockType::UnifiedDiff,
        };

        let applier = applier.clone();
        let handle = tokio::spawn(async move { applier.apply(&block).await });
        handles.push(handle);
    }

    for handle in handles {
        let result = handle.await.unwrap();
        assert!(
            result.is_ok(),
            "Concurrent diff application failed: {:?}",
            result.err()
        );
    }

    for i in 0..10 {
        let file_path = base_path.join(format!("test{}.rs", i));
        let content = fs::read_to_string(&file_path)
            .await
            .unwrap_or_else(|e| panic!("Failed to read file: {:?}", e));
        assert!(
            content.contains("fn main() { println!(\"Hello, Rust!\"); }\n"),
            "Content mismatch for file {}",
            i
        );
    }

    debug!("Test passed for concurrent diff application.");
}

#[tokio::test]
async fn test_concurrent_search_replace_application() {
    let dir = tempdir().unwrap();
    let base_path = dir.path().to_path_buf();
    let logs_path = base_path.clone();
    let applier = ContentApplier::new(base_path.clone(), logs_path);

    let initial_content = r#"use std::collections::HashMap;
fn main() { println!("Hello, world!"); }
"#;
    let mut handles = Vec::new();

    for i in 0..10 {
        let file_path = base_path.join(format!("test_search_replace{}.rs", i));
        fs::write(&file_path, initial_content)
            .await
            .unwrap_or_else(|e| panic!("Failed to write initial content: {:?}", e));

        let block = ParsedBlock {
            filename: format!("test_search_replace{}.rs", i),
            content: r#"<<<<<<< SEARCH
use std::collections::HashMap;
=======
use std::collections::BTreeMap;
>>>>>>> REPLACE
<<<<<<< SEARCH
fn main() { println!("Hello, world!"); }
=======
fn main() { println!("Hello, Rust!"); }
>>>>>>> REPLACE
"#
            .to_string(),
            block_type: BlockType::SearchReplaceBlock,
        };

        let applier = applier.clone();
        let handle = tokio::spawn(async move { applier.apply(&block).await });
        handles.push(handle);
    }

    for handle in handles {
        let result = handle.await.unwrap();
        assert!(
            result.is_ok(),
            "Concurrent search-replace application failed: {:?}",
            result.err()
        );
    }

    for i in 0..10 {
        let file_path = base_path.join(format!("test_search_replace{}.rs", i));
        let content = fs::read_to_string(&file_path)
            .await
            .unwrap_or_else(|e| panic!("Failed to read file: {:?}", e));
        assert_eq!(
            content,
            r#"use std::collections::BTreeMap;
fn main() { println!("Hello, Rust!"); }
"#,
            "Content mismatch for file {}",
            i
        );
    }

    debug!("Test passed for concurrent search-replace application.");
}

#[tokio::test]
async fn test_concurrent_extraction_from_large_files() {
    let count = 10000;
    let content = (0..count)
        .map(|i| {
            format!(
                "```rust\n// filename: test{}.rs\nfn main() {{ println!(\"Hello, {}!\"); }}\n```\n",
                i, i
            )
        })
        .collect::<String>();

    let mut handles = Vec::new();
    for _ in 0..10 {
        let extractor = MarkdownExtractor::new();
        let content = content.clone();
        let handle = tokio::spawn(async move { extractor.extract(&content) });
        handles.push(handle);
    }

    for handle in handles {
        let blocks = handle
            .await
            .unwrap()
            .unwrap_or_else(|e| panic!("Failed to extract content: {:?}", e));
        assert_eq!(
            blocks.len(),
            count,
            "Expected {} blocks, got {}",
            count,
            blocks.len()
        );
    }

    debug!("Test passed for concurrent extraction from large files.");
}