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
use regex::Regex;
enum OutputParsingStyle {
LiteralMatch(String),
PatternMatch(Regex),
}
const PATTERN_PREFIX: &str = "pattern:";
pub fn parse(debugger_output: String, expected_contents: Vec<&str>) -> anyhow::Result<()> {
if expected_contents.len() == 0 {
log::info!("No expected contents found.");
return anyhow::Ok(());
}
let debugger_output_lines = debugger_output
.trim()
.lines()
.map(|line| line.trim())
.collect::<Vec<&str>>();
let expected_contents = expected_contents
.iter()
.filter_map(|line| {
let str = line.trim();
match str.is_empty() {
false => Some(str),
true => None,
}
})
.map(|line| line.trim())
.collect::<Vec<&str>>();
let mut index = 0;
for expected in expected_contents {
let parsing_style = get_output_parsing_style(expected)?;
loop {
if index >= debugger_output_lines.len() {
let error_msg = format_error_message(&parsing_style);
anyhow::bail!(
"Unable to find expected content in the debugger output. {}",
error_msg
);
}
let debugger_output_line = debugger_output_lines[index];
index += 1;
match &parsing_style {
OutputParsingStyle::LiteralMatch(literal_str) => {
let str = literal_str.as_str();
if debugger_output_line.contains(&str) {
log::info!(
"Expected content found: `{}` at line `{}`",
str,
debugger_output_line
);
break;
}
}
OutputParsingStyle::PatternMatch(re) => {
if re.is_match(&debugger_output_line) {
log::info!("Expected pattern found: `{}`", debugger_output_line);
break;
}
}
}
}
}
anyhow::Ok(())
}
fn format_error_message(parsing_style: &OutputParsingStyle) -> String {
match parsing_style {
OutputParsingStyle::LiteralMatch(literal_string) => {
format!("Missing line: `{}`", literal_string)
}
OutputParsingStyle::PatternMatch(pattern) => {
format!("Found 0 matches for pattern: `{}`", pattern.to_string())
}
}
}
fn get_output_parsing_style(expected_output: &str) -> anyhow::Result<OutputParsingStyle> {
let parsing_style = if expected_output.starts_with(PATTERN_PREFIX) {
let re_pattern = expected_output
.strip_prefix(PATTERN_PREFIX)
.expect("string starts with `pattern:`");
let re = match Regex::new(re_pattern) {
Ok(re) => re,
Err(error) => anyhow::bail!("Invalid regex pattern: {}\n{}", re_pattern, error),
};
OutputParsingStyle::PatternMatch(re)
} else {
OutputParsingStyle::LiteralMatch(String::from(expected_output))
};
Ok(parsing_style)
}