liteboxfs 0.1.0

A modern POSIX filesystem in a SQLite database
Documentation
#![cfg(all(feature = "fs", target_os = "linux"))]

use std::time::{Duration, SystemTime};

use xpct::{approx_eq_time, be_ok, be_some, equal, expect};

use crate::{
    Connection,
    file_metadata::{FileKind, Owner},
    settings::Settings,
};

fn open() -> crate::Result<Connection> {
    Connection::open_for_testing(&Settings::default())
}

#[test]
fn touch_at_sets_atime_mtime_and_ctime_to_given_time() -> crate::Result<()> {
    let mut conn = open()?;

    let time = SystemTime::UNIX_EPOCH + Duration::from_secs(1_700_000_000);

    conn.exec(|fs| {
        let mut file = fs.create("/a.txt", FileKind::Regular, Owner::ROOT)?;
        expect!(file.touch_at(time)).to(be_ok());

        let metadata = file.metadata()?;
        expect!(metadata.accessed()).to(equal(time));
        expect!(metadata.modified()).to(equal(time));
        expect!(metadata.changed()).to(equal(time));

        crate::Result::Ok(())
    })?;

    Ok(())
}

#[test]
fn touch_at_does_not_change_btime() -> crate::Result<()> {
    let mut conn = open()?;

    let touch_time = SystemTime::UNIX_EPOCH + Duration::from_secs(1_700_000_000);

    conn.exec(|fs| {
        let mut file = fs.create("/a.txt", FileKind::Regular, Owner::ROOT)?;
        let original_btime = file.metadata()?.created();

        expect!(file.touch_at(touch_time)).to(be_ok());

        expect!(file.metadata()?.created()).to(equal(original_btime));

        crate::Result::Ok(())
    })?;

    Ok(())
}

#[test]
fn touch_at_overwrites_existing_timestamps() -> crate::Result<()> {
    let mut conn = open()?;

    let earlier = SystemTime::UNIX_EPOCH + Duration::from_secs(1_000_000_000);
    let later = SystemTime::UNIX_EPOCH + Duration::from_secs(1_700_000_000);

    conn.exec(|fs| {
        let mut file = fs.create("/a.txt", FileKind::Regular, Owner::ROOT)?;
        file.touch_at(later)?;
        expect!(file.touch_at(earlier)).to(be_ok());

        let metadata = file.metadata()?;
        expect!(metadata.accessed()).to(equal(earlier));
        expect!(metadata.modified()).to(equal(earlier));
        expect!(metadata.changed()).to(equal(earlier));

        crate::Result::Ok(())
    })?;

    Ok(())
}

#[test]
fn touch_sets_atime_mtime_and_ctime_to_now() -> crate::Result<()> {
    let mut conn = open()?;

    conn.exec(|fs| {
        let mut file = fs.create("/a.txt", FileKind::Regular, Owner::ROOT)?;

        expect!(file.touch()).to(be_ok());
        let now = SystemTime::now();

        let metadata = file.metadata()?;
        expect!(metadata.accessed()).to(approx_eq_time(now, Duration::from_secs(1)));
        expect!(metadata.modified()).to(approx_eq_time(now, Duration::from_secs(1)));
        expect!(metadata.changed()).to(approx_eq_time(now, Duration::from_secs(1)));

        crate::Result::Ok(())
    })?;

    Ok(())
}

#[test]
fn touch_does_not_change_btime() -> crate::Result<()> {
    let mut conn = open()?;

    conn.exec(|fs| {
        let mut file = fs.create("/a.txt", FileKind::Regular, Owner::ROOT)?;
        let original_btime = file.metadata()?.created();
        expect!(original_btime).to(be_some());

        expect!(file.touch()).to(be_ok());

        expect!(file.metadata()?.created()).to(equal(original_btime));

        crate::Result::Ok(())
    })?;

    Ok(())
}

#[test]
fn touch_at_works_on_directory() -> crate::Result<()> {
    let mut conn = open()?;

    let time = SystemTime::UNIX_EPOCH + Duration::from_secs(1_700_000_000);

    conn.exec(|fs| {
        let mut dir = fs.create("/dir", FileKind::Dir, Owner::ROOT)?;
        expect!(dir.touch_at(time)).to(be_ok());

        let metadata = dir.metadata()?;
        expect!(metadata.accessed()).to(equal(time));
        expect!(metadata.modified()).to(equal(time));
        expect!(metadata.changed()).to(equal(time));

        crate::Result::Ok(())
    })?;

    Ok(())
}

#[test]
fn touch_at_works_on_symlink() -> crate::Result<()> {
    let mut conn = open()?;

    let time = SystemTime::UNIX_EPOCH + Duration::from_secs(1_700_000_000);

    conn.exec(|fs| {
        let mut symlink = fs.create(
            "/link",
            FileKind::Symlink {
                target: "/target".into(),
            },
            Owner::ROOT,
        )?;
        expect!(symlink.touch_at(time)).to(be_ok());

        let metadata = symlink.metadata()?;
        expect!(metadata.accessed()).to(equal(time));
        expect!(metadata.modified()).to(equal(time));
        expect!(metadata.changed()).to(equal(time));

        crate::Result::Ok(())
    })?;

    Ok(())
}