use std::{
borrow::Cow,
fmt::{self, Display, Formatter, Write},
};
use bon::bon;
use log::debug;
use nix::unistd::{Gid, Group, User};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use crate::util::{Either, HARDENED_ENUM_VALUE_0, HARDENED_ENUM_VALUE_1, either_to_gid};
#[derive(Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(untagged, rename_all = "lowercase")]
pub enum SGenericActorType {
Id(u32),
Name(String),
}
impl SGenericActorType {
#[must_use]
pub fn as_str(&self) -> Cow<'_, str> {
match self {
Self::Id(id) => Cow::Owned(id.to_string()),
Self::Name(name) => Cow::Borrowed(name),
}
}
}
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct SUserType(SGenericActorType);
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(untagged, rename_all = "lowercase")]
pub enum DGenericActorType<'a> {
Id(u32),
#[serde(borrow)]
Name(Cow<'a, str>),
}
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct DUserType<'a>(#[serde(borrow)] DGenericActorType<'a>);
impl SUserType {
#[must_use]
pub fn fetch_id(&self) -> Option<u32> {
match &self.0 {
SGenericActorType::Id(id) => Some(*id),
SGenericActorType::Name(name) => match User::from_name(name) {
Ok(Some(user)) => Some(user.uid.as_raw()),
_ => None,
},
}
}
#[must_use]
pub fn fetch_user(&self) -> Option<User> {
match &self.0 {
SGenericActorType::Id(id) => User::from_uid((*id).into()).ok().flatten(),
SGenericActorType::Name(name) => User::from_name(name).ok().flatten(),
}
}
#[must_use]
pub fn fetch_eq(&self, other: &Self) -> bool {
let uid = self.fetch_id();
let ouid = other.fetch_id();
match (uid, ouid) {
(Some(uid), Some(ouid)) => uid == ouid,
_ => false,
}
}
#[allow(dead_code)]
#[must_use]
pub fn as_str(&self) -> Cow<'_, str> {
self.0.as_str()
}
}
impl DUserType<'_> {
#[must_use]
pub fn fetch_id(&self) -> Option<u32> {
match &self.0 {
DGenericActorType::Id(id) => Some(*id),
DGenericActorType::Name(name) => match User::from_name(name) {
Ok(Some(user)) => Some(user.uid.as_raw()),
_ => None,
},
}
}
#[must_use]
pub fn fetch_user(&self) -> Option<User> {
match &self.0 {
DGenericActorType::Id(id) => User::from_uid((*id).into()).ok().flatten(),
DGenericActorType::Name(name) => User::from_name(name).ok().flatten(),
}
}
}
impl fmt::Display for SUserType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match &self.0 {
SGenericActorType::Id(id) => write!(f, "{id}"),
SGenericActorType::Name(name) => write!(f, "{name}"),
}
}
}
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct SGroupType(SGenericActorType);
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct DGroupType<'a>(#[serde(borrow)] DGenericActorType<'a>);
impl fmt::Display for SGroupType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match &self.0 {
SGenericActorType::Id(id) => write!(f, "{id}"),
SGenericActorType::Name(name) => write!(f, "{name}"),
}
}
}
impl SGroupType {
#[must_use]
pub fn fetch_eq(&self, other: &Self) -> bool {
let uid = self.fetch_id();
let ouid = other.fetch_id();
match (uid, ouid) {
(Some(uid), Some(ouid)) => uid == ouid,
_ => false,
}
}
pub(super) fn fetch_id(&self) -> Option<u32> {
match &self.0 {
SGenericActorType::Id(id) => Some(*id),
SGenericActorType::Name(name) => match Group::from_name(name) {
Ok(Some(group)) => Some(group.gid.as_raw()),
_ => None,
},
}
}
#[must_use]
pub fn fetch_group(&self) -> Option<Group> {
match &self.0 {
SGenericActorType::Id(id) => Group::from_gid((*id).into()).ok().flatten(),
SGenericActorType::Name(name) => Group::from_name(name).ok().flatten(),
}
}
#[must_use]
pub fn as_str(&self) -> Cow<'_, str> {
self.0.as_str()
}
}
impl DGroupType<'_> {
#[must_use]
pub fn fetch_id(&self) -> Option<u32> {
match &self.0 {
DGenericActorType::Id(id) => Some(*id),
DGenericActorType::Name(name) => match Group::from_name(name) {
Ok(Some(group)) => Some(group.gid.as_raw()),
_ => None,
},
}
}
#[must_use]
pub fn fetch_group(&self) -> Option<Group> {
match &self.0 {
DGenericActorType::Id(id) => Group::from_gid((*id).into()).ok().flatten(),
DGenericActorType::Name(name) => Group::from_name(name).ok().flatten(),
}
}
}
impl Display for DGroupType<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match &self.0 {
DGenericActorType::Id(id) => write!(f, "{id}"),
DGenericActorType::Name(name) => write!(f, "{name}"),
}
}
}
impl Display for DUserType<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match &self.0 {
DGenericActorType::Id(id) => write!(f, "{id}"),
DGenericActorType::Name(name) => write!(f, "{name}"),
}
}
}
#[derive(Serialize, PartialEq, Eq, Debug, Clone)]
#[serde(untagged)]
#[repr(u32)]
pub enum SGroups {
Single(SGroupType) = HARDENED_ENUM_VALUE_0,
Multiple(Vec<SGroupType>) = HARDENED_ENUM_VALUE_1,
}
impl SGroups {
#[must_use]
pub const fn is_single(&self) -> bool {
matches!(self, Self::Single(_))
}
}
impl Display for SGroups {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Single(group) => write!(f, "[{group}]"),
Self::Multiple(groups) => {
let mut result = String::new();
for group in groups {
let _ = write!(result, "{group}, ");
}
result.pop(); result.pop(); write!(f, "[{result}]")
}
}
}
}
#[derive(Serialize, PartialEq, Eq, Debug, Clone)]
#[serde(untagged)]
pub enum DGroups<'a> {
Single(#[serde(borrow)] DGroupType<'a>),
Multiple(#[serde(borrow)] Cow<'a, [DGroupType<'a>]>),
}
impl SGroups {
#[must_use]
pub const fn len(&self) -> usize {
match self {
Self::Single(_) => 1,
Self::Multiple(groups) => groups.len(),
}
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn fetch_eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Single(group), Self::Single(ogroup)) => group.fetch_eq(ogroup),
(Self::Multiple(groups), Self::Multiple(ogroups)) => groups
.iter()
.all(|group| ogroups.iter().any(|ogroup| group.fetch_eq(ogroup))),
_ => false,
}
}
}
impl DGroups<'_> {
#[must_use]
pub fn len(&self) -> usize {
match self {
DGroups::Single(_) => 1,
DGroups::Multiple(groups) => groups.len(),
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'de: 'a, 'a> Deserialize<'de> for DGroups<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct DGroupsVisitor<'a> {
marker: std::marker::PhantomData<&'a ()>,
}
impl<'de: 'a, 'a> serde::de::Visitor<'de> for DGroupsVisitor<'a> {
type Value = DGroups<'a>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string or a number")
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.parse().map_or_else(
|_| {
Ok(DGroups::Single(DGroupType(DGenericActorType::Name(
Cow::Borrowed(v),
))))
},
|group| Ok(DGroups::Single(DGroupType(DGenericActorType::Id(group)))),
)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.parse().map_or_else(
|_| {
Ok(DGroups::Single(DGroupType(DGenericActorType::Name(
Cow::Owned(v.to_string()),
))))
},
|group| Ok(DGroups::Single(DGroupType(DGenericActorType::Id(group)))),
)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.parse().map_or_else(
|_| {
Ok(DGroups::Single(DGroupType(DGenericActorType::Name(
v.into(),
))))
},
|group| Ok(DGroups::Single(DGroupType(DGenericActorType::Id(group)))),
)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(DGroups::Single(DGroupType(DGenericActorType::Id(
u32::try_from(value).map_err(|_| E::custom("value is too large"))?,
))))
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut groups = Vec::new();
while let Some(group) = seq.next_element::<DGroupType<'a>>()? {
groups.push(group);
}
if groups.len() == 1 {
Ok(DGroups::Single(groups.remove(0)))
} else {
Ok(DGroups::Multiple(Cow::Owned(groups)))
}
}
}
deserializer.deserialize_any(DGroupsVisitor {
marker: std::marker::PhantomData,
})
}
}
impl<'de> Deserialize<'de> for SGroups {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct SGroupsVisitor;
impl<'de> serde::de::Visitor<'de> for SGroupsVisitor {
type Value = SGroups;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string or a number")
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(self)
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
debug!("SGroups: visit_borrowed_str: {v}");
v.parse().map_or_else(
|_| {
Ok(SGroups::Single(SGroupType(SGenericActorType::Name(
v.to_string(),
))))
},
|group| Ok(SGroups::Single(SGroupType(SGenericActorType::Id(group)))),
)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
debug!("SGroups: visit_str: {v}");
v.parse().map_or_else(
|_| {
Ok(SGroups::Single(SGroupType(SGenericActorType::Name(
v.into(),
))))
},
|group| Ok(SGroups::Single(SGroupType(SGenericActorType::Id(group)))),
)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
debug!("SGroups: visit_string: {v}");
v.parse().map_or_else(
|_| Ok(SGroups::Single(SGroupType(SGenericActorType::Name(v)))),
|group| Ok(SGroups::Single(SGroupType(SGenericActorType::Id(group)))),
)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
debug!("SGroups: visit_u64: {value}");
Ok(SGroups::Single(SGroupType(SGenericActorType::Id(
u32::try_from(value).map_err(|_| E::custom("value is too large"))?,
))))
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
debug!("SGroups: visit_seq");
let mut groups = Vec::new();
while let Some(group) = seq.next_element::<SGroupType>()? {
groups.push(group);
}
if groups.len() == 1 {
Ok(SGroups::Single(groups.remove(0)))
} else {
Ok(SGroups::Multiple(groups))
}
}
}
deserializer.deserialize_any(SGroupsVisitor)
}
}
impl From<u32> for SUserType {
fn from(id: u32) -> Self {
Self(id.into())
}
}
impl From<u32> for SGroupType {
fn from(id: u32) -> Self {
Self(id.into())
}
}
impl From<&str> for SUserType {
fn from(name: &str) -> Self {
Self(name.into())
}
}
impl<'a> From<&'a str> for DUserType<'a> {
fn from(name: &'a str) -> Self {
DUserType(name.into())
}
}
impl From<String> for DUserType<'_> {
fn from(name: String) -> Self {
DUserType(DGenericActorType::Name(name.into()))
}
}
impl<'a> From<&'a str> for DGroupType<'a> {
fn from(name: &'a str) -> Self {
DGroupType(name.into())
}
}
impl From<u32> for DUserType<'_> {
fn from(id: u32) -> Self {
DUserType(id.into())
}
}
impl From<u32> for DGroupType<'_> {
fn from(id: u32) -> Self {
DGroupType(id.into())
}
}
impl From<&str> for SGroupType {
fn from(name: &str) -> Self {
Self(name.into())
}
}
impl<'a> From<Cow<'a, str>> for DGroupType<'a> {
fn from(name: Cow<'a, str>) -> Self {
DGroupType(DGenericActorType::Name(name))
}
}
impl From<Group> for SGroupType {
fn from(group: Group) -> Self {
Self(SGenericActorType::Id(group.gid.as_raw()))
}
}
impl From<&str> for SGenericActorType {
fn from(name: &str) -> Self {
Self::Name(name.into())
}
}
impl<'a> From<&'a str> for DGenericActorType<'a> {
fn from(name: &'a str) -> Self {
name.parse::<u32>().map_or(
DGenericActorType::Name(Cow::Borrowed(name)),
DGenericActorType::Id,
)
}
}
impl From<u32> for DGenericActorType<'_> {
fn from(name: u32) -> Self {
DGenericActorType::Id(name)
}
}
impl From<u32> for SGenericActorType {
fn from(id: u32) -> Self {
Self::Id(id)
}
}
impl PartialEq<User> for SUserType {
fn eq(&self, other: &User) -> bool {
let uid = self.fetch_id();
uid.is_some_and(|uid| uid == other.uid.as_raw())
}
}
impl PartialEq<User> for DUserType<'_> {
fn eq(&self, other: &User) -> bool {
let uid = self.fetch_id();
uid.is_some_and(|uid| uid == other.uid.as_raw())
}
}
impl PartialEq<str> for SUserType {
fn eq(&self, other: &str) -> bool {
self.eq(&Self::from(other))
}
}
impl PartialEq<str> for SGroupType {
fn eq(&self, other: &str) -> bool {
self.eq(&Self::from(other))
}
}
impl PartialEq<u32> for SUserType {
fn eq(&self, other: &u32) -> bool {
self.eq(&Self::from(*other))
}
}
impl PartialEq<u32> for DUserType<'_> {
fn eq(&self, other: &u32) -> bool {
self.eq(&DUserType::from(*other))
}
}
impl PartialEq<u32> for SGroupType {
fn eq(&self, other: &u32) -> bool {
self.eq(&Self::from(*other))
}
}
impl PartialEq<Either<Group, Gid>> for SGroupType {
fn eq(&self, other: &Either<Group, Gid>) -> bool {
let gid = self.fetch_id();
gid.is_some_and(|gid| gid == either_to_gid(other).as_raw())
}
}
impl PartialEq<Either<Group, Gid>> for DGroupType<'_> {
fn eq(&self, other: &Either<Group, Gid>) -> bool {
let gid = self.fetch_id();
gid.is_some_and(|gid| gid == either_to_gid(other).as_raw())
}
}
impl<const N: usize> From<[SGroupType; N]> for SGroups {
fn from(groups: [SGroupType; N]) -> Self {
if N == 1 {
Self::Single(groups[0].clone())
} else {
Self::Multiple(groups.iter().map(std::borrow::ToOwned::to_owned).collect())
}
}
}
impl TryInto<Vec<u32>> for &DGroups<'_> {
type Error = String;
fn try_into(self) -> Result<Vec<u32>, Self::Error> {
match self {
DGroups::Single(group) => Ok(vec![
group
.fetch_id()
.ok_or_else(|| format!("{group} group does not exist"))?,
]),
DGroups::Multiple(groups) => {
let mut ids = Vec::new();
for group in groups.iter() {
ids.push(
group
.fetch_id()
.ok_or_else(|| format!("{group} group does not exist"))?,
);
}
Ok(ids)
}
}
}
}
impl TryInto<Vec<u32>> for SGroups {
type Error = String;
fn try_into(self) -> Result<Vec<u32>, Self::Error> {
match self {
Self::Single(group) => Ok(vec![
group
.fetch_id()
.ok_or_else(|| format!("{group} group does not exist"))?,
]),
Self::Multiple(groups) => {
let mut ids = Vec::new();
for group in groups {
ids.push(
group
.fetch_id()
.ok_or_else(|| format!("{group} group does not exist"))?,
);
}
Ok(ids)
}
}
}
}
impl<const N: usize> From<[&str; N]> for SGroups {
fn from(groups: [&str; N]) -> Self {
if N == 1 {
Self::Single(groups[0].into())
} else {
Self::Multiple(groups.iter().map(|&x| x.into()).collect())
}
}
}
impl From<Vec<u32>> for SGroups {
fn from(groups: Vec<u32>) -> Self {
if groups.len() == 1 {
Self::Single(groups[0].into())
} else {
Self::Multiple(groups.into_iter().map(std::convert::Into::into).collect())
}
}
}
impl From<Vec<SGroupType>> for SGroups {
fn from(groups: Vec<SGroupType>) -> Self {
if groups.len() == 1 {
Self::Single(groups[0].clone())
} else {
Self::Multiple(groups)
}
}
}
impl<'a> From<Vec<DGroupType<'a>>> for DGroups<'a> {
fn from(groups: Vec<DGroupType<'a>>) -> Self {
if groups.len() == 1 {
DGroups::Single(groups[0].clone())
} else {
DGroups::Multiple(Cow::Owned(groups))
}
}
}
impl<'a> From<DGroupType<'a>> for DGroups<'a> {
fn from(groups: DGroupType<'a>) -> Self {
DGroups::Single(groups)
}
}
impl From<u32> for SGroups {
fn from(group: u32) -> Self {
Self::Single(group.into())
}
}
impl From<&str> for SGroups {
fn from(group: &str) -> Self {
Self::Single(group.into())
}
}
impl PartialEq<Vec<SGroupType>> for SGroups {
fn eq(&self, other: &Vec<SGroupType>) -> bool {
match self {
Self::Single(actor) => {
if other.len() == 1 {
return actor == &other[0];
}
}
Self::Multiple(actors) => {
if actors.len() == other.len() {
return actors.iter().all(|actor| other.iter().any(|x| actor == x));
}
}
}
false
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum SActor {
#[serde(rename = "user")]
User {
#[serde(alias = "name", skip_serializing_if = "Option::is_none")]
id: Option<SUserType>,
#[serde(default, flatten, skip_serializing_if = "Map::is_empty")]
extra_fields: Map<String, Value>,
},
#[serde(rename = "group")]
Group {
#[serde(
alias = "names",
alias = "name",
skip_serializing_if = "Option::is_none"
)]
groups: Option<SGroups>,
#[serde(default, flatten)]
extra_fields: Map<String, Value>,
},
#[serde(untagged)]
Unknown(Value),
}
impl SActor {
#[must_use]
pub const fn is_user(&self) -> bool {
matches!(self, Self::User { .. })
}
#[must_use]
pub const fn is_group(&self) -> bool {
matches!(self, Self::Group { .. })
}
#[must_use]
pub const fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown(_))
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum DActor<'a> {
#[serde(rename = "user")]
User {
#[serde(borrow, alias = "name")]
id: DUserType<'a>,
},
#[serde(rename = "group")]
Group {
#[serde(borrow, alias = "names", alias = "name", alias = "id")]
groups: DGroups<'a>,
},
#[serde(untagged)]
Unknown(Value),
}
#[bon]
impl SActor {
#[builder(finish_fn = build)]
pub const fn user(
#[builder(start_fn, into)] id: SUserType,
#[builder(default, with = <_>::from_iter)] extra_fields: Map<String, Value>,
) -> Self {
Self::User {
id: Some(id),
extra_fields,
}
}
#[builder(finish_fn = build)]
pub const fn group(
#[builder(start_fn, into)] groups: SGroups,
#[builder(default, with = <_>::from_iter)] extra_fields: Map<String, Value>,
) -> Self {
Self::Group {
groups: Some(groups),
extra_fields,
}
}
}
impl core::fmt::Display for SActor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::User { id, .. } => match id.as_ref() {
Some(id) => write!(f, "User: {id}"),
None => write!(f, "User: <unknown>"),
},
Self::Group { groups, .. } => match groups.as_ref() {
Some(groups) => write!(f, "Group: {groups}"),
None => write!(f, "Group: <unknown>"),
},
Self::Unknown(unknown) => {
write!(f, "Unknown: {unknown}")
}
}
}
}
#[cfg(test)]
mod tests {
use nix::unistd::getuid;
use super::*;
#[test]
fn test_suser_type_creation() {
let user_by_id = SUserType::from(0);
let user_by_name = SUserType::from("testuser");
assert_eq!(user_by_id.to_string(), "0");
assert_eq!(user_by_name.to_string(), "testuser");
}
#[test]
fn test_fetch_id() {
let user = SUserType::from(0);
assert_eq!(user.fetch_id(), Some(0));
let group = SGroupType::from(0);
assert_eq!(group.fetch_id(), Some(0));
let user = SUserType::from("root");
assert_eq!(user.fetch_id(), Some(0));
let group = SGroupType::from("root");
assert_eq!(group.fetch_id(), Some(0));
let group = SGroupType::from("unkown");
assert_eq!(group.fetch_id(), None);
}
#[test]
fn test_fetch_user() {
let user = DUserType::from("root");
assert_eq!(
user.fetch_user(),
Some(User::from_uid(0.into()).unwrap().unwrap())
);
let user = DUserType::from(0);
assert_eq!(
user.fetch_user(),
Some(User::from_uid(0.into()).unwrap().unwrap())
);
}
#[test]
fn test_sgroups_multiple() {
let groups = SGroups::from(0);
assert_eq!(groups.len(), 1);
let groups = SGroups::from(vec![SGroupType::from(0), SGroupType::from(200)]);
assert_eq!(groups.len(), 2);
assert!(!groups.is_empty());
if let SGroups::Multiple(group_list) = groups {
assert_eq!(group_list[0].to_string(), "0");
assert_eq!(group_list[1].to_string(), "200");
} else {
panic!("Expected SGroups::Multiple");
}
}
#[test]
fn test_fech_group() {
let group = SGroupType::from(0);
assert_eq!(
group.fetch_group(),
Some(Group::from_gid(0.into()).unwrap().unwrap())
);
let group = SGroupType::from("root");
assert_eq!(
group.fetch_group(),
Some(Group::from_name("root").unwrap().unwrap())
);
}
#[test]
fn test_is_empty() {
let groups = SGroups::Multiple(vec![]);
assert!(groups.is_empty());
}
#[test]
fn test_fetch_eq_sgroupstype_false() {
let group1 = SGroupType::from("unkown");
let group2 = SGroupType::from("unkown2");
assert!(!group1.fetch_eq(&group2));
}
#[test]
fn test_duser_type_creation() {
let user_by_id = DUserType::from(0);
let user_by_name = DUserType::from("testuser");
assert_eq!(user_by_id.to_string(), "0");
assert_eq!(user_by_name.to_string(), "testuser");
}
#[test]
fn test_fetch_did() {
let user = DUserType::from(0);
assert_eq!(user.fetch_id(), Some(0));
let group = DGroupType::from(0);
assert_eq!(group.fetch_id(), Some(0));
let user = DUserType::from("root");
assert_eq!(user.fetch_id(), Some(0));
let group = DGroupType::from("root");
assert_eq!(group.fetch_id(), Some(0));
let group = DGroupType::from("unkown");
assert_eq!(group.fetch_id(), None);
}
#[test]
fn test_dgroups_single() {
let groups = DGroups::from(DGroupType::from(0));
assert_eq!(groups.len(), 1);
assert!(!groups.is_empty());
if let DGroups::Single(group_list) = groups {
assert_eq!(group_list.to_string(), "0");
} else {
panic!("Expected SGroups::Single");
}
}
#[test]
fn test_is_dempty() {
let groups = DGroups::Multiple(Cow::Borrowed(&[]));
assert!(groups.is_empty());
}
#[test]
fn test_sactor_display() {
let user = SActor::User {
id: Some(SUserType::from(0)),
extra_fields: Map::new(),
};
let group = SActor::Group {
groups: Some(SGroups::from(vec![SGroupType::from(0)])),
extra_fields: Map::new(),
};
assert_eq!(user.to_string(), "User: 0");
assert_eq!(group.to_string(), "Group: [0]");
let group = SActor::Group {
groups: Some(SGroups::from(vec![
SGroupType::from(0),
SGroupType::from("test"),
])),
extra_fields: Map::new(),
};
assert_eq!(group.to_string(), "Group: [0, test]");
let unknown = SActor::Unknown(Value::String("unknown".to_string()));
assert_eq!(unknown.to_string(), "Unknown: \"unknown\"");
}
#[test]
fn test_display_dgrouptype() {
let group = DGroupType::from("test");
assert_eq!(group.to_string(), "test");
}
#[test]
fn test_partialeq_sgroups() {
let groups = SGroups::from(vec![SGroupType::from(0), SGroupType::from("test")]);
let other_groups = vec![SGroupType::from(0), SGroupType::from("test")];
assert_eq!(groups, other_groups);
let other_groups = vec![SGroupType::from(0), SGroupType::from("test2")];
assert_ne!(groups, other_groups);
let other_groups = vec![SGroupType::from(0)];
assert_ne!(groups, other_groups);
let other_groups = vec![
SGroupType::from(0),
SGroupType::from("test"),
SGroupType::from("test2"),
];
assert_ne!(groups, other_groups);
let groups = SGroups::from(0);
let other_groups = vec![SGroupType::from(0)];
assert_eq!(groups, other_groups);
let other_groups = vec![SGroupType::from(0), SGroupType::from("test")];
assert_ne!(groups, other_groups);
}
#[test]
fn test_sfetcheq_group() {
let group1 = SGroupType::from(0);
let group2 = SGroupType::from(0);
assert!(group1.fetch_eq(&group2));
let group2 = SGroupType::from("root");
assert!(group1.fetch_eq(&group2));
let group2 = SGroupType::from("unkown");
assert!(!group1.fetch_eq(&group2));
let groups = SGroups::from(vec![
SGroupType::from(0),
SGroupType::from(getuid().as_raw() + 1),
]);
let other_groups = SGroups::from(vec![
SGroupType::from(0),
SGroupType::from(getuid().as_raw() + 1),
]);
assert!(groups.fetch_eq(&other_groups));
let other_groups = SGroups::from(vec![SGroupType::from(0), SGroupType::from("test2")]);
assert!(!groups.fetch_eq(&other_groups));
let other_groups = SGroups::from(0);
assert!(!groups.fetch_eq(&other_groups));
let groups = SGroups::from(0);
assert!(groups.fetch_eq(&other_groups));
}
#[test]
fn test_sfetcheq_user() {
let user1 = SUserType::from(0);
let user2 = SUserType::from(0);
assert!(user1.fetch_eq(&user2));
let user2 = SUserType::from("root");
assert!(user1.fetch_eq(&user2));
let user2 = SUserType::from("unkown");
assert!(!user1.fetch_eq(&user2));
}
#[test]
fn test_from() {
let cow = Cow::Borrowed("test");
let group = DGroupType::from(cow);
assert_eq!(group.to_string(), "test");
let group = Group::from_gid(0.into()).unwrap().unwrap();
let group = SGroupType::from(group);
assert_eq!(group.fetch_id(), Some(0));
let group = SGroups::from([SGroupType::from(0)]);
assert!(group.is_single());
let group = SGroups::from(["test"]);
assert!(group.is_single());
let group = SGroups::from("test");
assert!(group.is_single());
let group = SGroups::from(["test", "test2"]);
assert!(!group.is_single());
let group = SGroups::from(vec![0, 1]);
assert!(!group.is_single());
let group = SGroups::from(vec![0]);
assert!(group.is_single());
}
#[test]
#[allow(clippy::cmp_owned)]
fn test_partialeq_user() {
assert!(SUserType::from(0) == 0);
assert!(SUserType::from(0) != 1);
assert!(DUserType::from(0) == 0);
assert!(DUserType::from(0) != 1);
let user = User::from_uid(0.into()).unwrap().unwrap();
assert!(SUserType::from(0) == user);
assert!(SUserType::from(0) != 1);
assert!(DUserType::from(0) == user);
assert!(DUserType::from(0) != 1);
assert!(SUserType::from("root") == user);
assert!(SUserType::from("test") != user);
assert!(DUserType::from("root") == user);
assert!(DUserType::from("test") != user);
}
#[test]
fn test_partialeq_group() {
let group = Either::Left(Group::from_gid(0.into()).unwrap().unwrap());
assert!(SGroupType::from(0) == group);
assert!(SGroupType::from(1) != group);
assert!(SGroupType::from("root") == group);
assert!(SGroupType::from("test") != group);
assert!(DGroupType::from(0) == group);
assert!(DGroupType::from(1) != group);
assert!(DGroupType::from("root") == group);
assert!(DGroupType::from("test") != group);
}
#[test]
fn test_tryinto_sgroups() {
let groups = SGroups::from(vec![SGroupType::from(0), SGroupType::from(1)]);
let ids: Vec<u32> = groups.try_into().unwrap();
assert_eq!(ids, vec![0, 1]);
let groups = SGroups::from(vec![SGroupType::from(0)]);
let ids: Vec<u32> = groups.try_into().unwrap();
assert_eq!(ids, vec![0]);
let groups = SGroups::from(vec![SGroupType::from("unkown")]);
let ids: Result<Vec<u32>, _> = groups.try_into();
assert!(ids.is_err());
}
#[test]
fn test_tryinto_dgroups() {
let groups: DGroups<'_> = DGroups::from(vec![0.into(), 1.into()]);
let ids: Vec<u32> = (&groups).try_into().unwrap();
assert_eq!(ids, vec![0, 1]);
let groups = DGroups::from(vec![DGroupType::from(0)]);
let ids: Vec<u32> = (&groups).try_into().unwrap();
assert_eq!(ids, vec![0]);
let groups = DGroups::from(vec![DGroupType::from("unkown")]);
let ids: Result<Vec<u32>, _> = (&groups).try_into();
assert!(ids.is_err());
}
#[test]
fn test_as_str() {
let group = SGroupType::from("test");
assert_eq!(group.as_str(), "test");
let group = SGroupType::from(100);
assert_eq!(group.as_str(), "100");
let user = SUserType::from("test");
assert_eq!(user.as_str(), "test");
let user = SUserType::from(100);
assert_eq!(user.as_str(), "100");
}
}