Skip to content

Commit 186ccc4

Browse files
committed
Support #[itest(focus)]
1 parent 7f6b20a commit 186ccc4

File tree

3 files changed

+49
-16
lines changed

3 files changed

+49
-16
lines changed

godot-macros/src/itest.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub fn transform(input_decl: Declaration) -> ParseResult<TokenStream> {
5252
::godot::sys::plugin_add!(__GODOT_ITEST in crate; crate::RustTestCase {
5353
name: #test_name_str,
5454
skipped: #skipped,
55+
focused: #focused,
5556
file: std::file!(),
5657
line: std::line!(),
5758
function: #test_name,

itest/rust/src/lib.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,26 +61,39 @@ unsafe impl ExtensionLibrary for runner::IntegrationTests {}
6161
sys::plugin_registry!(__GODOT_ITEST: RustTestCase);
6262

6363
/// Finds all `#[itest]` tests.
64-
fn collect_rust_tests() -> (Vec<RustTestCase>, usize) {
64+
fn collect_rust_tests() -> (Vec<RustTestCase>, usize, bool) {
6565
let mut all_files = std::collections::HashSet::new();
6666
let mut tests: Vec<RustTestCase> = vec![];
67+
let mut is_focus_run = false;
6768

6869
sys::plugin_foreach!(__GODOT_ITEST; |test: &RustTestCase| {
69-
all_files.insert(test.file);
70-
tests.push(*test);
70+
// First time a focused test is encountered, switch to "focused" mode and throw everything away.
71+
if !is_focus_run && test.focused {
72+
tests.clear();
73+
all_files.clear();
74+
is_focus_run = true;
75+
}
76+
77+
// Only collect tests if normal mode, or focus mode and test is focused.
78+
if !is_focus_run || test.focused {
79+
all_files.insert(test.file);
80+
tests.push(*test);
81+
}
7182
});
7283

7384
// Sort alphabetically for deterministic run order
7485
tests.sort_by_key(|test| test.file);
7586

76-
(tests, all_files.len())
87+
(tests, all_files.len(), is_focus_run)
7788
}
7889

7990
#[derive(Copy, Clone)]
8091
struct RustTestCase {
8192
name: &'static str,
8293
file: &'static str,
8394
skipped: bool,
95+
/// If one or more tests are focused, only they will be executed. Helpful for debugging and working on specific features.
96+
focused: bool,
8497
#[allow(dead_code)]
8598
line: u32,
8699
function: fn(),

itest/rust/src/runner.rs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub(crate) struct IntegrationTests {
1616
total: i64,
1717
passed: i64,
1818
skipped: i64,
19+
focus_run: bool,
1920
}
2021

2122
#[godot_api]
@@ -28,23 +29,33 @@ impl IntegrationTests {
2829
FMT_GREEN_BOLD, FMT_END
2930
);
3031

31-
let (rust_tests, rust_file_count) = super::collect_rust_tests();
32+
let (rust_tests, rust_file_count, focus_run) = super::collect_rust_tests();
33+
self.focus_run = focus_run;
34+
if focus_run {
35+
println!(" Focused run -- execute only selected Rust tests.")
36+
}
3237
println!(
3338
" Rust: found {} tests in {} files.",
3439
rust_tests.len(),
3540
rust_file_count
3641
);
37-
println!(
38-
" GDScript: found {} tests in {} files.",
39-
gdscript_tests.len(),
40-
gdscript_file_count
41-
);
42+
if !focus_run {
43+
println!(
44+
" GDScript: found {} tests in {} files.",
45+
gdscript_tests.len(),
46+
gdscript_file_count
47+
);
48+
}
4249

4350
let clock = Instant::now();
4451
self.run_rust_tests(rust_tests);
4552
let rust_time = clock.elapsed();
46-
self.run_gdscript_tests(gdscript_tests);
47-
let gdscript_time = clock.elapsed() - rust_time;
53+
let gdscript_time = if !focus_run {
54+
self.run_gdscript_tests(gdscript_tests);
55+
Some(clock.elapsed() - rust_time)
56+
} else {
57+
None
58+
};
4859

4960
self.conclude(rust_time, gdscript_time)
5061
}
@@ -76,7 +87,7 @@ impl IntegrationTests {
7687
}
7788
}
7889

79-
fn conclude(&self, rust_time: Duration, gdscript_time: Duration) -> bool {
90+
fn conclude(&self, rust_time: Duration, gdscript_time: Option<Duration>) -> bool {
8091
let Self {
8192
total,
8293
passed,
@@ -91,17 +102,25 @@ impl IntegrationTests {
91102
let outcome = TestOutcome::from_bool(all_passed);
92103

93104
let rust_time = rust_time.as_secs_f32();
94-
let gdscript_time = gdscript_time.as_secs_f32();
95-
let total_time = rust_time + gdscript_time;
105+
let gdscript_time = gdscript_time.map(|t| t.as_secs_f32());
96106

97107
let extra = if skipped > 0 {
98108
format!(", {skipped} skipped")
109+
} else if gdscript_time.is_none() {
110+
" (focused run)".to_string()
99111
} else {
100112
"".to_string()
101113
};
102114

103115
println!("\nTest result: {outcome}. {passed} passed; {failed} failed{extra}.");
104-
println!(" Time: {total_time:.2}s. (Rust {rust_time:.2}s, GDScript {gdscript_time:.2}s)");
116+
if let Some(gdscript_time) = gdscript_time {
117+
let total_time = rust_time + gdscript_time;
118+
println!(
119+
" Time: {total_time:.2}s. (Rust {rust_time:.2}s, GDScript {gdscript_time:.2}s)"
120+
);
121+
} else {
122+
println!(" Time: {rust_time:.2}s.");
123+
}
105124
all_passed
106125
}
107126

0 commit comments

Comments
 (0)