Skip to content

Commit 019aeed

Browse files
committed
feat: Use test name for dir when running tests
1 parent e472ccc commit 019aeed

File tree

4 files changed

+113
-30
lines changed

4 files changed

+113
-30
lines changed

crates/cargo-test-macro/src/lib.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ pub fn cargo_test(attr: TokenStream, item: TokenStream) -> TokenStream {
133133
add_attr(&mut ret, "ignore", reason);
134134
}
135135

136+
let mut test_name = None;
137+
let mut num = 0;
138+
136139
// Find where the function body starts, and add the boilerplate at the start.
137140
for token in item {
138141
let group = match token {
@@ -144,18 +147,35 @@ pub fn cargo_test(attr: TokenStream, item: TokenStream) -> TokenStream {
144147
continue;
145148
}
146149
}
150+
TokenTree::Ident(i) => {
151+
// The first time through it will be `fn` the second time is the
152+
// name of the test.
153+
if test_name.is_none() && num == 1 {
154+
test_name = Some(i.to_string())
155+
} else {
156+
num += 1;
157+
}
158+
ret.extend(Some(TokenTree::Ident(i)));
159+
continue;
160+
}
147161
other => {
148162
ret.extend(Some(other));
149163
continue;
150164
}
151165
};
152166

153-
let mut new_body = to_token_stream(
154-
r#"let _test_guard = {
167+
let name = &test_name
168+
.clone()
169+
.map(|n| n.split("::").next().unwrap().to_string())
170+
.unwrap();
171+
172+
let mut new_body = to_token_stream(&format!(
173+
r#"let _test_guard = {{
155174
let tmp_dir = option_env!("CARGO_TARGET_TMPDIR");
156-
cargo_test_support::paths::init_root(tmp_dir)
157-
};"#,
158-
);
175+
let test_dir = cargo_test_support::paths::test_dir(std::file!(), "{name}");
176+
cargo_test_support::paths::init_root(tmp_dir, test_dir)
177+
}};"#
178+
));
159179

160180
new_body.extend(group.stream());
161181
ret.extend(Some(TokenTree::from(Group::new(

crates/cargo-test-support/src/paths.rs

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use std::fs;
77
use std::io::{self, ErrorKind};
88
use std::path::{Path, PathBuf};
99
use std::process::Command;
10-
use std::sync::atomic::{AtomicUsize, Ordering};
1110
use std::sync::Mutex;
1211

1312
static CARGO_INTEGRATION_TEST_DIR: &str = "cit";
@@ -51,28 +50,20 @@ pub fn global_root() -> PathBuf {
5150
}
5251
}
5352

54-
// We need to give each test a unique id. The test name could serve this
55-
// purpose, but the `test` crate doesn't have a way to obtain the current test
56-
// name.[*] Instead, we used the `cargo-test-macro` crate to automatically
57-
// insert an init function for each test that sets the test name in a thread
58-
// local variable.
59-
//
60-
// [*] It does set the thread name, but only when running concurrently. If not
61-
// running concurrently, all tests are run on the main thread.
53+
// We need to give each test a unique id. The test name serve this
54+
// purpose. We are able to get the test name by having the `cargo-test-macro`
55+
// crate automatically insert an init function for each test that sets the
56+
// test name in a thread local variable.
6257
thread_local! {
63-
static TEST_ID: RefCell<Option<usize>> = RefCell::new(None);
58+
static TEST_NAME: RefCell<Option<PathBuf>> = RefCell::new(None);
6459
}
6560

6661
pub struct TestIdGuard {
6762
_private: (),
6863
}
6964

70-
pub fn init_root(tmp_dir: Option<&'static str>) -> TestIdGuard {
71-
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
72-
73-
let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
74-
TEST_ID.with(|n| *n.borrow_mut() = Some(id));
75-
65+
pub fn init_root(tmp_dir: Option<&'static str>, test_name: PathBuf) -> TestIdGuard {
66+
TEST_NAME.with(|n| *n.borrow_mut() = Some(test_name));
7667
let guard = TestIdGuard { _private: () };
7768

7869
set_global_root(tmp_dir);
@@ -85,20 +76,20 @@ pub fn init_root(tmp_dir: Option<&'static str>) -> TestIdGuard {
8576

8677
impl Drop for TestIdGuard {
8778
fn drop(&mut self) {
88-
TEST_ID.with(|n| *n.borrow_mut() = None);
79+
TEST_NAME.with(|n| *n.borrow_mut() = None);
8980
}
9081
}
9182

9283
pub fn root() -> PathBuf {
93-
let id = TEST_ID.with(|n| {
94-
n.borrow().expect(
84+
let test_name = TEST_NAME.with(|n| {
85+
n.borrow().clone().expect(
9586
"Tests must use the `#[cargo_test]` attribute in \
9687
order to be able to use the crate root.",
9788
)
9889
});
9990

10091
let mut root = global_root();
101-
root.push(&format!("t{}", id));
92+
root.push(&test_name);
10293
root
10394
}
10495

@@ -345,3 +336,26 @@ pub fn windows_reserved_names_are_allowed() -> bool {
345336
true
346337
}
347338
}
339+
340+
/// This takes the test location (std::file!() should be passed) and the test name
341+
/// and outputs the location the test should be places in, inside of `target/tmp/cit`
342+
///
343+
/// `path: tests/testsuite/workspaces.rs`
344+
/// `name: `workspace_in_git
345+
/// `output: "testsuite/workspaces/workspace_in_git`
346+
pub fn test_dir(path: &str, name: &str) -> std::path::PathBuf {
347+
let test_dir: std::path::PathBuf = std::path::PathBuf::from(path)
348+
.components()
349+
// Trim .rs from any files
350+
.map(|c| c.as_os_str().to_str().unwrap().trim_end_matches(".rs"))
351+
// We only want to take once we have reached `tests` or `src`. This helps when in a
352+
// workspace: `workspace/more/src/...` would result in `src/...`
353+
.skip_while(|c| c != &"tests" && c != &"src")
354+
// We want to skip "tests" since it is taken in `skip_while`.
355+
// "src" is fine since you could have test in "src" named the same as one in "tests"
356+
// Skip "mod" since `snapbox` tests have a folder per test not a file and the files
357+
// are named "mod.rs"
358+
.filter(|c| c != &"tests" && c != &"mod")
359+
.collect();
360+
test_dir.join(name)
361+
}

src/doc/contrib/src/tests/writing.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ The [`#[cargo_test]` attribute](#cargo_test-attribute) is used in place of `#[te
6565
#### `#[cargo_test]` attribute
6666

6767
The `#[cargo_test]` attribute injects code which does some setup before starting the test.
68-
It will create a filesystem "sandbox" under the "cargo integration test" directory for each test, such as `/path/to/cargo/target/tmp/cit/t123/`.
69-
The sandbox will contain a `home` directory that will be used instead of your normal home directory.
68+
It will create a filesystem "sandbox" under the "cargo integration test" directory for each test, such as
69+
`/path/to/cargo/target/tmp/cit/testsuite/bad_config/bad1`. The sandbox will contain a `home` directory that
70+
will be used instead of your normal home directory.
7071

7172
The `#[cargo_test]` attribute takes several options that will affect how the test is generated.
7273
They are listed in parentheses separated with commas, such as:
@@ -200,7 +201,7 @@ Then populate
200201
- This attribute injects code which does some setup before starting the
201202
test, creating a filesystem "sandbox" under the "cargo integration test"
202203
directory for each test such as
203-
`/path/to/cargo/target/cit/t123/`
204+
`/path/to/cargo/target/tmp/cit/testsuite/cargo_add/add_basic`
204205
- The sandbox will contain a `home` directory that will be used instead of your normal home directory
205206

206207
`Project`:
@@ -267,9 +268,9 @@ environment. The general process is:
267268

268269
`cargo test --test testsuite -- features2::inactivate_targets`.
269270
2. In another terminal, head into the sandbox directory to inspect the files and run `cargo` directly.
270-
1. The sandbox directories start with `t0` for the first test.
271+
1. The sandbox directories match the format of `tests/testsuite`, just replace `tests` with `target/tmp/cit`
271272

272-
`cd target/tmp/cit/t0`
273+
`cd target/tmp/cit/testsuite/features2/inactivate_target`
273274
2. Set up the environment so that the sandbox configuration takes effect:
274275

275276
`export CARGO_HOME=$(pwd)/home/.cargo`

tests/testsuite/main.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,51 @@ fn aaa_trigger_cross_compile_disabled_check() {
143143
// This triggers the cross compile disabled check to run ASAP, see #5141
144144
cargo_test_support::cross_compile::disabled();
145145
}
146+
147+
// This is placed here as running tests in `cargo-test-support` would rebuild it
148+
#[cargo_test]
149+
fn check_test_dir() {
150+
let tests = vec![
151+
(
152+
"tests/testsuite/workspaces.rs",
153+
"workspace_in_git",
154+
"testsuite/workspaces/workspace_in_git",
155+
),
156+
(
157+
"tests/testsuite/cargo_remove/invalid_arg/mod.rs",
158+
"case",
159+
"testsuite/cargo_remove/invalid_arg/case",
160+
),
161+
(
162+
"tests/build-std/main.rs",
163+
"cross_custom",
164+
"build-std/main/cross_custom",
165+
),
166+
(
167+
"src/tools/cargo/tests/testsuite/build.rs",
168+
"cargo_compile_simple",
169+
"src/tools/cargo/testsuite/build/cargo_compile_simple",
170+
),
171+
(
172+
"src/tools/cargo/tests/testsuite/cargo_add/add_basic/mod.rs",
173+
"case",
174+
"src/tools/cargo/testsuite/cargo_add/add_basic/case",
175+
),
176+
(
177+
"src/tools/cargo/tests/build-std/main.rs",
178+
"cross_custom",
179+
"src/tools/cargo/build-std/main/cross_custom",
180+
),
181+
(
182+
"workspace/more/src/tools/cargo/tests/testsuite/build.rs",
183+
"cargo_compile_simple",
184+
"src/tools/cargo/testsuite/build/cargo_compile_simple",
185+
),
186+
];
187+
for (path, name, expected) in tests {
188+
assert_eq!(
189+
cargo_test_support::paths::test_dir(path, name),
190+
std::path::PathBuf::from(expected)
191+
);
192+
}
193+
}

0 commit comments

Comments
 (0)