Skip to main content

bake_test_rust/
lib.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4//! Shared test tasks for Rust projects using Bake.
5//!
6//! The crate provides `test` and `test:external`. Both tasks call the optional
7//! project task `test:before` before running Cargo tests.
8mod cargo;
9mod external;
10mod manifest;
11mod metadata;
12
13/// Rust testing tasks register as `test` and `test:external`.
14pub mod test {
15    use bake::{Context, Error, Result};
16
17    use crate::{cargo, external, manifest, metadata};
18
19    fn run_before_test_hook(context: &mut Context) -> Result<()> {
20        context.call_if_registered("test:before", &[])?;
21        Ok(())
22    }
23
24    /// Run the current Cargo workspace tests with the lockfile enforced.
25    #[bake::task(name = "test")]
26    pub fn run(
27        context: &mut Context,
28        #[bake(named, default = false, help = "Also test examples and benchmarks.")]
29        all_targets: bool,
30    ) -> Result<String> {
31        run_before_test_hook(context)?;
32
33        let mut arguments = vec![
34            "test".to_owned(),
35            "--workspace".to_owned(),
36            "--locked".to_owned(),
37        ];
38        if all_targets {
39            arguments.push("--all-targets".to_owned());
40        }
41
42        cargo::run(context, &arguments)?;
43        Ok("Cargo workspace tests passed".to_owned())
44    }
45
46    /// Test configured downstream repositories against this workspace's local packages.
47    #[bake::task(name = "test:external")]
48    pub fn external(
49        context: &mut Context,
50        #[bake(named, default = false, help = "Also test examples and benchmarks.")]
51        all_targets: bool,
52    ) -> Result<String> {
53        let workspace = metadata::read_workspace(context)?;
54        if workspace.external_repositories.is_empty() {
55            return Ok("No downstream repositories are configured for external tests".to_owned());
56        }
57        if workspace.packages.is_empty() {
58            return Err(Error::new(
59                "the current workspace has no crates.io packages to patch into downstream tests",
60            ));
61        }
62
63        let mut checkouts = Vec::with_capacity(workspace.external_repositories.len());
64        for repository in &workspace.external_repositories {
65            let checkout = external::checkout(context, repository)?;
66            manifest::patch_checkout(&checkout, &workspace.packages)?;
67            external::ensure_local_patches_are_selected(&checkout, &workspace.packages)?;
68            checkouts.push(checkout);
69        }
70
71        run_before_test_hook(context)?;
72
73        for checkout in &checkouts {
74            let mut arguments = vec!["test".to_owned(), "--workspace".to_owned()];
75            if all_targets {
76                arguments.push("--all-targets".to_owned());
77            }
78            external::run_cargo(checkout, &arguments)?;
79        }
80
81        let repository_count = checkouts.len();
82        let repository_label = if repository_count == 1 {
83            "repository"
84        } else {
85            "repositories"
86        };
87        Ok(format!(
88            "External tests passed for {repository_count} downstream {repository_label}"
89        ))
90    }
91}