Auto merge of #89752 - matthiaskrgr:rollup-v4fgmwg, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #89579 (Add regression test for issue 80108) - #89632 (Fix docblock code display on mobile) - #89691 (Move `DebuggerCommands` and `check_debugger_output` to a separate module) - #89707 (Apply clippy suggestions for std) - #89722 (Fix spelling: Cannonical -> Canonical) - #89736 (Remove unused CSS rule) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1ddd4e6d7e
15 changed files with 203 additions and 151 deletions
|
@ -264,14 +264,14 @@ impl EvaluationResult {
|
|||
/// Indicates that trait evaluation caused overflow and in which pass.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
|
||||
pub enum OverflowError {
|
||||
Cannonical,
|
||||
Canonical,
|
||||
ErrorReporting,
|
||||
}
|
||||
|
||||
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
||||
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
|
||||
match overflow_error {
|
||||
OverflowError::Cannonical => SelectionError::Overflow,
|
||||
OverflowError::Canonical => SelectionError::Overflow,
|
||||
OverflowError::ErrorReporting => SelectionError::ErrorReporting,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,10 +83,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
) -> EvaluationResult {
|
||||
match self.evaluate_obligation(obligation) {
|
||||
Ok(result) => result,
|
||||
Err(OverflowError::Cannonical) => {
|
||||
Err(OverflowError::Canonical) => {
|
||||
let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
|
||||
selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
|
||||
OverflowError::Cannonical => {
|
||||
OverflowError::Canonical => {
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"Overflow should be caught earlier in standard query mode: {:?}, {:?}",
|
||||
|
|
|
@ -161,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
|
||||
}
|
||||
Ok(_) => Ok(None),
|
||||
Err(OverflowError::Cannonical) => Err(Overflow),
|
||||
Err(OverflowError::Canonical) => Err(Overflow),
|
||||
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
|
||||
})
|
||||
.flat_map(Result::transpose)
|
||||
|
|
|
@ -900,7 +900,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match self.candidate_from_obligation(stack) {
|
||||
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
|
||||
Ok(None) => Ok(EvaluatedToAmbig),
|
||||
Err(Overflow) => Err(OverflowError::Cannonical),
|
||||
Err(Overflow) => Err(OverflowError::Canonical),
|
||||
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
|
||||
Err(..) => Ok(EvaluatedToErr),
|
||||
}
|
||||
|
@ -1064,7 +1064,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
self.infcx.report_overflow_error(error_obligation, true);
|
||||
}
|
||||
TraitQueryMode::Canonical => {
|
||||
return Err(OverflowError::Cannonical);
|
||||
return Err(OverflowError::Canonical);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,14 +242,13 @@ impl<R: Seek> BufReader<R> {
|
|||
self.pos = new_pos as usize;
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
if let Some(new_pos) = pos.checked_add(offset as u64) {
|
||||
if new_pos <= self.cap as u64 {
|
||||
self.pos = new_pos as usize;
|
||||
return Ok(());
|
||||
}
|
||||
} else if let Some(new_pos) = pos.checked_add(offset as u64) {
|
||||
if new_pos <= self.cap as u64 {
|
||||
self.pos = new_pos as usize;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
self.seek(SeekFrom::Current(offset)).map(drop)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -558,7 +558,7 @@ impl IntoInner<Handle> for File {
|
|||
|
||||
impl FromInner<Handle> for File {
|
||||
fn from_inner(handle: Handle) -> File {
|
||||
File { handle: handle }
|
||||
File { handle }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -672,7 +672,7 @@ impl FilePermissions {
|
|||
|
||||
impl FileType {
|
||||
fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
|
||||
FileType { attributes: attrs, reparse_tag: reparse_tag }
|
||||
FileType { attributes: attrs, reparse_tag }
|
||||
}
|
||||
pub fn is_dir(&self) -> bool {
|
||||
!self.is_symlink() && self.is_directory()
|
||||
|
|
|
@ -9,10 +9,10 @@ impl Handler {
|
|||
pub unsafe fn new() -> Handler {
|
||||
// This API isn't available on XP, so don't panic in that case and just
|
||||
// pray it works out ok.
|
||||
if c::SetThreadStackGuarantee(&mut 0x5000) == 0 {
|
||||
if c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32 {
|
||||
panic!("failed to reserve stack space for exception handling");
|
||||
}
|
||||
if c::SetThreadStackGuarantee(&mut 0x5000) == 0
|
||||
&& c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32
|
||||
{
|
||||
panic!("failed to reserve stack space for exception handling");
|
||||
}
|
||||
Handler
|
||||
}
|
||||
|
|
|
@ -93,10 +93,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
|
|||
if stop {
|
||||
return false;
|
||||
}
|
||||
if !hit {
|
||||
if start {
|
||||
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
|
||||
}
|
||||
if !hit && start {
|
||||
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
|
|
|
@ -78,7 +78,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
|||
);
|
||||
match infcx.evaluate_obligation(&obligation) {
|
||||
Ok(eval_result) if eval_result.may_apply() => {}
|
||||
Err(traits::OverflowError::Cannonical) => {}
|
||||
Err(traits::OverflowError::Canonical) => {}
|
||||
Err(traits::OverflowError::ErrorReporting) => {}
|
||||
_ => {
|
||||
return false;
|
||||
|
|
|
@ -773,8 +773,6 @@ h2.small-section-header > .anchor {
|
|||
|
||||
.item-table {
|
||||
display: table-row;
|
||||
/* align content left */
|
||||
justify-items: start;
|
||||
}
|
||||
.item-row {
|
||||
display: table-row;
|
||||
|
@ -1969,4 +1967,8 @@ details.undocumented[open] > summary::before {
|
|||
.docblock {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.docblock code {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
}
|
||||
|
|
9
src/test/rustdoc-gui/docblock-big-code-mobile.goml
Normal file
9
src/test/rustdoc-gui/docblock-big-code-mobile.goml
Normal file
|
@ -0,0 +1,9 @@
|
|||
// If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning
|
||||
// that it'll be on two lines.
|
||||
emulate: "iPhone 8" // it has the following size: (375, 667)
|
||||
goto: file://|DOC_PATH|/test_docs/long_code_block/index.html
|
||||
// We now check that the block is on two lines:
|
||||
show-text: true // We need to enable text draw to be able to have the "real" size
|
||||
// Little explanations for this test: if the text wasn't displayed on two lines, it would take
|
||||
// around 20px (which is the font size).
|
||||
assert-property: (".docblock p > code", {"offsetHeight": "42"})
|
|
@ -120,3 +120,6 @@ pub type SomeType = u32;
|
|||
pub mod huge_amount_of_consts {
|
||||
include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs"));
|
||||
}
|
||||
|
||||
/// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`.
|
||||
pub mod long_code_block {}
|
||||
|
|
15
src/test/ui/wasm/simd-to-array-80108.rs
Normal file
15
src/test/ui/wasm/simd-to-array-80108.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// only-wasm32
|
||||
// compile-flags: --crate-type=lib -Copt-level=2
|
||||
// build-pass
|
||||
#![feature(repr_simd)]
|
||||
|
||||
// Regression test for #80108
|
||||
|
||||
#[repr(simd)]
|
||||
pub struct Vector([i32; 4]);
|
||||
|
||||
impl Vector {
|
||||
pub const fn to_array(self) -> [i32; 4] {
|
||||
self.0
|
||||
}
|
||||
}
|
|
@ -38,6 +38,9 @@ use tracing::*;
|
|||
use crate::extract_gdb_version;
|
||||
use crate::is_android_gdb_target;
|
||||
|
||||
mod debugger;
|
||||
use debugger::{check_debugger_output, DebuggerCommands};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
@ -200,12 +203,6 @@ struct TestCx<'test> {
|
|||
revision: Option<&'test str>,
|
||||
}
|
||||
|
||||
struct DebuggerCommands {
|
||||
commands: Vec<String>,
|
||||
check_lines: Vec<String>,
|
||||
breakpoint_lines: Vec<usize>,
|
||||
}
|
||||
|
||||
enum ReadFrom {
|
||||
Path,
|
||||
Stdin(String),
|
||||
|
@ -235,10 +232,8 @@ impl<'test> TestCx<'test> {
|
|||
/// Code executed for each revision in turn (or, if there are no
|
||||
/// revisions, exactly once, with revision == None).
|
||||
fn run_revision(&self) {
|
||||
if self.props.should_ice {
|
||||
if self.config.mode != Incremental {
|
||||
self.fatal("cannot use should-ice in a test that is not cfail");
|
||||
}
|
||||
if self.props.should_ice && self.config.mode != Incremental {
|
||||
self.fatal("cannot use should-ice in a test that is not cfail");
|
||||
}
|
||||
match self.config.mode {
|
||||
RunPassValgrind => self.run_valgrind_test(),
|
||||
|
@ -674,7 +669,10 @@ impl<'test> TestCx<'test> {
|
|||
|
||||
// Parse debugger commands etc from test files
|
||||
let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
|
||||
self.parse_debugger_commands(prefixes);
|
||||
match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
|
||||
Ok(cmds) => cmds,
|
||||
Err(e) => self.fatal(&e),
|
||||
};
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
|
||||
let mut script_str = String::with_capacity(2048);
|
||||
|
@ -726,7 +724,9 @@ impl<'test> TestCx<'test> {
|
|||
self.fatal_proc_rec("Error while running CDB", &debugger_run_result);
|
||||
}
|
||||
|
||||
self.check_debugger_output(&debugger_run_result, &check_lines);
|
||||
if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
|
||||
self.fatal_proc_rec(&e, &debugger_run_result);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_debuginfo_gdb_test(&self) {
|
||||
|
@ -757,7 +757,10 @@ impl<'test> TestCx<'test> {
|
|||
};
|
||||
|
||||
let DebuggerCommands { commands, check_lines, breakpoint_lines } =
|
||||
self.parse_debugger_commands(prefixes);
|
||||
match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
|
||||
Ok(cmds) => cmds,
|
||||
Err(e) => self.fatal(&e),
|
||||
};
|
||||
let mut cmds = commands.join("\n");
|
||||
|
||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||
|
@ -960,7 +963,9 @@ impl<'test> TestCx<'test> {
|
|||
self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
|
||||
}
|
||||
|
||||
self.check_debugger_output(&debugger_run_result, &check_lines);
|
||||
if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
|
||||
self.fatal_proc_rec(&e, &debugger_run_result);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_debuginfo_lldb_test(&self) {
|
||||
|
@ -1018,7 +1023,10 @@ impl<'test> TestCx<'test> {
|
|||
|
||||
// Parse debugger commands etc from test files
|
||||
let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
|
||||
self.parse_debugger_commands(prefixes);
|
||||
match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
|
||||
Ok(cmds) => cmds,
|
||||
Err(e) => self.fatal(&e),
|
||||
};
|
||||
|
||||
// Write debugger script:
|
||||
// We don't want to hang when calling `quit` while the process is still running
|
||||
|
@ -1094,7 +1102,9 @@ impl<'test> TestCx<'test> {
|
|||
self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
|
||||
}
|
||||
|
||||
self.check_debugger_output(&debugger_run_result, &check_lines);
|
||||
if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
|
||||
self.fatal_proc_rec(&e, &debugger_run_result);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_lldb(
|
||||
|
@ -1131,45 +1141,6 @@ impl<'test> TestCx<'test> {
|
|||
ProcRes { status, stdout: out, stderr: err, cmdline: format!("{:?}", cmd) }
|
||||
}
|
||||
|
||||
fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands {
|
||||
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 = 1;
|
||||
let reader = BufReader::new(File::open(&self.testpaths.file).unwrap());
|
||||
for line in reader.lines() {
|
||||
match line {
|
||||
Ok(line) => {
|
||||
let line =
|
||||
if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() };
|
||||
|
||||
if line.contains("#break") {
|
||||
breakpoint_lines.push(counter);
|
||||
}
|
||||
|
||||
for &(ref command_directive, ref check_directive) in &directives {
|
||||
self.config
|
||||
.parse_name_value_directive(&line, command_directive)
|
||||
.map(|cmd| commands.push(cmd));
|
||||
|
||||
self.config
|
||||
.parse_name_value_directive(&line, check_directive)
|
||||
.map(|cmd| check_lines.push(cmd));
|
||||
}
|
||||
}
|
||||
Err(e) => self.fatal(&format!("Error while parsing debugger commands: {}", e)),
|
||||
}
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
DebuggerCommands { commands, check_lines, breakpoint_lines }
|
||||
}
|
||||
|
||||
fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> {
|
||||
if options.is_none() {
|
||||
return None;
|
||||
|
@ -1216,66 +1187,6 @@ impl<'test> TestCx<'test> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_debugger_output(&self, debugger_run_result: &ProcRes, check_lines: &[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 {
|
||||
self.fatal_proc_rec(
|
||||
&format!("line not found in debugger output: {}", check_lines[check_line_index]),
|
||||
debugger_run_result,
|
||||
);
|
||||
}
|
||||
|
||||
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() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn check_error_patterns(
|
||||
&self,
|
||||
output_to_check: &str,
|
||||
|
@ -2154,9 +2065,9 @@ impl<'test> TestCx<'test> {
|
|||
|
||||
fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
|
||||
if self.config.verbose {
|
||||
println!("------{}------------------------------", "stdout");
|
||||
println!("------stdout------------------------------");
|
||||
println!("{}", out);
|
||||
println!("------{}------------------------------", "stderr");
|
||||
println!("------stderr------------------------------");
|
||||
println!("{}", err);
|
||||
println!("------------------------------------------");
|
||||
}
|
||||
|
@ -3249,11 +3160,10 @@ impl<'test> TestCx<'test> {
|
|||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
} else {
|
||||
if proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run succeeded!", &proc_res);
|
||||
}
|
||||
} else if proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run succeeded!", &proc_res);
|
||||
}
|
||||
|
||||
if !self.props.error_patterns.is_empty() {
|
||||
// "// error-pattern" comments
|
||||
self.check_error_patterns(&proc_res.stderr, &proc_res, pm);
|
||||
|
@ -3300,10 +3210,11 @@ impl<'test> TestCx<'test> {
|
|||
if !res.status.success() {
|
||||
self.fatal_proc_rec("failed to compile fixed code", &res);
|
||||
}
|
||||
if !res.stderr.is_empty() && !self.props.rustfix_only_machine_applicable {
|
||||
if !json::rustfix_diagnostics_only(&res.stderr).is_empty() {
|
||||
self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
|
||||
}
|
||||
if !res.stderr.is_empty()
|
||||
&& !self.props.rustfix_only_machine_applicable
|
||||
&& !json::rustfix_diagnostics_only(&res.stderr).is_empty()
|
||||
{
|
||||
self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
115
src/tools/compiletest/src/runtest/debugger.rs
Normal file
115
src/tools/compiletest/src/runtest/debugger.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
use crate::common::Config;
|
||||
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],
|
||||
) -> 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 = 1;
|
||||
let reader = BufReader::new(File::open(file).unwrap());
|
||||
for line in reader.lines() {
|
||||
match line {
|
||||
Ok(line) => {
|
||||
let line =
|
||||
if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() };
|
||||
|
||||
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)),
|
||||
}
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
Loading…
Reference in a new issue