use std::collections::HashSet;
use std::ffi::{OsStr, OsString};
use xpct::{be_false, be_none, be_some, be_true, consist_of, equal, expect};
use liteboxfs::metadata::{Acl, AclMode, AclQualifier, Device, Gid, Owner, Uid, Xattrs};
mod device {
use super::*;
#[test]
fn roundtrips_major_and_minor() {
let device = Device::new(8, 1);
expect!(device.major()).to(equal(8));
expect!(device.minor()).to(equal(1));
}
#[test]
fn roundtrips_zero_values() {
let device = Device::new(0, 0);
expect!(device.major()).to(equal(0));
expect!(device.minor()).to(equal(0));
}
#[test]
fn roundtrips_large_values() {
let device = Device::new(255, 255);
expect!(device.major()).to(equal(255));
expect!(device.minor()).to(equal(255));
}
#[test]
fn equality_is_based_on_major_and_minor() {
let device1 = Device::new(8, 1);
let device2 = Device::new(8, 1);
let device3 = Device::new(8, 2);
expect!(device1).to(equal(device2));
expect!(device1 == device3).to(be_false());
}
#[test]
fn can_be_cloned() {
let device = Device::new(8, 1);
let cloned = device;
expect!(cloned).to(equal(device));
}
}
mod uid {
use super::*;
#[test]
fn roundtrips_through_from_raw_and_as_raw() {
let uid = Uid::from_raw(1000);
expect!(uid.as_raw()).to(equal(1000));
}
#[test]
fn roundtrips_root_constant() {
expect!(Uid::ROOT.as_raw()).to(equal(0));
}
#[test]
fn from_u32_creates_uid() {
let uid: Uid = 1000u32.into();
expect!(uid.as_raw()).to(equal(1000));
}
#[test]
fn into_u32_extracts_raw_value() {
let uid = Uid::from_raw(1000);
let raw: u32 = uid.into();
expect!(raw).to(equal(1000));
}
#[test]
fn from_and_into_are_inverses() {
let original: u32 = 42;
let uid: Uid = original.into();
let roundtripped: u32 = uid.into();
expect!(roundtripped).to(equal(original));
}
}
mod gid {
use super::*;
#[test]
fn roundtrips_through_from_raw_and_as_raw() {
let gid = Gid::from_raw(1000);
expect!(gid.as_raw()).to(equal(1000));
}
#[test]
fn roundtrips_root_constant() {
expect!(Gid::ROOT.as_raw()).to(equal(0));
}
#[test]
fn from_u32_creates_gid() {
let gid: Gid = 1000u32.into();
expect!(gid.as_raw()).to(equal(1000));
}
#[test]
fn into_u32_extracts_raw_value() {
let gid = Gid::from_raw(1000);
let raw: u32 = gid.into();
expect!(raw).to(equal(1000));
}
#[test]
fn from_and_into_are_inverses() {
let original: u32 = 42;
let gid: Gid = original.into();
let roundtripped: u32 = gid.into();
expect!(roundtripped).to(equal(original));
}
}
mod owner {
use super::*;
#[test]
fn root_constant_has_root_uid_and_gid() {
expect!(Owner::ROOT.user).to(equal(Uid::ROOT));
expect!(Owner::ROOT.group).to(equal(Gid::ROOT));
}
#[test]
fn fields_are_accessible() {
let owner = Owner {
user: Uid::from_raw(1000),
group: Gid::from_raw(1000),
};
expect!(owner.user.as_raw()).to(equal(1000));
expect!(owner.group.as_raw()).to(equal(1000));
}
}
mod xattrs {
use super::*;
#[test]
fn new_returns_empty() {
let xattrs = Xattrs::new();
expect!(xattrs.iter().len()).to(equal(0));
}
#[test]
fn default_returns_empty() {
let xattrs = Xattrs::default();
expect!(xattrs.iter().len()).to(equal(0));
}
#[test]
fn set_and_get_roundtrips() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.test"), b"value".to_vec());
expect!(xattrs.get("user.test"))
.to(be_some())
.to(equal(b"value".as_slice()));
}
#[test]
fn get_with_osstr_ref() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.test"), b"value".to_vec());
let name: &OsStr = OsStr::new("user.test");
expect!(xattrs.get(name))
.to(be_some())
.to(equal(b"value".as_slice()));
}
#[test]
fn get_returns_none_for_missing_key() {
let xattrs = Xattrs::new();
expect!(xattrs.get("user.missing")).to(be_none());
}
#[test]
fn set_overwrites_existing_value() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.test"), b"old".to_vec());
xattrs.set(OsString::from("user.test"), b"new".to_vec());
expect!(xattrs.get("user.test"))
.to(be_some())
.to(equal(b"new".as_slice()));
}
#[test]
fn remove_deletes_key() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.test"), b"value".to_vec());
xattrs.remove("user.test");
expect!(xattrs.get("user.test")).to(be_none());
}
#[test]
fn remove_with_osstr_ref() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.test"), b"value".to_vec());
let name: &OsStr = OsStr::new("user.test");
xattrs.remove(name);
expect!(xattrs.get("user.test")).to(be_none());
}
#[test]
fn remove_on_missing_key_is_noop() {
let mut xattrs = Xattrs::new();
xattrs.remove("user.missing");
expect!(xattrs.iter().len()).to(equal(0));
}
#[test]
fn clear_removes_all_entries() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.a"), b"a".to_vec());
xattrs.set(OsString::from("user.b"), b"b".to_vec());
xattrs.clear();
expect!(xattrs.iter().len()).to(equal(0));
}
#[test]
fn iter_returns_all_entries() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.a"), b"a".to_vec());
xattrs.set(OsString::from("user.b"), b"b".to_vec());
let entries: HashSet<_> = xattrs
.iter()
.map(|(k, v)| (k.to_os_string(), v.to_vec()))
.collect();
expect!(entries.len()).to(equal(2));
expect!(entries).to(consist_of([
(OsString::from("user.a"), b"a".to_vec()),
(OsString::from("user.b"), b"b".to_vec()),
]));
}
#[test]
fn from_iter_creates_xattrs() {
let entries = vec![
(OsString::from("user.a"), b"a".to_vec()),
(OsString::from("user.b"), b"b".to_vec()),
];
let xattrs: Xattrs = entries.into_iter().collect();
expect!(xattrs.get("user.a"))
.to(be_some())
.to(equal(b"a".as_slice()));
expect!(xattrs.get("user.b"))
.to(be_some())
.to(equal(b"b".as_slice()));
}
#[test]
fn into_iter_consumes_xattrs() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.a"), b"a".to_vec());
xattrs.set(OsString::from("user.b"), b"b".to_vec());
let entries: HashSet<_> = xattrs.into_iter().collect();
expect!(entries.len()).to(equal(2));
expect!(entries).to(consist_of([
(OsString::from("user.a"), b"a".to_vec()),
(OsString::from("user.b"), b"b".to_vec()),
]));
}
#[test]
fn into_iter_for_ref_borrows_xattrs() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.a"), b"a".to_vec());
let mut count = 0;
for (name, value) in &xattrs {
expect!(name).to(equal(OsStr::new("user.a")));
expect!(value).to(equal(b"a".as_slice()));
count += 1;
}
expect!(count).to(equal(1));
expect!(xattrs.get("user.a")).to(be_some());
}
}
mod xattrs_iter {
use super::*;
#[test]
fn len_returns_remaining_count() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.a"), b"a".to_vec());
xattrs.set(OsString::from("user.b"), b"b".to_vec());
let mut iter = xattrs.iter();
expect!(iter.len()).to(equal(2));
iter.next();
expect!(iter.len()).to(equal(1));
iter.next();
expect!(iter.len()).to(equal(0));
}
#[test]
fn is_fused() {
let xattrs = Xattrs::new();
let mut iter = xattrs.iter();
expect!(iter.next()).to(be_none());
expect!(iter.next()).to(be_none());
expect!(iter.next()).to(be_none());
}
}
mod xattrs_into_iter {
use super::*;
#[test]
fn len_returns_remaining_count() {
let mut xattrs = Xattrs::new();
xattrs.set(OsString::from("user.a"), b"a".to_vec());
xattrs.set(OsString::from("user.b"), b"b".to_vec());
let mut iter = xattrs.into_iter();
expect!(iter.len()).to(equal(2));
iter.next();
expect!(iter.len()).to(equal(1));
iter.next();
expect!(iter.len()).to(equal(0));
}
#[test]
fn is_fused() {
let xattrs = Xattrs::new();
let mut iter = xattrs.into_iter();
expect!(iter.next()).to(be_none());
expect!(iter.next()).to(be_none());
expect!(iter.next()).to(be_none());
}
}
mod acl {
use super::*;
#[test]
fn new_returns_empty() {
let acl = Acl::new();
expect!(acl.iter().len()).to(equal(0));
}
#[test]
fn default_returns_empty() {
let acl = Acl::default();
expect!(acl.iter().len()).to(equal(0));
}
#[test]
fn set_and_get_roundtrips() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::RWX);
expect!(acl.get(AclQualifier::OwningUser))
.to(be_some())
.to(equal(AclMode::RWX));
}
#[test]
fn get_returns_none_for_missing_qualifier() {
let acl = Acl::new();
expect!(acl.get(AclQualifier::OwningUser)).to(be_none());
}
#[test]
fn set_overwrites_existing_mode() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::R);
acl.set(AclQualifier::OwningUser, AclMode::RWX);
expect!(acl.get(AclQualifier::OwningUser))
.to(be_some())
.to(equal(AclMode::RWX));
}
#[test]
fn remove_deletes_qualifier() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::RWX);
acl.remove(AclQualifier::OwningUser);
expect!(acl.get(AclQualifier::OwningUser)).to(be_none());
}
#[test]
fn remove_on_missing_qualifier_is_noop() {
let mut acl = Acl::new();
acl.remove(AclQualifier::OwningUser);
expect!(acl.iter().len()).to(equal(0));
}
#[test]
fn clear_removes_all_entries() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::RWX);
acl.set(AclQualifier::OwningGroup, AclMode::R);
acl.clear();
expect!(acl.iter().len()).to(equal(0));
}
#[test]
fn named_user_qualifiers_are_distinct() {
let mut acl = Acl::new();
acl.set(AclQualifier::User(Uid::from_raw(1000)), AclMode::R);
acl.set(AclQualifier::User(Uid::from_raw(2000)), AclMode::W);
expect!(acl.get(AclQualifier::User(Uid::from_raw(1000))))
.to(be_some())
.to(equal(AclMode::R));
expect!(acl.get(AclQualifier::User(Uid::from_raw(2000))))
.to(be_some())
.to(equal(AclMode::W));
}
#[test]
fn named_group_qualifiers_are_distinct() {
let mut acl = Acl::new();
acl.set(AclQualifier::Group(Gid::from_raw(1000)), AclMode::R);
acl.set(AclQualifier::Group(Gid::from_raw(2000)), AclMode::W);
expect!(acl.get(AclQualifier::Group(Gid::from_raw(1000))))
.to(be_some())
.to(equal(AclMode::R));
expect!(acl.get(AclQualifier::Group(Gid::from_raw(2000))))
.to(be_some())
.to(equal(AclMode::W));
}
#[test]
fn all_qualifier_types_are_distinct() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::R);
acl.set(AclQualifier::OwningGroup, AclMode::W);
acl.set(AclQualifier::Other, AclMode::X);
acl.set(AclQualifier::Mask, AclMode::RWX);
acl.set(
AclQualifier::User(Uid::from_raw(1000)),
AclMode::R | AclMode::W,
);
acl.set(
AclQualifier::Group(Gid::from_raw(1000)),
AclMode::R | AclMode::X,
);
expect!(acl.iter().len()).to(equal(6));
expect!(acl.get(AclQualifier::OwningUser))
.to(be_some())
.to(equal(AclMode::R));
expect!(acl.get(AclQualifier::OwningGroup))
.to(be_some())
.to(equal(AclMode::W));
expect!(acl.get(AclQualifier::Other))
.to(be_some())
.to(equal(AclMode::X));
expect!(acl.get(AclQualifier::Mask))
.to(be_some())
.to(equal(AclMode::RWX));
expect!(acl.get(AclQualifier::User(Uid::from_raw(1000))))
.to(be_some())
.to(equal(AclMode::R | AclMode::W));
expect!(acl.get(AclQualifier::Group(Gid::from_raw(1000))))
.to(be_some())
.to(equal(AclMode::R | AclMode::X));
}
#[test]
fn iter_returns_all_entries() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::RWX);
acl.set(AclQualifier::Other, AclMode::R);
let entries: HashSet<_> = acl.iter().map(|(q, m)| (*q, *m)).collect();
expect!(entries.len()).to(equal(2));
expect!(entries).to(consist_of([
(AclQualifier::OwningUser, AclMode::RWX),
(AclQualifier::Other, AclMode::R),
]));
}
#[test]
fn from_iter_creates_acl() {
let entries = vec![
(AclQualifier::OwningUser, AclMode::RWX),
(AclQualifier::Other, AclMode::R),
];
let acl: Acl = entries.into_iter().collect();
expect!(acl.get(AclQualifier::OwningUser))
.to(be_some())
.to(equal(AclMode::RWX));
expect!(acl.get(AclQualifier::Other))
.to(be_some())
.to(equal(AclMode::R));
}
#[test]
fn into_iter_consumes_acl() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::RWX);
acl.set(AclQualifier::Other, AclMode::R);
let entries: HashSet<_> = acl.into_iter().collect();
expect!(entries.len()).to(equal(2));
expect!(entries).to(consist_of([
(AclQualifier::OwningUser, AclMode::RWX),
(AclQualifier::Other, AclMode::R),
]));
}
#[test]
fn into_iter_for_ref_borrows_acl() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::RWX);
let mut count = 0;
for (qualifier, mode) in &acl {
expect!(*qualifier).to(equal(AclQualifier::OwningUser));
expect!(*mode).to(equal(AclMode::RWX));
count += 1;
}
expect!(count).to(equal(1));
expect!(acl.get(AclQualifier::OwningUser)).to(be_some());
}
}
mod acl_iter {
use super::*;
#[test]
fn len_returns_remaining_count() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::RWX);
acl.set(AclQualifier::Other, AclMode::R);
let mut iter = acl.iter();
expect!(iter.len()).to(equal(2));
iter.next();
expect!(iter.len()).to(equal(1));
iter.next();
expect!(iter.len()).to(equal(0));
}
#[test]
fn is_fused() {
let acl = Acl::new();
let mut iter = acl.iter();
expect!(iter.next()).to(be_none());
expect!(iter.next()).to(be_none());
expect!(iter.next()).to(be_none());
}
}
mod acl_into_iter {
use super::*;
#[test]
fn len_returns_remaining_count() {
let mut acl = Acl::new();
acl.set(AclQualifier::OwningUser, AclMode::RWX);
acl.set(AclQualifier::Other, AclMode::R);
let mut iter = acl.into_iter();
expect!(iter.len()).to(equal(2));
iter.next();
expect!(iter.len()).to(equal(1));
iter.next();
expect!(iter.len()).to(equal(0));
}
#[test]
fn is_fused() {
let acl = Acl::new();
let mut iter = acl.into_iter();
expect!(iter.next()).to(be_none());
expect!(iter.next()).to(be_none());
expect!(iter.next()).to(be_none());
}
}
mod acl_mode {
use super::*;
#[test]
fn individual_bits_are_correct() {
expect!(AclMode::R.bits()).to(equal(0o4));
expect!(AclMode::W.bits()).to(equal(0o2));
expect!(AclMode::X.bits()).to(equal(0o1));
}
#[test]
fn rwx_is_combination_of_all_three() {
expect!(AclMode::RWX).to(equal(AclMode::R | AclMode::W | AclMode::X));
}
#[test]
fn empty_has_no_permissions() {
expect!(AclMode::empty().bits()).to(equal(0));
}
#[test]
fn bitwise_operations_work() {
let read_write = AclMode::R | AclMode::W;
expect!(read_write.contains(AclMode::R)).to(be_true());
expect!(read_write.contains(AclMode::W)).to(be_true());
expect!(read_write.contains(AclMode::X)).to(be_false());
}
}