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 log::{Level, LevelFilter, Log, Metadata, Record};
10use owo_colors::{OwoColorize, Style};
11use std::io::Write;
12
13struct SimpleLogger;
14
15impl Log for SimpleLogger {
16 fn enabled(&self, _metadata: &Metadata) -> bool {
17 true
18 }
19
20 fn log(&self, record: &Record) {
21 let level_style = match record.level() {
23 Level::Error => Style::new().fg_rgb::<243, 139, 168>(), Level::Warn => Style::new().fg_rgb::<249, 226, 175>(), Level::Info => Style::new().fg_rgb::<166, 227, 161>(), Level::Debug => Style::new().fg_rgb::<137, 180, 250>(), Level::Trace => Style::new().fg_rgb::<148, 226, 213>(), };
29
30 eprintln!(
32 "{} - {}: {}",
33 record.level().style(level_style),
34 record
35 .target()
36 .style(Style::new().fg_rgb::<137, 180, 250>()), record.args()
38 );
39 }
40
41 fn flush(&self) {
42 let _ = std::io::stderr().flush();
43 }
44}
45
46pub fn setup() {
53 let is_nextest = std::env::var("NEXTEST").as_deref() == Ok("1");
54 if !is_nextest {
55 let command = if cfg!(miri) {
56 "cargo miri nextest run"
57 } else {
58 "cargo nextest run"
59 };
60 let message = format!(
61 "This test suite requires cargo-nextest to run.\n\
62 \n\
63 cargo-nextest provides:\n\
64 • Process-per-test isolation (required for our logger setup)\n\
65 • Faster parallel test execution\n\
66 • Better test output and reporting\n\
67 \n\
68 Install it with:\n\
69 cargo install cargo-nextest\n\
70 \n\
71 Then run tests with:\n\
72 {command}\n\
73 \n\
74 For more information, visit: https://nexte.st"
75 );
76 let boxed = boxen::builder()
77 .border_style(boxen::BorderStyle::Round)
78 .padding(1)
79 .border_color("red")
80 .render(&message)
81 .unwrap();
82 panic!("\n{boxed}");
83 }
84
85 let logger = Box::new(SimpleLogger);
86 let _ = log::set_boxed_logger(logger);
89 log::set_max_level(LevelFilter::Trace);
90}
91
92#[derive(Debug)]
95pub struct IPanic;
96
97impl<E> From<E> for IPanic
98where
99 E: core::error::Error + Send + Sync,
100{
101 #[track_caller]
102 fn from(value: E) -> Self {
103 panic!("from: {}: {value}", core::panic::Location::caller())
104 }
105}