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 #[cfg(miri)]
39 let verbosity = color_backtrace::Verbosity::Medium;
40
41 #[cfg(not(miri))]
42 let verbosity = color_backtrace::Verbosity::Full;
43
44 color_backtrace::BacktracePrinter::new()
46 .verbosity(verbosity)
47 .add_frame_filter(Box::new(|frames| {
48 frames.retain(|frame| {
49 let dominated_by_noise = |name: &str| {
50 name.starts_with("test::run_test")
52 || name.starts_with("test::__rust_begin_short_backtrace")
53 || name.starts_with("std::panicking::")
55 || name.starts_with("std::panic::")
56 || name.starts_with("core::panicking::")
57 || name.starts_with("std::thread::Builder::spawn_unchecked_")
59 || name.starts_with("std::sys::thread::")
60 || name.starts_with("std::sys::backtrace::")
61 || name.starts_with("core::ops::function::FnOnce::call_once")
63 || name.starts_with("<alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once")
64 || name.starts_with("<core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once")
66 || name.starts_with("__pthread")
68 };
69 match &frame.name {
70 Some(name) => !dominated_by_noise(name),
71 None => true,
72 }
73 })
74 }))
75 .install(Box::new(termcolor::StandardStream::stderr(
76 termcolor::ColorChoice::AlwaysAnsi,
77 )));
78
79 let filter = std::env::var("FACET_LOG")
80 .ok()
81 .and_then(|s| s.parse::<Targets>().ok())
82 .unwrap_or_else(|| {
83 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)");
84 Targets::new().with_default(tracing::Level::DEBUG)
85 });
86
87 tracing_subscriber::registry()
88 .with(
89 tracing_subscriber::fmt::layer()
90 .with_ansi(true)
91 .with_timer(Uptime)
92 .with_target(false)
93 .with_level(true)
94 .with_file(false)
97 .with_line_number(false)
98 .compact(),
99 )
100 .with(filter)
101 .try_init()
102 .ok();
103});
104
105pub fn setup() {
123 let is_nextest = std::env::var("NEXTEST").as_deref() == Ok("1");
125 if !is_nextest {
126 static NEXTEST_WARNING: LazyLock<()> = LazyLock::new(|| {
127 eprintln!(
128 "💡 Tip: Consider using `cargo nextest run` for better test output and performance."
129 );
130 eprintln!(" Install with: cargo install cargo-nextest");
131 eprintln!(" More info: https://nexte.st");
132 eprintln!();
133 });
134 #[allow(clippy::let_unit_value)]
135 let _ = *NEXTEST_WARNING;
136 }
137
138 #[allow(clippy::let_unit_value)]
140 let _ = *SUBSCRIBER_INIT;
141}
142
143#[derive(Debug)]
146pub struct IPanic;
147
148impl<E> From<E> for IPanic
149where
150 E: core::error::Error + Send + Sync,
151{
152 #[track_caller]
153 fn from(value: E) -> Self {
154 panic!("from: {}: {value}", core::panic::Location::caller())
155 }
156}