This crate provides #[test_resources]
and #[bench_resources]
procedural macro attributes
that generates multiple parametrized tests using one body with different resource input parameters.
A test is generated for each resource matching the specific resource location pattern.
The following examples assume the package layout is as follows:
├── build.rs
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── res
│ ├── set1
│ │ ├── expect.txt
│ │ └── input.txt
│ ├── set2
│ │ ├── expect.txt
│ │ └── input.txt
│ └── set3
│ ├── expect.txt
│ └── input.txt
├── src
│ └── main.rs
├── benches
│ └── mybenches.rs
└── tests
└── mytests.rs
This is the package layout of the example package,
here the tests are located in file mytests.rs
and bench-tests are located in file mybenches.rs
; the tests and benches depend
on the content of the res/
directory.
The build-script build.rs
is used to realize conditional re-runs, in case a resource-file has changed or
(more interesting) if new resource-files have been added to the sub-folder structure res/
.
test
:The following test function verify_resource(str)
shall be executed for all items matching the
glob pattern res/*/input.txt
in the resource-folder res/
.
``` #![cfg(test)] extern crate test_generator;
use testgenerator::testresources;
#[testresources("res/*/input.txt")] fn verifyresource(resource: &str) { assert!(std::path::Path::new(resource).exists()); } ```
Output from cargo test
for 3 test-input-files matching the pattern, for this example:
``` $ cargo test
running 3 tests test tests::verifyresourceresset1inputtxt ... ok test tests::verifyresourceresset2inputtxt ... ok test tests::verifyresourceresset3input_txt ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
``
## Example usage
bench`:
``` #![feature(test)] // nightly feature required for API test::Bencher
extern crate test; /* required for test::Bencher */
extern crate testgenerator; use testgenerator::bench_resources;
mod bench {
#[benchresources("res/*/input.txt")]
fn measureresource(b: &mut test::Bencher, resource: &str) {
let path = std::path::Path::new(resource);
b.iter(|| path.exists());
}
}
``
Output from
cargo +nightly bench` for 3 bench-input-files matching the pattern, for this example:
``` running 3 tests test bench::measureresourceresset1inputtxt ... bench: 2,492 ns/iter (+/- 4,027) test bench::measureresourceresset2inputtxt ... bench: 2,345 ns/iter (+/- 2,167) test bench::measureresourceresset3input_txt ... bench: 2,269 ns/iter (+/- 1,527)
test result: ok. 0 passed; 0 failed; 0 ignored; 3 measured; 0 filtered out ```
The example demonstrates usage
and configuration of these macros, in combination with the crate
build-deps
monitoring for any change of these resource files and conditional rebuild.
Let's assume the following code and 3 files matching the pattern "res/*/input.txt"
#[test_resources("res/*/input.txt")]
fn verify_resource(resource: &str) {
assert!(std::path::Path::new(resource).exists());
}
the generated code for this input resource will look like
```
fn verify_resource(resource: &str) {
assert!(std::path::Path::new(resource).exists());
}
#[test] #[allow(nonsnakecase)] fn verifyresourceresset1inputtxt() { verifyresource("res/set1/input.txt".into()); } #[test] #[allow(nonsnakecase)] fn verifyresourceresset2inputtxt() { verifyresource("res/set2/input.txt".into()); } #[test] #[allow(nonsnakecase)] fn verifyresourceresset3inputtxt() { verifyresource("res/set3/input.txt".into()); } ```
Note: The trailing into()
method-call permits users to implement the Into
-Trait for auto-conversations.
The test-function-generator shall be rerun every time a new resource-file is added or one of the existing ones have been changed.
The conditional build can be realized using the crate build-deps, expanding
a glob
pattern such as res/*/input.txt
and registering these elements in cargo-monitoring list.
The user specifies a directory or a set of files, or a a filter-pattern to be watched by
cargo process shall for changes. In case of changes, the build-process of the Rust-sources is re-run.
The following diagram illustrates the integration of the build-script into the conditional cargo build-process.
The filter may be a glob-pattern containing wildcards, for example:
"res/*"
will enumerate all files/directories in directory "res/" and watching changes
"res/"
- will add the directory itself to the watch-list, triggering a rerun in case new entities are added.
"res/**/*.protobuf"
will traverse all sub-directories enumerating all protobuf files.
"res/**"
will traverse all sub-directories enumerating all directories