diff options
Diffstat (limited to 'test/test_lint.py')
-rw-r--r-- | test/test_lint.py | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/test/test_lint.py b/test/test_lint.py new file mode 100644 index 0000000..202245c --- /dev/null +++ b/test/test_lint.py @@ -0,0 +1,472 @@ +from pathlib import Path + +import pytest +from rpmlint.lint import Lint +from rpmlint.spellcheck import ENCHANT + +from Testing import ( + get_tested_path, HAS_CHECKBASHISMS, HAS_DASH, HAS_ENGLISH_DICTIONARY, HAS_RPMDB, + TEST_CONFIG +) + +TEST_RPMLINTRC = get_tested_path('configs/testing2-rpmlintrc') + +options_preset = { + 'config': TEST_CONFIG, + 'verbose': False, + 'strict': False, + 'permissive': False, + 'print_config': False, + 'explain': '', + 'rpmfile': '', + 'rpmlintrc': False, + 'installed': '', + 'time_report': False, + 'profile': False, + 'ignore_unused_rpmlintrc': False, + 'checks': None +} + +basic_tests = [ + 'AlternativesCheck', + 'AppDataCheck', + 'BinariesCheck', + 'BuildRootAndDateCheck', + 'ConfigFilesCheck', + 'DBusPolicyCheck', + 'DuplicatesCheck', + 'DocCheck', + 'ErlangCheck', + 'FHSCheck', + 'FilesCheck', + 'IconSizesCheck', + 'I18NCheck', + 'LibraryDependencyCheck', + 'LogrotateCheck', + 'MenuCheck', + 'MenuXDGCheck', + 'MixedOwnershipCheck', + 'PkgConfigCheck', + 'PostCheck', + 'PythonCheck', + 'SignatureCheck', + 'SourceCheck', + 'SpecCheck', + 'TagsCheck', + 'ZipCheck', + 'ZyppSyntaxCheck', +] + + +def _remove_except_zip(dictionary): + """ + In order to not lie in coverage redux the test run on the + tests to just ZipCheck which has full coverage + """ + return {'ZipCheck': dictionary['ZipCheck']} + + +def test_cases_loading(): + linter = Lint(options_preset) + assert list(linter.checks.keys()) == basic_tests + + +def test_configoutput(capsys): + additional_options = { + 'print_config': True, + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert out + assert 'Vendor = "Fedora Project"' in out + assert 're.compile' not in out + assert not err + + +def test_time_report(capsys): + additional_options = { + 'time_report': True, + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert out + assert 'Duration' in out + assert 'TOTAL' in out + + +def test_explain_unknown(capsys): + message = ['bullcrap'] + additional_options = { + 'explain': message, + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert 'bullcrap:\nUnknown message' in out + assert not err + + +def test_explain_known(capsys): + message = ['infopage-not-compressed'] + additional_options = { + 'explain': message, + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert 'This info page is not compressed' in out + assert 'Unknown message' not in out + assert not err + + +@pytest.mark.parametrize('configs', [ + # Message defined in configs/Fedora/warn-on-functions.toml + (Path('configs/Fedora/warn-on-functions.toml'), False), + (Path('configs/Fedora/scoring.toml'), True), +]) +def test_explain_known_warn_on_function(capsys, configs): + extraconfig, unknown = configs + message = ['crypto-policy-non-compliance-openssl'] + additional_options = { + 'explain': message, + 'config': [extraconfig], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + + assert ('Unknown message' in out) == unknown + assert not err + + +def test_explain_with_unknown(capsys): + message = ['infopage-not-compressed', 'blablablabla'] + additional_options = { + 'explain': message, + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert 'This info page is not compressed' in out + assert 'Unknown message' in out + assert not err + + +def test_explain_no_binary_from_cfg(capsys): + """ + Test that 'explain' option can read updated description from configuration. + + Test 'no-binary' error that is defined in CheckBinaries.toml file by + default and then it's overridden to the custom values defined in + 'descriptions.config' file. + """ + additional_options = { + 'config': [get_tested_path('configs/descriptions.config')], + 'explain': ['no-binary'] + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + + # the new string is present and the old one is not + assert 'A new text for no-binary error.' in out + assert 'The package should be of the noarch architecture' not in out + assert not err + + +def test_explain_non_standard_dir_from_cfg(capsys): + """ + Test that 'explain' option can read updated description from configuration. + + Test 'non-standard-dir-in-usr' error that is special because the original + description is not defined in FHSCheck.toml but in FHSCheck.py. Then it's + supposed to be overridden to the custom values defined in + 'descriptions.config' file. + """ + additional_options = { + 'config': [get_tested_path('configs/descriptions.config')], + 'explain': ['non-standard-dir-in-usr'] + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + + assert 'A new text for non-standard-dir-in-usr error.' in out + assert 'Your package is creating a non-standard subdirectory in /usr' not in out + assert not err + + +@pytest.mark.skipif(not ENCHANT, reason='Optional dependency pyenchant not install') +@pytest.mark.skipif(not HAS_ENGLISH_DICTIONARY, reason='Missing English dictionary') +@pytest.mark.parametrize('packages', [Path('test/binary/non-fhs-0-0.x86_64.rpm')]) +def test_descriptions_from_config(capsys, packages): + """ + Test that rpmlint updates 'parametrized' descriptions from configuration. + + We test that "parametrized" errors (non-standard-dir-in-usr + and non-standard-dir-in-var) were overridden by values from + 'descriptions.config' file. + """ + additional_options = { + 'config': [get_tested_path('configs/descriptions.config')], + 'rpmfile': [packages] + } + options_preset['verbose'] = True + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + + assert 'A new text for non-standard-dir-in-usr error.' in out + assert 'A new text for non-standard-dir-in-var error.' in out + + assert 'Your package is creating a non-standard subdirectory in /usr' \ + not in out + assert 'Your package is creating a non-standard subdirectory in /var' \ + not in out + assert not err + + +@pytest.mark.parametrize('packages', [Path('test/source/wrongsrc-0-0.src.rpm')]) +def test_run_single(capsys, packages): + additional_options = { + 'rpmfile': [packages], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.checks = _remove_except_zip(linter.checks) + linter.run() + out, err = capsys.readouterr() + assert '1 packages and 0 specfiles checked' in out + assert not err + + +@pytest.mark.skipif(not HAS_RPMDB, reason='No RPM database present') +@pytest.mark.parametrize('packages', [Path('test/source/wrongsrc-0-0.src.rpm')]) +def test_run_installed(capsys, packages): + # load up 1 normal path file and 2 installed packages + additional_options = { + 'rpmfile': [packages], + 'installed': ['binutils', 'rpm'], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.checks = _remove_except_zip(linter.checks) + linter.run() + out, err = capsys.readouterr() + assert '3 packages and 0 specfiles checked' in out + assert not err + + +@pytest.mark.parametrize('packages', [Path('test/binary/ruby2.5-rubygem-rubyzip-testsuite-1.2.1-0.x86_64.rpm')]) +def test_run_strict(capsys, packages): + """ + Test if we convert warning to error + """ + additional_options = { + 'rpmfile': [packages], + 'strict': True, + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.checks = _remove_except_zip(linter.checks) + linter.run() + out, err = capsys.readouterr() + assert 'W: unable-to-read-zip' not in out + assert 'E: unable-to-read-zip' in out + assert not err + + +@pytest.mark.skipif(not HAS_RPMDB, reason='No RPM database present') +def test_run_installed_not_present(capsys): + additional_options = { + 'rpmfile': [], + 'installed': ['non-existing-package'], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.checks = _remove_except_zip(linter.checks) + linter.run() + out, err = capsys.readouterr() + assert '0 packages and 0 specfiles checked' in out + assert 'there is no installed rpm' in err + assert 'There are no files to process' in err + + +@pytest.mark.skipif(not HAS_RPMDB, reason='No RPM database present') +def test_run_installed_and_no_files(capsys): + additional_options = { + 'rpmfile': [], + 'installed': ['rpm'], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.checks = _remove_except_zip(linter.checks) + linter.run() + out, err = capsys.readouterr() + assert '1 packages and 0 specfiles checked' in out + assert not err + + +@pytest.mark.skipif(not HAS_RPMDB, reason='No RPM database present') +def test_header_information(capsys): + additional_options = { + 'rpmfile': [], + 'installed': ['python3-rpm'], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.checks = _remove_except_zip(linter.checks) + linter.run() + out, err = capsys.readouterr() + assert 'packages: 1' in out + + +@pytest.mark.skipif(not HAS_CHECKBASHISMS, reason='Optional dependency checkbashisms not installed') +@pytest.mark.skipif(not HAS_DASH, reason='Optional dependency dash not installed') +@pytest.mark.parametrize('packages', [list(Path('test').glob('*/*.rpm'))]) +@pytest.mark.parametrize('configs', [list(Path('configs').glob('*/*.toml'))]) +@pytest.mark.no_cover +def test_run_full_rpm(capsys, packages, configs): + number_of_pkgs = len(packages) + additional_options = { + 'rpmfile': packages, + } + options_preset['config'] = configs + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert f'{number_of_pkgs} packages and 0 specfiles checked' in out + # we convert the err as we don't care about errors from missing + # spellchecking dictionaries -> we have to ignore it + err_reduced = [a for a in err.split('\n') if not a.startswith('(none): W: unable to load spellchecking dictionary for') and a != ''] + # also we can find out signatures are wrong because of the other distros + # could've signed it + err_reduced = [a for a in err_reduced if not a.startswith('Error checking signature of')] + assert not err_reduced + + +@pytest.mark.skipif(not HAS_CHECKBASHISMS, reason='Optional dependency checkbashisms not installed') +@pytest.mark.skipif(not HAS_DASH, reason='Optional dependency dash not installed') +@pytest.mark.parametrize('packages', [list(Path('test/spec').glob('*.spec'))]) +@pytest.mark.parametrize('configs', [list(Path('configs').glob('*/*.toml'))]) +@pytest.mark.no_cover +def test_run_full_specs(capsys, packages, configs): + number_of_pkgs = len(packages) + additional_options = { + 'rpmfile': packages, + } + options_preset['config'] = configs + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert f'0 packages and {number_of_pkgs} specfiles checked' in out + assert not err + + +@pytest.mark.skipif(not HAS_CHECKBASHISMS, reason='Optional dependency checkbashisms not installed') +@pytest.mark.skipif(not HAS_DASH, reason='Optional dependency dash not installed') +@pytest.mark.parametrize('packages', [Path('test/spec')]) +@pytest.mark.no_cover +def test_run_full_directory(capsys, packages): + assert packages.is_dir() + file_list = [] + for item in packages.iterdir(): + if item.is_file(): + file_list.append(item) + number_of_pkgs = len(file_list) + additional_options = { + 'rpmfile': [packages], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert f'0 packages and {number_of_pkgs} specfiles checked' in out + assert not err + + +@pytest.mark.skipif(not HAS_CHECKBASHISMS, reason='Optional dependency checkbashisms not installed') +@pytest.mark.skipif(not HAS_DASH, reason='Optional dependency dash not installed') +def test_run_empty(capsys): + linter = Lint(options_preset) + linter.run() + out, err = capsys.readouterr() + assert err + assert '0 packages and 0 specfiles checked; 0 errors, 0 warnings' in out + + +@pytest.mark.skipif(not HAS_CHECKBASHISMS, reason='Optional dependency checkbashisms not installed') +@pytest.mark.skipif(not HAS_DASH, reason='Optional dependency dash not installed') +@pytest.mark.parametrize('packages', [Path('test/rpmlintrc/single')]) +def test_run_rpmlintrc_single_dir(capsys, packages): + additional_options = { + 'rpmfile': [packages], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert not err + assert 'rpmlintrc:' in out + + +@pytest.mark.skipif(not HAS_CHECKBASHISMS, reason='Optional dependency checkbashisms not installed') +@pytest.mark.skipif(not HAS_DASH, reason='Optional dependency dash not installed') +@pytest.mark.parametrize('packages', [Path('test/rpmlintrc/multiple')]) +def test_run_rpmlintrc_multiple(capsys, packages): + additional_options = { + 'rpmfile': [packages], + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert 'rpmlintrc:' not in out + assert 'There are multiple items to be loaded for rpmlintrc' in err + assert '0 badness' in out + + +@pytest.mark.skipif(not HAS_CHECKBASHISMS, reason='Optional dependency checkbashisms not installed') +@pytest.mark.skipif(not HAS_DASH, reason='Optional dependency dash not installed') +@pytest.mark.parametrize('packages', [Path('test/rpmlintrc/single/sample.spec')]) +def test_run_rpmlintrc_single_file(capsys, packages): + additional_options = { + 'rpmfile': [packages], + 'rpmlintrc': TEST_RPMLINTRC + } + options = {**options_preset, **additional_options} + linter = Lint(options) + linter.run() + out, err = capsys.readouterr() + assert not err + assert 'rpmlintrc:' in out + assert 'E: unused-rpmlintrc-filter "I am not used"' in out + assert 'E: unused-rpmlintrc-filter "She is not used"' not in out + assert 'no-%build-section' not in out + + +@pytest.mark.skipif(not HAS_RPMDB, reason='No RPM database present') +def test_installed_package(capsys): + additional_options = { + 'installed': ['bzip2'], + 'permissive': True + } + options = {**options_preset, **additional_options} + linter = Lint(options) + retcode = linter.run() + out, err = capsys.readouterr() + assert '1 packages and 0 specfiles checked' in out + assert retcode == 0 |