给内核添加测试框架
为了方便开发我们给内核添加测试框架,rust 本来就有测试框架,可以利用起来
// in src/main.rs #![feature(custom_test_frameworks)] #![test_runner(crate::test_runner)] #![reexport_test_harness_main = "test_main"] #[cfg(test)] fn test_runner(tests: &[&dyn Fn()]) { println!("Running {} tests", tests.len()); for test in tests { test(); } }
- #![feature(custom_test_frameworks)] 是自定义测试框架
- #![test_runner(crate::test_runner)] 是用 test_runner 做为测试 runner
- 入口本来是测试框架自己生成的 _start ,我们指定 test_main
- 最后在我们的 rust_main 中调用 test_main
#[no_mangle] extern "C" fn rust_main() -> ! { clear_bss(); heap::init(); trap::init(); task::init(); #[cfg(test)] test_main(); task::run(); }
现在试试用 cargo test,可惜不行,因为我们要在 k210 上执行,所以改造 Makefile 吧。
test: env @echo Platform: $(BOARD) @cd ../user && make build $(eval override KERNEL_ELF := $(shell cargo test --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]")) @$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $(KERNEL_BIN) (which $(K210-BURNER)) || (cd .. && git clone https://github.com/sipeed/kflash.py.git && mv kflash.py tools) @cp $(BOOTLOADER) $(BOOTLOADER).copy @dd if=$(KERNEL_BIN) of=$(BOOTLOADER).copy bs=$(K210_BOOTLOADER_SIZE) seek=1 @mv $(BOOTLOADER).copy $(KERNEL_BIN) @sudo chmod 777 $(K210-SERIALPORT) python3 $(K210-BURNER) -p $(K210-SERIALPORT) -b 1500000 $(KERNEL_BIN) python3 -m serial.tools.miniterm --eol LF --dtr 0 --rts 0 --filter direct $(K210-SERIALPORT) 115200
- 先 build 应用程序,和直接 run 一样
- $(eval override KERNEL_ELF := $(shell cargo test --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]")) 这句不同,这句的意思是:
- 安装 jq,brew install jq
- 执行 cargo test --no-run --message-format=json ,带测试编译,不执行,结果 json 展示。
- 因为二进制文件带编译 hash 每次都不一样,我们用 --message-format=json ,然后用 jq 解析 json
- 最后赋值 KERNEL_ELF
- 后面同 build
接着就可以添加测试用例了,然后 make test 执行
#[test_case] pub fn heap_test() { use alloc::boxed::Box; use alloc::vec::Vec; extern "C" { fn sbss(); fn ebss(); } let bss_range = sbss as usize..ebss as usize; let a = Box::new(5); assert_eq!(*a, 5); assert!(bss_range.contains(&(a.as_ref() as *const _ as usize))); drop(a); let mut v: Vec<usize> = Vec::new(); for i in 0..500 { v.push(i); } for i in 0..500 { assert_eq!(v[i], i); } assert!(bss_range.contains(&(v.as_ptr() as usize))); drop(v); println!("heap_test passed!"); }
可以看到,make test 结果在 k210 上执行测试用例,而 make run 和以前一样。
[rustsbi] RustSBI version 0.2.0-alpha.3 .______ __ __ _______.___________. _______..______ __ | _ \ | | | | / | | / || _ \ | | | |_) | | | | | | (----`---| |----`| (----`| |_) || | | / | | | | \ \ | | \ \ | _ < | | | |\ \----.| `--' |.----) | | | .----) | | |_) || | | _| `._____| \______/ |_______/ |__| |_______/ |______/ |__| [rustsbi] Platform: K210 (Version 0.2.0) [rustsbi] misa: RV64ACDFIMSU [rustsbi] mideleg: 0x22 [rustsbi] medeleg: 0x1ab [rustsbi] Kernel entry: 0x80020000 [kernel] app_0 [0x80035018, 0x80035938) Running 1 tests heap_test passed! Hello OS from app [kernel] Application exited with code 0
代码请参考: https://github.com/buhe/bugu/tree/5-test