Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 83 additions & 8 deletions src/tools/compiletest/src/runtest/debugger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,24 @@ use crate::runtest::ProcRes;

/// Representation of information to invoke a debugger and check its output
pub(super) struct DebuggerCommands {
/// Commands for the debuuger
/// Commands for the debugger
pub commands: Vec<String>,
/// Lines to insert breakpoints at
pub breakpoint_lines: Vec<usize>,
/// Contains the source line number to check and the line itself
check_lines: Vec<(usize, String)>,
/// Source file name
file: Utf8PathBuf,
/// The revision being tested, if any
revision: Option<String>,
}

impl DebuggerCommands {
pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result<Self, String> {
pub fn parse_from(
file: &Utf8Path,
debugger_prefix: &str,
test_revision: Option<&str>,
) -> Result<Self, String> {
let command_directive = format!("{debugger_prefix}-command");
let check_directive = format!("{debugger_prefix}-check");

Expand All @@ -38,19 +44,59 @@ impl DebuggerCommands {
continue;
}

let Some(line) = line.trim_start().strip_prefix("//@").map(str::trim_start) else {
let Some(after_prefix) = line.trim_start().strip_prefix("//@").map(str::trim_start)
else {
continue;
};

if let Some(command) = parse_name_value(&line, &command_directive) {
// Handle revision-specific directives like `//@ [revision] directive`
// by stripping the revision prefix if present
let (line_revision, directive_line) =
if let Some(after_open_bracket) = after_prefix.strip_prefix('[') {
if let Some((revision, after_close_bracket)) =
after_open_bracket.split_once(']')
{
(Some(revision), after_close_bracket.trim_start())
} else {
// Malformed revision prefix, skip this line
continue;
}
} else {
(None, after_prefix)
};

// Only process directives that apply to the current revision:
// - Directives without a revision prefix apply to all revisions
// - Directives with a revision prefix only apply when it matches the test revision
let applies_to_revision = match (test_revision, line_revision) {
// Directives with a revision prefix only apply to that specific revision
(Some(test_rev), Some(line_rev)) => test_rev == line_rev,
// No test revision means we're not running a revisioned test,
// so directives with revision prefixes shouldn't be processed
(None, Some(_)) => false,
// If a directive has no revision prefix, it applies to all revisions
(_, None) => true,
};

if !applies_to_revision {
continue;
}

if let Some(command) = parse_name_value(directive_line, &command_directive) {
commands.push(command);
}
if let Some(pattern) = parse_name_value(&line, &check_directive) {
if let Some(pattern) = parse_name_value(directive_line, &check_directive) {
check_lines.push((line_no, pattern));
}
}

Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_path_buf() })
Ok(Self {
commands,
breakpoint_lines,
check_lines,
file: file.to_path_buf(),
revision: test_revision.map(str::to_owned),
})
}

/// Given debugger output and lines to check, ensure that every line is
Expand Down Expand Up @@ -82,9 +128,11 @@ impl DebuggerCommands {
Ok(())
} else {
let fname = self.file.file_name().unwrap();
let revision_suffix =
self.revision.as_ref().map_or(String::new(), |r| format!("#{}", r));
let mut msg = format!(
"check directive(s) from `{}` not found in debugger output. errors:",
self.file
"check directive(s) from `{}{}` not found in debugger output. errors:",
self.file, revision_suffix
);

for (src_lineno, err_line) in missing {
Expand Down Expand Up @@ -150,3 +198,30 @@ fn check_single_line(line: &str, check_line: &str) -> bool {

can_end_anywhere || rest.is_empty()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_check_single_line_exact_match() {
assert!(check_single_line("$1 = 42", "$1 = 42"));
assert!(!check_single_line("$1 = 42", "$1 = 43"));
}

#[test]
fn test_check_single_line_with_wildcard() {
assert!(check_single_line("$1 = 42 (some extra stuff)", "$1 = 42[...]"));
assert!(check_single_line("prefix $1 = 42 suffix", "[...]$1 = 42[...]"));
assert!(!check_single_line("$1 = 43", "$1 = 42[...]"));
}

#[test]
fn test_parse_name_value() {
assert_eq!(parse_name_value("gdb-command:run", "gdb-command"), Some("run".to_string()));
assert_eq!(parse_name_value("gdb-command:", "gdb-command"), Some("".to_string()));
assert_eq!(parse_name_value("gdb-check:$1 = 42", "gdb-check"), Some("$1 = 42".to_string()));
assert_eq!(parse_name_value("lldb-command:run", "gdb-command"), None);
assert_eq!(parse_name_value("gdb-command run", "gdb-command"), None);
}
}
6 changes: 3 additions & 3 deletions src/tools/compiletest/src/runtest/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl TestCx<'_> {
}

// Parse debugger commands etc from test files
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb")
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb", self.revision)
.unwrap_or_else(|e| self.fatal(&e));

// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
Expand Down Expand Up @@ -105,7 +105,7 @@ impl TestCx<'_> {
}

fn run_debuginfo_gdb_test(&self) {
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb")
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb", self.revision)
.unwrap_or_else(|e| self.fatal(&e));
let mut cmds = dbg_cmds.commands.join("\n");

Expand Down Expand Up @@ -360,7 +360,7 @@ impl TestCx<'_> {
}

// Parse debugger commands etc from test files
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb")
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb", self.revision)
.unwrap_or_else(|e| self.fatal(&e));

// Write debugger script:
Expand Down