1
0
Fork 0
mirror of synced 2025-01-22 19:52:06 -05:00

Merge branch 'kurtmckee/test-on-windows-issue-309'

This commit is contained in:
Anish Athalye 2022-12-17 14:01:22 -05:00
commit 3965e1a390
93 changed files with 2403 additions and 2115 deletions

View file

@ -6,11 +6,22 @@ on:
- cron: '0 8 * * 6'
jobs:
test:
runs-on: ubuntu-20.04
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
strategy:
fail-fast: false
matrix:
python: ["2.7", "pypy2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "pypy3.9"]
name: "Test: Python ${{ matrix.python }}"
os: ["ubuntu-20.04", "macos-latest"]
python: ["2.7", "pypy-2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "pypy-3.9"]
include:
- os: "windows-latest"
python: "3.8"
- os: "windows-latest"
python: "3.9"
- os: "windows-latest"
python: "3.10"
runs-on: ${{ matrix.os }}
name: "Test: Python ${{ matrix.python }} on ${{ matrix.os }}"
steps:
- uses: actions/checkout@v3
with:
@ -18,7 +29,14 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- run: ./test/test
- name: "Install dependencies"
run: |
python -m pip install --upgrade pip setuptools
python -m pip install tox tox-gh-actions
- name: "Run tests"
run: |
python -m tox
fmt:
name: Format
runs-on: ubuntu-22.04

6
.gitignore vendored
View file

@ -1,4 +1,10 @@
*.egg-info
*.pyc
.coverage*
.eggs/
.idea/
.tox/
.venv/
build/
dist/
htmlcov/

View file

@ -50,6 +50,31 @@ used in the rest of the project. The version history should be clean, and
commit messages should be descriptive and [properly
formatted][commit-messages].
When preparing a patch, it's recommended that you add unit tests
that demonstrate the bug is fixed (or that the feature works).
You can run the tests on your local machine by installing the `dev` extras.
The steps below do this using a virtual environment:
```shell
# Create a local virtual environment
$ python -m venv .venv
# Activate the virtual environment
# Cygwin, Linux, and MacOS:
$ . .venv/bin/activate
# Windows Powershell:
$ & .venv\Scripts\Activate.ps1
# Update pip and setuptools
(.venv) $ python -m pip install -U pip setuptools
# Install dotbot and its development dependencies
(.venv) $ python -m pip install -e .[dev]
# Run the unit tests
(.venv) $ tox
```
---
If you have any questions about anything, feel free to [ask][email]!

View file

@ -1,16 +1,16 @@
import os, glob
import sys
from argparse import ArgumentParser, RawTextHelpFormatter
from .config import ConfigReader, ReadingError
from .dispatcher import Dispatcher, DispatchError
from .messenger import Messenger
from .messenger import Level
from .util import module
import dotbot
import glob
import os
import subprocess
import sys
from argparse import ArgumentParser, RawTextHelpFormatter
import dotbot
from .config import ConfigReader, ReadingError
from .dispatcher import Dispatcher, DispatchError
from .messenger import Level, Messenger
from .plugins import Clean, Create, Link, Shell
from .util import module
def add_options(parser):
@ -118,9 +118,10 @@ def main():
else:
log.use_color(sys.stdout.isatty())
plugins = []
plugin_directories = list(options.plugin_dirs)
if not options.disable_built_in_plugins:
from .plugins import Clean, Create, Link, Shell
plugins.extend([Clean, Create, Link, Shell])
plugin_paths = []
for directory in plugin_directories:
for plugin_path in glob.glob(os.path.join(directory, "*.py")):
@ -129,7 +130,7 @@ def main():
plugin_paths.append(plugin_path)
for plugin_path in plugin_paths:
abspath = os.path.abspath(plugin_path)
module.load(abspath)
plugins.extend(module.load(abspath))
if not options.config_file:
log.error("No configuration file specified")
exit(1)
@ -151,6 +152,7 @@ def main():
skip=options.skip,
exit_on_failure=options.exit_on_failure,
options=options,
plugins=plugins,
)
success = dispatcher.dispatch(tasks)
if success:

View file

@ -1,6 +1,8 @@
import yaml
import json
import os.path
import yaml
from .util import string

View file

@ -1,17 +1,25 @@
import os
from argparse import Namespace
from .plugin import Plugin
from .messenger import Messenger
from .context import Context
from .messenger import Messenger
from .plugin import Plugin
class Dispatcher(object):
def __init__(
self, base_directory, only=None, skip=None, exit_on_failure=False, options=Namespace()
self,
base_directory,
only=None,
skip=None,
exit_on_failure=False,
options=Namespace(),
plugins=None,
):
self._log = Messenger()
self._setup_context(base_directory, options)
self._load_plugins()
plugins = plugins or []
self._plugins = [plugin(self._context) for plugin in plugins]
self._only = only
self._skip = skip
self._exit = exit_on_failure
@ -65,9 +73,6 @@ class Dispatcher(object):
return False
return success
def _load_plugins(self):
self._plugins = [plugin(self._context) for plugin in Plugin.__subclasses__()]
class DispatchError(Exception):
pass

View file

@ -1,2 +1,2 @@
from .messenger import Messenger
from .level import Level
from .messenger import Messenger

View file

@ -1,5 +1,5 @@
from ..util.singleton import Singleton
from ..util.compat import with_metaclass
from ..util.singleton import Singleton
from .color import Color
from .level import Level

View file

@ -1,5 +1,5 @@
from .messenger import Messenger
from .context import Context
from .messenger import Messenger
class Plugin(object):

View file

@ -1,8 +1,10 @@
import os
import dotbot
import sys
from ..plugin import Plugin
class Clean(dotbot.Plugin):
class Clean(Plugin):
"""
Cleans broken symbolic links.
"""
@ -42,7 +44,9 @@ class Clean(dotbot.Plugin):
self._log.debug("Ignoring nonexistent directory %s" % target)
return True
for item in os.listdir(os.path.expandvars(os.path.expanduser(target))):
path = os.path.join(os.path.expandvars(os.path.expanduser(target)), item)
path = os.path.abspath(
os.path.join(os.path.expandvars(os.path.expanduser(target)), item)
)
if recursive and os.path.isdir(path):
# isdir implies not islink -- we don't want to descend into
# symlinked directories. okay to do a recursive call here
@ -50,6 +54,8 @@ class Clean(dotbot.Plugin):
self._clean(path, force, recursive)
if not os.path.exists(path) and os.path.islink(path):
points_at = os.path.join(os.path.dirname(path), os.readlink(path))
if sys.platform[:5] == "win32" and points_at.startswith("\\\\?\\"):
points_at = points_at[4:]
if self._in_directory(path, self._context.base_directory()) or force:
self._log.lowinfo("Removing invalid link %s -> %s" % (path, points_at))
os.remove(path)

View file

@ -1,8 +1,9 @@
import os
import dotbot
from ..plugin import Plugin
class Create(dotbot.Plugin):
class Create(Plugin):
"""
Create empty paths.
"""
@ -21,7 +22,7 @@ class Create(dotbot.Plugin):
success = True
defaults = self._context.defaults().get("create", {})
for key in paths:
path = os.path.expandvars(os.path.expanduser(key))
path = os.path.abspath(os.path.expandvars(os.path.expanduser(key)))
mode = defaults.get("mode", 0o777) # same as the default for os.makedirs
if isinstance(paths, dict):
options = paths[key]
@ -48,6 +49,9 @@ class Create(dotbot.Plugin):
try:
self._log.lowinfo("Creating path %s" % path)
os.makedirs(path, mode)
# On Windows, the *mode* argument to `os.makedirs()` is ignored.
# The mode must be set explicitly in a follow-up call.
os.chmod(path, mode)
except OSError:
self._log.warning("Failed to create path %s" % path)
success = False

View file

@ -1,13 +1,13 @@
import os
import sys
import glob
import os
import shutil
import dotbot
import dotbot.util
import subprocess
import sys
from ..plugin import Plugin
from ..util import shell_command
class Link(dotbot.Plugin):
class Link(Plugin):
"""
Symbolically links dotfiles.
"""
@ -58,7 +58,7 @@ class Link(dotbot.Plugin):
if test is not None and not self._test_success(test):
self._log.lowinfo("Skipping %s" % destination)
continue
path = os.path.expandvars(os.path.expanduser(path))
path = os.path.normpath(os.path.expandvars(os.path.expanduser(path)))
if use_glob:
glob_results = self._create_glob_results(path, exclude_paths)
if len(glob_results) == 0:
@ -140,7 +140,7 @@ class Link(dotbot.Plugin):
return success
def _test_success(self, command):
ret = dotbot.util.shell_command(command, cwd=self._context.base_directory())
ret = shell_command(command, cwd=self._context.base_directory())
if ret != 0:
self._log.debug("Test '%s' returned false" % command)
return ret == 0
@ -166,6 +166,8 @@ class Link(dotbot.Plugin):
return []
# call glob.glob; only python >= 3.5 supports recursive globs
found = glob.glob(path) if (sys.version_info < (3, 5)) else glob.glob(path, recursive=True)
# normalize paths to ensure cross-platform compatibility
found = [os.path.normpath(p) for p in found]
# if using recursive glob (`**`), filter results to return only files:
if "**" in path and not path.endswith(str(os.sep)):
self._log.debug("Excluding directories from recursive glob: " + str(path))
@ -197,7 +199,10 @@ class Link(dotbot.Plugin):
Returns the destination of the symbolic link.
"""
path = os.path.expanduser(path)
return os.readlink(path)
path = os.readlink(path)
if sys.platform[:5] == "win32" and path.startswith("\\\\?\\"):
path = path[4:]
return path
def _exists(self, path):
"""
@ -223,7 +228,7 @@ class Link(dotbot.Plugin):
def _delete(self, source, path, relative, canonical_path, force):
success = True
source = os.path.join(self._context.base_directory(canonical_path=canonical_path), source)
fullpath = os.path.expanduser(path)
fullpath = os.path.abspath(os.path.expanduser(path))
if relative:
source = self._relative_path(source, fullpath)
if (self._is_link(path) and self._link_destination(path) != source) or (
@ -264,9 +269,10 @@ class Link(dotbot.Plugin):
Returns true if successfully linked files.
"""
success = False
destination = os.path.expanduser(link_name)
destination = os.path.abspath(os.path.expanduser(link_name))
base_directory = self._context.base_directory(canonical_path=canonical_path)
absolute_source = os.path.join(base_directory, source)
link_name = os.path.normpath(link_name)
if relative:
source = self._relative_path(absolute_source, destination)
else:

View file

@ -1,10 +1,8 @@
import os
import subprocess
import dotbot
import dotbot.util
from ..plugin import Plugin
from ..util import shell_command
class Shell(dotbot.Plugin):
class Shell(Plugin):
"""
Run arbitrary shell commands.
"""
@ -51,7 +49,7 @@ class Shell(dotbot.Plugin):
self._log.lowinfo("%s [%s]" % (msg, cmd))
stdout = options.get("stdout", stdout)
stderr = options.get("stderr", stderr)
ret = dotbot.util.shell_command(
ret = shell_command(
cmd,
cwd=self._context.base_directory(),
enable_stdin=stdin,

View file

@ -1,6 +1,6 @@
import os
import subprocess
import platform
import subprocess
def shell_command(command, cwd=None, enable_stdin=False, enable_stdout=False, enable_stderr=False):

View file

@ -1,4 +1,7 @@
import sys, os.path
import os
import sys
from dotbot.plugin import Plugin
# We keep references to loaded modules so they don't get garbage collected.
loaded_modules = []
@ -7,8 +10,17 @@ loaded_modules = []
def load(path):
basename = os.path.basename(path)
module_name, extension = os.path.splitext(basename)
plugin = load_module(module_name, path)
loaded_modules.append(plugin)
loaded_module = load_module(module_name, path)
plugins = []
for name in dir(loaded_module):
possible_plugin = getattr(loaded_module, name)
try:
if issubclass(possible_plugin, Plugin) and possible_plugin is not Plugin:
plugins.append(possible_plugin)
except TypeError:
pass
loaded_modules.append(loaded_module)
return plugins
if sys.version_info >= (3, 5):

View file

@ -58,6 +58,12 @@ setup(
install_requires=[
"PyYAML>=5.3,<6",
],
extras_require={
"dev": {
"pytest",
"tox",
}
},
# To provide executable scripts, use entry points in preference to the
# "scripts" keyword. Entry points provide cross-platform support and allow
# pip to create the appropriate form of executable for the target platform.

View file

@ -1,5 +0,0 @@
[Vagrantfile]
indent_size = 2
[{test,test_travis}]
indent_size = 4

2
test/.gitignore vendored
View file

@ -1,2 +0,0 @@
.vagrant/
*.log

View file

@ -1,86 +0,0 @@
Testing
=======
Dotbot testing code uses [Vagrant] to run all tests inside a virtual machine to
have tests be completely isolated from the host machine. Specifically, you
will need both:
- [VirtualBox]
- [Vagrant]
Install Dotbot dependencies
---------------------------
Ensure you have updated the `dotbot` submodule dependencies, on the host machine:
```bash
git submodule sync --quiet --recursive
git submodule update --init --recursive
```
Install Vagrant
---------------
### Debian-based distributions
```bash
sudo apt install vagrant virtualbox
```
### macOS
You can download those directly from the above URLs, or via some MacOS package managers.
e.g. using [HomeBrew](https://brew.sh/):
```bash
brew cask install virtualbox
brew cask install vagrant
# optional, adding menu-bar support:
brew cask install vagrant-manager
```
Running the Tests
-----------------
Before running the tests, you must start and `ssh` into the VM:
```bash
vagrant up
vagrant ssh
```
All remaining commands are run inside the VM.
First, you must install a version of Python to test against, using:
pyenv install -s {version}
You can choose any version you like, e.g. `3.8.1`. It isn't particularly
important to test against all supported versions of Python in the VM, because
they will be tested by CI. Once you've installed a specific version of Python,
activate it with:
pyenv global {version}
The VM mounts your host's Dotbot directory in `/dotbot` as read-only, allowing
you to make edits on your host machine. Run the entire test suite by:
```bash
cd /dotbot/test
./test
```
Selected tests can be run by passing paths to the tests as arguments, e.g.:
```bash
./test tests/create.bash tests/defaults.bash
```
To debug tests, you can run the test driver with the `--debug` (or `-d` short
form) flag, e.g. `./test --debug tests/link-if.bash`. This will enable printing
stdout/stderr.
When finished with testing, it is good to shut down the virtual machine by
running `vagrant halt`.
[VirtualBox]: https://www.virtualbox.org/
[Vagrant]: https://www.vagrantup.com/

28
test/Vagrantfile vendored
View file

@ -1,28 +0,0 @@
Vagrant.configure(2) do |config|
config.vm.box = 'ubuntu/jammy64'
config.vm.synced_folder "..", "/dotbot", mount_options: ["ro"]
# disable default synced folder
config.vm.synced_folder ".", "/vagrant", disabled: true
# install packages
config.vm.provision "shell", inline: <<-EOS
apt-get -y update
apt-get install -y git make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncurses5-dev
EOS
# install pyenv
config.vm.provision "shell", privileged: false, inline: <<-EOS
rm -rf ~/.pyenv
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
cat <<-'PYENV' > ~/.bashrc
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
PYENV
EOS
end

View file

@ -1,99 +0,0 @@
red() {
if [ -t 1 ]; then
printf "\033[31m%s\033[0m\n" "$*"
else
printf "%s\n" "$*"
fi
}
green() {
if [ -t 1 ]; then
printf "\033[32m%s\033[0m\n" "$*"
else
printf "%s\n" "$*"
fi
}
yellow() {
if [ -t 1 ]; then
printf "\033[33m%s\033[0m\n" "$*"
else
printf "%s\n" "$*"
fi
}
check_env() {
if [[ "$(whoami)" != "vagrant" && "${CI}" != true ]]; then
die "tests must be run inside Vagrant or CI"
fi
}
cleanup() {
rm -rf ~/fakehome
mkdir -p ~/fakehome
}
initialize() {
echo "initializing."
tests_run=0
tests_passed=0
tests_failed=0
tests_skipped=0
tests_total="${1}"
local plural="" && [ "${tests_total}" -gt 1 ] && plural="s"
printf -- "running %d test%s...\n\n" "${tests_total}" "${plural}"
}
pass() {
tests_passed=$((tests_passed + 1))
green "-> ok."
echo
}
fail() {
tests_failed=$((tests_failed + 1))
red "-> fail!"
echo
}
skip() {
tests_skipped=$((tests_skipped + 1))
yellow "-> skipped."
echo
}
run_test() {
tests_run=$((tests_run + 1))
printf '[%d/%d] (%s)\n' "${tests_run}" "${tests_total}" "${1}"
cleanup
if (cd "${BASEDIR}/test/tests" && HOME=~/fakehome DEBUG=${2} DOTBOT_TEST=true bash "${1}"); then
pass
elif [ $? -eq 42 ]; then
skip
else
fail
fi
}
report() {
printf -- "test report\n"
printf -- "-----------\n"
printf -- "- %3d run\n" ${tests_run}
printf -- "- %3d passed\n" ${tests_passed}
printf -- "- %3d skipped\n" ${tests_skipped}
printf -- "- %3d failed\n" ${tests_failed}
if [ ${tests_failed} -gt 0 ]; then
red "==> FAIL! "
return 1
else
green "==> PASS. "
return 0
fi
}
die() {
>&2 echo $@
>&2 echo "terminating..."
exit 1
}

View file

@ -1,53 +0,0 @@
#!/usr/bin/env bash
set -e
export BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${BASEDIR}/test"
. "./driver-lib.bash"
date_stamp="$(date --rfc-3339=ns)"
start="$(date +%s)"
check_env
# parse flags; must come before positional arguments
POSITIONAL=()
DEBUG=false
while [[ $# -gt 0 ]]; do
case $1 in
-d|--debug)
DEBUG=true
shift
;;
*)
POSITIONAL+=("$1")
shift
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional arguments
declare -a tests=()
if [ $# -eq 0 ]; then
while read file; do
tests+=("${file}")
done < <(find tests -type f -name '*.bash' | sort)
else
tests=("$@")
fi
initialize "${#tests[@]}"
for file in "${tests[@]}"; do
run_test "$(basename "${file}")" "${DEBUG}"
done
if report; then
ret=0
else
ret=1
fi
echo "(tests run in $(($(date +%s) - start)) seconds)"
exit ${ret}

View file

@ -1,76 +0,0 @@
DOTBOT_EXEC="${BASEDIR}/bin/dotbot"
DOTFILES="${HOME}/dotfiles"
INSTALL_CONF='install.conf.yaml'
INSTALL_CONF_JSON='install.conf.json'
test_run_() {
if ! ${DEBUG}; then
(eval "$*") >/dev/null 2>&1
else
(eval "$*")
fi
}
test_expect_success() {
local tag=${1} && shift
if ! test_run_ "$@"; then
>&2 echo "- ${tag} failed."
exit 1
fi
}
test_expect_failure() {
local tag=${1} && shift
if test_run_ "$@"; then
>&2 echo "- ${tag} failed."
exit 1
fi
}
skip_tests() {
# exit with special exit code picked up by driver-lib.bash
exit 42
}
check_env() {
if [ "${DOTBOT_TEST}" != "true" ]; then
>&2 echo "test must be run by test driver"
exit 1
fi
}
# run comparison check on python version; args:
# $1 - comparison operator (e.g. '>=')
# $2 - version number, to be passed to python (e.g. '3', '3.5', '3.6.4')
# status code will reflect if comparison is true/false
# e.g. `check_python_version '>=' 3.5`
check_python_version() {
check="$1"
version="$(echo "$2" | tr . , )"
# this call to just `python` will work in the Vagrant-based testing VM
# because `pyenv` will always create a link to the "right" version.
python -c "import sys; exit( not (sys.version_info ${check} (${version})) )"
}
initialize() {
check_env
echo "${test_description}"
mkdir -p "${DOTFILES}"
cd
}
run_dotbot() {
(
cat > "${DOTFILES}/${INSTALL_CONF}"
${DOTBOT_EXEC} -c "${DOTFILES}/${INSTALL_CONF}" "${@}"
)
}
run_dotbot_json() {
(
cat > "${DOTFILES}/${INSTALL_CONF_JSON}"
${DOTBOT_EXEC} -c "${DOTFILES}/${INSTALL_CONF_JSON}" "${@}"
)
}
initialize

View file

@ -1,19 +0,0 @@
test_description='clean uses default unless overridden'
. '../test-lib.bash'
test_expect_success 'setup' '
ln -s /nowhere ~/.g
'
test_expect_success 'run' '
run_dotbot <<EOF
- clean:
~/nonexistent:
force: true
~/:
EOF
'
test_expect_success 'test' '
test -h ~/.g
'

View file

@ -1,16 +0,0 @@
test_description='clean expands environment variables'
. '../test-lib.bash'
test_expect_success 'setup' '
ln -s ${DOTFILES}/f ~/.f
'
test_expect_success 'run' '
run_dotbot <<EOF
- clean: ["\$HOME"]
EOF
'
test_expect_success 'test' '
! test -h ~/.f
'

View file

@ -1,19 +0,0 @@
test_description='clean deletes links to missing files'
. '../test-lib.bash'
test_expect_success 'setup' '
touch ${DOTFILES}/f &&
ln -s ${DOTFILES}/f ~/.f &&
ln -s ${DOTFILES}/g ~/.g
'
test_expect_success 'run' '
run_dotbot <<EOF
- clean: ["~"]
EOF
'
test_expect_success 'test' '
test -f ~/.f &&
! test -h ~/.g
'

View file

@ -1,8 +0,0 @@
test_description='clean ignores nonexistent directories'
. '../test-lib.bash'
test_expect_success 'run' '
run_dotbot <<EOF
- clean: ["~", "~/fake"]
EOF
'

View file

@ -1,18 +0,0 @@
test_description='clean forced to remove files linking outside dotfiles directory'
. '../test-lib.bash'
test_expect_success 'setup' '
ln -s /nowhere ~/.g
'
test_expect_success 'run' '
run_dotbot <<EOF
- clean:
~/:
force: true
EOF
'
test_expect_success 'test' '
! test -h ~/.g
'

View file

@ -1,18 +0,0 @@
test_description='clean ignores files linking outside dotfiles directory'
. '../test-lib.bash'
test_expect_success 'setup' '
ln -s ${DOTFILES}/f ~/.f &&
ln -s ~/g ~/.g
'
test_expect_success 'run' '
run_dotbot <<EOF
- clean: ["~"]
EOF
'
test_expect_success 'test' '
! test -h ~/.f &&
test -h ~/.g
'

View file

@ -1,34 +0,0 @@
test_description='clean removes recursively'
. '../test-lib.bash'
test_expect_success 'setup' '
mkdir -p ~/a/b
ln -s /nowhere ~/c
ln -s /nowhere ~/a/d
ln -s /nowhere ~/a/b/e
'
test_expect_success 'run' '
run_dotbot <<EOF
- clean:
~/:
force: true
EOF
'
test_expect_success 'test' '
! test -h ~/c && test -h ~/a/d && test -h ~/a/b/e
'
test_expect_success 'run 2' '
run_dotbot <<EOF
- clean:
~/:
force: true
recursive: true
EOF
'
test_expect_success 'test 2' '
! test -h ~/a/d && ! test -h ~/a/b/e
'

View file

@ -1,8 +0,0 @@
test_description='blank config allowed'
. '../test-lib.bash'
test_expect_success 'run' '
run_dotbot <<EOF
[]
EOF
'

View file

@ -1,7 +0,0 @@
test_description='empty config allowed'
. '../test-lib.bash'
test_expect_success 'run' '
run_dotbot <<EOF
EOF
'

View file

@ -1,20 +0,0 @@
test_description='json config with tabs allowed'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "grape" > ${DOTFILES}/h
'
test_expect_success 'run' '
run_dotbot_json <<EOF
[{
"link": {
"~/.i": "h"
}
}]
EOF
'
test_expect_success 'test' '
grep "grape" ~/.i
'

View file

@ -1,20 +0,0 @@
test_description='json config allowed'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "grape" > ${DOTFILES}/h
'
test_expect_success 'run' '
run_dotbot_json <<EOF
[{
"link": {
"~/.i": "h"
}
}]
EOF
'
test_expect_success 'test' '
grep "grape" ~/.i
'

View file

@ -1,26 +0,0 @@
test_description='create mode'
. '../test-lib.bash'
test_expect_success 'run' '
run_dotbot -v <<EOF
- defaults:
create:
mode: 0755
- create:
- ~/downloads
- ~/.vim/undo-history
- create:
~/.ssh:
mode: 0700
~/projects:
EOF
'
test_expect_success 'test' '
[ -d ~/downloads ] &&
[ -d ~/.vim/undo-history ] &&
[ -d ~/.ssh ] &&
[ -d ~/projects ] &&
[ "$(stat -c %a ~/.ssh)" = "700" ] &&
[ "$(stat -c %a ~/downloads)" = "755" ]
'

View file

@ -1,23 +0,0 @@
test_description='create folders'
. '../test-lib.bash'
test_expect_success 'run' '
run_dotbot <<EOF
- create:
- ~/somedir
- ~/nested/somedir
EOF
'
test_expect_success 'test' '
[ -d ~/somedir ] &&
[ -d ~/nested/somedir ]
'
test_expect_success 'run 2' '
run_dotbot <<EOF
- create:
- ~/somedir
- ~/nested/somedir
EOF
'

View file

@ -1,59 +0,0 @@
test_description='defaults setting works'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "apple" > ${DOTFILES}/f &&
echo "grape" > ~/f &&
ln -s ~/f ~/.f &&
ln -s /nowhere ~/.g
'
test_expect_failure 'run-fail' '
run_dotbot <<EOF
- link:
~/.f: f
EOF
'
test_expect_failure 'test-fail' '
grep "apple" ~/.f
'
test_expect_success 'run' '
run_dotbot <<EOF
- defaults:
link:
relink: true
- link:
~/.f: f
EOF
'
test_expect_success 'test' '
grep "apple" ~/.f
'
test_expect_success 'run-fail 2' '
run_dotbot <<EOF
- clean: ["~"]
EOF
'
test_expect_failure 'test-fail 2' '
! test -h ~/.g
'
test_expect_success 'run 2' '
run_dotbot <<EOF
- defaults:
clean:
force: true
- clean: ["~"]
EOF
'
test_expect_success 'test 2' '
! test -h ~/.g
'

View file

@ -1,21 +0,0 @@
test_description='--except with multiple arguments'
. '../test-lib.bash'
test_expect_success 'setup' '
ln -s ${DOTFILES}/nonexistent ~/bad && touch ${DOTFILES}/y
'
test_expect_success 'run' '
run_dotbot --except clean shell <<EOF
- clean: ["~"]
- shell:
- echo "x" > ~/x
- link:
~/y: y
EOF
'
test_expect_success 'test' '
[ "$(readlink ~/bad | cut -d/ -f5-)" = "dotfiles/nonexistent" ] &&
! test -f ~/x && test -f ~/y
'

View file

@ -1,32 +0,0 @@
test_description='--except'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "apple" > ${DOTFILES}/x
'
test_expect_success 'run' '
run_dotbot --except link <<EOF
- shell:
- echo "pear" > ~/y
- link:
~/x: x
EOF
'
test_expect_success 'test' '
grep "pear" ~/y && ! test -f ~/x
'
test_expect_success 'run 2' '
run_dotbot --except shell <<EOF
- shell:
- echo "pear" > ~/z
- link:
~/x: x
EOF
'
test_expect_success 'test' '
grep "apple" ~/x && ! test -f ~/z
'

View file

@ -1,32 +0,0 @@
test_description='test exit on failure'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "apple" > ${DOTFILES}/f1 &&
echo "orange" > ${DOTFILES}/f2 &&
echo "pineapple" > ${DOTFILES}/f3
'
test_expect_failure 'run_case1' '
run_dotbot -x <<EOF
- shell:
- "this_is_not_a_command"
- link:
~/f1:
EOF
'
test_expect_failure 'run_case2' '
run_dotbot -x <<EOF
- link:
~/f2:
- shell:
- "this_is_not_a_command"
- link:
~/f3:
EOF
'
test_expect_success 'test' '
[[ ! -f ~/f1 ]] && [[ -f ~/f2 ]] && [[ ! -f ~/f3 ]]
'

View file

@ -1,60 +0,0 @@
test_description='can find python executable with different names'
. '../test-lib.bash'
# the test machine needs to have a binary named `python`
test_expect_success 'setup' '
mkdir ~/tmp_bin &&
(
IFS=:
for p in $PATH; do
if [ -d $p ]; then
find $p -maxdepth 1 -mindepth 1 -exec sh -c \
'"'"'ln -sf {} $HOME/tmp_bin/$(basename {})'"'"' \;
fi
done
) &&
rm -f ~/tmp_bin/python &&
rm -f ~/tmp_bin/python2 &&
rm -f ~/tmp_bin/python3
'
test_expect_failure 'run' '
PATH="$HOME/tmp_bin" run_dotbot <<EOF
[]
EOF
'
test_expect_success 'setup 2' '
touch ~/tmp_bin/python &&
chmod +x ~/tmp_bin/python &&
cat >> ~/tmp_bin/python <<EOF
#!$HOME/tmp_bin/bash
exec $(command -v python)
EOF
'
test_expect_success 'run 2' '
PATH="$HOME/tmp_bin" run_dotbot <<EOF
[]
EOF
'
test_expect_success 'setup 3' '
mv ~/tmp_bin/python ~/tmp_bin/python2
'
test_expect_success 'run 3' '
PATH="$HOME/tmp_bin" run_dotbot <<EOF
[]
EOF
'
test_expect_success 'setup 4' '
mv ~/tmp_bin/python2 ~/tmp_bin/python3
'
test_expect_success 'run 4' '
PATH="$HOME/tmp_bin" run_dotbot <<EOF
[]
EOF
'

View file

@ -1,20 +0,0 @@
test_description='linking canonicalizes path by default'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "apple" > ${DOTFILES}/f &&
ln -s dotfiles dotfiles-symlink
'
test_expect_success 'run' '
cat > "${DOTFILES}/${INSTALL_CONF}" <<EOF
- link:
~/.f:
path: f
EOF
${DOTBOT_EXEC} -c dotfiles-symlink/${INSTALL_CONF}
'
test_expect_success 'test' '
[ "$(readlink ~/.f | cut -d/ -f5-)" = "dotfiles/f" ]
'

View file

@ -1,26 +0,0 @@
test_description='link uses destination if source is null'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "apple" > ${DOTFILES}/f &&
echo "grape" > ${DOTFILES}/fd
'
test_expect_success 'run' '
run_dotbot <<EOF
- link:
~/f:
~/.f:
~/fd:
force: false
~/.fd:
force: false
EOF
'
test_expect_success 'test' '
grep "apple" ~/f &&
grep "apple" ~/.f &&
grep "grape" ~/fd &&
grep "grape" ~/.fd
'

View file

@ -1,17 +0,0 @@
test_description='link expands user in target'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "apple" > ~/f
'
test_expect_success 'run' '
run_dotbot <<EOF
- link:
~/g: ~/f
EOF
'
test_expect_success 'test' '
grep "apple" ~/g
'

View file

@ -1,20 +0,0 @@
test_description='link expands environment variables in extended config syntax'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "grape" > ${DOTFILES}/h
'
test_expect_success 'run' '
export APPLE="h" &&
run_dotbot <<EOF
- link:
~/.i:
path: \$APPLE
relink: true
EOF
'
test_expect_success 'test' '
grep "grape" ~/.i
'

View file

@ -1,18 +0,0 @@
test_description='link expands environment variables in source'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "grape" > ${DOTFILES}/h
'
test_expect_success 'run' '
export APPLE