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}