1#![warn(missing_docs)]
2#![warn(clippy::std_instead_of_core)]
3#![warn(clippy::std_instead_of_alloc)]
4#![forbid(unsafe_code)]
5#![doc = include_str!("../README.md")]
6
7pub use facet_testhelpers_macros::test;
8
9use std::sync::LazyLock;
10use std::time::Instant;
11use tracing_subscriber::filter::Targets;
12use tracing_subscriber::fmt::format::Writer;
13use tracing_subscriber::fmt::time::FormatTime;
14use tracing_subscriber::layer::SubscriberExt;
15use tracing_subscriber::util::SubscriberInitExt;
16
17static START_TIME: LazyLock<Instant> = LazyLock::new(Instant::now);
18
19struct Uptime;
20
21impl FormatTime for Uptime {
22 fn format_time(&self, w: &mut Writer<'_>) -> core::fmt::Result {
23 let elapsed = START_TIME.elapsed();
24 let secs = elapsed.as_secs();
25 let millis = elapsed.subsec_millis();
26 write!(w, "{:4}.{:03}s", secs, millis)
27 }
28}
29
30static SUBSCRIBER_INIT: LazyLock<()> = LazyLock::new(|| {
35 let _ = *START_TIME;
37
38 let verbosity = color_backtrace::Verbosity::Medium;
39
40 color_backtrace::BacktracePrinter::new()
42 .verbosity(verbosity)
43 .add_frame_filter(Box::new(|frames| {
44 frames.retain(|frame| {
45 let dominated_by_noise = |name: &str| {
46 name.starts_with("test::run_test")
48 || name.starts_with("test::__rust_begin_short_backtrace")
49 || name.starts_with("std::panicking::")
51 || name.starts_with("std::panic::")
52 || name.starts_with("core::panicking::")
53 || name.starts_with("std::thread::Builder::spawn_unchecked_")
55 || name.starts_with("std::sys::thread::")
56 || name.starts_with("std::sys::backtrace::")
57 || name.starts_with("core::ops::function::FnOnce::call_once")
59 || name.starts_with("<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once")
60 || name.starts_with("<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once")
62 || name.starts_with("__pthread")
64 };
65 match &frame.name {
66 Some(name) => !dominated_by_noise(name),
67 None => true,
68 }
69 })
70 }))
71 .install(Box::new(termcolor::StandardStream::stderr(
72 termcolor::ColorChoice::AlwaysAnsi,
73 )));
74
75 let filter = std::env::var("FACET_LOG")
76 .ok()
77 .and_then(|s| s.parse::<Targets>().ok())
78 .unwrap_or_else(|| {
79 eprintln!("Assuming FACET_LOG=debug (feel free to set the $FACET_LOG env var to override tracing filters) (note: $RUST_LOG doesn't do anything)");
80 Targets::new().with_default(tracing::Level::DEBUG)
81 });
82
83 fn is_set_to_1(key: &str) -> bool {
84 match std::env::var(key) {
85 Ok(val) => val == "1",
86 Err(_) => false,
87 }
88 }
89
90 let is_verbose = is_set_to_1("FACET_LOG_VERBOSE");
91 if !is_verbose {
92 eprintln!(
93 "You can set FACET_LOG_VERBOSE=1 to see targets, files and line numbers for each tracing message"
94 );
95 }
96
97 tracing_subscriber::registry()
98 .with(
99 tracing_subscriber::fmt::layer()
100 .with_ansi(true)
101 .with_timer(Uptime)
102 .with_target(false)
103 .with_level(true)
104 .with_file(is_verbose)
105 .with_line_number(is_verbose)
106 .compact(),
107 )
108 .with(filter)
109 .try_init()
110 .ok();
111});
112
113pub fn setup() {
131 let is_nextest = std::env::var("NEXTEST").as_deref() == Ok("1");
133 if !is_nextest {
134 static NEXTEST_WARNING: LazyLock<()> = LazyLock::new(|| {
135 eprintln!(
136 "💡 Tip: Consider using `cargo nextest run` for better test output and performance."
137 );
138 eprintln!(" Install with: cargo install cargo-nextest");
139 eprintln!(" More info: https://nexte.st");
140 eprintln!();
141 });
142 #[allow(clippy::let_unit_value)]
143 let _ = *NEXTEST_WARNING;
144 }
145
146 #[allow(clippy::let_unit_value)]
148 let _ = *SUBSCRIBER_INIT;
149}
150
151#[derive(Debug)]
154pub struct IPanic;
155
156impl<E> From<E> for IPanic
157where
158 E: core::error::Error + Send + Sync,
159{
160 #[track_caller]
161 fn from(value: E) -> Self {
162 panic!("from: {}: {value}", core::panic::Location::caller())
163 }
164}