Skip to content

Commit 274e658

Browse files
committed
Tests: Add TestEnv, to manage temp dir creation and cleanup, nextest compatible
1 parent 94f83f1 commit 274e658

File tree

8 files changed

+137
-84
lines changed

8 files changed

+137
-84
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ members = [
77
exclude = [
88
# This currently needs to be excluded because it depends on a version of `rust-gpu` that
99
# uses a toolchain whose Cargo version doesn't recognise version 4 of `Cargo.lock`.
10-
"crates/shader-crate-template"
10+
"crates/shader-crate-template",
11+
# Testing infra may copy the `shader-crate-template` into subdirs of target
12+
"target",
1113
]
1214

1315
resolver = "2"

crates/cargo-gpu/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ semver.workspace = true
2727
dunce.workspace = true
2828

2929
[dev-dependencies]
30+
tempfile.workspace = true
3031
test-log.workspace = true
3132
cargo_metadata = { workspace = true, features = ["builder"] }
3233
cargo-util-schemas = "0.8.2"

crates/cargo-gpu/src/build.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,6 @@ mod test {
181181

182182
#[test_log::test]
183183
fn builder_from_params() {
184-
crate::test::tests_teardown();
185-
186184
let shader_crate_path = crate::test::shader_crate_template_path();
187185
let output_dir = shader_crate_path.join("shaders");
188186

crates/cargo-gpu/src/config.rs

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,13 @@ impl Config {
8686
mod test {
8787
use super::*;
8888

89+
use crate::test::TestEnv;
8990
use std::io::Write as _;
9091

9192
#[test_log::test]
9293
fn booleans_from_cli() {
93-
let shader_crate_path = crate::test::shader_crate_test_path();
94+
let _env = TestEnv::new();
95+
let shader_crate_path = _env.setup_shader_crate().unwrap();
9496

9597
let args = Config::clap_command_with_cargo_config(
9698
&shader_crate_path,
@@ -108,43 +110,45 @@ mod test {
108110

109111
#[test_log::test]
110112
fn booleans_from_cargo() {
111-
let shader_crate_path = crate::test::shader_crate_test_path();
112-
let mut file = crate::test::overwrite_shader_cargo_toml(&shader_crate_path);
113-
file.write_all(
114-
[
115-
"[package.metadata.rust-gpu.build]",
116-
"release = false",
117-
"[package.metadata.rust-gpu.install]",
118-
"auto-install-rust-toolchain = true",
119-
]
120-
.join("\n")
121-
.as_bytes(),
122-
)
123-
.unwrap();
113+
let _env = TestEnv::new();
114+
let shader_crate_path = _env
115+
.setup_shader_crate_with_cargo_toml(|file| {
116+
file.write_all(
117+
[
118+
"[package.metadata.rust-gpu.build]",
119+
"release = false",
120+
"[package.metadata.rust-gpu.install]",
121+
"auto-install-rust-toolchain = true",
122+
]
123+
.join("\n")
124+
.as_bytes(),
125+
)
126+
})
127+
.unwrap();
124128

125129
let args = Config::clap_command_with_cargo_config(&shader_crate_path, vec![]).unwrap();
126130
assert!(!args.build.spirv_builder.release);
127131
assert!(args.install.auto_install_rust_toolchain);
128132
}
129133

130-
fn update_cargo_output_dir() -> std::path::PathBuf {
131-
let shader_crate_path = crate::test::shader_crate_test_path();
132-
let mut file = crate::test::overwrite_shader_cargo_toml(&shader_crate_path);
133-
file.write_all(
134-
[
135-
"[package.metadata.rust-gpu.build]",
136-
"output-dir = \"/the/moon\"",
137-
]
138-
.join("\n")
139-
.as_bytes(),
140-
)
141-
.unwrap();
142-
shader_crate_path
134+
fn update_cargo_output_dir(_env: &TestEnv) -> std::path::PathBuf {
135+
_env.setup_shader_crate_with_cargo_toml(|file| {
136+
file.write_all(
137+
[
138+
"[package.metadata.rust-gpu.build]",
139+
"output-dir = \"/the/moon\"",
140+
]
141+
.join("\n")
142+
.as_bytes(),
143+
)
144+
})
145+
.unwrap()
143146
}
144147

145148
#[test_log::test]
146149
fn string_from_cargo() {
147-
let shader_crate_path = update_cargo_output_dir();
150+
let _env = TestEnv::new();
151+
let shader_crate_path = update_cargo_output_dir(&_env);
148152

149153
let args = Config::clap_command_with_cargo_config(&shader_crate_path, vec![]).unwrap();
150154
if cfg!(target_os = "windows") {
@@ -156,7 +160,8 @@ mod test {
156160

157161
#[test_log::test]
158162
fn string_from_cargo_overwritten_by_cli() {
159-
let shader_crate_path = update_cargo_output_dir();
163+
let _env = TestEnv::new();
164+
let shader_crate_path = update_cargo_output_dir(&_env);
160165

161166
let args = Config::clap_command_with_cargo_config(
162167
&shader_crate_path,
@@ -173,17 +178,19 @@ mod test {
173178

174179
#[test_log::test]
175180
fn arrays_from_cargo() {
176-
let shader_crate_path = crate::test::shader_crate_test_path();
177-
let mut file = crate::test::overwrite_shader_cargo_toml(&shader_crate_path);
178-
file.write_all(
179-
[
180-
"[package.metadata.rust-gpu.build]",
181-
"capabilities = [\"AtomicStorage\", \"Matrix\"]",
182-
]
183-
.join("\n")
184-
.as_bytes(),
185-
)
186-
.unwrap();
181+
let _env = TestEnv::new();
182+
let shader_crate_path = _env
183+
.setup_shader_crate_with_cargo_toml(|file| {
184+
file.write_all(
185+
[
186+
"[package.metadata.rust-gpu.build]",
187+
"capabilities = [\"AtomicStorage\", \"Matrix\"]",
188+
]
189+
.join("\n")
190+
.as_bytes(),
191+
)
192+
})
193+
.unwrap();
187194

188195
let args = Config::clap_command_with_cargo_config(&shader_crate_path, vec![]).unwrap();
189196
assert_eq!(
@@ -197,7 +204,8 @@ mod test {
197204

198205
#[test_log::test]
199206
fn rename_manifest_parse() {
200-
let shader_crate_path = crate::test::shader_crate_test_path();
207+
let _env = TestEnv::new();
208+
let shader_crate_path = _env.setup_shader_crate().unwrap();
201209

202210
let args = Config::clap_command_with_cargo_config(
203211
&shader_crate_path,

crates/cargo-gpu/src/lib.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@
5050
//! conduct other post-processing, like converting the `spv` files into `wgsl` files,
5151
//! for example.
5252
53-
use anyhow::Context as _;
54-
5553
use crate::dump_usage::dump_full_usage_for_readme;
5654
use build::Build;
5755
use show::Show;
@@ -171,21 +169,18 @@ pub struct Cli {
171169
/// # Errors
172170
/// may fail if we can't find the user home directory
173171
#[inline]
172+
#[cfg(not(test))]
174173
pub fn cache_dir() -> anyhow::Result<std::path::PathBuf> {
175-
let dir = directories::BaseDirs::new()
174+
use anyhow::Context as _;
175+
Ok(directories::BaseDirs::new()
176176
.with_context(|| "could not find the user home directory")?
177177
.cache_dir()
178-
.join("rust-gpu");
179-
180-
Ok(if cfg!(test) {
181-
let thread_id = std::thread::current().id();
182-
let id = format!("{thread_id:?}").replace('(', "-").replace(')', "");
183-
dir.join("tests").join(id)
184-
} else {
185-
dir
186-
})
178+
.join("rust-gpu"))
187179
}
188180

181+
#[cfg(test)]
182+
pub use test::test_cache_dir as cache_dir;
183+
189184
/// Returns a string suitable to use as a directory.
190185
///
191186
/// Created from the spirv-builder source dep and the rustc channel.

crates/cargo-gpu/src/spirv_source.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ pub fn get_channel_from_rustc_codegen_spirv_build_script(
248248
#[cfg(test)]
249249
mod test {
250250
use super::*;
251+
use crate::test::TestEnv;
251252
use cargo_metadata::{PackageBuilder, PackageId, Source};
252253
use cargo_util_schemas::manifest::PackageName;
253254

@@ -272,6 +273,7 @@ mod test {
272273

273274
#[test_log::test]
274275
fn cached_checkout_dir_sanity() {
276+
let _env = TestEnv::new();
275277
let shader_template_path = crate::test::shader_crate_template_path();
276278
let source = SpirvSource::get_rust_gpu_deps_from_shader(&shader_template_path).unwrap();
277279
let dir = source.install_dir().unwrap();

crates/cargo-gpu/src/test.rs

Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,80 @@
11
//! utilities for tests
22
#![cfg(test)]
33

4-
use crate::cache_dir;
4+
use anyhow::Context;
5+
use std::cell::RefCell;
6+
use std::fs::File;
57
use std::io::Write as _;
8+
use std::path::PathBuf;
9+
use tempfile::TempDir;
10+
11+
#[must_use]
12+
pub struct TestEnv(TempDir);
13+
14+
impl TestEnv {
15+
pub fn new() -> Self {
16+
let target_dir = cargo_metadata::MetadataCommand::new()
17+
.exec()
18+
.unwrap()
19+
.target_directory
20+
.into_std_path_buf();
21+
let tests_dir = target_dir.join("cargo-gpu-test");
22+
std::fs::create_dir_all(&tests_dir).ok();
23+
let test_dir = TempDir::new_in(tests_dir).unwrap();
24+
25+
let had_old = TESTDIR
26+
.replace(Some(test_dir.path().to_path_buf()))
27+
.is_some();
28+
if had_old {
29+
panic!("TestEnv is not reentrant!")
30+
}
31+
32+
TestEnv(test_dir)
33+
}
34+
35+
pub fn setup_shader_crate(&self) -> anyhow::Result<PathBuf> {
36+
let shader_crate_path = crate::cache_dir().unwrap().join("shader_crate");
37+
copy_dir_all(shader_crate_template_path(), &shader_crate_path)?;
38+
Ok(shader_crate_path)
39+
}
40+
41+
pub fn setup_shader_crate_with_cargo_toml(
42+
&self,
43+
f: impl FnOnce(&mut File) -> std::io::Result<()>,
44+
) -> anyhow::Result<PathBuf> {
45+
let shader_crate_path = self.setup_shader_crate()?;
46+
let cargo_toml = shader_crate_path.join("Cargo.toml");
47+
let mut file = std::fs::OpenOptions::new()
48+
.write(true)
49+
.truncate(true)
50+
.open(cargo_toml)?;
51+
writeln!(file, "[package]")?;
52+
writeln!(file, "name = \"test\"")?;
53+
f(&mut file)?;
54+
Ok(shader_crate_path)
55+
}
56+
}
57+
58+
impl Drop for TestEnv {
59+
fn drop(&mut self) {
60+
TESTDIR.replace(None).unwrap();
61+
// when a test fails, keep directory
62+
if std::thread::panicking() {
63+
self.0.disable_cleanup(true);
64+
}
65+
}
66+
}
67+
68+
thread_local! {
69+
static TESTDIR: RefCell<Option<PathBuf>> = RefCell::new(None);
70+
}
71+
72+
/// [`crate::cache_dir`] for testing
73+
pub fn test_cache_dir() -> anyhow::Result<PathBuf> {
74+
Ok(TESTDIR.with_borrow(|a| a.clone()).context(
75+
"TestEnv is not initialized! Add `let _env = TestEnv::new();` to the beginning of your test",
76+
)?)
77+
}
678

779
fn copy_dir_all(
880
src: impl AsRef<std::path::Path>,
@@ -21,33 +93,7 @@ fn copy_dir_all(
2193
Ok(())
2294
}
2395

24-
pub fn shader_crate_template_path() -> std::path::PathBuf {
96+
pub fn shader_crate_template_path() -> PathBuf {
2597
let project_base = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
2698
project_base.join("../shader-crate-template")
2799
}
28-
29-
pub fn shader_crate_test_path() -> std::path::PathBuf {
30-
let shader_crate_path = crate::cache_dir().unwrap().join("shader_crate");
31-
copy_dir_all(shader_crate_template_path(), shader_crate_path.clone()).unwrap();
32-
shader_crate_path
33-
}
34-
35-
pub fn overwrite_shader_cargo_toml(shader_crate_path: &std::path::Path) -> std::fs::File {
36-
let cargo_toml = shader_crate_path.join("Cargo.toml");
37-
let mut file = std::fs::OpenOptions::new()
38-
.write(true)
39-
.truncate(true)
40-
.open(cargo_toml)
41-
.unwrap();
42-
writeln!(file, "[package]").unwrap();
43-
writeln!(file, "name = \"test\"").unwrap();
44-
file
45-
}
46-
47-
pub fn tests_teardown() {
48-
let cache_dir = cache_dir().unwrap();
49-
if !cache_dir.exists() {
50-
return;
51-
}
52-
std::fs::remove_dir_all(cache_dir).unwrap();
53-
}

0 commit comments

Comments
 (0)