rustic_testing/
lib.rs

1//! Testing utilities for the `rustic` ecosystem.
2
3// formatting args are used for error messages
4#![allow(clippy::literal_string_with_formatting_args)]
5
6/// Backends to be used solely for testing.
7pub mod backend;
8
9use aho_corasick::{AhoCorasick, PatternID};
10use std::{error::Error, ffi::OsStr};
11use tempfile::NamedTempFile;
12
13/// A test result.
14pub type TestResult<T> = Result<T, Box<dyn Error>>;
15
16/// Get the matches for the given patterns and output.
17///
18/// # Arguments
19///
20/// * `patterns` - The patterns to search for.
21/// * `output` - The output to search in.
22///
23/// # Errors
24///
25/// If the patterns are invalid.
26///
27/// # Returns
28///
29/// The matches for the given patterns and output.
30pub fn get_matches<I, P>(patterns: I, output: &str) -> TestResult<Vec<(PatternID, usize)>>
31where
32    I: IntoIterator<Item = P>,
33    P: AsRef<[u8]>,
34{
35    let ac = AhoCorasick::new(patterns)?;
36    let mut matches = vec![];
37    for mat in ac.find_iter(output) {
38        add_match_to_vector(&mut matches, mat);
39    }
40    Ok(matches)
41}
42
43/// Add a match to the given vector.
44///
45/// # Arguments
46///
47/// * `matches` - The vector to add the match to.
48/// * `mat` - The `aho_corasick::Match` to add.
49pub fn add_match_to_vector(matches: &mut Vec<(PatternID, usize)>, mat: aho_corasick::Match) {
50    matches.push((mat.pattern(), mat.end() - mat.start()));
51}
52
53/// Get a temporary file.
54///
55/// # Errors
56///
57/// If the temporary file could not be created.
58///
59/// # Returns
60///
61/// A temporary file.
62pub fn get_temp_file() -> TestResult<NamedTempFile> {
63    Ok(NamedTempFile::new()?)
64}
65
66/// Check if the given files differ.
67///
68/// # Arguments
69///
70/// * `path_left` - The left file to compare.
71/// * `path_right` - The right file to compare.
72///
73/// # Errors
74///
75/// If the files could not be compared.
76///
77/// # Returns
78///
79/// `true` if the files differ, `false` otherwise.
80pub fn files_differ(
81    path_left: impl AsRef<OsStr>,
82    path_right: impl AsRef<OsStr>,
83) -> TestResult<bool> {
84    // diff the directories
85    #[cfg(not(windows))]
86    {
87        let proc = std::process::Command::new("diff")
88            .arg(path_left)
89            .arg(path_right)
90            .output()?;
91
92        if proc.stdout.is_empty() {
93            return Ok(false);
94        }
95    }
96
97    #[cfg(windows)]
98    {
99        let proc = std::process::Command::new("fc.exe")
100            .arg("/L")
101            .arg(path_left)
102            .arg(path_right)
103            .output()?;
104
105        let output = String::from_utf8(proc.stdout)?;
106
107        dbg!(&output);
108
109        let patterns = &["FC: no differences encountered"];
110        let ac = AhoCorasick::new(patterns)?;
111        let mut matches = vec![];
112
113        for mat in ac.find_iter(output.as_str()) {
114            matches.push((mat.pattern(), mat.end() - mat.start()));
115        }
116
117        if matches == vec![(PatternID::must(0), 30)] {
118            return Ok(false);
119        }
120    }
121
122    Ok(true)
123}