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}