~gpanders/pushbroom

06028f1dea6ded0c705c55233b00d3880399c672 — Greg Anders 1 year, 10 months ago 41329ea
Add unit tests
A test/configs/delete.conf => test/configs/delete.conf +3 -0
@@ 0,0 1,3 @@
[Test Dir witout Trash]
Path = ~/.cache/pushbroom/test_delete
NumDays = 1

A test/configs/home.conf => test/configs/home.conf +3 -0
@@ 0,0 1,3 @@
[Home]
Path = ~
NumDays = 1

A test/configs/ignore.conf => test/configs/ignore.conf +4 -0
@@ 0,0 1,4 @@
[Test Ignore]
Path = ~/.cache/pushbroom/test_ignore
NumDays = 1
Ignore = ignored.txt

A test/configs/match.conf => test/configs/match.conf +4 -0
@@ 0,0 1,4 @@
[Test Match]
Path = ~/.cache/pushbroom/test_match
NumDays = 1
Match = matched.txt

A test/configs/match_and_ignore.conf => test/configs/match_and_ignore.conf +5 -0
@@ 0,0 1,5 @@
[Test Match and Ignore]
Path = ~/.cache/pushbroom/test_match_and_ignore
NumDays = 1
Match = *.txt
Ignore = ignored.txt

A test/configs/missing_numdays.conf => test/configs/missing_numdays.conf +2 -0
@@ 0,0 1,2 @@
[Missing NumDays]
Path = ~/.cache/pushbroom/test_missing_numdays

A test/configs/missing_path.conf => test/configs/missing_path.conf +2 -0
@@ 0,0 1,2 @@
[Missing Path]
NumDays = 1

A test/configs/shred_and_trash.conf => test/configs/shred_and_trash.conf +5 -0
@@ 0,0 1,5 @@
[Test Dir with Shred and Trash]
Path = ~/.cache/pushbroom/test_shred_and_trash
NumDays = 1
Trash = ~/.cache/pushbroom/trash
Shred = True

A test/configs/trash.conf => test/configs/trash.conf +4 -0
@@ 0,0 1,4 @@
[Test Dir with Trash]
Path = ~/.cache/pushbroom/test_trash
NumDays = 1
Trash = ~/.cache/pushbroom/trash

M test/test_pushbroom.py => test/test_pushbroom.py +186 -12
@@ 1,24 1,198 @@
# pylint: disable = redefined-outer-name
"""
Pushbroom unit tests
"""
import configparser
import os
import shutil
from datetime import datetime, timedelta
from pathlib import Path

import pytest

import pushbroom
from pushbroom import console

TRASH_DIR = Path("~/.cache/pushbroom/trash").expanduser()


def get_config(name):
    """
    Read the given configuration file and return the configuration object
    """
    conf_file = os.path.join(os.path.join(os.path.dirname(__file__), "configs"), name)
    return console.read_config(conf_file)


def get_config_path(config):
    """
    Retrieve the absolute, expanded path from the given configuration object
    """
    section = config.sections()[0]
    return Path(config.get(section, "path")).expanduser().absolute()


def make_test_file(path, name=None):
    """
    Create a file with the given ``name`` under the given ``path``. Set the file's
    mtime to two days ago.
    """
    if not name:
        name = "test.txt"

    path.mkdir(parents=True, exist_ok=True)
    test_file = path.joinpath(name)
    test_file.touch()
    mtime = (datetime.today() - timedelta(2)).timestamp()
    os.utime(test_file, (mtime, mtime))
    return test_file


@pytest.fixture
def trash_dir():
    """
    Create and provide the path to the trash directory.
    Delete the directory and all of its contents after use.
    """
    TRASH_DIR.mkdir(parents=True, exist_ok=True)
    yield TRASH_DIR
    shutil.rmtree(TRASH_DIR)


def test_tilde_home(monkeypatch):
    """
    Paths with a tilde should expand to the user's home directory
    """
    config = get_config("home.conf")

    def mock_sweep(name, path, *args, **kwargs):
        # pylint: disable = unused-argument
        assert Path(path) == Path.home()

    monkeypatch.setattr(console, "sweep", mock_sweep)
    console.pushbroom(config, dry_run=True)


def test_required_options():
    """
    If any required options are missing, an exception should be raised
    """
    config = get_config("missing_path.conf")
    with pytest.raises(configparser.NoOptionError):
        console.pushbroom(config)

    config = get_config("missing_numdays.conf")
    path = get_config_path(config)
    path.mkdir(parents=True, exist_ok=True)
    with pytest.raises(configparser.NoOptionError):
        console.pushbroom(config)
    path.rmdir()


@pytest.mark.xfail
def test_dry_run():
    assert False
    """
    Running with dry_run=True should not delete anything.
    Running without dry_run=True should delete the file.
    """
    config = get_config("delete.conf")
    path = get_config_path(config)
    test_file = make_test_file(path)

    console.pushbroom(config, dry_run=True)
    assert test_file.exists()

    console.pushbroom(config)
    assert not test_file.exists()

    path.rmdir()


@pytest.mark.xfail
def test_ignore():
    assert False
    """
    Files matching the Ignore pattern should not be deleted
    """
    config = get_config("ignore.conf")
    path = get_config_path(config)
    ignored_file = make_test_file(path, "ignored.txt")
    not_ignored_file = make_test_file(path, "not_ignored.txt")

    console.pushbroom(config)
    assert ignored_file.exists()
    assert not not_ignored_file.exists()

    ignored_file.unlink()
    path.rmdir()


@pytest.mark.xfail
def test_match():
    assert False
    """
    Only files matching the Match pattern should be deleted
    """
    config = get_config("match.conf")
    path = get_config_path(config)
    matched_file = make_test_file(path, "matched.txt")
    not_matched_file = make_test_file(path, "not_matched.txt")

    console.pushbroom(config)
    assert not matched_file.exists()
    assert not_matched_file.exists()

    not_matched_file.unlink()
    path.rmdir()


@pytest.mark.xfail
def test_match_with_ignore():
    assert False
    """
    When both Match and Ignore are specified, only files that match the Match pattern
    but not the Ignore pattern should be deleted
    """
    config = get_config("match_and_ignore.conf")
    path = get_config_path(config)
    ignored_file = make_test_file(path, "ignored.txt")
    matched_file = make_test_file(path, "matched.txt")

    console.pushbroom(config)
    assert ignored_file.exists()
    assert not matched_file.exists()

    ignored_file.unlink()
    path.rmdir()


def test_trash(trash_dir):
    """
    File should be moved to the Trash dir and not deleted
    """
    config = get_config("trash.conf")
    path = get_config_path(config)
    test_file = make_test_file(path, "file_to_go_in_trash.txt")

    console.pushbroom(config)
    assert not test_file.exists()
    assert trash_dir.joinpath(test_file.name).exists()

    path.rmdir()


def test_shred_with_trash(trash_dir):
    """
    When both Shred and Trash are specified, Shred should be ignored
    """
    config = get_config("shred_and_trash.conf")
    path = get_config_path(config)
    test_file = make_test_file(path, "shred_and_trash.txt")

    mtime = test_file.stat().st_mtime
    with open(test_file, "w", encoding="utf8") as fil:
        fil.write("Hello, world!")

    # Force mtime back to what it was
    os.utime(test_file, (mtime, mtime))

    console.pushbroom(config)
    assert not test_file.exists()
    assert trash_dir.joinpath(test_file.name).exists()

    with open(trash_dir.joinpath(test_file.name), "r", encoding="utf8") as fil:
        assert "Hello, world!" in fil.readlines()

@pytest.mark.xfail
def test_trash():
    assert False
    path.rmdir()