Skip to main content

os_test_framework/
lib.rs

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