tryexpand 0.9.2

Test harness for macro expansion
Documentation
# `tryexpand`

[![Crates.io](https://img.shields.io/crates/v/tryexpand)](https://crates.io/crates/tryexpand)
[![Crates.io](https://img.shields.io/crates/d/tryexpand)](https://crates.io/crates/tryexpand)
[![Crates.io](https://img.shields.io/crates/l/tryexpand)](https://crates.io/crates/tryexpand)
[![docs.rs](https://docs.rs/tryexpand/badge.svg)](https://docs.rs/tryexpand/)

Similar to [trybuild](https://crates.io/crates/trybuild), but allows you to test how declarative or procedural macros are expanded.

----

## Documentation

Please refer to the documentation on [docs.rs](https://docs.rs/tryexpand).

## Requirements

`tryexpand` requires [cargo-expand](https://crates.io/crates/cargo-expand) to be installed.

## Usage

### Installation

Add `tryexpand` to your project as a dev-dependency by running

```terminal
cargo install --dev tryexpand
```

### Writing tests

Then under your crate's `tests/` directory, create `tests.rs` file containing calls to `tryexpand::expand()` and populate the `tests/expand/pass/`, `tests/expand/checked_pass/` and `tests/expand/fail/` directories with corresponding Rust source files under test.

### Test actions

The `tryexpand` crate exposes the following functions test actions:

#### cargo expand

The `tryexpand::expand(…)` function runs `cargo expand` for each test file and snapshot the results:

```rust
tryexpand::expand(
    // ...
)
.expect_pass();
```

If you wish to also perform additional snapshot tests for all successfully expanded files you can do so via an additional call to either of these:

- `.and_check()` to run `cargo check` for each test file and snapshot the results:

  ```rust
  tryexpand::expand(
      // ...
  )
  .and_check()
  .expect_pass();
  ```

- `.and_run()` to run `cargo run` for each test file and snapshot the results:

  ```rust
  tryexpand::expand(
      // ...
  )
  .and_run()
  .expect_pass();
  ```

- `.and_run_tests()` to run `cargo test` for each test file and snapshot the results:

  ```rust
  tryexpand::expand(
      // ...
  )
  .and_run_tests()
  .expect_pass();
  ```

#### cargo check

The `tryexpand::check(…)` function runs `cargo check` for each test file and snapshot the results:

```rust
tryexpand::check(
    // ...
)
.expect_pass();
```

#### cargo run

The `tryexpand::run(…)` function runs `cargo run` for each test file and snapshot the results:

```rust
tryexpand::run(
    // ...
)
.expect_pass();
```

#### cargo test

The `tryexpand::run_tests(…)` function runs `cargo test` for each test file and snapshot the results:

```rust
tryexpand::run_tests(
    // ...
)
.expect_pass();
```

#### Pass

The base of each `tryexpand` test suite is the corresponding [test action](#test-actions) function (we're using `tryexpand::expand(…)` here, but this applies to all actions), which you pass a list of file paths (or glob patterns) to:

```rust
#[test]
pub fn pass() {
    tryexpand::expand(
        ["tests/expand/pass/*.rs"]
    ).expect_pass();

    // or its short-hand (by default `.expect_pass()` is implied):

    tryexpand::expand(
        ["tests/expand/pass/*.rs"]
    );
}
```

By default `tryexpand`'s [test action](#test-actions) functions assert matched test files to pass their tests.

#### Fail

If instead you want to write tests for a failure's diagnostics, then ou can do so via an additional call to `.expect_fail()` (we're using `tryexpand::expand(…)` here, but this applies to all actions):

```rust
#[test]
pub fn fail() {
    tryexpand::expand(
        ["tests/expand/fail/*.rs"]
    ).expect_fail();
}
```

#### CLI arguments

Additionally you can specify arguments to pass to the `cargo` command:

```rust
#[test]
tryexpand::expand(
    // ...
)
// ...
.args(["--features", "test-feature"])
.expect_pass();
```

#### CLI env vars

As well as environment variables to set for the `cargo` command:

```rust
tryexpand::expand(
    // ...
)
// ...
.envs([("MY_ENV", "my env var value")])
.expect_pass();
```

### Running tests

The test can be run with:

```terminal
cargo test
```

While it is possible to run parallel tests it is recommended to run them serially:

```terminal
cargo test -- --test-threads=1
```

For debugging purposes you may want to see the output for all tests, not just the failing ones:

```terminal
cargo test -- --no-capture
```

Each `tryexpand` test will invoke the `cargo expand` command (as well as any of the optional follow-up commands: `cargo check`, `cargo run`, `cargo test`) on each of the source files that matches the glob pattern and will compare the expansion result with the corresponding `*.out.rs`, `*.out.txt` or `*.err.txt` snapshot files.

If the environment variable `TRYEXPAND=overwrite` is provided (e.g. `$ TRYEXPAND=overwrite cargo test`), then snapshot files will be created, or overwritten, if one already exists. Snapshot files should get checked into version control.

Hand-writing snapshot files is not recommended.

### Performance considerations

When working with multiple expansion test files, it is recommended to specify wildcard (`*.rs`) instead of doing a multiple calls to the `expand` functions for individual files.

Usage of wildcards for multiple files will group them under a single temporary crate for which dependencies will be built a single time. In contrast, calling `expand` functions for each source file will create multiple temporary crates and that will reduce performance as dependencies will be build for each of the temporary crates.

[More info](https://en.wikipedia.org/wiki/Glob_(programming)) on how glob patterns work.

See [tests/macro-tests](tests/macro-tests) and [tests/proc-macro-tests](tests/proc-macro-tests) as a reference.

### Reliability considerations

Since each rustc/cargo release might make changes to the emitted diagnostics
it is recommended to run `tryexpand` tests using a [pinned](https://rust-lang.github.io/rustup/overrides.html) [toolchain](https://rust-lang.github.io/rustup/concepts/toolchains.html), e.g.:

```terminal
cargo +1.76.0 test <OPTIONS>
```

### Debugging

#### `TRYEXPAND_KEEP_ARTIFACTS`

For each `expand()`-like method call within your tests a temporary and uniquely named Rust project will get generated within `$CARGO_TARGET_DIR/target/tests/`.
By default these projects will get deleted upon test completion (regardless of the outcome).
If you wish to take a look at the actual code/projects being expanded you can provide `TRYEXPAND_KEEP_ARTIFACTS=1` and `tryexpand` will skip the cleanup:

```terminal
TRYEXPAND_KEEP_ARTIFACTS=1 cargo test
```

#### `TRYEXPAND_TRUNCATE_OUTPUT`

By default `tryexpand` truncates console output that's longer than 100 lines.
If you wish to temporarily turn this behavior you can provide `TRYEXPAND_TRUNCATE_OUTPUT=0` and `tryexpand` will produce the full console output:

```terminal
TRYEXPAND_TRUNCATE_OUTPUT=0 cargo test
```

#### `TRYEXPAND_DEBUG_LOG`

If you wish to see the exact commands that `tryexpand` is executing you can provide `TRYEXPAND_DEBUG_LOG=1` (together with `--nocapture`, if you also wish to see logs of passing tests) and `tryexpand` will print additional debug logs:

```terminal
TRYEXPAND_DEBUG_LOG=0 cargo test -- --nocapture
```

## Contributing

Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our [code of conduct](https://www.rust-lang.org/conduct.html),  
and the process for submitting pull requests to us.

## Versioning

We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/regexident/cargo-modules/tags).

## License

This project is licensed under the [**MIT**][mit-license] or [**Apache-2.0**][apache-license] – see the [LICENSE-MIT.md](LICENSE-MIT.md)/[LICENSE-APACHE.md](LICENSE-APACHE.md) files for details.

## Provenance

The `tryexpand` crate originated as a fork of [eupn](https://github.com/eupn)'s `macrotest` ([crates.io](https://crates.io/crates/macrotest)).

[mit-license]: https://www.tldrlegal.com/license/mit-license
[apache-license]: https://www.tldrlegal.com/l/apache-license-2-0-apache-2-0