From 6dcf08cadb0b1fe47d75f5e0db38a599145ee096 Mon Sep 17 00:00:00 2001 From: bconn98 Date: Mon, 1 Apr 2024 21:38:15 -0400 Subject: [PATCH] backout: console changes and pattern changes for separate PR --- src/encode/pattern/mod.rs | 337 ++++------------------------------- src/encode/writer/console.rs | 236 +++++------------------- 2 files changed, 72 insertions(+), 501 deletions(-) diff --git a/src/encode/pattern/mod.rs b/src/encode/pattern/mod.rs index 15c42dc8..5215f2ec 100644 --- a/src/encode/pattern/mod.rs +++ b/src/encode/pattern/mod.rs @@ -744,16 +744,18 @@ impl Deserialize for PatternEncoderDeserializer { #[cfg(test)] mod tests { - #[cfg(feature = "config_parsing")] - use crate::config::Deserializers; - #[cfg(feature = "simple_writer")] - use crate::encode::{writer::simple::SimpleWriter, Encode, Write as EncodeWrite}; #[cfg(feature = "simple_writer")] use log::{Level, Record}; #[cfg(feature = "simple_writer")] - use std::{io::Write, process, thread}; + use std::process; + #[cfg(feature = "simple_writer")] + use std::thread; - use super::*; + use super::{Chunk, PatternEncoder}; + #[cfg(feature = "simple_writer")] + use crate::encode::writer::simple::SimpleWriter; + #[cfg(feature = "simple_writer")] + use crate::encode::Encode; fn error_free(encoder: &PatternEncoder) -> bool { encoder.chunks.iter().all(|c| match *c { @@ -763,18 +765,18 @@ mod tests { } #[test] - fn test_invalid_formatter() { + fn invalid_formatter() { assert!(!error_free(&PatternEncoder::new("{x}"))); } #[test] - fn test_unclosed_delimiter() { + fn unclosed_delimiter() { assert!(!error_free(&PatternEncoder::new("{d(%Y-%m-%d)"))); } #[test] #[cfg(feature = "simple_writer")] - fn test_log() { + fn log() { let pw = PatternEncoder::new("{l} {m} at {M} in {f}:{L}"); let mut buf = vec![]; pw.encode( @@ -794,7 +796,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_unnamed_thread() { + fn unnamed_thread() { thread::spawn(|| { let pw = PatternEncoder::new("{T}"); let mut buf = vec![]; @@ -808,7 +810,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_named_thread() { + fn named_thread() { thread::Builder::new() .name("foobar".to_string()) .spawn(|| { @@ -825,7 +827,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_thread_id_field() { + fn thread_id_field() { thread::spawn(|| { let pw = PatternEncoder::new("{I}"); let mut buf = vec![]; @@ -839,7 +841,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_process_id() { + fn process_id() { let pw = PatternEncoder::new("{P}"); let mut buf = vec![]; @@ -851,7 +853,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_system_thread_id() { + fn system_thread_id() { let pw = PatternEncoder::new("{i}"); let mut buf = vec![]; @@ -863,13 +865,13 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_default_okay() { + fn default_okay() { assert!(error_free(&PatternEncoder::default())); } #[test] #[cfg(feature = "simple_writer")] - fn test_left_align() { + fn left_align() { let pw = PatternEncoder::new("{m:~<5.6}"); let mut buf = vec![]; @@ -891,7 +893,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_right_align() { + fn right_align() { let pw = PatternEncoder::new("{m:~>5.6}"); let mut buf = vec![]; @@ -913,7 +915,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_left_align_formatter() { + fn left_align_formatter() { let pw = PatternEncoder::new("{({l} {m}):15}"); let mut buf = vec![]; @@ -930,7 +932,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_right_align_formatter() { + fn right_align_formatter() { let pw = PatternEncoder::new("{({l} {m}):>15}"); let mut buf = vec![]; @@ -946,27 +948,27 @@ mod tests { } #[test] - fn test_custom_date_format() { + fn custom_date_format() { assert!(error_free(&PatternEncoder::new( "{d(%Y-%m-%d %H:%M:%S)} {m}{n}" ))); } #[test] - fn test_timezones() { + fn timezones() { assert!(error_free(&PatternEncoder::new("{d(%+)(utc)}"))); assert!(error_free(&PatternEncoder::new("{d(%+)(local)}"))); assert!(!error_free(&PatternEncoder::new("{d(%+)(foo)}"))); } #[test] - fn test_unescaped_parens() { + fn unescaped_parens() { assert!(!error_free(&PatternEncoder::new("(hi)"))); } #[test] #[cfg(feature = "simple_writer")] - fn test_escaped_chars() { + fn escaped_chars() { let pw = PatternEncoder::new("{{{m}(())}}"); let mut buf = vec![]; @@ -980,7 +982,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_quote_braces_with_backslash() { + fn quote_braces_with_backslash() { let pw = PatternEncoder::new(r"\{\({l}\)\}\\"); let mut buf = vec![]; @@ -994,7 +996,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_mdc() { + fn mdc() { let pw = PatternEncoder::new("{X(user_id)}"); log_mdc::insert("user_id", "mdc value"); @@ -1007,7 +1009,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_mdc_missing_default() { + fn mdc_missing_default() { let pw = PatternEncoder::new("{X(user_id)}"); let mut buf = vec![]; @@ -1019,7 +1021,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_mdc_missing_custom() { + fn mdc_missing_custom() { let pw = PatternEncoder::new("{X(user_id)(missing value)}"); let mut buf = vec![]; @@ -1031,7 +1033,7 @@ mod tests { #[test] #[cfg(feature = "simple_writer")] - fn test_debug_release() { + fn debug_release() { let debug_pat = "{D({l})}"; let release_pat = "{R({l})}"; @@ -1061,283 +1063,4 @@ mod tests { assert!(debug_buf.is_empty()); } } - - #[test] - #[cfg(feature = "simple_writer")] - fn test_max_width_writer() { - let mut buf = vec![]; - let mut w = SimpleWriter(&mut buf); - - let mut w = MaxWidthWriter { - remaining: 2, - w: &mut w, - }; - - let res = w.write(b"test write"); - assert!(res.is_ok()); - assert_eq!(res.unwrap(), 2); - assert_eq!(w.remaining, 0); - assert!(w.flush().is_ok()); - assert!(w.set_style(&Style::new()).is_ok()); - assert_eq!(buf, b"te"); - - let mut buf = vec![]; - let mut w = SimpleWriter(&mut buf); - - let mut w = MaxWidthWriter { - remaining: 15, - w: &mut w, - }; - let res = w.write(b"test write"); - assert!(res.is_ok()); - assert_eq!(res.unwrap(), 10); - assert_eq!(w.remaining, 5); - assert_eq!(buf, b"test write"); - } - - #[test] - #[cfg(feature = "simple_writer")] - fn test_left_align_writer() { - let mut buf = vec![]; - let mut w = SimpleWriter(&mut buf); - - let mut w = LeftAlignWriter { - to_fill: 4, - fill: ' ', - w: &mut w, - }; - - let res = w.write(b"test write"); - assert!(res.is_ok()); - assert!(w.flush().is_ok()); - assert!(w.set_style(&Style::new()).is_ok()); - } - - #[test] - #[cfg(feature = "simple_writer")] - fn test_right_align_writer() { - let mut write_buf = vec![]; - let buf = vec![BufferedOutput::Style(Style::new())]; - let mut w = SimpleWriter(&mut write_buf); - - let mut w = RightAlignWriter { - to_fill: 4, - fill: ' ', - w: &mut w, - buf, - }; - - let res = w.write(b"test write"); - assert!(res.is_ok()); - assert!(w.flush().is_ok()); - assert!(w.set_style(&Style::new()).is_ok()); - assert!(w.finish().is_ok()); - } - - #[test] - #[cfg(feature = "config_parsing")] - fn test_cfg_deserializer() { - let pattern_cfg = PatternEncoderConfig { - pattern: Some("[{d(%Y-%m-%dT%H:%M:%S%.6f)} {h({l}):<5.5} {M}] {m}{n}".to_owned()), - }; - - let deserializer = PatternEncoderDeserializer; - - let res = deserializer.deserialize(pattern_cfg, &Deserializers::default()); - assert!(res.is_ok()); - - let pattern_cfg = PatternEncoderConfig { pattern: None }; - - let res = deserializer.deserialize(pattern_cfg, &Deserializers::default()); - assert!(res.is_ok()); - } - - #[test] - #[cfg(feature = "simple_writer")] - fn test_chunk_no_min_width() { - let mut buf = vec![]; - let pattern = "[{h({l}):<.5} {M}]"; - let chunks: Vec = Parser::new(pattern).map(From::from).collect(); - for chunk in chunks { - assert!(chunk - .encode( - &mut SimpleWriter(&mut buf), - &Record::builder() - .level(Level::Debug) - .args(format_args!("the message")) - .module_path(Some("path")) - .file(Some("file")) - .line(Some(132)) - .build() - ) - .is_ok()) - } - assert!(!String::from_utf8(buf).unwrap().contains("ERROR")); - } - - #[test] - #[cfg(feature = "simple_writer")] - fn test_chunk_encode_err() { - let mut buf = vec![]; - let pattern = "[{h({l):<.5}]"; - let chunks: Vec = Parser::new(pattern).map(From::from).collect(); - for chunk in chunks { - assert!(chunk - .encode( - &mut SimpleWriter(&mut buf), - &Record::builder() - .level(Level::Debug) - .args(format_args!("the message")) - .module_path(Some("path")) - .file(Some("file")) - .line(Some(132)) - .build() - ) - .is_ok()) - } - assert!(String::from_utf8(buf).unwrap().contains("ERROR")); - } - - #[test] - fn test_from_piece_to_chunk() { - // Test 3 args passed to date - let pattern = "[{d(%Y-%m-%d %H:%M:%S %Z)(utc)(local)}]"; - let chunks: Vec = Parser::new(pattern).map(From::from).collect(); - match chunks.get(1).unwrap() { - Chunk::Error(err) => assert_eq!(err, "expected at most two arguments"), - _ => assert!(false), - } - - // Test unexepected formatter - let pattern = "[{d({l} %Y-%m-%d %H:%M:%S %Z)}]"; - let chunks: Vec = Parser::new(pattern).map(From::from).collect(); - match chunks.get(1).unwrap() { - Chunk::Formatted { chunk, .. } => match chunk { - FormattedChunk::Time(value, _tz) => { - assert_eq!(value, "{ERROR: unexpected formatter} %Y-%m-%d %H:%M:%S %Z") - } - _ => assert!(false), - }, - _ => assert!(false), - } - - let tests = vec![ - ("[{d(%Y-%m-%d %H:%M:%S %Z)(zulu)}]", "invalid timezone"), - ("[{d(%Y-%m-%d %H:%M:%S %Z)({l})}]", "invalid timezone"), - ("[{d(%Y-%m-%d %H:%M:%S %Z)()}]", "invalid timezone"), - ("[{h({l})({M}):<5.5}]", "expected exactly one argument"), - ( - "[{D({l})({M}):<5.5}{R({l})({M}):<5.5}]", - "expected exactly one argument", - ), - ( - "[{X(user_id)(foobar)(test):<5.5}]", - "expected at most two arguments", - ), - ("[{X({l user_id):<5.5}]", "expected '}'"), - ("[{X({l} user_id):<5.5}]", "invalid MDC key"), - ("[{X:<5.5}]", "missing MDC key"), - ("[{X(user_id)({l):<5.5}]", "expected '}'"), - ("[{X(user_id)({l}):<5.5}]", "invalid MDC default"), - ("[{X(user_id)():<5.5} {M}]", "invalid MDC default"), - ]; - - for (pattern, error_msg) in tests { - let chunks: Vec = Parser::new(pattern).map(From::from).collect(); - match chunks.get(1).unwrap() { - Chunk::Error(err) => assert!(err.contains(error_msg)), - _ => assert!(false), - } - } - - // Test expected 1 arg - let pattern = "{({l} {m})()}"; - let chunks: Vec = Parser::new(pattern).map(From::from).collect(); - match chunks.get(0).unwrap() { - Chunk::Error(err) => assert!(err.contains("expected exactly one argument")), - _ => assert!(false), - } - - // Test no_args - let pattern = "{l()}"; - let chunks: Vec = Parser::new(pattern).map(From::from).collect(); - match chunks.get(0).unwrap() { - Chunk::Error(err) => assert!(err.contains("unexpected arguments")), - _ => assert!(false), - } - } - - #[test] - #[cfg(feature = "simple_writer")] - fn test_encode_formatted_chunk() { - // Each test gets a new buf and writer to allow for checking the - // buffer and utilizing completely clean buffers. - - let record = Record::builder() - .level(Level::Info) - .args(format_args!("the message")) - .module_path(Some("path")) - .file(Some("file")) - .line(None) - .target("target") - .build(); - - // Limit the time tests to the year. Just need to verify that time can - // be written. Don't need to be precise. This should limit potential - // race condition failures. - - // Test UTC Time - let mut write_buf = vec![]; - let mut w = SimpleWriter(&mut write_buf); - let chunk = FormattedChunk::Time("%Y".to_owned(), Timezone::Utc); - chunk.encode(&mut w, &record).unwrap(); - assert_eq!(write_buf, Utc::now().format("%Y").to_string().as_bytes()); - - // Test Local Time - let mut write_buf = vec![]; - let mut w = SimpleWriter(&mut write_buf); - let chunk = FormattedChunk::Time("%Y".to_owned(), Timezone::Local); - chunk.encode(&mut w, &record).unwrap(); - assert_eq!(write_buf, Local::now().format("%Y").to_string().as_bytes()); - - // Test missing Line - let mut write_buf = vec![]; - let mut w = SimpleWriter(&mut write_buf); - let chunk = FormattedChunk::Line; - chunk.encode(&mut w, &record).unwrap(); - assert_eq!(write_buf, b"???"); - - // Test Target - let mut write_buf = vec![]; - let mut w = SimpleWriter(&mut write_buf); - let chunk = FormattedChunk::Target; - chunk.encode(&mut w, &record).unwrap(); - assert_eq!(write_buf, b"target"); - - // Test Newline - let mut write_buf = vec![]; - let mut w = SimpleWriter(&mut write_buf); - let chunk = FormattedChunk::Newline; - chunk.encode(&mut w, &record).unwrap(); - assert_eq!(write_buf, NEWLINE.as_bytes()); - - // Loop over to hit each possible styling - for level in Level::iter() { - let record = Record::builder() - .level(level) - .args(format_args!("the message")) - .module_path(Some("path")) - .file(Some("file")) - .line(None) - .target("target") - .build(); - - let mut write_buf = vec![]; - let mut w = SimpleWriter(&mut write_buf); - let chunk = FormattedChunk::Highlight(vec![Chunk::Text("Text".to_owned())]); - chunk.encode(&mut w, &record).unwrap(); - assert_eq!(write_buf, b"Text"); - // No style updates in the buffer to check for - } - } } diff --git a/src/encode/writer/console.rs b/src/encode/writer/console.rs index eaaf0974..6209fb97 100644 --- a/src/encode/writer/console.rs +++ b/src/encode/writer/console.rs @@ -2,37 +2,36 @@ //! //! Requires the `console_writer` feature. -use std::{env, fmt, io}; +use std::{fmt, io}; use crate::encode::{self, Style}; -use once_cell::sync::OnceCell; - -static COLOR_MODE: OnceCell = OnceCell::new(); - -fn set_color_mode( - no_color: Result, - clicolor_force: Result, - clicolor: Result, -) -> ColorMode { - let no_color = no_color.map(|var| var != "0").unwrap_or(false); - let clicolor_force = clicolor_force.map(|var| var != "0").unwrap_or(false); - +use once_cell::sync::Lazy; + +static COLOR_MODE: Lazy = Lazy::new(|| { + let no_color = std::env::var("NO_COLOR") + .map(|var| var != "0") + .unwrap_or(false); + let clicolor_force = std::env::var("CLICOLOR_FORCE") + .map(|var| var != "0") + .unwrap_or(false); if no_color { ColorMode::Never } else if clicolor_force { ColorMode::Always } else { - let clicolor = clicolor.map(|var| var != "0").unwrap_or(true); + let clicolor = std::env::var("CLICOLOR") + .map(|var| var != "0") + .unwrap_or(true); if clicolor { ColorMode::Auto } else { ColorMode::Never } } -} +}); /// The color output mode for a `ConsoleAppender` -#[derive(Clone, Copy, Default, Debug, PartialEq)] +#[derive(Clone, Copy, Default)] pub enum ColorMode { /// Print color only if the output is recognized as a console #[default] @@ -122,14 +121,14 @@ impl<'a> encode::Write for ConsoleWriterLock<'a> { #[cfg(unix)] mod imp { - use std::{env, fmt, io}; + use std::{fmt, io}; use crate::{ encode::{ self, writer::{ ansi::AnsiWriter, - console::{set_color_mode, ColorMode, COLOR_MODE}, + console::{ColorMode, COLOR_MODE}, }, Style, }, @@ -141,13 +140,7 @@ mod imp { impl Writer { pub fn stdout() -> Option { let writer = || Writer(AnsiWriter(StdWriter::stdout())); - let color_mode_init = { - let no_color = env::var("NO_COLOR"); - let clicolor_force = env::var("CLICOLOR_FORCE"); - let clicolor = env::var("CLICOLOR"); - set_color_mode(no_color, clicolor_force, clicolor) - }; - match COLOR_MODE.get_or_init(|| color_mode_init) { + match *COLOR_MODE { ColorMode::Auto => { if unsafe { libc::isatty(libc::STDOUT_FILENO) } != 1 { None @@ -162,13 +155,7 @@ mod imp { pub fn stderr() -> Option { let writer = || Writer(AnsiWriter(StdWriter::stderr())); - let color_mode_init = { - let no_color = env::var("NO_COLOR"); - let clicolor_force = env::var("CLICOLOR_FORCE"); - let clicolor = env::var("CLICOLOR"); - set_color_mode(no_color, clicolor_force, clicolor) - }; - match COLOR_MODE.get_or_init(|| color_mode_init) { + match *COLOR_MODE { ColorMode::Auto => { if unsafe { libc::isatty(libc::STDERR_FILENO) } != 1 { None @@ -240,7 +227,7 @@ mod imp { #[cfg(windows)] mod imp { use std::{ - env, fmt, + fmt, io::{self, Write}, mem, }; @@ -252,7 +239,7 @@ mod imp { use crate::{ encode::{ self, - writer::console::{set_color_mode, ColorMode, COLOR_MODE}, + writer::console::{ColorMode, COLOR_MODE}, Color, Style, }, priv_io::{StdWriter, StdWriterLock}, @@ -348,13 +335,7 @@ mod imp { inner: StdWriter::stdout(), }; - let color_mode_init = { - let no_color = env::var("NO_COLOR"); - let clicolor_force = env::var("CLICOLOR_FORCE"); - let clicolor = env::var("CLICOLOR"); - set_color_mode(no_color, clicolor_force, clicolor) - }; - match COLOR_MODE.get_or_init(|| color_mode_init) { + match *COLOR_MODE { ColorMode::Auto | ColorMode::Always => Some(writer), ColorMode::Never => None, } @@ -381,13 +362,7 @@ mod imp { inner: StdWriter::stdout(), }; - let color_mode_init = { - let no_color = env::var("NO_COLOR"); - let clicolor_force = env::var("CLICOLOR_FORCE"); - let clicolor = env::var("CLICOLOR"); - set_color_mode(no_color, clicolor_force, clicolor) - }; - match COLOR_MODE.get_or_init(|| color_mode_init) { + match *COLOR_MODE { ColorMode::Auto | ColorMode::Always => Some(writer), ColorMode::Never => None, } @@ -460,159 +435,32 @@ mod imp { #[cfg(test)] mod test { + use std::io::Write; + use super::*; use crate::encode::{Color, Style, Write as EncodeWrite}; - use std::{env::VarError, io::Write}; - // Unable to test the non locked Console as by definition, the unlocked - // console results in race conditions. Codecov tooling does not seem to - // see this test as coverage of the ConsoleWritterLock or WriterLock - // class, however, it should completely cover either. #[test] - fn test_stdout_console_writer_lock() { + fn basic() { let w = match ConsoleWriter::stdout() { Some(w) => w, None => return, }; - let mut writer = w.lock(); - - writer.write(b"normal ").unwrap(); - writer - .set_style( - Style::new() - .text(Color::Red) - .background(Color::Blue) - .intense(true), - ) - .unwrap(); - writer.write_all(b"styled").unwrap(); - writer - .set_style(&Style::new().text(Color::Green).intense(false)) - .unwrap(); - writer.write_all(b" styled2").unwrap(); - writer.set_style(&Style::new()).unwrap(); - writer.write_fmt(format_args!(" {} \n", "normal")).unwrap(); - writer.flush().unwrap(); - } - - #[test] - fn test_stderr_console_writer_lock() { - let w = match ConsoleWriter::stderr() { - Some(w) => w, - None => return, - }; - - // Do not operate on the stderr writer. Doing so results in undefined - // test result behavior due to tests running in parallel - let _ = w.lock(); - } - - #[test] - fn test_color_mode_default() { - let no_color = Err(VarError::NotPresent); - let clicolor_force = Err(VarError::NotPresent); - let clicolor = Err(VarError::NotPresent); - - let color_mode: OnceCell = OnceCell::new(); - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Auto - ); - } - - // Note that NO_COLOR has priority over all other fields - #[test] - fn test_no_color() { - let no_color = Ok("1".to_owned()); - let clicolor_force = Err(VarError::NotPresent); - let clicolor = Err(VarError::NotPresent); - - let mut color_mode: OnceCell = OnceCell::new(); - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Never - ); - - let no_color = Ok("1".to_owned()); - let clicolor_force = Ok("1".to_owned()); - let clicolor = Ok("1".to_owned()); - - let _ = color_mode.take(); // Clear the owned value - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Never - ); - } - - #[test] - fn test_cli_force() { - // CLICOLOR_FORCE is the only set field - let no_color = Err(VarError::NotPresent); - let clicolor_force = Ok("1".to_owned()); - let clicolor = Err(VarError::NotPresent); - - let mut color_mode: OnceCell = OnceCell::new(); - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Always - ); - - // Although NO_COLOR has priority, when set to 0 next in line - // is CLICOLOR_FORCE which maintains precedence over clicolor - // regardless of how it's set. Attempt both settings below - let no_color = Ok("0".to_owned()); - let clicolor_force = Ok("1".to_owned()); - let clicolor = Ok("1".to_owned()); - - let _ = color_mode.take(); // Clear the owned value - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Always - ); - - let no_color = Ok("0".to_owned()); - let clicolor_force = Ok("1".to_owned()); - let clicolor = Ok("0".to_owned()); - - let _ = color_mode.take(); // Clear the owned value - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Always - ); - } - - #[test] - fn test_cli_on() { - // CLICOLOR is the only set field - let no_color = Err(VarError::NotPresent); - let clicolor_force = Err(VarError::NotPresent); - let clicolor = Ok("1".to_owned()); - - let mut color_mode: OnceCell = OnceCell::new(); - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Auto - ); - - let no_color = Err(VarError::NotPresent); - let clicolor_force = Err(VarError::NotPresent); - let clicolor = Ok("0".to_owned()); - - let _ = color_mode.take(); // Clear the owned value - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Never - ); - - // CLICOLOR_FORCE is disabled - let no_color = Err(VarError::NotPresent); - let clicolor_force = Ok("0".to_owned()); - let clicolor = Ok("1".to_owned()); - - let _ = color_mode.take(); // Clear the owned value - assert_eq!( - color_mode.get_or_init(|| set_color_mode(no_color, clicolor_force, clicolor)), - &ColorMode::Auto - ); + let mut w = w.lock(); + + w.write_all(b"normal ").unwrap(); + w.set_style( + Style::new() + .text(Color::Red) + .background(Color::Blue) + .intense(true), + ) + .unwrap(); + w.write_all(b"styled").unwrap(); + w.set_style(Style::new().text(Color::Green)).unwrap(); + w.write_all(b" styled2").unwrap(); + w.set_style(&Style::new()).unwrap(); + w.write_all(b" normal\n").unwrap(); + w.flush().unwrap(); } }