@@ -12,7 +12,10 @@ use crate::services::setup::{
1212} ;
1313#[ cfg( test) ]
1414use crate :: services:: setup:: { iter_embedded_assets_for_setup_target, SetupTarget } ;
15- use crate :: services:: style:: { heading, label, success, value, OwoColorize } ;
15+ use crate :: services:: style:: {
16+ heading, label, status_tag_fail, status_tag_miss, status_tag_pass, status_tag_warn, success,
17+ value,
18+ } ;
1619
1720pub const NAME : & str = "doctor" ;
1821
@@ -1473,10 +1476,10 @@ fn format_tagged_lines(lines: Vec<TaggedLine>) -> String {
14731476fn status_tag_prefix ( tag : StatusTag ) -> String {
14741477 let prefix = format ! ( "[{}]" , status_tag_label( tag) ) ;
14751478 match tag {
1476- StatusTag :: Pass => prefix . green ( ) . to_string ( ) ,
1477- StatusTag :: Fail => prefix . red ( ) . to_string ( ) ,
1478- StatusTag :: Warn => prefix . yellow ( ) . to_string ( ) ,
1479- StatusTag :: Miss => prefix . blue ( ) . to_string ( ) ,
1479+ StatusTag :: Pass => status_tag_pass ( & prefix ) ,
1480+ StatusTag :: Fail => status_tag_fail ( & prefix ) ,
1481+ StatusTag :: Warn => status_tag_warn ( & prefix ) ,
1482+ StatusTag :: Miss => status_tag_miss ( & prefix ) ,
14801483 }
14811484}
14821485
@@ -1960,21 +1963,38 @@ mod tests {
19601963 }
19611964
19621965 fn assert_all_lines_tagged ( output : & str ) {
1963- let prefixes = [
1964- super :: status_tag_prefix ( super :: StatusTag :: Pass ) ,
1965- super :: status_tag_prefix ( super :: StatusTag :: Fail ) ,
1966- super :: status_tag_prefix ( super :: StatusTag :: Miss ) ,
1967- super :: status_tag_prefix ( super :: StatusTag :: Warn ) ,
1968- ]
1969- . map ( |prefix| format ! ( "{prefix} " ) ) ;
19701966 for line in output. lines ( ) {
1967+ let normalized = strip_ansi_codes ( line) ;
19711968 assert ! (
1972- prefixes. iter( ) . any( |prefix| line. starts_with( prefix) ) ,
1969+ normalized. starts_with( "[PASS] " )
1970+ || normalized. starts_with( "[FAIL] " )
1971+ || normalized. starts_with( "[MISS] " )
1972+ || normalized. starts_with( "[WARN] " ) ,
19731973 "line missing status tag: '{line}'"
19741974 ) ;
19751975 }
19761976 }
19771977
1978+ fn strip_ansi_codes ( input : & str ) -> String {
1979+ let mut output = String :: with_capacity ( input. len ( ) ) ;
1980+ let mut chars = input. chars ( ) . peekable ( ) ;
1981+ while let Some ( ch) = chars. next ( ) {
1982+ if ch == '\u{1b}' {
1983+ if matches ! ( chars. peek( ) , Some ( '[' ) ) {
1984+ chars. next ( ) ;
1985+ for next in chars. by_ref ( ) {
1986+ if next == 'm' {
1987+ break ;
1988+ }
1989+ }
1990+ }
1991+ continue ;
1992+ }
1993+ output. push ( ch) ;
1994+ }
1995+ output
1996+ }
1997+
19781998 fn base_report ( mode : DoctorMode , readiness : Readiness ) -> HookDoctorReport {
19791999 HookDoctorReport {
19802000 mode,
@@ -2093,7 +2113,8 @@ mod tests {
20932113 let output = super :: format_execution ( & execution) ;
20942114
20952115 assert_all_lines_tagged ( & output) ;
2096- assert ! ( output. contains( & super :: status_tag_prefix( super :: StatusTag :: Fail ) ) ) ;
2116+ let normalized = strip_ansi_codes ( & output) ;
2117+ assert ! ( normalized. contains( "[FAIL]" ) ) ;
20972118 }
20982119
20992120 #[ test]
@@ -2116,7 +2137,8 @@ mod tests {
21162137 let output = super :: format_execution ( & execution) ;
21172138
21182139 assert_all_lines_tagged ( & output) ;
2119- assert ! ( output. contains( & super :: status_tag_prefix( super :: StatusTag :: Fail ) ) ) ;
2140+ let normalized = strip_ansi_codes ( & output) ;
2141+ assert ! ( normalized. contains( "[FAIL]" ) ) ;
21202142 }
21212143
21222144 #[ test]
@@ -2142,11 +2164,32 @@ mod tests {
21422164 let output = super :: format_execution ( & execution) ;
21432165
21442166 assert_all_lines_tagged ( & output) ;
2145- assert ! ( output. contains( & super :: status_tag_prefix( super :: StatusTag :: Warn ) ) ) ;
2146- assert ! ( output. contains( & super :: status_tag_prefix( super :: StatusTag :: Miss ) ) ) ;
2167+ let normalized = strip_ansi_codes ( & output) ;
2168+ assert ! ( normalized. contains( "[WARN]" ) ) ;
2169+ assert ! ( normalized. contains( "[MISS]" ) ) ;
21472170 assert ! ( output. contains( "warning from test" ) ) ;
21482171 }
21492172
2173+ #[ test]
2174+ fn doctor_text_output_disables_prefix_colors_when_no_color_set ( ) {
2175+ let previous = std:: env:: var ( "NO_COLOR" ) . ok ( ) ;
2176+ std:: env:: set_var ( "NO_COLOR" , "1" ) ;
2177+ let execution = DoctorExecution {
2178+ report : base_report ( DoctorMode :: Diagnose , Readiness :: Ready ) ,
2179+ fix_results : Vec :: new ( ) ,
2180+ } ;
2181+ let output = super :: format_execution ( & execution) ;
2182+
2183+ match previous {
2184+ Some ( value) => std:: env:: set_var ( "NO_COLOR" , value) ,
2185+ None => std:: env:: remove_var ( "NO_COLOR" ) ,
2186+ }
2187+
2188+ assert_all_lines_tagged ( & output) ;
2189+ assert ! ( output. contains( "[PASS] " ) ) ;
2190+ assert ! ( !output. contains( "\u{1b} [" ) ) ;
2191+ }
2192+
21502193 #[ test]
21512194 fn doctor_reports_local_config_validation_failures ( ) -> Result < ( ) > {
21522195 let test_dir = TestDir :: new ( "doctor-local-config" ) ?;
0 commit comments