From f5aac570ee4e9d84fb543c6e844853139d0d18c0 Mon Sep 17 00:00:00 2001 From: funky Date: Sun, 24 Nov 2024 19:06:49 +1100 Subject: [PATCH] Ktest major improvements Added a custom assert_[eq/neq] Better test info including name reporting And probably more that I forgot --- kernel/ktest_macro/src/lib.rs | 70 +++++++++++++++++++++++++++++++---- kernel/src/ktest.rs | 48 ++++++++++++++---------- kernel/src/lib.rs | 7 ++-- 3 files changed, 95 insertions(+), 30 deletions(-) diff --git a/kernel/ktest_macro/src/lib.rs b/kernel/ktest_macro/src/lib.rs index c1c3a8a..6ef8251 100644 --- a/kernel/ktest_macro/src/lib.rs +++ b/kernel/ktest_macro/src/lib.rs @@ -4,25 +4,81 @@ extern crate syn; use { proc_macro::TokenStream, quote::quote, - syn::{parse_macro_input, ItemFn} + syn::{parse::Parse, parse_macro_input, Expr, ItemFn, Token} }; +struct KtestInput { + lhs: Expr, + _comma: Token![,], + rhs: Expr, +} + +impl Parse for KtestInput { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Self { + lhs: input.parse()?, + _comma: input.parse()?, + rhs: input.parse()?, + }) + } +} + +#[proc_macro] +pub fn ktest_eq(item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as KtestInput); + + let lhs = input.lhs; + let rhs = input.rhs; + + let out = quote! { + if #lhs != #rhs { + return Err(name); + } + }; + TokenStream::from(out) +} + +#[proc_macro] +pub fn ktest_neq(item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as KtestInput); + + let lhs = input.lhs; + let rhs = input.rhs; + + let out = quote! { + if #lhs == #rhs { + return Err(name); + } + }; + TokenStream::from(out) +} + #[proc_macro_attribute] pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream { let input = parse_macro_input!(item as ItemFn); let test_name = &input.sig.ident; + let test_string = test_name.to_string(); let static_var_name = syn::Ident::new( - &format!("__ktest_{}", test_name), + &format!("__ktest_{}", test_name).to_uppercase(), test_name.span(), ); - let out = quote! { - // #[cfg(feature = "ktest")] - #input - // #[cfg(feature = "ktest")] + let block = &input.block; + let out = quote! { + #[cfg(feature = "ktest")] + fn #test_name() -> Result { + use crate::alloc::string::ToString; + let name = #test_string.to_string(); + + #block + + return Ok(name); + } + + #[cfg(feature = "ktest")] #[unsafe(link_section = ".note.ktest")] #[used] - pub static #static_var_name: fn() = #test_name; + pub static #static_var_name: fn() -> Result = #test_name; }; TokenStream::from(out) diff --git a/kernel/src/ktest.rs b/kernel/src/ktest.rs index 43a2a11..1c3a6f9 100644 --- a/kernel/src/ktest.rs +++ b/kernel/src/ktest.rs @@ -1,38 +1,48 @@ -pub use ktest_macro::ktest; -use log::debug; +use { + alloc::string::String, + log::debug, +}; + +pub use ktest_macro::*; extern "C" { - static __ktest_start: fn(); - static __ktest_end: fn(); + static __ktest_start: fn() -> Result; + static __ktest_end: fn() -> Result; } -// TODO: Get test_fn linker name (may require no_mangle in macro) -// More info on tests (run the rest even if panic) -// Implement ktest for arm and riscv (Later problems, see below) +// TODO: Implement ktest for arm and riscv (Later problems, see below) // Allow for arch specific tests (Leave for now) -// Allow for ktest test name attr -// Usefull message at the end of testing pub fn test_main() { unsafe { - let mut current_test = &__ktest_start as *const fn(); - let mut current = 1; - let test_end = &__ktest_end as *const fn(); + let mut current_test = &__ktest_start as *const fn() -> Result; + let test_end = &__ktest_end as *const fn() -> Result; + + let mut pass = 0; + let mut fail = 0; while current_test < test_end { let test_fn = *current_test; - - debug!("Running test {}", current); - test_fn(); - debug!("Test {} passed", current); + let test_name = test_fn(); + match test_name { + Ok(name) => { + debug!("Test: {} passed", name); + pass += 1; + }, + Err(ename) => { + debug!("Test: {} failed", ename); + fail += 1; + } + } current_test = current_test.add(1); - current += 1; } + + debug!("{}/{} tests passed", pass, pass + fail); } } #[ktest] -pub fn trivial_assertion() { - assert_eq!(1, 1); +fn trivial_assertion() { + ktest_eq!(1, 0); } \ No newline at end of file diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 52956ec..bb9ed8e 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -27,15 +27,12 @@ mod handle; mod holeybytes; mod ipc; mod kmain; +mod ktest; mod logger; mod memory; mod task; mod utils; -// #[cfg(feature = "tests")] -mod ktest; - -use alloc::string::ToString; use versioning::Version; /// Kernel's version @@ -48,6 +45,8 @@ pub const VERSION: Version = Version { #[panic_handler] #[cfg(target_os = "none")] fn panic(info: &core::panic::PanicInfo) -> ! { + use crate::alloc::string::ToString; + arch::register_dump(); if let Some(loc) = info.location() {