use std::{error::Error, fmt, io, path::PathBuf};
use libc::c_int;
use crate::landlock::{Access, AccessFs, AccessNet, Scope};
#[derive(Debug)]
#[non_exhaustive]
pub enum RulesetError {
HandleAccesses(HandleAccessesError),
CreateRuleset(CreateRulesetError),
AddRules(AddRulesError),
RestrictSelf(RestrictSelfError),
}
impl Error for RulesetError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
RulesetError::HandleAccesses(err) => Error::source(err),
RulesetError::CreateRuleset(err) => Error::source(err),
RulesetError::AddRules(err) => Error::source(err),
RulesetError::RestrictSelf(err) => Error::source(err),
}
}
}
impl fmt::Display for RulesetError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RulesetError::HandleAccesses(err) => fmt::Display::fmt(err, f),
RulesetError::CreateRuleset(err) => fmt::Display::fmt(err, f),
RulesetError::AddRules(err) => fmt::Display::fmt(err, f),
RulesetError::RestrictSelf(err) => fmt::Display::fmt(err, f),
}
}
}
impl std::convert::From<HandleAccessesError> for RulesetError {
fn from(source: HandleAccessesError) -> Self {
RulesetError::HandleAccesses(source)
}
}
impl std::convert::From<CreateRulesetError> for RulesetError {
fn from(source: CreateRulesetError) -> Self {
RulesetError::CreateRuleset(source)
}
}
impl std::convert::From<AddRulesError> for RulesetError {
fn from(source: AddRulesError) -> Self {
RulesetError::AddRules(source)
}
}
impl std::convert::From<RestrictSelfError> for RulesetError {
fn from(source: RestrictSelfError) -> Self {
RulesetError::RestrictSelf(source)
}
}
#[test]
fn ruleset_error_breaking_change() {
use crate::*;
let _: RulesetError = RulesetError::HandleAccesses(HandleAccessesError::Fs(
HandleAccessError::Compat(CompatError::Access(AccessError::Empty)),
));
}
#[derive(Debug)]
#[non_exhaustive]
pub enum HandleAccessError<T>
where
T: Access,
{
Compat(CompatError<T>),
}
impl<T> Error for HandleAccessError<T>
where
T: Access,
CompatError<T>: Error,
Self: fmt::Debug + fmt::Display,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
HandleAccessError::Compat(err) => Error::source(err),
}
}
}
impl<T> fmt::Display for HandleAccessError<T>
where
T: Access,
CompatError<T>: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
HandleAccessError::Compat(err) => fmt::Display::fmt(err, f),
}
}
}
impl<T> std::convert::From<CompatError<T>> for HandleAccessError<T>
where
T: Access,
{
fn from(source: CompatError<T>) -> Self {
HandleAccessError::Compat(source)
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum HandleAccessesError {
Fs(HandleAccessError<AccessFs>),
Net(HandleAccessError<AccessNet>),
Scope(HandleAccessError<Scope>),
}
impl Error for HandleAccessesError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
HandleAccessesError::Fs(err) => Error::source(err),
HandleAccessesError::Net(err) => Error::source(err),
HandleAccessesError::Scope(err) => Error::source(err),
}
}
}
impl fmt::Display for HandleAccessesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
HandleAccessesError::Fs(err) => fmt::Display::fmt(err, f),
HandleAccessesError::Net(err) => fmt::Display::fmt(err, f),
HandleAccessesError::Scope(err) => fmt::Display::fmt(err, f),
}
}
}
impl<A> From<HandleAccessError<A>> for HandleAccessesError
where
A: Access,
{
fn from(error: HandleAccessError<A>) -> Self {
A::into_handle_accesses_error(error)
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum CreateRulesetError {
#[non_exhaustive]
CreateRulesetCall { source: io::Error },
MissingHandledAccess,
}
impl Error for CreateRulesetError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
CreateRulesetError::CreateRulesetCall { source, .. } => Some(source),
CreateRulesetError::MissingHandledAccess => None,
}
}
}
impl fmt::Display for CreateRulesetError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CreateRulesetError::CreateRulesetCall { source } => {
write!(f, "failed to create a ruleset: {source}",)
}
CreateRulesetError::MissingHandledAccess => {
write!(f, "missing handled access")
}
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum AddRuleError<T>
where
T: Access,
{
#[non_exhaustive]
AddRuleCall {
source: io::Error,
},
UnhandledAccess {
access: T,
incompatible: T,
},
Compat(CompatError<T>),
}
impl<T> Error for AddRuleError<T>
where
T: Access,
CompatError<T>: Error,
Self: fmt::Debug + fmt::Display,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
AddRuleError::AddRuleCall { source, .. } => Some(source),
AddRuleError::UnhandledAccess { .. } => None,
AddRuleError::Compat(err) => Error::source(err),
}
}
}
impl<T> fmt::Display for AddRuleError<T>
where
T: Access,
T: fmt::Debug,
CompatError<T>: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AddRuleError::AddRuleCall { source } => {
write!(f, "failed to add a rule: {source}",)
}
AddRuleError::UnhandledAccess {
access: _,
incompatible,
} => write!(
f,
"access-rights not handled by the ruleset: {incompatible:?}",
),
AddRuleError::Compat(err) => fmt::Display::fmt(err, f),
}
}
}
impl<T> std::convert::From<CompatError<T>> for AddRuleError<T>
where
T: Access,
{
fn from(source: CompatError<T>) -> Self {
AddRuleError::Compat { 0: source }
}
}
impl<A> From<AddRuleError<A>> for AddRulesError
where
A: Access,
{
fn from(error: AddRuleError<A>) -> Self {
A::into_add_rules_error(error)
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum AddRulesError {
Fs(AddRuleError<AccessFs>),
Net(AddRuleError<AccessNet>),
Scope(AddRuleError<Scope>),
}
impl Error for AddRulesError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
AddRulesError::Fs(err) => Error::source(err),
AddRulesError::Net(err) => Error::source(err),
AddRulesError::Scope(err) => Error::source(err),
}
}
}
impl fmt::Display for AddRulesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AddRulesError::Fs(err) => fmt::Display::fmt(err, f),
AddRulesError::Net(err) => fmt::Display::fmt(err, f),
AddRulesError::Scope(err) => fmt::Display::fmt(err, f),
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum CompatError<T>
where
T: Access,
{
PathBeneath(PathBeneathError),
Access(AccessError<T>),
}
impl<T> Error for CompatError<T>
where
T: Access,
AccessError<T>: Error,
Self: fmt::Debug + fmt::Display,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
CompatError::PathBeneath(err) => Error::source(err),
CompatError::Access(err) => Error::source(err),
}
}
}
impl<T> fmt::Display for CompatError<T>
where
T: Access,
AccessError<T>: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CompatError::PathBeneath(err) => fmt::Display::fmt(err, f),
CompatError::Access(err) => fmt::Display::fmt(err, f),
}
}
}
impl<T> std::convert::From<PathBeneathError> for CompatError<T>
where
T: Access,
{
fn from(source: PathBeneathError) -> Self {
CompatError::PathBeneath(source)
}
}
impl<T> std::convert::From<AccessError<T>> for CompatError<T>
where
T: Access,
{
fn from(source: AccessError<T>) -> Self {
CompatError::Access(source)
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum PathBeneathError {
#[non_exhaustive]
StatCall { source: io::Error },
DirectoryAccess {
access: AccessFs,
incompatible: AccessFs,
},
}
impl Error for PathBeneathError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
PathBeneathError::StatCall { source, .. } => Some(source),
PathBeneathError::DirectoryAccess { .. } => None,
}
}
}
impl fmt::Display for PathBeneathError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PathBeneathError::StatCall { source } => {
write!(f, "failed to check file descriptor type: {source}",)
}
PathBeneathError::DirectoryAccess {
access: _,
incompatible,
} => write!(
f,
"incompatible directory-only access-rights: {incompatible:?}",
),
}
}
}
#[derive(Debug)]
pub enum AccessError<T>
where
T: Access,
{
Empty,
Incompatible { access: T },
PartiallyCompatible { access: T, incompatible: T },
}
impl<T> Error for AccessError<T>
where
T: Access,
Self: fmt::Debug + fmt::Display,
{
}
impl<T> fmt::Display for AccessError<T>
where
T: Access,
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AccessError::Empty => write!(f, "empty access-right"),
AccessError::Incompatible { access } => {
write!(f, "fully incompatible access-rights: {access:?}",)
}
AccessError::PartiallyCompatible {
access: _,
incompatible,
} => write!(f, "partially incompatible access-rights: {incompatible:?}",),
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum RestrictSelfError {
#[non_exhaustive]
SetNoNewPrivsCall { source: io::Error },
#[non_exhaustive]
RestrictSelfCall { source: io::Error },
}
impl Error for RestrictSelfError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
RestrictSelfError::SetNoNewPrivsCall { source, .. } => Some(source),
RestrictSelfError::RestrictSelfCall { source, .. } => Some(source),
}
}
}
impl fmt::Display for RestrictSelfError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RestrictSelfError::SetNoNewPrivsCall { source } => {
write!(f, "failed to set no_new_privs: {source}",)
}
RestrictSelfError::RestrictSelfCall { source } => {
write!(f, "failed to restrict the calling thread: {source}",)
}
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum PathFdError {
#[non_exhaustive]
OpenCall { source: io::Error, path: PathBuf },
}
impl Error for PathFdError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
PathFdError::OpenCall { source, .. } => Some(source),
}
}
}
impl fmt::Display for PathFdError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PathFdError::OpenCall { source, path } => {
write!(
f,
"failed to open \"{path}\": {source}",
path = path.display()
)
}
}
}
}
#[cfg(test)]
#[derive(Debug)]
pub(crate) enum TestRulesetError {
Ruleset(RulesetError),
PathFd(PathFdError),
File(std::io::Error),
}
#[derive(Debug, PartialEq, Eq)]
pub struct Errno(c_int);
impl Errno {
pub fn new(value: c_int) -> Self {
Self(value)
}
}
impl<T> From<T> for Errno
where
T: std::error::Error,
{
fn from(error: T) -> Self {
let default = libc::EINVAL;
if let Some(e) = error.source() {
if let Some(e) = e.downcast_ref::<std::io::Error>() {
return Errno(e.raw_os_error().unwrap_or(default));
}
}
Errno(default)
}
}
impl std::ops::Deref for Errno {
type Target = c_int;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(test)]
impl Error for TestRulesetError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
TestRulesetError::Ruleset(err) => Error::source(err),
TestRulesetError::PathFd(err) => Error::source(err),
TestRulesetError::File(err) => Error::source(err),
}
}
}
#[cfg(test)]
impl fmt::Display for TestRulesetError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TestRulesetError::Ruleset(err) => fmt::Display::fmt(err, f),
TestRulesetError::PathFd(err) => fmt::Display::fmt(err, f),
TestRulesetError::File(err) => fmt::Display::fmt(err, f),
}
}
}
#[cfg(test)]
impl std::convert::From<RulesetError> for TestRulesetError {
fn from(source: RulesetError) -> Self {
TestRulesetError::Ruleset(source)
}
}
#[cfg(test)]
impl std::convert::From<PathFdError> for TestRulesetError {
fn from(source: PathFdError) -> Self {
TestRulesetError::PathFd(source)
}
}
#[cfg(test)]
impl std::convert::From<std::io::Error> for TestRulesetError {
fn from(source: std::io::Error) -> Self {
TestRulesetError::File(source)
}
}
#[cfg(test)]
fn _test_ruleset_errno(expected_errno: c_int) {
use std::io::Error;
let handle_access_err = RulesetError::HandleAccesses(HandleAccessesError::Fs(
HandleAccessError::Compat(CompatError::Access(AccessError::Empty)),
));
assert_eq!(*Errno::from(handle_access_err), libc::EINVAL);
let create_ruleset_err = RulesetError::CreateRuleset(CreateRulesetError::CreateRulesetCall {
source: Error::from_raw_os_error(expected_errno),
});
assert_eq!(*Errno::from(create_ruleset_err), expected_errno);
let add_rules_fs_err = RulesetError::AddRules(AddRulesError::Fs(AddRuleError::AddRuleCall {
source: Error::from_raw_os_error(expected_errno),
}));
assert_eq!(*Errno::from(add_rules_fs_err), expected_errno);
let add_rules_net_err = RulesetError::AddRules(AddRulesError::Net(AddRuleError::AddRuleCall {
source: Error::from_raw_os_error(expected_errno),
}));
assert_eq!(*Errno::from(add_rules_net_err), expected_errno);
let add_rules_other_err =
RulesetError::AddRules(AddRulesError::Fs(AddRuleError::UnhandledAccess {
access: AccessFs::Execute.into(),
incompatible: AccessFs::EMPTY,
}));
assert_eq!(*Errno::from(add_rules_other_err), libc::EINVAL);
let restrict_self_err = RulesetError::RestrictSelf(RestrictSelfError::RestrictSelfCall {
source: Error::from_raw_os_error(expected_errno),
});
assert_eq!(*Errno::from(restrict_self_err), expected_errno);
let set_no_new_privs_err = RulesetError::RestrictSelf(RestrictSelfError::SetNoNewPrivsCall {
source: Error::from_raw_os_error(expected_errno),
});
assert_eq!(*Errno::from(set_no_new_privs_err), expected_errno);
let create_ruleset_missing_err =
RulesetError::CreateRuleset(CreateRulesetError::MissingHandledAccess);
assert_eq!(*Errno::from(create_ruleset_missing_err), libc::EINVAL);
}
#[test]
fn test_ruleset_errno() {
_test_ruleset_errno(libc::EACCES);
_test_ruleset_errno(libc::EIO);
}
#[test]
fn test_display_create_ruleset_error_0() {
let err = CreateRulesetError::MissingHandledAccess;
assert_eq!(format!("{err}"), "missing handled access");
}
#[test]
fn test_display_create_ruleset_error_1() {
let err = CreateRulesetError::CreateRulesetCall {
source: std::io::Error::from_raw_os_error(libc::ENOMEM),
};
let msg = format!("{err}");
assert!(msg.starts_with("failed to create a ruleset:"));
}
#[test]
fn test_source_create_ruleset_error_0() {
let err = CreateRulesetError::MissingHandledAccess;
assert!(err.source().is_none());
}
#[test]
fn test_source_create_ruleset_error_1() {
let err = CreateRulesetError::CreateRulesetCall {
source: std::io::Error::from_raw_os_error(libc::ENOMEM),
};
assert!(err.source().is_some());
}
#[test]
fn test_display_path_beneath_error_0() {
let err = PathBeneathError::StatCall {
source: std::io::Error::from_raw_os_error(libc::EBADF),
};
let msg = format!("{err}");
assert!(msg.starts_with("failed to check file descriptor type:"));
}
#[test]
fn test_display_path_beneath_error_1() {
let err = PathBeneathError::DirectoryAccess {
access: AccessFs::ReadDir,
incompatible: AccessFs::ReadDir,
};
let msg = format!("{err}");
assert!(msg.contains("incompatible directory-only access-rights:"));
}
#[test]
fn test_source_path_beneath_error_0() {
let err = PathBeneathError::StatCall {
source: std::io::Error::from_raw_os_error(libc::EBADF),
};
assert!(err.source().is_some());
}
#[test]
fn test_source_path_beneath_error_1() {
let err = PathBeneathError::DirectoryAccess {
access: AccessFs::ReadDir,
incompatible: AccessFs::ReadDir,
};
assert!(err.source().is_none());
}
#[test]
fn test_display_access_error_0() {
let err: AccessError<AccessFs> = AccessError::Empty;
assert_eq!(format!("{err}"), "empty access-right");
}
#[test]
fn test_display_access_error_1() {
let err: AccessError<AccessFs> = AccessError::Incompatible {
access: AccessFs::Execute,
};
let msg = format!("{err}");
assert!(msg.starts_with("fully incompatible access-rights:"));
}
#[test]
fn test_display_access_error_2() {
let err: AccessError<AccessFs> = AccessError::PartiallyCompatible {
access: AccessFs::Execute | AccessFs::Refer,
incompatible: AccessFs::Refer,
};
let msg = format!("{err}");
assert!(msg.starts_with("partially incompatible access-rights:"));
}
#[test]
fn test_display_restrict_self_error_0() {
let err = RestrictSelfError::SetNoNewPrivsCall {
source: std::io::Error::from_raw_os_error(libc::EPERM),
};
let msg = format!("{err}");
assert!(msg.starts_with("failed to set no_new_privs:"));
}
#[test]
fn test_display_restrict_self_error_1() {
let err = RestrictSelfError::RestrictSelfCall {
source: std::io::Error::from_raw_os_error(libc::EPERM),
};
let msg = format!("{err}");
assert!(msg.starts_with("failed to restrict the calling thread:"));
}
#[test]
fn test_source_restrict_self_error_0() {
let err = RestrictSelfError::SetNoNewPrivsCall {
source: std::io::Error::from_raw_os_error(libc::EPERM),
};
assert!(err.source().is_some());
}
#[test]
fn test_source_restrict_self_error_1() {
let err = RestrictSelfError::RestrictSelfCall {
source: std::io::Error::from_raw_os_error(libc::EPERM),
};
assert!(err.source().is_some());
}
#[test]
fn test_display_path_fd_error_0() {
let err = PathFdError::OpenCall {
source: std::io::Error::from_raw_os_error(libc::ENOENT),
path: PathBuf::from("/no/such/path"),
};
let msg = format!("{err}");
assert!(msg.contains("/no/such/path"));
assert!(msg.starts_with("failed to open"));
}
#[test]
fn test_source_path_fd_error_0() {
let err = PathFdError::OpenCall {
source: std::io::Error::from_raw_os_error(libc::ENOENT),
path: PathBuf::from("/no/such/path"),
};
assert!(err.source().is_some());
}
#[test]
fn test_display_add_rule_error_0() {
let err: AddRuleError<AccessFs> = AddRuleError::AddRuleCall {
source: std::io::Error::from_raw_os_error(libc::EBADF),
};
let msg = format!("{err}");
assert!(msg.starts_with("failed to add a rule:"));
}
#[test]
fn test_display_add_rule_error_1() {
let err: AddRuleError<AccessFs> = AddRuleError::UnhandledAccess {
access: AccessFs::Execute,
incompatible: AccessFs::Execute,
};
let msg = format!("{err}");
assert!(msg.contains("access-rights not handled by the ruleset:"));
}
#[test]
fn test_source_add_rule_error_0() {
let err: AddRuleError<AccessFs> = AddRuleError::UnhandledAccess {
access: AccessFs::Execute,
incompatible: AccessFs::Execute,
};
assert!(err.source().is_none());
}
#[test]
fn test_from_compat_error_to_handle_access_error_0() {
let compat_err: CompatError<AccessFs> = CompatError::Access(AccessError::Empty);
let handle_err: HandleAccessError<AccessFs> = compat_err.into();
assert!(matches!(handle_err, HandleAccessError::Compat(_)));
}
#[test]
fn test_from_compat_error_to_add_rule_error_0() {
let compat_err: CompatError<AccessFs> = CompatError::Access(AccessError::Empty);
let add_err: AddRuleError<AccessFs> = compat_err.into();
assert!(matches!(add_err, AddRuleError::Compat(_)));
}
#[test]
fn test_from_path_beneath_error_to_compat_error_0() {
let pbe = PathBeneathError::DirectoryAccess {
access: AccessFs::ReadDir,
incompatible: AccessFs::ReadDir,
};
let ce: CompatError<AccessFs> = pbe.into();
assert!(matches!(ce, CompatError::PathBeneath(_)));
}
#[test]
fn test_from_access_error_to_compat_error_0() {
let ae: AccessError<AccessFs> = AccessError::Empty;
let ce: CompatError<AccessFs> = ae.into();
assert!(matches!(ce, CompatError::Access(AccessError::Empty)));
}
#[test]
fn test_display_compat_error_0() {
let err: CompatError<AccessFs> = CompatError::Access(AccessError::Empty);
assert_eq!(format!("{err}"), "empty access-right");
}
#[test]
fn test_display_compat_error_1() {
let err: CompatError<AccessFs> = CompatError::PathBeneath(PathBeneathError::DirectoryAccess {
access: AccessFs::ReadDir,
incompatible: AccessFs::ReadDir,
});
let msg = format!("{err}");
assert!(msg.contains("incompatible directory-only access-rights:"));
}
#[test]
fn test_display_handle_accesses_error_0() {
let err = HandleAccessesError::Fs(HandleAccessError::Compat(CompatError::Access(
AccessError::Empty,
)));
assert_eq!(format!("{err}"), "empty access-right");
}
#[test]
fn test_display_add_rules_error_0() {
let err = AddRulesError::Fs(AddRuleError::UnhandledAccess {
access: AccessFs::Execute,
incompatible: AccessFs::Execute,
});
let msg = format!("{err}");
assert!(msg.contains("access-rights not handled by the ruleset:"));
}
#[test]
fn test_display_ruleset_error_0() {
let err = RulesetError::CreateRuleset(CreateRulesetError::MissingHandledAccess);
assert_eq!(format!("{err}"), "missing handled access");
}
#[test]
fn test_from_handle_accesses_error_to_ruleset_error_0() {
let inner = HandleAccessesError::Fs(HandleAccessError::Compat(CompatError::Access(
AccessError::Empty,
)));
let err: RulesetError = inner.into();
assert!(matches!(err, RulesetError::HandleAccesses(_)));
}
#[test]
fn test_from_create_ruleset_error_to_ruleset_error_0() {
let inner = CreateRulesetError::MissingHandledAccess;
let err: RulesetError = inner.into();
assert!(matches!(err, RulesetError::CreateRuleset(_)));
}
#[test]
fn test_from_add_rules_error_to_ruleset_error_0() {
let inner = AddRulesError::Fs(AddRuleError::UnhandledAccess {
access: AccessFs::Execute,
incompatible: AccessFs::Execute,
});
let err: RulesetError = inner.into();
assert!(matches!(err, RulesetError::AddRules(_)));
}
#[test]
fn test_from_restrict_self_error_to_ruleset_error_0() {
let inner = RestrictSelfError::SetNoNewPrivsCall {
source: std::io::Error::from_raw_os_error(libc::EPERM),
};
let err: RulesetError = inner.into();
assert!(matches!(err, RulesetError::RestrictSelf(_)));
}
#[test]
fn test_errno_new_0() {
let e = Errno::new(42);
assert_eq!(*e, 42);
}
#[test]
fn test_errno_deref_0() {
let e = Errno::new(libc::ENOENT);
assert_eq!(*e, libc::ENOENT);
}
#[test]
fn test_errno_eq_0() {
assert_eq!(Errno::new(1), Errno::new(1));
assert_ne!(Errno::new(1), Errno::new(2));
}
#[test]
fn test_source_handle_accesses_error_0() {
let err = HandleAccessesError::Fs(HandleAccessError::Compat(CompatError::Access(
AccessError::Empty,
)));
assert!(err.source().is_none());
}
#[test]
fn test_source_add_rules_error_0() {
let err = AddRulesError::Fs(AddRuleError::UnhandledAccess {
access: AccessFs::Execute,
incompatible: AccessFs::Execute,
});
assert!(err.source().is_none());
}
#[test]
fn test_source_ruleset_error_0() {
let err = RulesetError::CreateRuleset(CreateRulesetError::MissingHandledAccess);
assert!(err.source().is_none());
}