use std::fs::Permissions;
#[cfg(not(target_os = "windows"))]
use std::os::unix::fs::PermissionsExt;
use regex::Regex;
use crate::checkers::file::{FileCheck, get_option_string_value_from_checktable};
use super::super::{
GenericChecker,
base::{CheckConstructor, CheckDefinitionError, CheckError, Checker},
};
#[derive(Debug)]
pub(crate) struct FilePresent {
file_check: FileCheck,
permissions: Option<std::fs::Permissions>,
placeholder: Option<String>,
regex: Option<Regex>,
}
pub(crate) fn get_permissions_from_checktable(
check_table: &toml_edit::Table,
) -> Result<Option<Permissions>, CheckDefinitionError> {
if let Some(permissions) = check_table.get("permissions") {
#[cfg(target_os = "windows")]
{
Ok(None)
}
#[cfg(not(target_os = "windows"))]
match permissions.as_str() {
None => Err(CheckDefinitionError::InvalidDefinition(
"permissions is not a string".into(),
)),
Some(permissions) => match u32::from_str_radix(permissions, 8) {
Err(_) => Err(CheckDefinitionError::InvalidDefinition(
"permission can not be converted to an octal mode".into(),
)),
Ok(mode) => {
if mode > 0o777 {
return Err(CheckDefinitionError::InvalidDefinition(
"permission is not a valid mode".into(),
));
}
Ok(Some(std::fs::Permissions::from_mode(mode)))
}
},
}
} else {
Ok(None)
}
}
pub(crate) fn get_regex_from_checktable(
check_table: &toml_edit::Table,
) -> Result<Option<Regex>, CheckDefinitionError> {
match get_option_string_value_from_checktable(check_table, "regex") {
Err(err) => Err(err),
Ok(None) => Ok(None),
Ok(Some(regex)) => match Regex::new(regex.as_str()) {
Ok(r) => Ok(Some(r)),
Err(_) => Err(CheckDefinitionError::InvalidDefinition(format!(
"regex ({regex}) is not a valid regex"
))),
},
}
}
impl CheckConstructor for FilePresent {
type Output = Self;
fn from_check_table(
generic_check: GenericChecker,
value: toml_edit::Table,
) -> Result<Self::Output, CheckDefinitionError> {
let file_check = FileCheck::from_check_table(generic_check, &value)?;
let permissions = get_permissions_from_checktable(&value)?;
let placeholder = get_option_string_value_from_checktable(&value, "placeholder")?;
let regex = get_regex_from_checktable(&value)?;
Ok(Self {
file_check,
permissions,
placeholder,
regex,
})
}
}
impl Checker for FilePresent {
fn checker_type(&self) -> String {
"file_present".to_string()
}
fn generic_checker(&self) -> &GenericChecker {
&self.file_check.generic_check
}
fn checker_object(&self) -> String {
self.file_check.check_object()
}
fn check_(&self, fix: bool) -> Result<crate::checkers::base::CheckResult, CheckError> {
self.file_check.conclude_check_file_exists(
self.placeholder.clone(),
self.permissions.clone(),
self.regex.clone(),
fix,
)
}
}
#[cfg(test)]
mod tests {
use std::fs::write;
use crate::checkers::{base::CheckResult, test_helpers};
use super::*;
use tempfile::tempdir;
fn get_file_present_check_with_result(
placeholder: Option<String>,
permissions: Option<String>,
regex: Option<String>,
) -> (Result<FilePresent, CheckDefinitionError>, tempfile::TempDir) {
let generic_check = test_helpers::get_generic_check();
let mut check_table = toml_edit::Table::new();
let dir = tempdir().unwrap();
let file_to_check = dir.path().join("file_to_check");
check_table.insert("file", file_to_check.to_string_lossy().to_string().into());
if let Some(placeholder) = placeholder {
check_table.insert("placeholder", placeholder.into());
}
if let Some(permissions) = permissions {
check_table.insert("permissions", permissions.into());
}
if let Some(regex) = regex {
check_table.insert("regex", regex.into());
}
(
FilePresent::from_check_table(generic_check, check_table),
dir,
)
}
fn get_file_present_check(
placeholder: Option<String>,
permissions: Option<String>,
regex: Option<String>,
) -> (FilePresent, tempfile::TempDir) {
let (file_present_with_result, tempdir) =
get_file_present_check_with_result(placeholder, permissions, regex);
(file_present_with_result.unwrap(), tempdir)
}
#[test]
fn test_file_present() {
let (file_present_check, _tempdir) = get_file_present_check(None, None, None);
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::FixNeeded("create file".into())
);
assert_eq!(
file_present_check.check_(true).unwrap(),
CheckResult::FixExecuted("create file".into())
);
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::NoFixNeeded
);
}
#[test]
fn test_file_present_with_placeholder() {
let (file_present_check, _tempdir) =
get_file_present_check(Some("placeholder".into()), None, None);
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::FixNeeded("create file\nset contents to placeholder".into())
);
assert_eq!(
file_present_check.check_(true).unwrap(),
CheckResult::FixExecuted("create file\nset contents to placeholder".into())
);
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::NoFixNeeded
);
}
#[test]
fn test_file_present_with_permissions() {
let (file_present_check, _tempdir) = get_file_present_check(None, Some("666".into()), None);
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::FixNeeded("create file\nfix permissions to 666".into())
);
assert_eq!(
file_present_check.check_(true).unwrap(),
CheckResult::FixExecuted("create file\nfix permissions to 666".into())
);
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::NoFixNeeded
);
}
#[test]
fn test_file_present_with_regex() {
let file_present_error =
get_file_present_check_with_result(None, None, Some("^[0-9]{1,3$".into()))
.0
.expect_err("must give error");
assert_eq!(
file_present_error,
CheckDefinitionError::InvalidDefinition(
"regex (^[0-9]{1,3$) is not a valid regex".into()
)
);
let (file_present_check, _tempdir) =
get_file_present_check(None, None, Some("[0-9]{1,3}".into()));
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::FixNeeded("create file\nfix content to match regex \"[0-9]{1,3}\"".into())
);
let _ = write(
file_present_check.file_check.file_to_check.as_ref().clone(),
"bla",
);
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::FixNeeded("fix content to match regex \"[0-9]{1,3}\"".into())
);
let _ = write(
file_present_check.file_check.file_to_check.as_ref().clone(),
"129",
);
assert_eq!(
file_present_check.check_(false).unwrap(),
CheckResult::NoFixNeeded
);
}
}