diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..cdbc48a --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,29 @@ +stages: + - build + - test + +build:image: + image: docker:git + stage: build + services: + - docker:dind + script: + - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com + - docker build -t registry.gitlab.com/danielsiepmann/neotags . + - docker push registry.gitlab.com/danielsiepmann/neotags:latest + # only: + # - master + +lint:coding-guideline: + image: 'registry.gitlab.com/danielsiepmann/neotags:latest' + stage: test + script: + - pep8 . + +test: + image: 'registry.gitlab.com/danielsiepmann/neotags:latest' + stage: test + before_script: + - cd rplugin + script: + - python -m unittest test.test_neotags diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e1406b4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3 + +MAINTAINER Daniel Siepmann +LABEL Description="This image should provide environment to lint neotags" Vendor="DanielSiepmann" Version="1.0" + +# Install dependencies +RUN pip install --upgrade pip +RUN pip install --no-cache-dir pep8 neovim pyfakefs diff --git a/readme.rst b/readme.rst index 6068f46..995af81 100644 --- a/readme.rst +++ b/readme.rst @@ -38,3 +38,14 @@ The following options are available: - ``let g:neotags_logging = 0`` Defines whether to log anything to vims messages. + +Development +=========== + +Install dependencies: + +- ``pip install pyfakefs`` + +Run tests: + +``cd rplugin && python -m unittest test.test_neotags`` diff --git a/rplugin/python3/__init__.py b/rplugin/python3/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rplugin/python3/neotags.py b/rplugin/python3/neotags.py index b2b7f5e..44ec7a6 100644 --- a/rplugin/python3/neotags.py +++ b/rplugin/python3/neotags.py @@ -12,6 +12,8 @@ class NeotagsPlugin(object): def __init__(self, nvim): self.nvim = nvim # Perhaps debugging settings? + # Like autotags, configure regex compared to filename to ignore, e.g. + # fugitive buffers, git commits, etc. self.options = { 'tags_filename': 'tags', 'ctags_cmd': 'ctags', diff --git a/rplugin/test/__init__.py b/rplugin/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rplugin/test/templates/example.py b/rplugin/test/templates/example.py new file mode 100644 index 0000000..f271883 --- /dev/null +++ b/rplugin/test/templates/example.py @@ -0,0 +1,7 @@ +class SomeClass(object): + + def __init__(self): + pass + + def method(self): + pass diff --git a/rplugin/test/templates/expected_tags b/rplugin/test/templates/expected_tags new file mode 100644 index 0000000..d086ef2 --- /dev/null +++ b/rplugin/test/templates/expected_tags @@ -0,0 +1,6 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 0.0.0 /4f741b9/ diff --git a/rplugin/test/templates/tags b/rplugin/test/templates/tags new file mode 100644 index 0000000..b2352b5 --- /dev/null +++ b/rplugin/test/templates/tags @@ -0,0 +1,9 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 0.0.0 /4f741b9/ +SomeClass example.py /^class SomeClass(object):$/;" kind:class line:1 language:Python inherits:object access:public end:7 +__init__ example.py /^ def __init__(self):$/;" kind:member line:3 language:Python scope:class:SomeClass access:public signature:(self) end:5 +method example.py /^ def method(self):$/;" kind:member line:6 language:Python scope:class:SomeClass access:public signature:(self) end:7 diff --git a/rplugin/test/test_neotags.py b/rplugin/test/test_neotags.py new file mode 100644 index 0000000..25e5b26 --- /dev/null +++ b/rplugin/test/test_neotags.py @@ -0,0 +1,130 @@ +from unittest.mock import Mock +from unittest.mock import MagicMock +from pyfakefs import fake_filesystem_unittest +import neovim +import os + +from python3.neotags import NeotagsPlugin + + +class TestNeotagsPlugin(fake_filesystem_unittest.TestCase): + + def setUp(self): + self.templates_dirname = os.path.join( + os.path.dirname(__file__), + 'templates' + ) + self.setUpPyfakefs() + self.plugin = NeotagsPlugin(Mock(neovim.api.nvim)) + + def test_default_options(self): + self.assertEqual('ctags', self.plugin.options['ctags_cmd']) + self.assertEqual('tags', self.plugin.options['tags_filename']) + self.assertEqual(False, self.plugin.options['logging']) + + def test_default_options(self): + self.plugin.nvim.configure_mock(vars={}) + self.plugin.nvim.vars['neotags_tags_filename'] = 'new_tags' + self.plugin.nvim.vars['neotags_ctags_cmd'] = 'new_ctags' + self.plugin.nvim.vars['neotags_logging'] = True + + self.plugin.update_settings() + + self.assertEqual('new_tags', self.plugin.options['tags_filename']) + self.assertEqual('new_ctags', self.plugin.options['ctags_cmd']) + self.assertEqual(True, self.plugin.options['logging']) + + def test_debug_logs_to_nvim_when_logging_is_active(self): + self.plugin.options['logging'] = True + self.plugin.nvim.out_write = MagicMock() + + self.plugin.debug('some message') + self.plugin.nvim.out_write.assert_called_once_with( + "neotags > some message\n" + ) + + def test_debug_does_not_log_to_nvim_when_logging_is_inactive(self): + self.plugin.options['logging'] = False + self.plugin.nvim.out_write = MagicMock() + + self.plugin.debug('some message') + self.plugin.nvim.out_write.assert_not_called() + + def test_error_logs_to_nvim_when_logging_is_active(self): + self.plugin.options['logging'] = True + self.plugin.nvim.err_write = MagicMock() + + self.plugin.error('some message') + self.plugin.nvim.err_write.assert_called_once_with( + "neotags > some message\n" + ) + + def test_error_does_not_log_to_nvim_when_logging_is_inactive(self): + self.plugin.options['logging'] = False + self.plugin.nvim.err_write = MagicMock() + + self.plugin.error('some message') + self.plugin.nvim.err_write.assert_not_called() + + def test_get_tags_file_in_same_folder(self): + filename = '/var/data/some_file.py' + expected_tags_filename = '/var/data/tags' + + self.fs.CreateFile(filename) + self.fs.CreateFile(expected_tags_filename) + + self.assertEqual( + expected_tags_filename, + self.plugin.get_tags_file(filename) + ) + + def test_get_tags_file_in_parent_folder(self): + filename = '/var/data/some_file.py' + expected_tags_filename = '/var/tags' + + self.fs.CreateFile(filename) + self.fs.CreateFile(expected_tags_filename) + + self.assertEqual( + expected_tags_filename, + self.plugin.get_tags_file(filename) + ) + + def test_get_tags_file_in_root_folder(self): + filename = '/var/data/some_file.py' + expected_tags_filename = '/tags' + + self.fs.CreateFile(filename) + self.fs.CreateFile(expected_tags_filename) + + self.assertEqual( + expected_tags_filename, + self.plugin.get_tags_file(filename) + ) + + def test_strips_existing_tags(self): + filename = '/var/data/example.py' + tags_file = '/var/data/tags' + expected_tags_file = os.path.join( + self.templates_dirname, + 'expected_tags' + ) + + self.copyRealFile( + expected_tags_file, + expected_tags_file + ) + self.copyRealFile( + os.path.join(self.templates_dirname, 'example.py'), + os.path.join(os.path.dirname(filename), os.path.basename(filename)) + ) + self.copyRealFile( + os.path.join(self.templates_dirname, 'tags'), + os.path.join( + os.path.dirname(tags_file), os.path.basename(tags_file) + ) + ) + + self.plugin.strip_existing_tags(tags_file, os.path.basename(filename)) + with open(tags_file) as f, open(expected_tags_file) as e: + self.assertEqual(e.read(), f.read())