# `cargo-needy` and `#[needy::requirements(...)]` ## Usage ### 1. Add `requirements_ids` to your dev-dependencies. ```console $ cargo add --dev requirements_ids ``` > [!TIP] > If you want to trace non-test functions, you will need to add it as a > normal dependency. ### 2. Annotate your test functions with the corresponding requirement ids The requirement can be any valid identifier ([see syntax in FLS](https://spec.ferrocene.dev/lexical-elements.html#syntax_identifier)). ```rust use needy::requirements; // test a single requirement #[requirements(REQ_001)] #[test] fn it_works() { assert_eq!(1 + 1, 2); } // test multiple requirements #[requirements(REQ_001, REQ_002)] #[test] fn it_works_also() { assert_eq!(1 + 1, 2); } ``` ### 3. Use `cargo-needy` to export a JSON of all requirements > [!WARNING] > At the moment `cargo-needy` requires Rust nightly from 2024-09-26 or > later, because of some rust-analyzer features we rely on. > > This restriction will be lifted as soon as that rust-analyzer version becomes > stable. > > Until then run set your Rust toolchain to nightly: > > ```console > $ # set nightly globally > $ rustup default nightly > $ > $ # set nightly for the current directory > $ rustup override set nightly > $ > $ # set nightly for the command only > $ cargo +nightly needy > ``` ```console $ rustup component add rust-analyzer $ cargo install cargo-needy $ cargo needy ``` This outputs the collected requirement ids as JSON. For example for `cargo-needy/tests/test-crate` it looks like this: ```console $ cargo needy cargo-needy/tests/test-crate/ Running `cargo check --manifest-path cargo-needy/tests/test-crate/Cargo.toml --all-targets` took 45.6ms Running `rust-analyzer lsif cargo-needy/tests/test-crate/` took 11.5s Analyzing lsif output took 89.6ms {"file":"file:///home/urhengulas/Documents/github.com/ferrocene/cargo-needy/cargo-needy/tests/test-crate/src/main.rs","function_name":"test_main","module":"test_crate","requirement_id":"REQ_001","span":{"start":{"line":10,"character":22},"end":{"line":10,"character":29}},"version":"v1"} {"file":"file:///home/urhengulas/Documents/github.com/ferrocene/cargo-needy/cargo-needy/tests/test-crate/tests/it_works.rs","function_name":"it_works","module":"it_works","requirement_id":"REQ_002","span":{"start":{"line":0,"character":35},"end":{"line":0,"character":42}},"version":"v1"} {"file":"file:///home/urhengulas/Documents/github.com/ferrocene/cargo-needy/cargo-needy/tests/test-crate/tests/it_works.rs","function_name":"it_works","module":"it_works","requirement_id":"REQ_003","span":{"start":{"line":0,"character":44},"end":{"line":0,"character":51}},"version":"v1"} ``` ## Benchmark In order to optimize the project there is a benchmark crate which heavily uses the `needy::requirements` macro. To get end-to-end timings you can use `bench.py` which runs `cargo-needy` multiple iterations via `hyperfine`. ```console $ python bench.py Benchmark 1: cargo +nightly run --release -q -- tests/bench-crate/ 1> /dev/null Time (mean ± σ): 8288.6 ms ± 327.0 ms [User: 8056.2 ms, System: 497.2 ms] Range (min … max): 7509.9 ms … 8674.0 ms 10 runs $ # To get timings of the analysis stage, pass the `--bench-analyze` flag. $ python bench.py --bench-analyze $ # To benchmark more iterations, pass the `--more-runs` flag. $ python bench.py --bench-analyze ``` Please take care to have a similar setup when you compare timing runs and be aware that there is noise.