#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone, Default)]
pub struct OutputConfig {
quiet: bool,
verbose: bool,
use_color: bool,
show_timing: bool,
}
impl OutputConfig {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn from_cli(quiet: bool, verbose: bool, no_color: bool) -> Self {
Self {
quiet,
verbose,
use_color: !no_color && Self::detect_color_support(),
show_timing: verbose,
}
}
fn detect_color_support() -> bool {
if std::env::var("NO_COLOR").is_ok() {
return false;
}
#[cfg(feature = "colors")]
{
use is_terminal::IsTerminal;
std::io::stderr().is_terminal()
}
#[cfg(not(feature = "colors"))]
false
}
#[must_use]
pub const fn with_quiet(mut self, quiet: bool) -> Self {
self.quiet = quiet;
self
}
#[must_use]
pub const fn with_verbose(mut self, verbose: bool) -> Self {
self.verbose = verbose;
self
}
#[must_use]
pub const fn with_color(mut self, color: bool) -> Self {
self.use_color = color;
self
}
#[must_use]
pub const fn with_timing(mut self, timing: bool) -> Self {
self.show_timing = timing;
self
}
#[must_use]
pub const fn is_quiet(&self) -> bool {
self.quiet
}
#[must_use]
pub const fn is_verbose(&self) -> bool {
self.verbose
}
#[must_use]
pub const fn use_color(&self) -> bool {
self.use_color
}
#[must_use]
pub const fn show_timing(&self) -> bool {
self.show_timing
}
}
#[cfg(test)]
#[allow(unsafe_code)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = OutputConfig::default();
assert!(!config.is_quiet());
assert!(!config.is_verbose());
assert!(!config.use_color());
assert!(!config.show_timing());
}
#[test]
fn test_new() {
let config = OutputConfig::new();
assert!(!config.is_quiet());
assert!(!config.is_verbose());
assert!(!config.use_color());
assert!(!config.show_timing());
}
#[test]
fn test_from_cli_quiet() {
let config = OutputConfig::from_cli(true, false, false);
assert!(config.is_quiet());
assert!(!config.is_verbose());
}
#[test]
fn test_from_cli_verbose() {
let config = OutputConfig::from_cli(false, true, false);
assert!(!config.is_quiet());
assert!(config.is_verbose());
assert!(config.show_timing());
}
#[test]
fn test_from_cli_no_color() {
let config = OutputConfig::from_cli(false, false, true);
assert!(!config.use_color());
}
#[test]
fn test_with_quiet() {
let config = OutputConfig::new().with_quiet(true);
assert!(config.is_quiet());
}
#[test]
fn test_with_verbose() {
let config = OutputConfig::new().with_verbose(true);
assert!(config.is_verbose());
}
#[test]
fn test_with_color() {
let config = OutputConfig::new().with_color(true);
assert!(config.use_color());
}
#[test]
fn test_with_timing() {
let config = OutputConfig::new().with_timing(true);
assert!(config.show_timing());
}
#[test]
fn test_builder_chaining() {
let config = OutputConfig::new()
.with_quiet(false)
.with_verbose(true)
.with_color(true)
.with_timing(true);
assert!(!config.is_quiet());
assert!(config.is_verbose());
assert!(config.use_color());
assert!(config.show_timing());
}
#[test]
#[allow(clippy::unwrap_used)]
fn test_detect_color_support_with_no_color_env() {
unsafe {
std::env::set_var("NO_COLOR", "1");
}
let supported = OutputConfig::detect_color_support();
unsafe {
std::env::remove_var("NO_COLOR");
}
assert!(!supported);
}
#[test]
#[allow(clippy::unwrap_used)]
fn test_from_cli_respects_no_color_env() {
unsafe {
std::env::set_var("NO_COLOR", "1");
}
let config = OutputConfig::from_cli(false, false, false);
unsafe {
std::env::remove_var("NO_COLOR");
}
assert!(!config.use_color());
}
}