diff --git a/test/test_clean.py b/test/test_clean.py index 02060c5..aa21c70 100644 --- a/test/test_clean.py +++ b/test/test_clean.py @@ -21,9 +21,7 @@ class MissingTestCase(DotbotTestCase): def test_ignores_outside_linking(self): """ clean ignores files linking outside dotfiles directory """ self.add_symlink('f') - - with open(os.path.join(self.home_dir, 'g'), 'w') as g: - g.write('') + self.add_home_file('g') os.symlink(os.path.join(self.home_dir, 'g'), os.path.join(self.home_dir, '.g')) self.run_dotbot(config='- clean: ["~"]') diff --git a/test/test_config.py b/test/test_config.py index 7a25e97..0ad61a9 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -4,7 +4,9 @@ from utils import DotbotTestCase class ConfigTestCase(DotbotTestCase): def test_blank_config_allowed(self): + """ blank config allowed """ self.run_dotbot(config='[]') def test_empty_config_not_allowed(self): + """ empty config disallowed """ self.assertRaises(SystemExit, self.run_dotbot, skip_config=True) diff --git a/test/test_link.py b/test/test_link.py new file mode 100644 index 0000000..ca7be73 --- /dev/null +++ b/test/test_link.py @@ -0,0 +1,92 @@ +import os +from utils import DotbotTestCase + + +class LinkTestCase(DotbotTestCase): + def test_var_expansion_source(self): + """ link expands environment variables in source """ + self.add_file('h') + os.environ['DB_TEST_ENV'] = 'h' + + self.run_dotbot([{'link': + {'~/.i': '$DB_TEST_ENV'} + }]) + + self.assertIsLinked('.i', dotbot_path='h') + + + def test_var_expansion_target(self): + """ link expands environment variables in target """ + self.add_file('f') + self.add_file('h') + os.environ['DB_TEST_DIR'] = '.config' + os.environ['DB_TEST_FILE'] = 'g' + if 'DB_UNSET_VAR' in os.environ: + del os.environ['DB_UNSET_VAR'] + + self.run_dotbot([{'link': { + '~/${DB_TEST_DIR}/$DB_TEST_FILE': {'path': 'f', + 'create': True}, + '~/$DB_UNSET_VAR': 'h' + }}]) + + self.assertIsLinked('.config/g', 'f') + self.assertIsLinked('$DB_UNSET_VAR', 'h') + + + def test_leaves_unset_vars(self): + """ link leaves unset environment variables """ + if 'DB_UNSET_VAR' in os.environ: + del os.environ['DB_UNSET_VAR'] + self.add_file('$DB_UNSET_VAR') + + self.run_dotbot([{'link': {'~/.f': '$DB_UNSET_VAR'}}]) + + self.assertIsLinked('.f', '$DB_UNSET_VAR') + + + def test_force_overwrite_symlinked_directory(self): + """ force overwrites symlinked directory """ + self.add_dirs('dir') + os.makedirs(os.path.join(self.home_dir, 'dir')) + os.symlink(os.path.join(self.home_dir, 'dir'), + os.path.join(self.home_dir, '.dir')) + + self.run_dotbot([{'link': {'~/.dir': {'path': 'dir', 'force': True}}}]) + + self.assertIsLinked(path='.dir', dotbot_path='dir') + + + def test_leaves_file(self): + """ relink does not overwrite file """ + self.add_file('f') + self.add_home_file('.f') + + self.assertRaises(SystemExit, self.run_dotbot, + [{'link': {'~/.f': 'f'}}]) + + self.assertNotLinked(path='.f', dotbot_path='f') + + + def test_relink_no_overwrite(self): + """ relink does not overwrite file """ + self.add_file('f') + self.add_home_file('.f') + + self.assertRaises(SystemExit, self.run_dotbot, + [{'link': {'~/.f': {'path': 'f', 'relink': True}}}]) + + self.assertNotLinked(path='.f', dotbot_path='f') + + + def test_relink_overwrites_symlink(self): + """ relink overwrites symlink """ + self.add_file('f') + self.add_home_file('f') + os.symlink(os.path.join(self.home_dir, 'f'), + os.path.join(self.home_dir, '.f')) + + + self.run_dotbot([{'link':{'~/.f': {'path': 'f', 'relink': True}}}]) + + self.assertIsLinked('.f', dotbot_path='f') diff --git a/test/test_shell.py b/test/test_shell.py new file mode 100644 index 0000000..9df44f6 --- /dev/null +++ b/test/test_shell.py @@ -0,0 +1,29 @@ +import os +from utils import DotbotTestCase, mock + + +class ShellTestCase(DotbotTestCase): + def test_stdout_disabled_default(self): + """ shell command stdout disabled by default """ + with mock.patch('dotbot.executor.commandrunner.subprocess.call', + return_value=0) as mock_call: + self.run_dotbot([{'shell': [ + {'command': 'echo test'} + ]}]) + assert mock_call.called + + args, kwargs = mock_call.call_args + self.assertTrue('stdout' in kwargs and kwargs['stdout'] is not None) + + + def test_stdout_works(self): + """ shell command stdout works """ + with mock.patch('dotbot.executor.commandrunner.subprocess.call', + return_value=0) as mock_call: + self.run_dotbot([{'shell': [ + {'command': 'echo test', 'stdout': True} + ]}]) + assert mock_call.called + + args, kwargs = mock_call.call_args + self.assertTrue('stdout' in kwargs and kwargs['stdout'] is None) diff --git a/test/utils.py b/test/utils.py index c90d55f..0473fac 100644 --- a/test/utils.py +++ b/test/utils.py @@ -24,6 +24,7 @@ import dotbot import tempfile import unittest import shlex +import yaml try: from StringIO import StringIO @@ -59,22 +60,42 @@ class DotbotTestCase(unittest.TestCase): with open(os.path.join(self.dotbot_dir, filename), 'w') as f: f.write(contents) + def add_home_file(self, filename, contents=""): + """ Create a file in the temporary home_dir. Optionally with content """ + with open(os.path.join(self.home_dir, filename), 'w') as f: + f.write(contents) + def add_dirs(self, path): """ Create directories within the temporary dotbot_dir. Acts like ``mkdir -p``. Path is relative to the dotbot dir """ os.makedirs(os.path.join(self.dotbot_dir, path)) - def add_symlink(self, path): - """ Creates a symlink from ``self.home_dir``/path to ``self.dotbot_dir``/path """ - os.symlink(os.path.join(self.dotbot_dir, path), os.path.join(self.home_dir, path)) + def add_home_dirs(self, path): + """ Create directories within the temporary home_dir. Acts like ``mkdir -p``. Path is relative to the + home dir """ + os.makedirs(os.path.join(self.home_dir, path)) - def assertIsLinked(self, path): + def add_symlink(self, path, dotbot_path=None): + """ Creates a symlink from ``self.home_dir``/path to ``self.dotbot_dir``/dotbot_path. + If dotbot_path is None, path will be used for home_dir and dotbot_dir """ + dotbot_path = path if dotbot_path is None else dotbot_path + os.symlink(os.path.join(self.dotbot_dir, dotbot_path), os.path.join(self.home_dir, path)) + + def assertIsLinked(self, path, dotbot_path=None): """ Asserts that the given ``path`` in self.home_dir is symlinked to the corresponding ``path`` in self.dotbot_dir """ + dotbot_path = path if dotbot_path is None else dotbot_path self.assertTrue(os.path.islink(os.path.join(self.home_dir, path))) - self.assertEqual(os.stat(os.path.join(self.dotbot_dir, path)), + self.assertEqual(os.stat(os.path.join(self.dotbot_dir, dotbot_path)), os.stat(os.path.join(self.home_dir, path))) + def assertNotLinked(self, path, dotbot_path=None): + """ Asserts that the given ``path`` in self.home_dir is symlinked to the corresponding ``path`` + in self.dotbot_dir """ + dotbot_path = path if dotbot_path is None else dotbot_path + self.assertNotEqual(os.stat(os.path.join(self.dotbot_dir, dotbot_path)), + os.stat(os.path.join(self.home_dir, path))) + def assertDoesNotExist(self, path): """ Asserts the given ``path`` in self.home_dir does not exist """ self.assertFalse(os.path.exists(os.path.join(self.home_dir, path)) or @@ -97,11 +118,14 @@ class DotbotTestCase(unittest.TestCase): if not skip_config: with open(self.config_file, 'w') as f: - f.write(config) + if not isinstance(config, str): + f.write(yaml.dump(config, default_flow_style=False)) + else: + f.write(config) base_args = [ 'dotbot', - '--base-directory', self.tempdir, + '--base-directory', self.dotbot_dir, '--config-file', self.config_file, ] @@ -109,17 +133,22 @@ class DotbotTestCase(unittest.TestCase): old_stdout, sys.stdout = sys.stdout, StringIO() old_stderr, sys.stderr = sys.stderr, StringIO() old_argv, sys.argv = sys.argv, base_args + shlex.split(args) + old_environ = os.environ.copy() try: - dotbot.cli.main() + dotbot.cli.main() finally: os.environ['HOME'] = old_home out, sys.stdout = sys.stdout.getvalue(), old_stdout err, sys.stderr = sys.stderr.getvalue(), old_stderr sys.argv = old_argv - print("\nDotbot Output:") - print('out:\n', out) - print('err:\n', err) + os.environ.clear() + os.environ.update(old_environ) + + if int(os.environ.get('DEBUG', '0')): + print("\nDotbot Output:") + print('out:\n', out) + print('err:\n', err) return out, err