diff options
| author | Jakub Beránek <berykubik@gmail.com> | 2025-06-12 19:42:03 +0200 |
|---|---|---|
| committer | Jakub Beránek <berykubik@gmail.com> | 2025-06-12 19:42:03 +0200 |
| commit | 6feb9b792c2780c11574ff2b2b6aa9062882cea3 (patch) | |
| tree | 2703e76e6762ddf394d13e94f3a6d9c6caed0c6d /src/bootstrap | |
| parent | 983fe4f2655d6e7c22dfd06be3d2e9a31d33c033 (diff) | |
| download | rust-6feb9b792c2780c11574ff2b2b6aa9062882cea3.tar.gz rust-6feb9b792c2780c11574ff2b2b6aa9062882cea3.zip | |
Add lightweight snapshot testing for bootstrap tests
Diffstat (limited to 'src/bootstrap')
| -rw-r--r-- | src/bootstrap/src/core/builder/tests.rs | 78 | ||||
| -rw-r--r-- | src/bootstrap/src/utils/cache.rs | 39 |
2 files changed, 107 insertions, 10 deletions
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 6db96668cf5..d07df7f4a84 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1231,3 +1231,81 @@ fn any_debug() { // Downcasting to the underlying type should succeed. assert_eq!(x.downcast_ref::<MyStruct>(), Some(&MyStruct { x: 7 })); } + +/// The staging tests use insta for snapshot testing. +/// See bootstrap's README on how to bless the snapshots. +mod staging { + use crate::core::builder::tests::{ + TEST_TRIPLE_1, configure, configure_with_args, render_steps, run_build, + }; + + #[test] + fn build_compiler_stage_1() { + let mut cache = run_build( + &["compiler".into()], + configure_with_args(&["build", "--stage", "1"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]), + ); + let steps = cache.into_executed_steps(); + insta::assert_snapshot!(render_steps(&steps), @r" + [build] rustc 0 <target1> -> std 0 <target1> + [build] llvm <target1> + [build] rustc 0 <target1> -> rustc 1 <target1> + [build] rustc 0 <target1> -> rustc 1 <target1> + "); + } +} + +/// Renders the executed bootstrap steps for usage in snapshot tests with insta. +/// Only renders certain important steps. +/// Each value in `steps` should be a tuple of (Step, step output). +fn render_steps(steps: &[(Box<dyn Any>, Box<dyn Any>)]) -> String { + steps + .iter() + .filter_map(|(step, output)| { + // FIXME: implement an optional method on Step to produce metadata for test, instead + // of this downcasting + if let Some((rustc, output)) = downcast_step::<compile::Rustc>(step, output) { + Some(format!( + "[build] {} -> {}", + render_compiler(rustc.build_compiler), + // FIXME: return the correct stage from the `Rustc` step, now it behaves weirdly + render_compiler(Compiler::new(rustc.build_compiler.stage + 1, rustc.target)), + )) + } else if let Some((std, output)) = downcast_step::<compile::Std>(step, output) { + Some(format!( + "[build] {} -> std {} <{}>", + render_compiler(std.compiler), + std.compiler.stage, + std.target + )) + } else if let Some((llvm, output)) = downcast_step::<llvm::Llvm>(step, output) { + Some(format!("[build] llvm <{}>", llvm.target)) + } else { + None + } + }) + .map(|line| { + line.replace(TEST_TRIPLE_1, "target1") + .replace(TEST_TRIPLE_2, "target2") + .replace(TEST_TRIPLE_3, "target3") + }) + .collect::<Vec<_>>() + .join("\n") +} + +fn downcast_step<'a, S: Step>( + step: &'a Box<dyn Any>, + output: &'a Box<dyn Any>, +) -> Option<(&'a S, &'a S::Output)> { + let Some(step) = step.downcast_ref::<S>() else { + return None; + }; + let Some(output) = output.downcast_ref::<S::Output>() else { + return None; + }; + Some((step, output)) +} + +fn render_compiler(compiler: Compiler) -> String { + format!("rustc {} <{}>", compiler.stage, compiler.host) +} diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs index 46eeffad88c..0c737470958 100644 --- a/src/bootstrap/src/utils/cache.rs +++ b/src/bootstrap/src/utils/cache.rs @@ -17,6 +17,7 @@ use std::borrow::Borrow; use std::cell::RefCell; use std::cmp::Ordering; use std::collections::HashMap; +use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::Deref; @@ -208,25 +209,30 @@ pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default); /// any type in its output. It is a write-once cache; values are never evicted, /// which means that references to the value can safely be returned from the /// `get()` method. -#[derive(Debug)] -pub struct Cache( - RefCell< +#[derive(Debug, Default)] +pub struct Cache { + cache: RefCell< HashMap< TypeId, Box<dyn Any>, // actually a HashMap<Step, Interned<Step::Output>> >, >, -); + #[cfg(test)] + /// Contains steps in the same order in which they were executed + /// Useful for tests + /// Tuples (step, step output) + executed_steps: RefCell<Vec<(Box<dyn Any>, Box<dyn Any>)>>, +} impl Cache { /// Creates a new empty cache. pub fn new() -> Cache { - Cache(RefCell::new(HashMap::new())) + Cache::default() } /// Stores the result of a computation step in the cache. pub fn put<S: Step>(&self, step: S, value: S::Output) { - let mut cache = self.0.borrow_mut(); + let mut cache = self.cache.borrow_mut(); let type_id = TypeId::of::<S>(); let stepcache = cache .entry(type_id) @@ -234,12 +240,20 @@ impl Cache { .downcast_mut::<HashMap<S, S::Output>>() .expect("invalid type mapped"); assert!(!stepcache.contains_key(&step), "processing {step:?} a second time"); + + #[cfg(test)] + { + let step: Box<dyn Any> = Box::new(step.clone()); + let output: Box<dyn Any> = Box::new(value.clone()); + self.executed_steps.borrow_mut().push((step, output)); + } + stepcache.insert(step, value); } /// Retrieves a cached result for the given step, if available. pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> { - let mut cache = self.0.borrow_mut(); + let mut cache = self.cache.borrow_mut(); let type_id = TypeId::of::<S>(); let stepcache = cache .entry(type_id) @@ -252,8 +266,8 @@ impl Cache { #[cfg(test)] impl Cache { - pub fn all<S: Ord + Clone + Step>(&mut self) -> Vec<(S, S::Output)> { - let cache = self.0.get_mut(); + pub fn all<S: Ord + Step>(&mut self) -> Vec<(S, S::Output)> { + let cache = self.cache.get_mut(); let type_id = TypeId::of::<S>(); let mut v = cache .remove(&type_id) @@ -265,7 +279,12 @@ impl Cache { } pub fn contains<S: Step>(&self) -> bool { - self.0.borrow().contains_key(&TypeId::of::<S>()) + self.cache.borrow().contains_key(&TypeId::of::<S>()) + } + + #[cfg(test)] + pub fn into_executed_steps(mut self) -> Vec<(Box<dyn Any>, Box<dyn Any>)> { + mem::take(&mut self.executed_steps.borrow_mut()) } } |
