dev-fixtures 0.9.1

Repeatable test environments, sample data, and controlled inputs. Part of the dev-* verification suite.
Documentation

What it does

Builds disposable, deterministic test environments. The most common primitive is TempProject, which lets you stage a project tree, run your test against it, and have the directory cleaned up on drop.

Quick start

[dependencies]
dev-fixtures = "0.9.1"
use dev_fixtures::TempProject;

let project = TempProject::new()
    .with_file("Cargo.toml", "[package]\nname = \"sample\"\n")
    .with_file("src/lib.rs", "pub fn answer() -> u32 { 42 }")
    .build()
    .unwrap();

// project.path() points at a temp directory.
// It is deleted automatically when `project` is dropped.

File-tree builders

use dev_fixtures::tree::{rust_workspace, FileTree};

let dir = tempfile::tempdir().unwrap();

// One-line workspace.
rust_workspace(dir.path(), &["alpha", "beta"]).unwrap();

// Or build trees by hand.
FileTree::new(dir.path())
    .file("README.md", "hello")
    .dir("data")
    .file("data/sample.txt", "...")
    .build()
    .unwrap();

Adversarial inputs

use dev_fixtures::adversarial;

let dir = tempfile::tempdir().unwrap();

adversarial::oversized_zeros(&dir.path().join("big.bin"), 1_000_000).unwrap();
adversarial::malformed_utf8(&dir.path().join("bad.txt")).unwrap();
adversarial::random_bytes(&dir.path().join("rand.bin"), 1024, 42).unwrap();

let names = adversarial::unusual_names(5); // emoji, Unicode, dotted, etc.

Golden snapshots

use dev_fixtures::golden::Golden;

let dir = tempfile::tempdir().unwrap();
let g = Golden::new(dir.path().join("snap.txt"));

// First call creates the snapshot (verdict=Skip, tag=created).
let _ = g.compare("greet", "hello\n");
// Subsequent calls verify (Pass / Fail with diff).
let check = g.compare("greet", "hello\n");
assert!(matches!(check.verdict, dev_report::Verdict::Pass));

Set DEV_FIXTURES_UPDATE_GOLDEN=1 to regenerate snapshots on intentional changes.

Mock data

use dev_fixtures::mock::{bytes, csv, json_array, Rng};

// Deterministic CSV.
let csv = csv::generate(&["id", "name"], 10, 42, |rng| {
    vec![rng.range(1000).to_string(), format!("user_{}", rng.range(100))]
});

// Deterministic JSON array.
let json = json_array::generate(10, 42, |rng| format!("{{\"id\":{}}}", rng.range(1000)));

// Raw bytes.
let zeroed = bytes::zeros(1024);
let patterned = bytes::patterned(1024, &[0xDE, 0xAD, 0xBE, 0xEF]);
let random = bytes::random(1024, 42);

dev-report integration

Wrap a fixture lifecycle as a Producer:

use dev_fixtures::{FixtureProducer, TempProject};
use dev_report::Producer;

let producer = FixtureProducer::new(
    "temp_project_lifecycle",
    "0.1.0",
    || {
        let _p = TempProject::new()
            .with_file("README.md", "hello")
            .build()?;
        Ok(())
    },
);
let _report = producer.produce();

Or use Fixture::set_up_checked(name) directly to emit a CheckResult tagged fixtures (and setup_failed + regression on failure).

The dev-* suite

dev-fixtures is one of the producer crates in the dev-* verification suite. See dev-tools for the umbrella crate.

Status

v0.9.x is the pre-1.0 stabilization line. APIs are expected to be near-final; minor adjustments may still happen ahead of 1.0. Cleanup-on-drop and determinism guarantees are the contract.

Cross-platform support

Linux, macOS, and Windows. Symlink helpers are Unix-only and silently no-op on Windows; all other features behave identically across platforms.

Minimum supported Rust version

1.85 — pinned in Cargo.toml via rust-version and verified by the MSRV job in CI. (Bumped from 1.75 because tempfile's transitive dep getrandom requires edition2024, stabilized in Rust 1.85.)

License

Apache-2.0. See LICENSE.