
OS 简单教程番外1:给内核添加测试框架
给内核添加测试框架
为了方便开发我们给内核添加测试框架,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