Next Generation WASM Microkernel Operating System
1// Copyright 2025 Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use super::args::FormatSetting;
9use super::{Conclusion, Outcome};
10use alloc::boxed::Box;
11use core::sync::atomic::Ordering;
12use ktest::{Test, TestInfo};
13
14pub struct Printer {
15 format: FormatSetting,
16}
17
18impl Printer {
19 pub fn new(format: FormatSetting) -> Self {
20 Self { format }
21 }
22
23 pub(crate) fn print_title(&self, num_tests: u64) {
24 match self.format {
25 FormatSetting::Pretty | FormatSetting::Terse => {
26 let plural_s = if num_tests == 1 { "" } else { "s" };
27
28 tracing::info!("\nrunning {num_tests} test{plural_s}");
29 }
30 FormatSetting::Json => tracing::info!(
31 r#"{{ "type": "suite", "event": "started", "test_count": {num_tests} }}"#,
32 ),
33 }
34 }
35
36 pub(crate) fn print_test(&self, info: &TestInfo) {
37 let TestInfo { module, name, .. } = info;
38 match self.format {
39 FormatSetting::Pretty => {
40 tracing::info!("test {module}::{name} ... ",);
41 }
42 FormatSetting::Terse => {
43 // In terse mode, nothing is printed before the job. Only
44 // `print_single_outcome` prints one character.
45 }
46 FormatSetting::Json => {
47 tracing::info!(
48 r#"{{ "type": "test", "event": "started", "name": "{module}::{name}" }}"#,
49 )
50 }
51 }
52 }
53
54 pub(crate) fn print_single_outcome(&self, info: &TestInfo, outcome: &Outcome) {
55 let TestInfo { module, name, .. } = info;
56 match self.format {
57 FormatSetting::Pretty => {
58 self.print_outcome_pretty(outcome);
59 }
60 FormatSetting::Terse => {
61 let c = match outcome {
62 Outcome::Passed => '.',
63 Outcome::Failed { .. } => 'F',
64 Outcome::Ignored => 'i',
65 };
66
67 tracing::info!("{c}");
68 }
69 FormatSetting::Json => {
70 tracing::info!(
71 r#"{{ "type": "test", "name": "{module}::{name}", "event": "{}" }}"#,
72 match outcome {
73 Outcome::Passed => "ok",
74 Outcome::Failed(_) => "failed",
75 Outcome::Ignored => "ignored",
76 }
77 );
78 }
79 }
80 }
81
82 fn print_outcome_pretty(&self, outcome: &Outcome) {
83 match outcome {
84 Outcome::Passed => tracing::info!("ok"),
85 Outcome::Failed(_) => {
86 tracing::info!("FAILED");
87 }
88 Outcome::Ignored => tracing::info!("ignored"),
89 }
90 }
91
92 pub(crate) fn print_list(&self, tests: &[Test], ignored: bool) {
93 for test in tests {
94 // libtest prints out:
95 // * all tests without `--ignored`
96 // * just the ignored tests with `--ignored`
97 if ignored && !test.info.ignored {
98 continue;
99 }
100
101 tracing::info!("{}::{}: test", test.info.module, test.info.name,);
102 }
103 }
104
105 pub(crate) fn print_summary(&self, conclusion: &Conclusion) {
106 match self.format {
107 FormatSetting::Pretty | FormatSetting::Terse => {
108 let outcome = if conclusion.has_failed() {
109 Outcome::Failed(Box::new(()))
110 } else {
111 Outcome::Passed
112 };
113
114 tracing::info!("test result: ");
115 self.print_outcome_pretty(&outcome);
116 tracing::info!(
117 "{} passed; {} failed; {} ignored; {} measured; \
118 {} filtered out",
119 conclusion.num_passed.load(Ordering::Acquire),
120 conclusion.num_failed.load(Ordering::Acquire),
121 conclusion.num_ignored.load(Ordering::Acquire),
122 conclusion.num_measured.load(Ordering::Acquire),
123 conclusion.num_filtered_out.load(Ordering::Acquire),
124 );
125 }
126 FormatSetting::Json => {
127 tracing::info!(
128 concat!(
129 r#"{{ "type": "suite", "event": "{}", "passed": {}, "failed": {},"#,
130 r#" "ignored": {}, "measured": {}, "filtered_out": {} }}"#,
131 ),
132 if conclusion.has_failed() {
133 "failed"
134 } else {
135 "ok"
136 },
137 conclusion.num_passed.load(Ordering::Acquire),
138 conclusion.num_failed.load(Ordering::Acquire),
139 conclusion.num_ignored.load(Ordering::Acquire),
140 conclusion.num_measured.load(Ordering::Acquire),
141 conclusion.num_filtered_out.load(Ordering::Acquire),
142 )
143 }
144 }
145 }
146}