tracing_test/internal.rs
1//! Internal functionality used by the [`#[traced_test]`](attr.traced_test.html) macro.
2//!
3//! These functions should usually not be accessed from user code. The stability of these functions
4//! is not guaranteed, the API may change even in patch releases.
5use std::sync::{Mutex, Once, OnceLock};
6
7pub use crate::subscriber::{get_subscriber, MockWriter};
8
9/// Static variable to ensure that logging is only initialized once.
10pub static INITIALIZED: Once = Once::new();
11
12/// The global log output buffer used in tests.
13#[doc(hidden)]
14pub fn global_buf() -> &'static Mutex<Vec<u8>> {
15 static GLOBAL_BUF: OnceLock<Mutex<Vec<u8>>> = OnceLock::new();
16 GLOBAL_BUF.get_or_init(|| Mutex::new(vec![]))
17}
18
19/// Return whether the logs with the specified scope contain the specified value.
20///
21/// This function should usually not be used directly, instead use the `logs_contain(val: &str)`
22/// function injected by the [`#[traced_test]`](attr.traced_test.html) macro.
23pub fn logs_with_scope_contain(scope: &str, val: &str) -> bool {
24 let logs = String::from_utf8(global_buf().lock().unwrap().to_vec()).unwrap();
25 for line in logs.split('\n') {
26 if line.contains(&format!(" {}:", scope)) && line.contains(val) {
27 return true;
28 }
29 }
30 false
31}
32
33/// Run a function against a slice of logs for the specified scope and return
34/// its result.
35///
36/// This function should usually not be used directly, instead use the
37/// `logs_assert(F) where F: Fn(&[&str]) -> Result<(), String>` function
38/// injected by the [`#[traced_test]`](attr.traced_test.html) macro.
39pub fn logs_assert<F>(scope: &str, f: F) -> std::result::Result<(), String>
40where
41 F: Fn(&[&str]) -> std::result::Result<(), String>,
42{
43 let buf = global_buf().lock().unwrap();
44 let logs: Vec<&str> = std::str::from_utf8(&buf)
45 .expect("Logs contain invalid UTF8")
46 .lines()
47 .filter(|line| line.contains(&format!(" {}:", scope)))
48 .collect();
49 f(&logs)
50}