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
//! Datastructures and operations used for normalizing test output.
use bstr::ByteSlice;
use lazy_static::lazy_static;
use regex::bytes::{Captures, Regex};
use std::borrow::Cow;
use std::path::Path;
/// A filter's match rule.
#[derive(Clone, Debug)]
pub enum Match {
/// If the regex matches, the filter applies
Regex(Regex),
/// If the exact byte sequence is found, the filter applies
Exact(Vec<u8>),
/// Uses a heuristic to find backslashes in windows style paths
PathBackslash,
}
impl Match {
pub(crate) fn replace_all<'a>(&self, text: &'a [u8], replacement: &[u8]) -> Cow<'a, [u8]> {
match self {
Match::Regex(regex) => regex.replace_all(text, replacement),
Match::Exact(needle) => text.replace(needle, replacement).into(),
Match::PathBackslash => {
lazy_static! {
static ref PATH_RE: Regex = Regex::new(
r"(?x)
(?:
# Match paths to files with extensions that don't include spaces
\\(?:[\pL\pN.\-_']+[/\\])*[\pL\pN.\-_']+\.\pL+
|
# Allow spaces in absolute paths
[A-Z]:\\(?:[\pL\pN.\-_'\ ]+[/\\])+
)",
)
.unwrap();
}
PATH_RE.replace_all(text, |caps: &Captures<'_>| {
caps[0].replace(r"\", replacement)
})
}
}
}
}
impl From<&'_ Path> for Match {
fn from(v: &Path) -> Self {
let mut v = v.display().to_string();
// Normalize away windows canonicalized paths.
if v.starts_with(r"\\?\") {
v.drain(0..4);
}
let mut v = v.into_bytes();
// Normalize paths on windows to use slashes instead of backslashes,
// So that paths are rendered the same on all systems.
for c in &mut v {
if *c == b'\\' {
*c = b'/';
}
}
Self::Exact(v)
}
}
impl From<Regex> for Match {
fn from(v: Regex) -> Self {
Self::Regex(v)
}
}