Skip to main content

os_test_framework/
lib.rs

1//! # os-test-framework
2//!
3//! Test framework for embedded systems and OS kernels.
4//! `os-test-framework` requires `alloc`, so your kernel will need a `global-allocator`.
5//!
6//! ## Getting Started
7//!
8//! First, enable `custom_test_frameworks`, set `test_runner` as the test runner
9//! from `os-test-framework`, and `reexport_test_harness_main`.
10//!
11//! ```rust,ignore
12//! #![feature(custom_test_frameworks)]
13//! #![reexport_test_harness_main = "test_main"]
14//! #![test_runner(os_test_framework::run_tests)]
15//! ```
16//!
17//! Implement `Platform`. The framework writes output through
18//! `core::fmt::Write` and finishes the run through `Platform::exit`:
19//!
20//! ```rust,ignore
21//! use core::fmt::Write;
22//!
23//! use os_test_framework::platform::{ExitState, Platform};
24//!
25//! struct MyPlatform;
26//!
27//! impl Platform for MyPlatform {
28//!     fn exit(&self, state: ExitState) -> ! {
29//!         match state {
30//!             ExitState::Success => todo!(),
31//!             ExitState::Failed => todo!(),
32//!         }
33//!     }
34//! }
35//!
36//! impl Write for MyPlatform {
37//!     fn write_str(&mut self, s: &str) -> core::fmt::Result {
38//!         // Write to serial, frame buffer, UART, etc.
39//!         let _ = s;
40//!         todo!()
41//!     }
42//! }
43//! ```
44//!
45//! Call `init_platform` with your `Platform`, and `test_main` from your kernel
46//! entry point:
47//!
48//! ```rust,ignore
49//! use os_test_framework::platform::init_platform;
50//!
51//! fn kernel_entry() {
52//!     init_platform(MyPlatform);
53//!     test_main();
54//! }
55//! ```
56//!
57//! Forward panics from your OS to `os-test-framework`:
58//!
59//! ```rust,ignore
60//! use core::panic::PanicInfo;
61//!
62//! #[cfg(test)]
63//! #[panic_handler]
64//! fn panic(info: &PanicInfo) -> ! {
65//!     os_test_framework::panic::handle_panic(info)
66//! }
67//! ```
68//!
69//! ## Adding A Test
70//!
71//! You can declare tests like this:
72//!
73//! ```rust,ignore
74//! use os_test_framework::test;
75//!
76//! test! {
77//!     "Hello" {
78//!         assert!(true);
79//!     }
80//! }
81//! ```
82//!
83//! You can add multiple tests in the same file:
84//!
85//! ```rust,ignore
86//! use os_test_framework::test;
87//!
88//! test! {
89//!     "Hello" {
90//!         assert!(true);
91//!     }
92//! }
93//!
94//! test! {
95//!     "Hello2" {
96//!         assert!(true);
97//!     }
98//! }
99//! ```
100#![no_std]
101
102use owo_colors::OwoColorize;
103
104use crate::platform::{ExitState, platform};
105
106extern crate alloc;
107
108pub mod panic;
109pub mod platform;
110#[doc(hidden)]
111pub mod __private {
112    pub use crate::_run_test;
113    pub use crate::printing::_print;
114}
115
116mod make_test;
117mod printing;
118
119pub fn run_tests(tests: &[&dyn Fn()]) -> ! {
120    println!("\nRunning {} tests", tests.len().bold());
121
122    for test in tests {
123        test()
124    }
125
126    platform().lock().exit(ExitState::Success);
127}
128
129#[doc(hidden)]
130pub fn _run_test(name: &str, func: impl FnOnce()) {
131    print!("{}", name);
132    func();
133    println!(" {}", "OK".green().bold());
134}