Skip to content

Commit b3210fd

Browse files
authored
Merge pull request #51 from qorix-group/pawelrutkaq_testing_with_log
Testing macro crate: Auto init logging
2 parents 49e4d62 + 7a7589f commit b3210fd

File tree

6 files changed

+148
-4
lines changed

6 files changed

+148
-4
lines changed

Cargo.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ default-members = [
2121
"src/elementary",
2222
"src/log/score_log_fmt_macro",
2323
"src/log/stdout_logger",
24+
"src/testing_macros",
2425
]
2526
# Include tests and examples as a member for IDE support and Bazel builds.
2627
members = [
@@ -31,6 +32,7 @@ members = [
3132
"src/log/score_log_fmt",
3233
"src/log/score_log_fmt_macro",
3334
"src/log/stdout_logger",
35+
"src/testing_macros",
3436
"examples/log_builtin",
3537
"examples/log_custom",
3638
]
@@ -47,6 +49,7 @@ score_log_fmt = { path = "src/log/score_log_fmt" }
4749
score_log_fmt_macro = { path = "src/log/score_log_fmt_macro" }
4850
stdout_logger = { path = "src/log/stdout_logger" }
4951
elementary = { path = "src/elementary" }
52+
testing_macros = { path = "src/testing_macros" }
5053

5154
[workspace.lints.clippy]
5255
std_instead_of_core = "warn"

src/log/stdout_logger/lib.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,19 @@ impl StdoutLoggerBuilder {
204204

205205
/// Build the `StdoutLogger` and set it as the default logger.
206206
pub fn set_as_default_logger(self) {
207-
let logger = self.build();
208-
score_log::set_max_level(logger.log_level());
209-
if let Err(e) = score_log::set_global_logger(Box::new(logger)) {
207+
if let Err(e) = self.try_set_as_default_logger() {
210208
panic!("unable to set logger: {e}");
211209
}
212210
}
211+
212+
/// Build the `StdoutLogger` and try to set it as the default logger.
213+
pub fn try_set_as_default_logger(self) -> core::result::Result<(), score_log::SetLoggerError> {
214+
let logger = self.build();
215+
let level = logger.log_level();
216+
score_log::set_global_logger(Box::new(logger))?;
217+
score_log::set_max_level(level);
218+
Ok(())
219+
}
213220
}
214221

215222
impl Default for StdoutLoggerBuilder {
@@ -291,6 +298,8 @@ impl Log for StdoutLogger {
291298
}
292299

293300
fn flush(&self) {
294-
// No-op.
301+
use std::io::Write;
302+
let mut stdout = std::io::stdout();
303+
stdout.flush().unwrap();
295304
}
296305
}

src/testing_macros/BUILD

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
load("@rules_rust//rust:defs.bzl", "rust_proc_macro")
14+
15+
rust_proc_macro(
16+
name = "score_testing_macros",
17+
srcs = glob(["*.rs"]),
18+
visibility = ["//visibility:public"],
19+
deps = [
20+
"//src/log/stdout_logger",
21+
"@score_crates//:quote",
22+
"@score_crates//:syn",
23+
],
24+
)

src/testing_macros/Cargo.toml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
14+
[package]
15+
name = "score_testing_macros"
16+
version.workspace = true
17+
authors.workspace = true
18+
readme.workspace = true
19+
edition.workspace = true
20+
21+
[lib]
22+
proc-macro = true
23+
path = "lib.rs"
24+
25+
[dependencies]
26+
syn = { version = "2" }
27+
quote = "1"
28+
stdout_logger.workspace = true

src/testing_macros/lib.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// *******************************************************************************
2+
// Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
//
4+
// See the NOTICE file(s) distributed with this work for additional
5+
// information regarding copyright ownership.
6+
//
7+
// This program and the accompanying materials are made available under the
8+
// terms of the Apache License Version 2.0 which is available at
9+
// https://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
// *******************************************************************************
13+
14+
use proc_macro::TokenStream;
15+
use quote::quote;
16+
use syn::{parse_macro_input, ItemFn, ItemMod};
17+
18+
/// Attribute macro to create a test function with stdout logger initialized.
19+
#[proc_macro_attribute]
20+
pub fn test_with_log(_attr: TokenStream, item: TokenStream) -> TokenStream {
21+
let input = parse_macro_input!(item as ItemFn);
22+
23+
let vis = &input.vis;
24+
let sig = &input.sig;
25+
let block = &input.block;
26+
let attrs = &input.attrs;
27+
28+
TokenStream::from(quote! {
29+
#(#attrs)*
30+
#vis #sig {
31+
let _ = stdout_logger::StdoutLoggerBuilder::new()
32+
.context("TEST")
33+
.log_level(score_log::LevelFilter::Trace)
34+
.try_set_as_default_logger();
35+
#block
36+
score_log::global_logger().flush();
37+
}
38+
})
39+
}
40+
41+
/// Attribute macro that modifies a test module to initialize stdout logger for each test.
42+
#[proc_macro_attribute]
43+
pub fn test_mod_with_log(_attr: TokenStream, item: TokenStream) -> TokenStream {
44+
let mut input = parse_macro_input!(item as ItemMod);
45+
46+
if let Some((_, ref mut items)) = input.content {
47+
// Wrap each #[test] function to call test_hook automatically
48+
for item in items.iter_mut() {
49+
if let syn::Item::Fn(ref mut f) = item {
50+
let is_test = f.attrs.iter().any(|a| a.path().is_ident("test"));
51+
if is_test {
52+
let block = &f.block;
53+
f.block = syn::parse_quote!({
54+
55+
let _ = stdout_logger::StdoutLoggerBuilder::new()
56+
.context("TEST")
57+
.log_level(score_log::LevelFilter::Trace)
58+
.try_set_as_default_logger();
59+
#block
60+
61+
score_log::global_logger().flush();
62+
});
63+
}
64+
}
65+
}
66+
}
67+
68+
TokenStream::from(quote! {
69+
#input
70+
})
71+
}

0 commit comments

Comments
 (0)