mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 18:03:25 +00:00
312 lines
8.8 KiB
Rust
312 lines
8.8 KiB
Rust
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
//! The source module tree of ktests.
|
|
//!
|
|
//! In the `KtestTree`, the root is abstract, and the children of the root are the
|
|
//! crates. The leaves are the test functions. Nodes other than the root and the
|
|
//! leaves are modules.
|
|
//!
|
|
|
|
use alloc::{
|
|
collections::{btree_map, BTreeMap},
|
|
string::{String, ToString},
|
|
vec,
|
|
vec::Vec,
|
|
};
|
|
|
|
use crate::{
|
|
path::{KtestPath, PathElement},
|
|
KtestItem,
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
pub struct KtestModule {
|
|
nr_tot_tests: usize,
|
|
name: PathElement,
|
|
children: BTreeMap<PathElement, KtestModule>,
|
|
tests: Vec<KtestItem>,
|
|
}
|
|
|
|
impl KtestModule {
|
|
pub fn nr_this_tests(&self) -> usize {
|
|
self.tests.len()
|
|
}
|
|
|
|
pub fn nr_tot_tests(&self) -> usize {
|
|
self.nr_tot_tests
|
|
}
|
|
|
|
pub fn name(&self) -> &PathElement {
|
|
&self.name
|
|
}
|
|
|
|
fn insert(&mut self, module_path: &mut KtestPath, test: KtestItem) {
|
|
self.nr_tot_tests += 1;
|
|
if module_path.is_empty() {
|
|
self.tests.push(test);
|
|
} else {
|
|
let module_name = module_path.pop_front().unwrap();
|
|
let node = self.children.entry(module_name.clone()).or_insert(Self {
|
|
nr_tot_tests: 0,
|
|
name: module_name,
|
|
children: BTreeMap::new(),
|
|
tests: Vec::new(),
|
|
});
|
|
node.nr_tot_tests += 1;
|
|
node.insert(module_path, test);
|
|
}
|
|
}
|
|
|
|
fn new(name: PathElement) -> Self {
|
|
Self {
|
|
nr_tot_tests: 0,
|
|
name,
|
|
children: BTreeMap::new(),
|
|
tests: Vec::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct KtestCrate {
|
|
// Crate behaves just like modules, which can own it's children and tests.
|
|
// But the iterator it provides will only iterate over the modules not tests.
|
|
root_module: KtestModule,
|
|
}
|
|
|
|
impl KtestCrate {
|
|
pub fn nr_tot_tests(&self) -> usize {
|
|
self.root_module.nr_tot_tests()
|
|
}
|
|
|
|
pub fn name(&self) -> &str {
|
|
self.root_module.name()
|
|
}
|
|
}
|
|
|
|
pub struct KtestTree {
|
|
nr_tot_tests: usize,
|
|
crates: BTreeMap<String, KtestCrate>,
|
|
}
|
|
|
|
impl FromIterator<KtestItem> for KtestTree {
|
|
fn from_iter<I: IntoIterator<Item = KtestItem>>(iter: I) -> Self {
|
|
let mut tree = Self::new();
|
|
for test in iter {
|
|
tree.add_ktest(test);
|
|
}
|
|
tree
|
|
}
|
|
}
|
|
|
|
impl KtestTree {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
nr_tot_tests: 0,
|
|
crates: BTreeMap::new(),
|
|
}
|
|
}
|
|
|
|
pub fn add_ktest(&mut self, test: KtestItem) {
|
|
self.nr_tot_tests += 1;
|
|
let package = test.info().package.to_string();
|
|
let module_path = test.info().module_path;
|
|
let node = self.crates.entry(package.clone()).or_insert(KtestCrate {
|
|
root_module: KtestModule::new(PathElement::from(package)),
|
|
});
|
|
node.root_module
|
|
.insert(&mut KtestPath::from(module_path), test);
|
|
}
|
|
|
|
pub fn nr_tot_tests(&self) -> usize {
|
|
self.nr_tot_tests
|
|
}
|
|
|
|
pub fn nr_tot_crates(&self) -> usize {
|
|
self.crates.len()
|
|
}
|
|
}
|
|
|
|
impl Default for KtestTree {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
/// The `KtestTreeIter` will iterate over all crates. Yielding `KtestCrate`s.
|
|
pub struct KtestTreeIter<'a> {
|
|
crate_iter: btree_map::Iter<'a, String, KtestCrate>,
|
|
}
|
|
|
|
impl KtestTree {
|
|
pub fn iter(&self) -> KtestTreeIter<'_> {
|
|
KtestTreeIter {
|
|
crate_iter: self.crates.iter(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for KtestTreeIter<'a> {
|
|
type Item = &'a KtestCrate;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.crate_iter.next().map(|(_, v)| v)
|
|
}
|
|
}
|
|
|
|
type CrateChildrenIter<'a> = btree_map::Iter<'a, String, KtestModule>;
|
|
|
|
/// The `KtestCrateIter` will iterate over all modules in a crate. Yielding `KtestModule`s.
|
|
/// The iterator will return modules in the depth-first-search order of the module tree.
|
|
pub struct KtestCrateIter<'a> {
|
|
path: Vec<(&'a KtestModule, CrateChildrenIter<'a>)>,
|
|
}
|
|
|
|
impl KtestCrate {
|
|
pub fn iter(&self) -> KtestCrateIter<'_> {
|
|
KtestCrateIter {
|
|
path: vec![(&self.root_module, self.root_module.children.iter())],
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for KtestCrateIter<'a> {
|
|
type Item = &'a KtestModule;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let next_module = loop {
|
|
let Some(last) = self.path.last_mut() else {
|
|
break None;
|
|
};
|
|
if let Some((_, next_module)) = last.1.next() {
|
|
break Some(next_module);
|
|
}
|
|
let (_, _) = self.path.pop().unwrap();
|
|
};
|
|
if let Some(next_module) = next_module {
|
|
self.path.push((next_module, next_module.children.iter()));
|
|
Some(next_module)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The `KtestModuleIter` will iterate over all tests in a crate. Yielding `KtestItem`s.
|
|
pub struct KtestModuleIter<'a> {
|
|
test_iter: core::slice::Iter<'a, KtestItem>,
|
|
}
|
|
|
|
impl KtestModule {
|
|
pub fn iter(&self) -> KtestModuleIter<'_> {
|
|
KtestModuleIter {
|
|
test_iter: self.tests.iter(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for KtestModuleIter<'a> {
|
|
type Item = &'a KtestItem;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.test_iter.next()
|
|
}
|
|
}
|
|
|
|
#[cfg(ktest)]
|
|
mod tests {
|
|
use ostd::prelude::ktest;
|
|
|
|
use super::*;
|
|
|
|
macro_rules! gen_test_case {
|
|
() => {{
|
|
fn dummy_fn() {}
|
|
let mut tree = KtestTree::new();
|
|
let new = |m: &'static str, f: &'static str, p: &'static str| {
|
|
KtestItem::new(
|
|
dummy_fn,
|
|
(false, None),
|
|
ostd::ktest::KtestItemInfo {
|
|
module_path: m,
|
|
fn_name: f,
|
|
package: p,
|
|
source: "unrelated",
|
|
line: 0,
|
|
col: 0,
|
|
},
|
|
)
|
|
};
|
|
tree.add_ktest(new("crate1::mod1::mod2", "test21", "crate1"));
|
|
tree.add_ktest(new("crate1::mod1", "test11", "crate1"));
|
|
tree.add_ktest(new("crate1::mod1::mod2", "test22", "crate1"));
|
|
tree.add_ktest(new("crate1::mod1::mod2", "test23", "crate1"));
|
|
tree.add_ktest(new("crate1::mod1::mod3", "test31", "crate1"));
|
|
tree.add_ktest(new("crate1::mod1::mod3::mod4", "test41", "crate1"));
|
|
tree.add_ktest(new("crate2::mod1::mod2", "test2", "crate2"));
|
|
tree.add_ktest(new("crate2::mod1", "test1", "crate2"));
|
|
tree.add_ktest(new("crate2::mod1::mod2", "test3", "crate2"));
|
|
tree
|
|
}};
|
|
}
|
|
|
|
#[ktest]
|
|
fn test_tree_iter() {
|
|
let tree = gen_test_case!();
|
|
let mut iter = tree.iter();
|
|
let c1 = iter.next().unwrap();
|
|
assert_eq!(c1.name(), "crate1");
|
|
let c2 = iter.next().unwrap();
|
|
assert_eq!(c2.name(), "crate2");
|
|
assert!(iter.next().is_none());
|
|
}
|
|
|
|
#[ktest]
|
|
fn test_crate_iter() {
|
|
let tree = gen_test_case!();
|
|
for crate_ in tree.iter() {
|
|
if crate_.name() == "crate1" {
|
|
let mut len = 0;
|
|
for module in crate_.iter() {
|
|
len += 1;
|
|
let modules = ["crate1", "mod1", "mod2", "mod3", "mod4"];
|
|
assert!(modules.contains(&module.name().as_str()));
|
|
}
|
|
assert_eq!(len, 5);
|
|
} else if crate_.name() == "crate2" {
|
|
let mut len = 0;
|
|
for module in crate_.iter() {
|
|
len += 1;
|
|
let modules = ["crate2", "mod1", "mod2"];
|
|
assert!(modules.contains(&module.name().as_str()));
|
|
}
|
|
assert_eq!(len, 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[ktest]
|
|
fn test_module_iter() {
|
|
let tree = gen_test_case!();
|
|
let mut collection = Vec::<&KtestItem>::new();
|
|
for crate_ in tree.iter() {
|
|
for mov in crate_.iter() {
|
|
let module = mov;
|
|
for test in module.iter() {
|
|
collection.push(test);
|
|
}
|
|
}
|
|
}
|
|
assert_eq!(collection.len(), 9);
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test1"));
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test2"));
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test3"));
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test11"));
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test21"));
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test22"));
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test23"));
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test31"));
|
|
assert!(collection.iter().any(|t| t.info().fn_name == "test41"));
|
|
}
|
|
}
|