Skip to content

Commit

Permalink
[meta] add support for include_dir
Browse files Browse the repository at this point in the history
I wanted to publish a crate to crates.io containing a bunch of files with test
vectors that can be reused, and then use it within datatest-stable. To address
this use case, add `include_dir` as an optional dependency.

See the documentation for more.
  • Loading branch information
sunshowers committed Dec 24, 2024
1 parent 8a4af0c commit 09cbeed
Show file tree
Hide file tree
Showing 12 changed files with 818 additions and 210 deletions.
25 changes: 16 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
uses: taiki-e/install-action@8484225d9734e230a8bf38421a4ffec1cc249372 # v2
with:
tool: cargo-sync-rdme,just
- name: Install nightly toolchain for cargo-sync-rdme
uses: dtolnay/rust-toolchain@nightly
- name: Generate readmes
run: just generate-readmes
- name: Check for differences
Expand Down Expand Up @@ -68,24 +70,29 @@ jobs:
- uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2
with:
key: ${{ matrix.rust-version }}
- name: Install tools
uses: taiki-e/install-action@8484225d9734e230a8bf38421a4ffec1cc249372 # v2
with:
tool: cargo-hack,just,nextest
- name: Build
run: cargo build
- name: Install latest nextest release
uses: taiki-e/install-action@nextest
- name: Build datatest-stable
run: cargo build
run: just powerset build
- name: Build with all targets
run: just powerset build --all-targets
- name: Run tests
run: cargo nextest run
run: just powerset nextest run
- name: Run tests with cargo test
run: cargo test
run: just powerset test

# Remove Cargo.lock to ensure that building with the latest versions works on stable.
- name: Remove Cargo.lock and rebuild on stable
if: matrix.rust-version == 'stable'
run: rm Cargo.lock && cargo build
- name: Build with all targets
if: matrix.rust-version == 'stable'
run: just powerset build --all-targets
- name: Run tests on stable
if: matrix.rust-version == 'stable'
run: cargo nextest run
run: just powerset nextest run
- name: Run tests with cargo test on stable
if: matrix.rust-version == 'stable'
run: cargo test
run: just powerset test
20 changes: 20 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,17 @@ crates-io = true
docs-rs = true
rust-version = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg=doc_cfg"]

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(doc_cfg)'] }

[dependencies]
camino = "1.1.9"
fancy-regex = "0.14.0"
include_dir = { version = "0.7.4", optional = true }
libtest-mimic = "0.8.1"
walkdir = "2.5.0"

Expand All @@ -38,3 +46,6 @@ harness = false
[[test]]
name = "run_example"
harness = true

[features]
include-dir = ["dep:include_dir"]
7 changes: 6 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
help:
just --list


# Run `cargo hack --feature-powerset` with the given arguments.
powerset *args:
cargo hack --feature-powerset {{args}}

# Build docs for crates and direct dependencies
rustdoc:
@cargo tree --depth 1 -e normal --prefix none --workspace \
Expand All @@ -11,4 +16,4 @@ rustdoc:

# Generate README.md files using `cargo-sync-rdme`.
generate-readmes:
cargo sync-rdme --toolchain nightly
cargo sync-rdme --toolchain nightly --all-features
105 changes: 101 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
<!-- cargo-sync-rdme ]] -->
<!-- cargo-sync-rdme rustdoc [[ -->
`datatest-stable` is a test harness intended to write *file-driven* or *data-driven* tests,
where individual test cases are specified as files and not as code.
where individual test case fixtures are specified as files and not as code.

Given:

* a test `my_test` that accepts a path, and optionally the contents as input
* a directory to look for files in
* a directory to look for files (test fixtures) in
* a pattern to match files on

`datatest-stable` will call the `my_test` function once per matching file in the directory.
`datatest-stable` will call the `my_test` function once per matching file in
the directory. Directory traversals are recursive.

`datatest-stable` works with [cargo nextest](https://nexte.st/), and is part of the [nextest-rs
organization](https://github.com/nextest-rs/) on GitHub.
Expand All @@ -38,6 +39,7 @@ harness = false

* `testfn` - The test function to be executed on each matching input. This function can be one
of:

* `fn(&Path) -> datatest_stable::Result<()>`
* `fn(&Utf8Path) -> datatest_stable::Result<()>` (`Utf8Path` is part of the
[`camino`](https://docs.rs/camino) library, and is re-exported here for convenience.)
Expand All @@ -49,14 +51,23 @@ harness = false
in as a `Vec<u8>` (erroring out if that failed).
* `root` - The path to the root directory where the input files (fixtures) live. This path is
relative to the root of the crate (the directory where the crate’s `Cargo.toml` is located).

`root` is an arbitrary expression that implements `Display`, such as `&str`, or a
function call that returns a `Utf8PathBuf`.

* `pattern` - a regex used to match against and select each file to be tested. Extended regexes
with lookaround and backtracking are supported via the
[`fancy_regex`](https://docs.rs/fancy-regex) crate.

`pattern` is an arbitrary expression that implements `Display`, such as
`&str`, or a function call that returns a `String`.

The passed-in `Path` and `Utf8Path` are **absolute** paths to the files to be tested.

The three parameters can be repeated if you have multiple sets of data-driven tests to be run:
`datatest_stable::harness!(testfn1, root1, pattern1, testfn2, root2, pattern2)`.

## Examples
### Examples

This is an example test. Use it with `harness = false`.

Expand All @@ -82,6 +93,92 @@ datatest_stable::harness!(
);
````

### Embedding directories at compile time

With the `include-dir` feature enabled, you can use the
[`include_dir`](https://docs.rs/include_dir) crate’s [`include_dir!`](https://docs.rs/include_dir_macros/0.7.4/include_dir_macros/macro.include_dir.html) macro.
This allows you to embed directories into the binary at compile time.

This is generally not recommended for rapidly-changing test data, since each
change will force a rebuild. But it can be useful for relatively-unchanging
data suites distributed separately, e.g. on crates.io.

With the `include-dir` feature enabled, you can use:

````rust
// The `include_dir!` macro is re-exported for convenience.
use datatest_stable::include_dir;
use std::path::Path;

fn my_test(path: &Path, contents: Vec<u8>) -> datatest_stable::Result<()> {
// ... write test here
Ok(())
}

datatest_stable::harness!(
my_test, include_dir!("tests/files"), r"^.*/*",
);
````

You can also use directories published as `static` items in upstream crates:

````rust
use datatest_stable::{include_dir, Utf8Path};

// In the upstream crate:
pub static FIXTURES: include_dir::Dir<'static> = include_dir!("tests/files");

// In your test:
fn my_test(path: &Utf8Path, contents: String) -> datatest_stable::Result<()> {
// ... write test here
Ok(())
}

datatest_stable::harness!(
my_test, &FIXTURES, r"^.*/*",
);
````

In this case, the passed-in `Path` and `Utf8Path` are **relative** to the
root of the included directory.

Because the files don’t exist on disk, the test functions must accept their
contents as either a `String` or a `Vec<u8>`. If the argument is not
provided, the harness will panic at runtime.

### Conditionally embedding directories

It is also possible to conditionally include directories at compile time via
a feature flag. For example, you might have an internal-only `testing`
feature that you turn on locally, but users don’t on crates.io. In that
case, you can use:

````rust
use datatest_stable::Utf8Path;

static FIXTURES: &str = "tests/files";

static FIXTURES: include_dir::Dir<'static> = datatest_stable::include_dir!("tests/files");

fn my_test(path: &Utf8Path, contents: String) -> datatest_stable::Result<()> {
// ... write test here
Ok(())
}

datatest_stable::harness!(
my_test, &FIXTURES, r"^.*/*",
);
````

In this case, note that `path` will be absolute if `FIXTURES` is a string,
and relative if `FIXTURES` is a `Dir`. Your test should be prepared to
handle either case.

## Features

* `include-dir`: Enables the `include_dir!` macro, which allows embedding
directories at compile time. This feature is disabled by default.

## Minimum supported Rust version (MSRV)

The minimum supported Rust version is **Rust 1.72**. MSRV bumps may be accompanied by a minor
Expand Down
Loading

0 comments on commit 09cbeed

Please sign in to comment.