From 95cf948d594eca4c5f68013d3e0f6e09705c99a8 Mon Sep 17 00:00:00 2001
From: funky <funkyeggdev@proton.me>
Date: Wed, 27 Nov 2024 19:09:15 +1100
Subject: [PATCH] Ktest major improvements

---
 kernel/ktest_macro/src/lib.rs | 71 +++++++++++++++++++++++++++++++----
 kernel/lds/aarch64-qemu.ld    |  5 +++
 kernel/src/kmain.rs           |  7 +++-
 kernel/src/ktest.rs           | 49 +++++++++++++++---------
 kernel/src/lib.rs             |  1 -
 5 files changed, 105 insertions(+), 28 deletions(-)

diff --git a/kernel/ktest_macro/src/lib.rs b/kernel/ktest_macro/src/lib.rs
index c1c3a8a..ebff040 100644
--- a/kernel/ktest_macro/src/lib.rs
+++ b/kernel/ktest_macro/src/lib.rs
@@ -1,28 +1,85 @@
 extern crate proc_macro;
 extern crate quote;
 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<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]
 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<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")]
         #[used]
-        pub static #static_var_name: fn() = #test_name;
+        pub static #static_var_name: fn() -> Result<String, String> = #test_name;
     };
 
     TokenStream::from(out)
diff --git a/kernel/lds/aarch64-qemu.ld b/kernel/lds/aarch64-qemu.ld
index dbcbacf..adf13fb 100644
--- a/kernel/lds/aarch64-qemu.ld
+++ b/kernel/lds/aarch64-qemu.ld
@@ -6,6 +6,11 @@ SECTIONS
     .text.boot : { *(.text.boot) }
     .text : { *(.text) }
     .data : { *(.data) }
+    .note.ktest : {
+		__ktest_start = .;
+    	*(.note.ktest)
+    	__ktest_end = .;
+	}
     .rodata : { *(.rodata) }
     .bss : {
         *(COMMON)
diff --git a/kernel/src/kmain.rs b/kernel/src/kmain.rs
index 928dbe5..8d9d398 100644
--- a/kernel/src/kmain.rs
+++ b/kernel/src/kmain.rs
@@ -24,8 +24,11 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
 
     #[cfg(feature = "ktest")]
     {
-        use crate::ktest;
-        debug!("TESTING");
+        use {
+			crate::ktest,
+			log::info,
+		};
+        info!("Running tests");
         ktest::test_main();
 
         loop {}
diff --git a/kernel/src/ktest.rs b/kernel/src/ktest.rs
index bd5ec7f..c194445 100644
--- a/kernel/src/ktest.rs
+++ b/kernel/src/ktest.rs
@@ -1,38 +1,51 @@
-pub use ktest_macro::ktest;
-use log::debug;
+pub use ktest_macro::*;
+
+use {
+	alloc::string::String,
+	log::{error, info},
+};
 
 extern "C" {
-    static __ktest_start: fn();
-    static __ktest_end: fn();
+    static __ktest_start: fn() -> Result<String, String>;
+    static __ktest_end: fn() -> Result<String, String>;
 }
 
-// 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
+//       Should panic tests
+//       Test specific panic handler
 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<String, String>;
+        let test_end = &__ktest_end as *const fn() -> Result<String, String>;
+
+		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) => {
+                    info!("Test: {} passed", name);
+                    pass += 1;
+                },
+                Err(name) => {
+                    error!("Test: {} failed", name);
+                    fail += 1;
+                }
+            }
 
             current_test = current_test.add(1);
-            current += 1;
         }
+
+        info!("{}/{} tests passed", pass, pass + fail);
     }
 }
 
 #[ktest]
 pub fn trivial_assertion() {
-    assert_eq!(1, 1);
+    ktest_eq!(1, 1);
+	ktest_neq!(0, 1);
 }
diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs
index 3f2be11..b0005d8 100644
--- a/kernel/src/lib.rs
+++ b/kernel/src/lib.rs
@@ -34,7 +34,6 @@ mod memory;
 mod task;
 mod utils;
 
-// #[cfg(feature = "tests")]
 #[allow(improper_ctypes, non_upper_case_globals)]
 mod ktest;