mini-static 0.20.0

A secure, async static file server with streaming, traversal protection, and connection limits.
Documentation
use super::*;
use tempfile::TempDir;

#[tokio::test]
async fn bundle_mode_concatenates_discovered_files_in_sorted_order() {
    let src = TempDir::new().unwrap();
    let out = TempDir::new().unwrap();
    let output = out.path().join("styles.css");

    fs::write(src.path().join("a.css"), "A").unwrap();
    fs::write(src.path().join("b.css"), "B").unwrap();

    let options = CssOptions::new().bundle(true).minify(true);
    build_css_bundle(
        CssTool::TestEcho,
        &options,
        &[src.path().to_path_buf()],
        &output,
    )
    .await
    .unwrap();

    let content = fs::read_to_string(&output).unwrap();
    assert_eq!(content, "AB", "files must concatenate in sorted path order");
}

#[tokio::test]
async fn bundle_false_minify_false_is_a_passthrough_copy() {
    let src = TempDir::new().unwrap();
    let out = TempDir::new().unwrap();
    let output = out.path().join("styles.css");

    fs::write(src.path().join("only.css"), "body{color:red}").unwrap();

    let options = CssOptions::new();
    build_css_bundle(
        CssTool::TestMissing,
        &options,
        &[src.path().to_path_buf()],
        &output,
    )
    .await
    .unwrap();

    assert_eq!(fs::read_to_string(&output).unwrap(), "body{color:red}");
}

#[tokio::test]
async fn no_css_files_is_an_error() {
    let src = TempDir::new().unwrap();
    let out = TempDir::new().unwrap();
    let output = out.path().join("styles.css");

    let result = build_css_bundle(
        CssTool::TestEcho,
        &CssOptions::new().bundle(true),
        &[src.path().to_path_buf()],
        &output,
    )
    .await;

    assert!(matches!(result, Err(CssError::NoFilesFound(_))));
}

#[tokio::test]
async fn a_failing_tool_leaves_previous_bundle_output_untouched() {
    let src = TempDir::new().unwrap();
    let out = TempDir::new().unwrap();
    let output = out.path().join("styles.css");
    fs::write(&output, "/* previous good build */").unwrap();
    fs::write(src.path().join("a.css"), "A").unwrap();

    let result = build_css_bundle(
        CssTool::TestMissing,
        &CssOptions::new().bundle(true).minify(true),
        &[src.path().to_path_buf()],
        &output,
    )
    .await;

    assert!(result.is_err());
    assert_eq!(
        fs::read_to_string(&output).unwrap(),
        "/* previous good build */",
        "a failed rebuild must not overwrite the previous good bundle"
    );
}

#[tokio::test]
async fn per_file_mode_with_minify_false_copies_through_unchanged() {
    let src = TempDir::new().unwrap();
    let out = TempDir::new().unwrap();
    let source = src.path().join("app.css");
    let output = out.path().join("app.css");
    fs::write(&source, "body{color:blue}").unwrap();

    build_css_file(CssTool::TestMissing, &CssOptions::new(), &source, &output)
        .await
        .unwrap();

    assert_eq!(fs::read_to_string(&output).unwrap(), "body{color:blue}");
}

#[tokio::test]
async fn per_file_mode_already_minified_skips_the_tool() {
    let src = TempDir::new().unwrap();
    let out = TempDir::new().unwrap();
    let source = src.path().join("app.min.css");
    let output = out.path().join("app.min.css");
    fs::write(&source, "body{color:blue}").unwrap();

    // TestMissing would error if invoked; success proves the tool was skipped.
    build_css_file(
        CssTool::TestMissing,
        &CssOptions::new().minify(true),
        &source,
        &output,
    )
    .await
    .unwrap();

    assert_eq!(fs::read_to_string(&output).unwrap(), "body{color:blue}");
}

#[tokio::test]
async fn per_file_mode_degrades_to_raw_copy_when_the_tool_fails() {
    let src = TempDir::new().unwrap();
    let out = TempDir::new().unwrap();
    let source = src.path().join("app.css");
    let output = out.path().join("app.css");
    fs::write(&source, "body{color:blue}").unwrap();

    build_css_file(
        CssTool::TestMissing,
        &CssOptions::new().minify(true),
        &source,
        &output,
    )
    .await
    .unwrap();

    assert_eq!(
        fs::read_to_string(&output).unwrap(),
        "body{color:blue}",
        "a failing tool must degrade to serving the raw source, not fail the pipeline"
    );
}