diff --git a/setup.cfg b/setup.cfg index 45580a9..9f2b4c9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,7 +28,7 @@ install_requires = colcon-core>=0.5.6 packages = find: tests_require = - flake8 + flake8>=3.6.0 flake8-blind-except flake8-builtins flake8-class-newline @@ -38,10 +38,10 @@ tests_require = flake8-import-order flake8-quotes pep8-naming - pyenchant pylint pytest pytest-cov + scspell3k>=2.2 zip_safe = true [options.package_data] @@ -51,6 +51,11 @@ colcon_lcov_result.verb.configuration = lcovrc colcon_core.verb = lcov-result = colcon_lcov_result.verb.lcov_result:LcovResultVerb +[tool:pytest] +markers = + flake8 + linter + [flake8] import-order-style = google max-line-length = 99 diff --git a/test/spell_check.words b/test/spell_check.words index ffc2d82..f9bcbee 100644 --- a/test/spell_check.words +++ b/test/spell_check.words @@ -1,17 +1,29 @@ -CMake +ament +apache +cmake colcon -filt +demangle gcno gcov genhtml -html +iterdir lcov lcovrc +linter +nargs +nofilt noqa -pragma +pathlib +pkgs +plugin +pydocstyle +pytest +returncode rtype -stderr -stdout -str +scspell +setuptools +staticmethod +thomas tracefile tracefiles +zerocounters diff --git a/test/test_copyright_license.py b/test/test_copyright_license.py index 01d0c85..dffe460 100644 --- a/test/test_copyright_license.py +++ b/test/test_copyright_license.py @@ -4,8 +4,11 @@ from pathlib import Path import sys +import pytest -def test_copyright_licence(): + +@pytest.mark.linter +def test_copyright_license(): missing = check_files([Path(__file__).parents[1]]) assert not len(missing), \ 'In some files no copyright / license line was found' @@ -25,8 +28,8 @@ def check_files(paths): if not content: continue lines = content.splitlines() - has_copyright = \ - any(line for line in lines if line.startswith('# Copyright')) + has_copyright = any(filter( + lambda line: line.startswith('# Copyright'), lines)) has_license = \ '# Licensed under the Apache License, Version 2.0' in lines if not has_copyright or not has_license: diff --git a/test/test_flake8.py b/test/test_flake8.py index 48eece0..5ff3e4d 100644 --- a/test/test_flake8.py +++ b/test/test_flake8.py @@ -5,21 +5,27 @@ from pathlib import Path import sys -from flake8 import LOG -from flake8.api.legacy import get_style_guide +import pytest -# avoid debug and info messages from flake8 internals -LOG.setLevel(logging.WARN) +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + from flake8.api.legacy import get_style_guide + # avoid debug / info / warning messages from flake8 internals + logging.getLogger('flake8').setLevel(logging.ERROR) + + # for some reason the pydocstyle logger changes to an effective level of 1 + # set higher level to prevent the output to be flooded with debug messages + logging.getLogger('pydocstyle').setLevel(logging.WARNING) -def test_flake8(): style_guide = get_style_guide( - ignore=['D100', 'D104'], + extend_ignore=['D100', 'D104'], show_source=True, ) style_guide_tests = get_style_guide( - ignore=['D100', 'D101', 'D102', 'D103', 'D104', 'D105', 'D107'], + extend_ignore=['D100', 'D101', 'D102', 'D103', 'D104', 'D105', 'D107'], show_source=True, ) @@ -38,10 +44,11 @@ def test_flake8(): if total_errors: # pragma: no cover # output summary with per-category counts print() - report._application.formatter.show_statistics(report._stats) - print( - 'flake8 reported {total_errors} errors' - .format_map(locals()), file=sys.stderr) - - assert not report.total_errors, \ - 'flake8 reported {total_errors} errors'.format_map(locals()) + if report.total_errors: + report._application.formatter.show_statistics(report._stats) + if report_tests.total_errors: + report_tests._application.formatter.show_statistics( + report_tests._stats) + print(f'flake8 reported {total_errors} errors', file=sys.stderr) + + assert not total_errors, f'flake8 reported {total_errors} errors' diff --git a/test/test_spell_check.py b/test/test_spell_check.py index e60a791..677efdc 100644 --- a/test/test_spell_check.py +++ b/test/test_spell_check.py @@ -1,45 +1,59 @@ -# Copyright 2016-2018 Dirk Thomas +# Copyright 2016-2019 Dirk Thomas # Licensed under the Apache License, Version 2.0 from pathlib import Path -from pylint.lint import Run import pytest - spell_check_words_path = Path(__file__).parent / 'spell_check.words' -def test_spell_check(): +@pytest.fixture(scope='module') +def known_words(): global spell_check_words_path + return spell_check_words_path.read_text().splitlines() - try: - import enchant # noqa: F401 - except ImportError: # pragma: no cover - pytest.skip( - "Skipping spell checking tests since 'enchant' was not found") - - try: - Run([ - '--disable=all', - '--enable=spelling', - '--spelling-dict=en_US', - '--ignore-comments=no', - '--spelling-private-dict-file=' + str(spell_check_words_path), - str(Path(__file__).parents[1] / 'colcon_lcov_result'), - ] + [ - str(p) for p in - (Path(__file__).parents[1] / 'test').glob('**/*.py') - ]) - except SystemExit as e: - assert not e.code, 'Some spell checking errors' - else: - assert False, 'The pylint API is supposed to raise a SystemExit' - - -def test_spell_check_word_list(): - global spell_check_words_path - with spell_check_words_path.open('r') as h: - lines = h.read().splitlines() - assert lines == sorted(lines), \ + +@pytest.mark.linter +def test_spell_check(known_words): + from scspell import Report + from scspell import SCSPELL_BUILTIN_DICT + from scspell import spell_check + + source_filenames = [Path(__file__).parents[1] / 'setup.py'] + \ + list( + (Path(__file__).parents[1] / 'colcon_lcov_result') + .glob('**/*.py')) + \ + list((Path(__file__).parents[1] / 'test').glob('**/*.py')) + + for source_filename in sorted(source_filenames): + print('Spell checking:', source_filename) + + # check all files + report = Report(known_words) + spell_check( + [str(p) for p in source_filenames], base_dicts=[SCSPELL_BUILTIN_DICT], + report_only=report, additional_extensions=[('', 'Python')]) + + unknown_word_count = len(report.unknown_words) + assert unknown_word_count == 0, \ + f'Found {unknown_word_count} unknown words: ' + \ + ', '.join(sorted(report.unknown_words)) + + unused_known_words = set(known_words) - report.found_known_words + unused_known_word_count = len(unused_known_words) + assert unused_known_word_count == 0, \ + f'{unused_known_word_count} words in the word list are not used: ' + \ + ', '.join(sorted(unused_known_words)) + + +@pytest.mark.linter +def test_spell_check_word_list_order(known_words): + assert known_words == sorted(known_words), \ 'The word list should be ordered alphabetically' + + +@pytest.mark.linter +def test_spell_check_word_list_duplicates(known_words): + assert len(known_words) == len(set(known_words)), \ + 'The word list should not contain duplicates'