1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
use crate::common::Config;
use crate::header::line_directive;
use crate::runtest::ProcRes;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
pub(super) struct DebuggerCommands {
pub commands: Vec<String>,
pub check_lines: Vec<String>,
pub breakpoint_lines: Vec<usize>,
}
impl DebuggerCommands {
pub(super) fn parse_from(
file: &Path,
config: &Config,
debugger_prefixes: &[&str],
rev: Option<&str>,
) -> Result<Self, String> {
let directives = debugger_prefixes
.iter()
.map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix)))
.collect::<Vec<_>>();
let mut breakpoint_lines = vec![];
let mut commands = vec![];
let mut check_lines = vec![];
let mut counter = 0;
let reader = BufReader::new(File::open(file).unwrap());
for line in reader.lines() {
counter += 1;
match line {
Ok(line) => {
let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line));
// Skip any revision specific directive that doesn't match the current
// revision being tested
if lnrev.is_some() && lnrev != rev {
continue;
}
if line.contains("#break") {
breakpoint_lines.push(counter);
}
for &(ref command_directive, ref check_directive) in &directives {
config
.parse_name_value_directive(&line, command_directive)
.map(|cmd| commands.push(cmd));
config
.parse_name_value_directive(&line, check_directive)
.map(|cmd| check_lines.push(cmd));
}
}
Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)),
}
}
Ok(Self { commands, check_lines, breakpoint_lines })
}
}
pub(super) fn check_debugger_output(
debugger_run_result: &ProcRes,
check_lines: &[String],
) -> Result<(), String> {
let num_check_lines = check_lines.len();
let mut check_line_index = 0;
for line in debugger_run_result.stdout.lines() {
if check_line_index >= num_check_lines {
break;
}
if check_single_line(line, &(check_lines[check_line_index])[..]) {
check_line_index += 1;
}
}
if check_line_index != num_check_lines && num_check_lines > 0 {
Err(format!("line not found in debugger output: {}", check_lines[check_line_index]))
} else {
Ok(())
}
}
fn check_single_line(line: &str, check_line: &str) -> bool {
// Allow check lines to leave parts unspecified (e.g., uninitialized
// bits in the wrong case of an enum) with the notation "[...]".
let line = line.trim();
let check_line = check_line.trim();
let can_start_anywhere = check_line.starts_with("[...]");
let can_end_anywhere = check_line.ends_with("[...]");
let check_fragments: Vec<&str> =
check_line.split("[...]").filter(|frag| !frag.is_empty()).collect();
if check_fragments.is_empty() {
return true;
}
let (mut rest, first_fragment) = if can_start_anywhere {
match line.find(check_fragments[0]) {
Some(pos) => (&line[pos + check_fragments[0].len()..], 1),
None => return false,
}
} else {
(line, 0)
};
for current_fragment in &check_fragments[first_fragment..] {
match rest.find(current_fragment) {
Some(pos) => {
rest = &rest[pos + current_fragment.len()..];
}
None => return false,
}
}
if !can_end_anywhere && !rest.is_empty() { false } else { true }
}
|