use std::fs;
use std::path::{Path, PathBuf};
use deslop::{ScanOptions, ScanReport, scan_repository, scan_repository_with_go_semantic};
use tempfile::TempDir;
pub(crate) struct FixtureWorkspace {
root: TempDir,
}
impl FixtureWorkspace {
pub(crate) fn new() -> Self {
let root = tempfile::Builder::new()
.prefix("deslop-test-")
.tempdir()
.expect("temp dir creation should succeed");
Self { root }
}
#[allow(dead_code)]
pub(crate) fn root(&self) -> &Path {
self.root.path()
}
pub(crate) fn write_file(&self, relative_path: &str, contents: &str) {
write_fixture(self.root.path(), relative_path, contents);
}
pub(crate) fn write_files(&self, files: &[(&str, &str)]) {
write_files(self.root.path(), files);
}
pub(crate) fn scan(&self) -> ScanReport {
self.scan_with_options(true)
}
pub(crate) fn scan_report(&self) -> ScanReport {
self.scan()
}
pub(crate) fn scan_with_options(&self, respect_ignore: bool) -> ScanReport {
scan_root_with_options(self.root.path().to_path_buf(), respect_ignore)
}
#[allow(dead_code)]
pub(crate) fn scan_with_go_semantic(&self, go_semantic: bool) -> ScanReport {
scan_root_with_go_semantic(self.root.path().to_path_buf(), go_semantic)
}
}
pub(crate) fn write_fixture(root: &Path, relative_path: &str, contents: &str) {
let path = root.join(relative_path);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("parent dir creation should succeed");
}
fs::write(path, contents).expect("fixture write should succeed");
}
pub(crate) fn write_files(root: &Path, files: &[(&str, &str)]) {
for (relative_path, contents) in files {
write_fixture(root, relative_path, contents);
}
}
#[allow(dead_code)]
pub(crate) fn fixture_path(relative_path: &str) -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures")
.join(relative_path)
}
#[allow(dead_code)]
pub(crate) fn load_fixture(relative_path: &str) -> String {
let path = fixture_path(relative_path);
fs::read_to_string(&path).unwrap_or_else(|error| {
panic!(
"fixture load should succeed for {}: {error}",
path.display()
)
})
}
#[allow(dead_code)]
pub(crate) fn scan_single_file(relative_path: &str, contents: &str) -> ScanReport {
let workspace = FixtureWorkspace::new();
workspace.write_file(relative_path, contents);
workspace.scan_with_options(false)
}
#[allow(dead_code)]
pub(crate) fn scan_fixture(fixture_relative_path: &str, target_relative_path: &str) -> ScanReport {
let contents = load_fixture(fixture_relative_path);
scan_single_file(target_relative_path, &contents)
}
#[allow(dead_code)]
pub(crate) fn scan_files(files: &[(&str, &str)]) -> ScanReport {
let workspace = FixtureWorkspace::new();
workspace.write_files(files);
workspace.scan_report()
}
#[allow(dead_code)]
pub(crate) fn scan_root(root: PathBuf) -> ScanReport {
scan_root_with_options(root, true)
}
#[allow(dead_code)]
pub(crate) fn scan_root_with_options(root: PathBuf, respect_ignore: bool) -> ScanReport {
scan_repository(&ScanOptions {
root,
respect_ignore,
})
.expect("scan should succeed")
}
#[allow(dead_code)]
pub(crate) fn scan_root_with_go_semantic(root: PathBuf, go_semantic: bool) -> ScanReport {
scan_repository_with_go_semantic(
&ScanOptions {
root,
respect_ignore: true,
},
go_semantic,
)
.expect("scan should succeed")
}
#[allow(dead_code)]
pub(crate) fn report_has_rule(report: &ScanReport, rule_id: &str) -> bool {
report
.findings
.iter()
.any(|finding| finding.rule_id == rule_id)
}
#[allow(dead_code)]
pub(crate) fn find_rule<'a>(report: &'a ScanReport, rule_id: &str) -> Option<&'a deslop::Finding> {
report
.findings
.iter()
.find(|finding| finding.rule_id == rule_id)
}
#[allow(dead_code)]
pub(crate) fn assert_rule_severity(report: &ScanReport, rule_id: &str, severity: deslop::Severity) {
let finding = find_rule(report, rule_id)
.unwrap_or_else(|| panic!("missing rule for severity assertion: {rule_id}"));
assert_eq!(
finding.severity, severity,
"unexpected severity for rule {rule_id}"
);
}
#[allow(dead_code)]
pub(crate) fn assert_rules_present(report: &ScanReport, rule_ids: &[&str]) {
for rule_id in rule_ids {
assert!(
report_has_rule(report, rule_id),
"missing rule: {rule_id}; findings were {:?}",
report
.findings
.iter()
.map(|finding| finding.rule_id.as_str())
.collect::<Vec<_>>()
);
}
}
#[allow(dead_code)]
pub(crate) fn assert_rules_absent(report: &ScanReport, rule_ids: &[&str]) {
for rule_id in rule_ids {
assert!(
!report_has_rule(report, rule_id),
"unexpected rule: {rule_id}; findings were {:?}",
report
.findings
.iter()
.map(|finding| finding.rule_id.as_str())
.collect::<Vec<_>>()
);
}
}