From a8dd89f48fe6dcd3edf07cba1c156a75d44b68ec Mon Sep 17 00:00:00 2001 From: Kurt McKee Date: Fri, 29 Apr 2022 08:26:55 -0500 Subject: [PATCH] Migrate CLI argument tests to Python --- tests/dotbot_plugin_directory.py | 24 +++++ tests/dotbot_plugin_file.py | 27 ++++++ tests/test_cli.py | 150 +++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 tests/dotbot_plugin_directory.py create mode 100644 tests/dotbot_plugin_file.py create mode 100644 tests/test_cli.py diff --git a/tests/dotbot_plugin_directory.py b/tests/dotbot_plugin_directory.py new file mode 100644 index 0000000..5ab828a --- /dev/null +++ b/tests/dotbot_plugin_directory.py @@ -0,0 +1,24 @@ +"""Test that a plugin can be loaded by directory. + +This file is copied to a location with the name "directory.py", +and is then loaded from within the `test_cli.py` code. +""" + +import dotbot +import os.path + + +class Directory(dotbot.Plugin): + def can_handle(self, directive): + return directive == "plugin_directory" + + def handle(self, directive, data): + self._log.debug("Attempting to get options from Context") + options = self._context.options() + if len(options.plugin_dirs) != 1: + self._log.debug("Context.options.plugins length is %i, expected 1" % len(options.plugins)) + return False + + with open(os.path.abspath(os.path.expanduser("~/flag")), "w") as file: + file.write("directory plugin loading works") + return True diff --git a/tests/dotbot_plugin_file.py b/tests/dotbot_plugin_file.py new file mode 100644 index 0000000..23b6a36 --- /dev/null +++ b/tests/dotbot_plugin_file.py @@ -0,0 +1,27 @@ +"""Test that a plugin can be loaded by filename. + +This file is copied to a location with the name "file.py", +and is then loaded from within the `test_cli.py` code. +""" + +import dotbot +import os.path + + +class File(dotbot.Plugin): + def can_handle(self, directive): + return directive == "plugin_file" + + def handle(self, directive, data): + self._log.debug("Attempting to get options from Context") + options = self._context.options() + if len(options.plugins) != 1: + self._log.debug("Context.options.plugins length is %i, expected 1" % len(options.plugins)) + return False + if not options.plugins[0].endswith("file.py"): + self._log.debug("Context.options.plugins[0] is %s, expected end with file.py" % options.plugins[0]) + return False + + with open(os.path.abspath(os.path.expanduser("~/flag")), "w") as file: + file.write("file plugin loading works") + return True diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..8ce690a --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,150 @@ +import os +import shutil + +import pytest + + +def test_except_create(capfd, home, dotfiles, run_dotbot): + """Verify that `--except` works as intended.""" + + dotfiles.write_config([ + {"create": ["~/a"]}, + {"shell": [ + {"command": "echo success", "stdout": True}, + ]}, + ]) + run_dotbot("--except", "create") + + assert not os.path.exists(os.path.join(home, "a")) + stdout = capfd.readouterr().out.splitlines() + assert any(line.startswith("success") for line in stdout) + + +def test_except_shell(capfd, home, dotfiles, run_dotbot): + """Verify that `--except` works as intended.""" + + dotfiles.write_config([ + {"create": ["~/a"]}, + {"shell": [ + {"command": "echo failure", "stdout": True}, + ]}, + ]) + run_dotbot("--except", "shell") + + assert os.path.exists(os.path.join(home, "a")) + stdout = capfd.readouterr().out.splitlines() + assert not any(line.startswith("failure") for line in stdout) + + +def test_except_multiples(capfd, home, dotfiles, run_dotbot): + """Verify that `--except` works with multiple exceptions.""" + + dotfiles.write_config([ + {"create": ["~/a"]}, + {"shell": [ + {"command": "echo failure", "stdout": True}, + ]}, + ]) + run_dotbot("--except", "create", "shell") + + assert not os.path.exists(os.path.join(home, "a")) + stdout = capfd.readouterr().out.splitlines() + assert not any(line.startswith("failure") for line in stdout) + + +def test_exit_on_failure(capfd, home, dotfiles, run_dotbot): + """Verify that processing can halt immediately on failures.""" + + dotfiles.write_config([ + {"create": ["~/a"]}, + {"shell": ["this_is_not_a_command"]}, + {"create": ["~/b"]}, + ]) + with pytest.raises(SystemExit): + run_dotbot("-x") + + assert os.path.isdir(os.path.join(home, "a")) + assert not os.path.isdir(os.path.join(home, "b")) + + +def test_only(capfd, home, dotfiles, run_dotbot): + """Verify that `--only` works as intended.""" + + dotfiles.write_config([ + {"create": ["~/a"]}, + {"shell": [{"command": "echo success", "stdout": True}]}, + ]) + run_dotbot("--only", "shell") + + assert not os.path.exists(os.path.join(home, "a")) + stdout = capfd.readouterr().out.splitlines() + assert any(line.startswith("success") for line in stdout) + + +def test_only_with_defaults(capfd, home, dotfiles, run_dotbot): + """Verify that `--only` does not suppress defaults.""" + + dotfiles.write_config([ + {"defaults": {"shell": {"stdout": True}}}, + {"create": ["~/a"]}, + {"shell": [{"command": "echo success"}]}, + ]) + run_dotbot("--only", "shell") + + assert not os.path.exists(os.path.join(home, "a")) + stdout = capfd.readouterr().out.splitlines() + assert any(line.startswith("success") for line in stdout) + + +def test_only_with_multiples(capfd, home, dotfiles, run_dotbot): + """Verify that `--only` works as intended.""" + + dotfiles.write_config([ + {"create": ["~/a"]}, + {"shell": [{"command": "echo success", "stdout": True}]}, + {"link": ["~/.f"]} + ]) + run_dotbot("--only", "create", "shell") + + assert os.path.isdir(os.path.join(home, "a")) + stdout = capfd.readouterr().out.splitlines() + assert any(line.startswith("success") for line in stdout) + assert not os.path.exists(os.path.join(home, ".f")) + + +def test_plugin_loading_file(home, dotfiles, run_dotbot): + """Verify that plugins can be loaded by file.""" + + plugin_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "dotbot_plugin_file.py") + shutil.copy(plugin_file, os.path.join(dotfiles.directory, "file.py")) + dotfiles.write_config([{"plugin_file": "~"}]) + run_dotbot("--plugin", os.path.join(dotfiles.directory, "file.py")) + + with open(os.path.join(home, "flag"), "r") as file: + assert file.read() == "file plugin loading works" + + +def test_plugin_loading_directory(home, dotfiles, run_dotbot): + """Verify that plugins can be loaded from a directory.""" + + dotfiles.makedirs("plugins") + plugin_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "dotbot_plugin_directory.py") + shutil.copy(plugin_file, os.path.join(dotfiles.directory, "plugins", "directory.py")) + dotfiles.write_config([{"plugin_directory": "~"}]) + run_dotbot("--plugin-dir", os.path.join(dotfiles.directory, "plugins")) + + with open(os.path.join(home, "flag"), "r") as file: + assert file.read() == "directory plugin loading works" + + +def test_disable_builtin_plugins(home, dotfiles, run_dotbot): + """Verify that builtin plugins can be disabled.""" + + dotfiles.write("f", "apple") + dotfiles.write_config([{"link": {"~/.f": "f"}}]) + + # The link directive will be unhandled so dotbot will raise SystemExit. + with pytest.raises(SystemExit): + run_dotbot("--disable-built-in-plugins") + + assert not os.path.exists(os.path.join(home, ".f"))