Compare commits

...

5 commits

Author SHA1 Message Date
FunkyEgg de817e2c4d
Ktest log fixes, maybe arm? 2024-11-25 17:28:49 +11:00
funky d52f14ee1f Ktest: minor cleanup 2024-11-24 19:28:05 +11:00
FunkyEgg 4cd7a76ee7 Merge branch 'master' into ktest 2024-11-24 02:14:39 -06:00
funky f3a4a6b4f5 Fixed failing test
I'm dumb
2024-11-24 19:13:32 +11:00
funky f5aac570ee Ktest major improvements
Added a custom assert_[eq/neq]
Better test info including name reporting
And probably more that I forgot
2024-11-24 19:06:49 +11:00
5 changed files with 112 additions and 34 deletions

View file

@ -4,25 +4,81 @@ extern crate syn;
use { use {
proc_macro::TokenStream, proc_macro::TokenStream,
quote::quote, 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<Self> {
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] #[proc_macro_attribute]
pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream { pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn); let input = parse_macro_input!(item as ItemFn);
let test_name = &input.sig.ident; let test_name = &input.sig.ident;
let test_string = test_name.to_string();
let static_var_name = syn::Ident::new( let static_var_name = syn::Ident::new(
&format!("__ktest_{}", test_name), &format!("__ktest_{}", test_name).to_uppercase(),
test_name.span(), 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<String, String> {
use crate::alloc::string::ToString;
let name = #test_string.to_string();
#block
return Ok(name);
}
#[cfg(feature = "ktest")]
#[unsafe(link_section = ".note.ktest")] #[unsafe(link_section = ".note.ktest")]
#[used] #[used]
pub static #static_var_name: fn() = #test_name; pub static #static_var_name: fn() -> Result<String, String> = #test_name;
}; };
TokenStream::from(out) TokenStream::from(out)

View file

@ -7,6 +7,11 @@ SECTIONS
.text : { *(.text) } .text : { *(.text) }
.data : { *(.data) } .data : { *(.data) }
.rodata : { *(.rodata) } .rodata : { *(.rodata) }
.note.ktest : {
__ktest_start = .;
*(.note.ktest)
__ktest_end = .;
}
.bss : { .bss : {
*(COMMON) *(COMMON)
*(.bss .bss.*) *(.bss .bss.*)

View file

@ -23,11 +23,14 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
debug!("Entered kmain"); debug!("Entered kmain");
#[cfg(feature = "ktest")] { #[cfg(feature = "ktest")] {
use crate::ktest; use {
debug!("TESTING"); crate::ktest::test_main,
ktest::test_main(); log::info,
};
info!("Running tests");
test_main();
loop {}; loop {}
} }
// let kcmd = build_cmd("Kernel Command Line", cmdline); // let kcmd = build_cmd("Kernel Command Line", cmdline);

View file

@ -1,38 +1,53 @@
pub use ktest_macro::ktest; use {
use log::debug; alloc::string::String,
log::{info, error},
};
pub use ktest_macro::*;
#[allow(improper_ctypes)]
extern "C" { extern "C" {
static __ktest_start: fn(); static __ktest_start: fn() -> Result<String, String>;
static __ktest_end: fn(); static __ktest_end: fn() -> Result<String, String>;
} }
// TODO: Get test_fn linker name (may require no_mangle in macro) // TODO: Implement ktest for arm and riscv (Later problems, see below)
// More info on tests (run the rest even if panic)
// Implement ktest for arm and riscv (Later problems, see below)
// Allow for arch specific tests (Leave for now) // Allow for arch specific tests (Leave for now)
// Allow for ktest test name attr // Should panic tests
// Usefull message at the end of testing // Test specific panic handler
pub fn test_main() { pub fn test_main() {
unsafe { unsafe {
let mut current_test = &__ktest_start as *const fn(); let mut current_test = &__ktest_start as *const fn() -> Result<String, String>;
let mut current = 1; let test_end = &__ktest_end as *const fn() -> Result<String, String>;
let test_end = &__ktest_end as *const fn();
let mut pass = 0;
let mut fail = 0;
while current_test < test_end { while current_test < test_end {
let test_fn = *current_test; let test_fn = *current_test;
debug!("Running test {}", current);
test_fn(); let test_name = test_fn();
debug!("Test {} passed", current); match test_name {
Ok(name) => {
info!("Test: {} passed", name);
pass += 1;
},
Err(name) => {
error!("Test: {} failed", name);
fail += 1;
}
}
current_test = current_test.add(1); current_test = current_test.add(1);
current += 1;
} }
info!("{}/{} tests passed", pass, pass + fail);
} }
} }
#[ktest] #[ktest]
pub fn trivial_assertion() { fn trivial_assertion() {
assert_eq!(1, 1); ktest_eq!(1, 1);
ktest_neq!(0, 1);
} }

View file

@ -27,15 +27,12 @@ mod handle;
mod holeybytes; mod holeybytes;
mod ipc; mod ipc;
mod kmain; mod kmain;
mod ktest;
mod logger; mod logger;
mod memory; mod memory;
mod task; mod task;
mod utils; mod utils;
// #[cfg(feature = "tests")]
mod ktest;
use alloc::string::ToString;
use versioning::Version; use versioning::Version;
/// Kernel's version /// Kernel's version
@ -48,6 +45,8 @@ pub const VERSION: Version = Version {
#[panic_handler] #[panic_handler]
#[cfg(target_os = "none")] #[cfg(target_os = "none")]
fn panic(info: &core::panic::PanicInfo) -> ! { fn panic(info: &core::panic::PanicInfo) -> ! {
use crate::alloc::string::ToString;
arch::register_dump(); arch::register_dump();
if let Some(loc) = info.location() { if let Some(loc) = info.location() {