Skip to content

Commit

Permalink
[nextest-runner] update display of Windows aborts slightly
Browse files Browse the repository at this point in the history
  • Loading branch information
sunshowers committed Dec 15, 2024
1 parent f706ade commit 24ce512
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 25 deletions.
19 changes: 14 additions & 5 deletions nextest-runner/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,11 @@ pub(crate) fn display_abort_status(abort_status: AbortStatus) -> String {
},
#[cfg(windows)]
AbortStatus::WindowsNtStatus(nt_status) => {
format!("code {}", crate::helpers::display_nt_status(nt_status))
format!(
"code {}",
// TODO: pass down a style here
crate::helpers::display_nt_status(nt_status, Style::new())
)
}
}
}
Expand Down Expand Up @@ -351,18 +355,23 @@ pub(crate) fn signal_str(signal: i32) -> Option<&'static str> {
}

#[cfg(windows)]
pub(crate) fn display_nt_status(nt_status: windows_sys::Win32::Foundation::NTSTATUS) -> String {
pub(crate) fn display_nt_status(
nt_status: windows_sys::Win32::Foundation::NTSTATUS,
bold_style: Style,
) -> String {
// 10 characters ("0x" + 8 hex digits) is how an NTSTATUS with the high bit set is going to be
// displayed anyway. It also ensures alignment for the displayer.
let bolded_status = format!("{:#010x}", nt_status.style(bold_style));
// Convert the NTSTATUS to a Win32 error code.
let win32_code = unsafe { windows_sys::Win32::Foundation::RtlNtStatusToDosError(nt_status) };

if win32_code == windows_sys::Win32::Foundation::ERROR_MR_MID_NOT_FOUND {
// The Win32 code was not found.
return format!("{nt_status:#x} ({nt_status})");
return format!("{bolded_status}");
}

format!(
"{:#x}: {}",
nt_status,
"{bolded_status}: {}",
io::Error::from_raw_os_error(win32_code as i32)
)
}
Expand Down
70 changes: 51 additions & 19 deletions nextest-runner/src/reporter/displayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1323,7 +1323,7 @@ impl<'a> TestReporterImpl<'a> {
leaked: _,
} = last_status.result
{
self.write_windows_message_line(nt_status, writer)?;
write_windows_message_line(nt_status, &self.styles, writer)?;
}

Ok(())
Expand Down Expand Up @@ -1397,7 +1397,7 @@ impl<'a> TestReporterImpl<'a> {
leaked: _,
} = last_status.result
{
self.write_windows_message_line(nt_status, writer)?;
write_windows_message_line(nt_status, &self.styles, writer)?;
}

Ok(())
Expand Down Expand Up @@ -1815,23 +1815,6 @@ impl<'a> TestReporterImpl<'a> {
write!(writer, "[>{:>7.3?}s] ", duration.as_secs_f64())
}

#[cfg(windows)]
fn write_windows_message_line(
&self,
nt_status: windows_sys::Win32::Foundation::NTSTATUS,
writer: &mut dyn Write,
) -> io::Result<()> {
write!(writer, "{:>12} ", "Message".style(self.styles.fail))?;
write!(writer, "[ ] ")?;
writeln!(
writer,
"code {}",
crate::helpers::display_nt_status(nt_status)
)?;

Ok(())
}

fn write_setup_script_execute_status(
&self,
script_id: &ScriptId,
Expand Down Expand Up @@ -2523,6 +2506,25 @@ fn short_status_str(result: ExecutionResult) -> Cow<'static, str> {
}
}

#[cfg(windows)]
fn write_windows_message_line(
nt_status: windows_sys::Win32::Foundation::NTSTATUS,
styles: &Styles,
writer: &mut dyn Write,
) -> io::Result<()> {
// Note that display_nt_status ensures that codes are aligned properly. For subsequent lines,
// use an indented displayer with 25 spaces (ensuring that message lines are aligned).
const INDENT: &str = " - ";
let mut indented = IndentWriter::new_skip_initial(INDENT, writer);
writeln!(
indented,
"{:>12} {}",
"with code".style(styles.fail),
crate::helpers::display_nt_status(nt_status, styles.count)
)?;
indented.flush()
}

fn write_final_warnings(
final_stats: FinalRunStats,
cancel_status: Option<CancelReason>,
Expand Down Expand Up @@ -3719,3 +3721,33 @@ mod tests {
String::from_utf8(buf).unwrap()
}
}

#[cfg(all(windows, test))]
mod windows_tests {
use super::*;
use windows_sys::Win32::{
Foundation::{NTSTATUS, STATUS_CONTROL_C_EXIT, STATUS_CONTROL_STACK_VIOLATION},
Globalization::SetThreadUILanguage,
};

#[test]
fn test_write_windows_message_line() {
unsafe {
// Set the thread UI language to US English for consistent output.
SetThreadUILanguage(0x0409);
}

insta::assert_snapshot!("ctrl_c_code", to_message_line(STATUS_CONTROL_C_EXIT));
insta::assert_snapshot!(
"stack_violation_code",
to_message_line(STATUS_CONTROL_STACK_VIOLATION),
);
}

#[track_caller]
fn to_message_line(status: NTSTATUS) -> String {
let mut buf = Vec::new();
write_windows_message_line(status as i32, &Styles::default(), &mut buf).unwrap();
String::from_utf8(buf).unwrap()
}
}
4 changes: 3 additions & 1 deletion nextest-runner/src/reporter/error_description.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ impl fmt::Display for UnitAbortDescription {
write!(
f,
" with code {}",
crate::helpers::display_nt_status(exception)
// TODO: pass in bold style (probably need to not use
// fmt::Display)
crate::helpers::display_nt_status(exception, owo_colors::Style::new())
)?;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
source: nextest-runner/src/reporter/displayer.rs
expression: buf
snapshot_kind: text
---
with code 0xc000013a: {Application Exit by CTRL+C}
The application terminated as a result of a CTRL+C. (os error 572)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: nextest-runner/src/reporter/displayer.rs
expression: to_message_line(STATUS_CONTROL_STACK_VIOLATION)
snapshot_kind: text
---
with code 0xc00001b2: Invalid access to memory location. (os error 998)

0 comments on commit 24ce512

Please sign in to comment.