Files
autospec/tests/test_buildreq.py
William Douglas 1f398f5e7b Add config for using ninja instead of make
Given more packages are using ninja as the build system of choice
instead of make, add flag to enable ninja usage.

Signed-off-by: William Douglas <william.douglas@intel.com>
2024-05-29 16:02:05 -07:00

862 lines
34 KiB
Python

import unittest
import tempfile
import os
from unittest.mock import MagicMock, mock_open, patch
import json
import io
import buildreq
import config
import pypidata
bak_get_pypi_name = pypidata.get_pypi_name
def get_pypi_name_wrapper(name, miss=None):
"""Ignore missing packags in pypi"""
return bak_get_pypi_name(name)
class TestBuildreq(unittest.TestCase):
def setUp(self):
"""
Test setup method to reset the buildreq module
"""
self.reqs = buildreq.Requirements("")
self.reqs.banned_buildreqs.add('bannedreq')
def test_add_buildreq(self):
"""
Test add_buildreq with unbanned new req. Follow up by asserting that
trying to add the same req a second time results in a False return.
"""
self.assertTrue(self.reqs.add_buildreq('testreq'))
self.assertIn('testreq', self.reqs.buildreqs)
self.assertFalse(self.reqs.add_buildreq('testreq'))
def test_add_buildreq_banned(self):
"""
Test add_buildreq with banned new req
"""
self.assertFalse(self.reqs.add_buildreq('bannedreq'))
self.assertNotIn('bannedreq', self.reqs.buildreqs)
def test_ban_requires(self):
"""
Test ban_requires with req already present in requires
"""
self.reqs.requires[None] = set(['testreq'])
self.reqs.ban_requires('testreq')
self.assertNotIn('testreq', self.reqs.requires[None])
def test_ban_requires_subpkg(self):
"""
Test ban_requires on a subpkg with req already present in requires
"""
self.reqs.requires['subpkg'] = set(['testreq'])
self.reqs.ban_requires('testreq', subpkg='subpkg')
self.assertNotIn('testreq', self.reqs.requires['subpkg'])
def test_add_requires(self):
"""
Test add_requires with unbanned new req already present in
buildreqs but not yet present in requires
"""
self.reqs.add_buildreq('testreq')
self.assertTrue(self.reqs.add_requires('testreq', ['testreq']))
self.assertIn('testreq', self.reqs.requires[None])
def test_add_requires_subpkg(self):
"""
Test add_requires on a subpkg with unbanned new req already present in
buildreqs but not yet present in requires
"""
self.reqs.add_buildreq('testreq')
self.assertTrue(self.reqs.add_requires('testreq', ['testreq'], subpkg='subpkg'))
self.assertIn('testreq', self.reqs.requires['subpkg'])
def test_add_requires_not_in_buildreqs(self):
"""
Test add_requires with unbanned new req not present in buildreqs.
"""
self.assertFalse(self.reqs.add_requires('testreq', []))
self.assertNotIn('testreq', self.reqs.requires[None])
def test_add_banned_requires(self):
"""
Test add_requires with banned new req (override buildreq).
"""
self.assertFalse(self.reqs.add_requires('pypi(nose)', [], override=True))
self.assertNotIn('testreq', self.reqs.requires[None])
def test_ban_provides(self):
"""
Test ban_provides with prov already present in provides
"""
self.reqs.provides[None] = set(['testreq'])
self.reqs.ban_provides('testreq')
self.assertNotIn('testreq', self.reqs.provides[None])
def test_ban_provides_subpkg(self):
"""
Test ban_provides on a subpkg with prov already present in provides
"""
self.reqs.provides['subpkg'] = set(['testreq'])
self.reqs.ban_provides('testreq', subpkg='subpkg')
self.assertNotIn('testreq', self.reqs.provides['subpkg'])
def test_add_provides(self):
"""
Test add_provides with unbanned new prov
"""
self.assertTrue(self.reqs.add_provides('testreq'))
self.assertIn('testreq', self.reqs.provides[None])
def test_add_provides_subpkg(self):
"""
Test add_provides on a subpkg with unbanned new prov
"""
self.assertTrue(self.reqs.add_provides('testreq', subpkg='subpkg'))
self.assertIn('testreq', self.reqs.provides['subpkg'])
def test_add_pkgconfig_buildreq(self):
"""
Test add_pkgconfig_buildreq with config_opts['32bit'] set to False
"""
self.assertTrue(self.reqs.add_pkgconfig_buildreq('testreq', False))
self.assertIn('pkgconfig(testreq)', self.reqs.buildreqs)
def test_add_pkgconfig_buildreq_32bit(self):
"""
Test add_pkgconfig_buildreq with config_opts['32bit'] set to True
"""
self.assertTrue(self.reqs.add_pkgconfig_buildreq('testreq', True))
self.assertIn('pkgconfig(testreq)', self.reqs.buildreqs)
self.assertIn('pkgconfig(32testreq)', self.reqs.buildreqs)
def test_configure_ac_line(self):
"""
Test configure_ac_line with standard pattern
"""
self.reqs.configure_ac_line('AC_CHECK_FUNC([tgetent])', False)
self.assertIn('ncurses-devel', self.reqs.buildreqs)
def test_configure_ac_line_comment(self):
"""
Test configure_ac_line with commented line
"""
self.reqs.configure_ac_line('# AC_CHECK_FUNC([tgetent])', False)
self.assertEqual(self.reqs.buildreqs, set())
def test_configure_ac_line_pkg_check_modules(self):
"""
Test the somewhat complicated logic of configure_ac_line check for the
PKG_CHECK_MODULES((.*?)) line.
"""
self.reqs.configure_ac_line(
'PKG_CHECK_MODULES(prefix, '
'[module > 2 module2 < 2], '
'action-if-found, action-if-not-found)', False)
self.assertEqual(self.reqs.buildreqs,
set(['pkgconfig(module)', 'pkgconfig(module2)']))
def test_configure_ac_line_xdt_check_package(self):
"""
Test configure_ac_line for the XFCE version of PKG_CHECK_MODULES
"""
self.reqs.configure_ac_line(
'XDT_CHECK_PACKAGE(prefix, '
'[module = 2 module2 > 9], '
'action-if-found, action-if-not-found)', False)
self.assertEqual(self.reqs.buildreqs,
set(['pkgconfig(module)', 'pkgconfig(module2)']))
def test_configure_ac_line_pkg_check_exists(self):
"""
Test configure_ac_line for the PKG_CHECK_EXISTS macro
"""
self.reqs.configure_ac_line('PKG_CHECK_EXISTS([module1 > 1 module2], '
'action-if-found, '
'action-if-not-found)', False)
self.assertEqual(self.reqs.buildreqs,
set(['pkgconfig(module1)', 'pkgconfig(module2)']))
def test_parse_configure_ac(self):
"""
Test parse_configure_ac with changing () depths and package
requirements
"""
conf = config.Config("")
content = 'AC_CHECK_FUNC([tgetent])\n' \
'XDT_CHECK_PACKAGE(prefix, ' \
'[module = 2 module2 > 9], ' \
'action-if-found, action-if-not-found)\n' \
'next two lines should be read in batch ( \n' \
'PROG_INTLTOOL\n' \
'AC_PROG_SED)\n' \
'GETTEXT_PACKAGE'
with tempfile.TemporaryDirectory() as tmpd:
with open(os.path.join(tmpd, 'fname'), 'w') as f:
f.write(content)
self.reqs.parse_configure_ac(os.path.join(tmpd, 'fname'), conf)
self.assertEqual(self.reqs.buildreqs,
set(['gettext',
'ncurses-devel',
'perl(XML::Parser)',
'pkgconfig(module2)',
'pkgconfig(module)',
'intltool',
'sed']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_clean_python_req(self):
"""
Test clean_python_req with a common python requirements string
"""
self.assertEqual(buildreq.clean_python_req('requirement >= 1.1.2'),
'requirement')
self.assertEqual(buildreq.clean_python_req('requirement ; python_version > 1.1.2'),
'requirement')
self.assertEqual(buildreq.clean_python_req('requirement ; python_version < 1.1.2'),
'')
self.assertEqual(buildreq.clean_python_req('requirement <= 1.1.2'),
'requirement')
self.assertEqual(buildreq.clean_python_req('requirement = 1.1.2'),
'requirement')
self.assertEqual(buildreq.clean_python_req('requirement \n ; rsa>= 1.1.2'),
'requirement')
self.assertEqual(buildreq.clean_python_req('requirement != 1.1.2'),
'requirement')
self.assertEqual(buildreq.clean_python_req('[:python > 2]'),
'')
self.assertEqual(buildreq.clean_python_req('requirement ~= 1.1.2'),
'requirement')
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_clean_python_req_comment(self):
"""
Test clean_python_req with a comment
"""
self.assertEqual(buildreq.clean_python_req('# hello'), '')
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_clean_python_req_whitespace(self):
"""
Test clean_python_req with strange whitespaced string
"""
self.assertEqual(buildreq.clean_python_req(' requirement < 1.1'),
'requirement')
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_grab_python_requirements(self):
"""
Test grab_python_requirements with a reasonable requirements file
"""
# buildreqs must include the requires also
open_name = 'buildreq.util.open_auto'
content = 'req1 <= 1.2.3\n' \
'req2 >= 1.55\n' \
'req7 == 3.3.3\n'
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.grab_python_requirements('filename', [])
self.assertEqual(self.reqs.requires["python3"], set(['pypi(req1)', 'pypi(req2)', 'pypi(req7)']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_grab_python_requirements_strange_file(self):
"""
Test grab_python_requirements with a poorly written file
"""
# buildreqs must include the requires also
open_name = 'buildreq.util.open_auto'
content = ' req1 <= 1.2.3\n ' \
'req2 >= 1.55 \n' \
' req7 == 3.3.3\n '
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.grab_python_requirements('filename', [])
self.assertEqual(self.reqs.requires["python3"], set(['pypi(req1)', 'pypi(req2)', 'pypi(req7)']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_add_setup_py_requires(self):
"""
Test add_setup_py_requires with a single item in install_requires and
setup_requires
"""
open_name = 'buildreq.util.open_auto'
content = "install_requires=['req1']\n" \
"setup_requires=['req2']"
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.add_setup_py_requires('filename', [])
self.assertEqual(self.reqs.buildreqs, set(['pypi(req1)', 'pypi(req2)']))
self.assertEqual(self.reqs.requires["python3"], set(['pypi(req1)']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_add_setup_py_requires_multiline(self):
"""
Test add_setup_py_requires with a multiline item in install_requires
"""
open_name = 'buildreq.util.open_auto'
content = "install_requires=['req1',\n" \
"'req2',\n" \
"'req7']\n"
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.add_setup_py_requires('filename', [])
self.assertEqual(self.reqs.buildreqs, set(['pypi(req1)', 'pypi(req2)', 'pypi(req7)']))
self.assertEqual(self.reqs.requires["python3"], set(['pypi(req1)', 'pypi(req2)', 'pypi(req7)']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_add_setup_py_requires_multiline_formatted(self):
"""
Test add_setup_py_requires with a multiline item in install_requires
with brackets on their own lines.
"""
open_name = 'buildreq.util.open_auto'
content = "install_requires=[\n " \
"'req1',\n" \
"'req2',\n" \
"'req7',\n" \
"]\n"
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.add_setup_py_requires('filename', [])
self.assertEqual(self.reqs.buildreqs, set(['pypi(req1)', 'pypi(req2)', 'pypi(req7)']))
self.assertEqual(self.reqs.requires["python3"], set(['pypi(req1)', 'pypi(req2)', 'pypi(req7)']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_add_setup_py_requires_multiline_variable(self):
"""
Test add_setup_py_requires with multiline item in install_requires that
contains a non-literal object.
"""
open_name = 'buildreq.util.open_auto'
content = "install_requires=[\n" \
"reqvar,\n" \
"'req1',\n" \
"'req2'" \
"]\n"
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.add_setup_py_requires('filename', [])
self.assertEqual(self.reqs.buildreqs, set(['pypi(req1)', 'pypi(req2)']))
self.assertEqual(self.reqs.requires["python3"], set(['pypi(req1)', 'pypi(req2)']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_add_setup_py_requires_multiline_install_requires_variable(self):
"""
Test add_setup_py_requires with multiline item in install_requires that
contains an extra bit of content that shouldn't be parsed as install_requires.
"""
open_name = 'buildreq.util.open_auto'
content = "install_requires=[\n" \
"'req1',\n" \
"'req2'" \
"] + install_requires\n" \
"'bad']\n"
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.add_setup_py_requires('filename', [])
self.assertEqual(self.reqs.buildreqs, set(['pypi(req1)', 'pypi(req2)']))
self.assertEqual(self.reqs.requires["python3"], set(['pypi(req1)', 'pypi(req2)']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_add_setup_py_requires_variable(self):
"""
Test add_setup_py_requires that contains a non-literal object.
"""
open_name = 'buildreq.util.open_auto'
content = "install_requires=[reqname, 'req1', 'req2']\n"
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.add_setup_py_requires('filename', [])
self.assertEqual(self.reqs.buildreqs, set(['pypi(req1)', 'pypi(req2)']))
self.assertEqual(self.reqs.requires["python3"], set(['pypi(req1)', 'pypi(req2)']))
@patch('buildreq.pypidata.get_pypi_name', get_pypi_name_wrapper)
def test_add_setup_py_requires_single_variable(self):
"""
Test add_setup_py_requires with a single non-literal object
"""
open_name = 'buildreq.util.open_auto'
content = "install_requires='reqname'"
m_open = mock_open(read_data=content)
with patch(open_name, m_open, create=True):
self.reqs.add_setup_py_requires('filename', [])
self.assertEqual(self.reqs.buildreqs, set(['pypi(reqname)']))
self.assertEqual(self.reqs.requires['python3'], set(['pypi(reqname)']))
def test_scan_for_configure_setup(self):
"""
Test scan_for_configure with a mocked package structure. There is so
much to test here that uses the same logic, a representative test
should be sufficient.
"""
conf = config.Config("")
conf.config_opts['use_ninja'] = False
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, 'subdir'))
open(os.path.join(tmpd, 'setup.py'), 'w').close()
self.reqs.scan_for_configure(tmpd, "", conf)
self.assertEqual(self.reqs.buildreqs,
set(['buildreq-distutils3']))
def test_scan_for_configure_cmake(self):
"""
Test scan_for_configure with a mocked package structure. There is so
much to test here that uses the same logic, a representative test
should be sufficient.
"""
conf = config.Config("")
conf.config_opts['use_ninja'] = False
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, 'subdir'))
open(os.path.join(tmpd, 'CMakeLists.txt'), 'w').close()
self.reqs.scan_for_configure(tmpd, "", conf)
self.assertEqual(self.reqs.buildreqs,
set(['buildreq-cmake']))
def test_scan_for_configure_scons(self):
"""
Test scan_for_configure with a mocked package structure. There is so
much to test here that uses the same logic, a representative test
should be sufficient.
"""
conf = config.Config("")
conf.config_opts['use_ninja'] = False
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, 'subdir'))
open(os.path.join(tmpd, 'SConstruct'), 'w').close()
self.reqs.scan_for_configure(tmpd, "", conf)
self.assertEqual(self.reqs.buildreqs,
set(['buildreq-scons']))
def test_scan_for_configure_meson(self):
"""
Test scan_for_configure with a mocked package structure. There is so
much to test here that uses the same logic, a representative test
should be sufficient.
"""
conf = config.Config("")
conf.config_opts['use_ninja'] = False
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, 'subdir'))
open(os.path.join(tmpd, 'meson.build'), 'w').close()
self.reqs.scan_for_configure(tmpd, "", conf)
self.assertEqual(self.reqs.buildreqs,
set(['buildreq-meson']))
def test_scan_for_configure_pypi(self):
"""
Test scan_for_configure when distutils is being used for the build
pattern to test pypi metadata handling.
"""
orig_summary = buildreq.specdescription.default_summary
orig_sscore = buildreq.specdescription.default_summary_score
orig_pypi_name = buildreq.pypidata.get_pypi_name
orig_pypi_meta = buildreq.pypidata.get_pypi_metadata
name = "name"
requires = ["abc",
"def"]
pypi_requires = set(f"pypi({x})" for x in requires)
summary = "summary"
content = json.dumps({"name": name,
"summary": summary,
"requires": requires})
buildreq.pypidata.get_pypi_name = MagicMock(return_value=True)
buildreq.pypidata.get_pypi_metadata = MagicMock(return_value=content)
with tempfile.TemporaryDirectory() as tmpd:
conf = config.Config(tmpd)
conf.config_opts['use_ninja'] = False
os.mkdir(os.path.join(tmpd, 'subdir'))
open(os.path.join(tmpd, 'subdir', 'pyproject.toml'), 'w').close()
self.reqs.scan_for_configure(os.path.join(tmpd, 'subdir'), "", conf)
ssummary = buildreq.specdescription.default_summary
buildreq.specdescription.default_summary = orig_summary
buildreq.specdescription.default_summary_score = orig_sscore
buildreq.pypidata.get_pypi_name = orig_pypi_name
buildreq.pypidata.get_pypi_metadata = orig_pypi_meta
self.assertEqual(self.reqs.pypi_provides, name)
self.assertEqual(self.reqs.requires['python3'], pypi_requires)
self.assertEqual(ssummary, summary)
def test_scan_for_configure_pypi_override(self):
"""
Test scan_for_configure when distutils is being used for the build
pattern to test pypi metadata file override handling.
"""
open_name = 'buildreq.open'
orig_summary = buildreq.specdescription.default_summary
orig_sscore = buildreq.specdescription.default_summary_score
name = "name"
summary = "summary"
requires = ["req"]
pypi_requires = set(f"pypi({x})" for x in requires)
content = json.dumps({"name": name,
"summary": summary,
"requires": requires})
m_open = mock_open(read_data=content)
with tempfile.TemporaryDirectory() as tmpd:
conf = config.Config(tmpd)
conf.config_opts['use_ninja'] = False
os.mkdir(os.path.join(tmpd, 'subdir'))
open(os.path.join(tmpd, 'subdir', 'pyproject.toml'), 'w').close()
open(os.path.join(tmpd, 'pypi.json'), 'w').close()
with patch(open_name, m_open, create=True):
self.reqs.scan_for_configure(os.path.join(tmpd, 'subdir'), "", conf)
ssummary = buildreq.specdescription.default_summary
buildreq.specdescription.default_summary = orig_summary
buildreq.specdescription.default_summary_score = orig_sscore
self.assertEqual(self.reqs.pypi_provides, name)
self.assertEqual(self.reqs.requires['python3'], pypi_requires)
self.assertEqual(ssummary, summary)
def test_scan_for_configure_setup_with_requires(self):
"""
Test scan_for_configure when distutils is being used for the build
pattern to test requires.txt handling.
"""
self.reqs.add_pyproject_requires = MagicMock()
self.reqs.add_setup_py_requires = MagicMock()
self.reqs.grab_python_requirements = MagicMock()
with tempfile.TemporaryDirectory() as tmpd:
conf = config.Config(tmpd)
conf.config_opts['use_ninja'] = False
os.mkdir(os.path.join(tmpd, 'subdir'))
open(os.path.join(tmpd, 'subdir', 'setup.py'), 'w').close()
open(os.path.join(tmpd, 'subdir', 'requires.txt'), 'w').close()
self.reqs.scan_for_configure(os.path.join(tmpd, 'subdir'), "", conf)
self.reqs.add_pyproject_requires.assert_not_called()
self.reqs.add_setup_py_requires.assert_called_once()
self.reqs.grab_python_requirements.assert_called_once()
def test_scan_for_configure_ninja(self):
"""
Test scan_for_configure when ninja is enabled.
"""
conf = config.Config("")
conf.config_opts['use_ninja'] = True
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, 'subdir'))
open(os.path.join(tmpd, 'setup.py'), 'w').close()
self.reqs.scan_for_configure(tmpd, "", conf)
self.assertEqual(self.reqs.buildreqs,
set(['buildreq-distutils3', 'ninja']))
def test_parse_cmake_pkg_check_modules(self):
"""
Test parse_cmake to ensure accurate detection of versioned and
unversioned pkgconfig modules.
"""
conf = config.Config("")
conf.setup_patterns()
content = 'pkg_check_modules(GLIB gio-unix-2.0>=2.46.0 glib-2.0 REQUIRED)'
with tempfile.TemporaryDirectory() as tmpd:
with open(os.path.join(tmpd, 'fname'), 'w') as f:
f.write(content)
self.reqs.parse_cmake(os.path.join(tmpd, 'fname'), conf.cmake_modules, False)
self.assertEqual(self.reqs.buildreqs,
set(['pkgconfig(gio-unix-2.0)', 'pkgconfig(glib-2.0)']))
def test_parse_cmake_pkg_check_modules_whitespace(self):
"""
Test parse_cmake to ensure accurate handling of versioned
pkgconfig modules with whitespace.
"""
conf = config.Config("")
conf.setup_patterns()
content = 'pkg_check_modules(GLIB gio-unix-2.0 >= 2.46.0 glib-2.0 REQUIRED)'
with tempfile.TemporaryDirectory() as tmpd:
with open(os.path.join(tmpd, 'fname'), 'w') as f:
f.write(content)
self.reqs.parse_cmake(os.path.join(tmpd, 'fname'), conf.cmake_modules, False)
self.assertEqual(self.reqs.buildreqs,
set(['pkgconfig(gio-unix-2.0)', 'pkgconfig(glib-2.0)']))
def test_parse_cmake_pkg_check_modules_in_a_comment(self):
"""
Test parse_cmake to ensure it ignores pkg_check_modules in comments.
"""
conf = config.Config("")
conf.setup_patterns()
content = '''
# For example, consider the following patch to some CMakeLists.txt.
# - pkg_check_modules(FOO REQUIRED foo>=1.0)
# + pkg_check_modules(FOO REQUIRED foo>=2.0)
'''
with tempfile.TemporaryDirectory() as tmpd:
with open(os.path.join(tmpd, 'fname'), 'w') as f:
f.write(content)
self.reqs.parse_cmake(os.path.join(tmpd, 'fname'), conf.cmake_modules, False)
self.assertEqual(self.reqs.buildreqs,
set([]))
def test_parse_cmake_pkg_check_modules_variables(self):
"""
Test parse_cmake to ensure accurate handling of versioned
pkgconfig modules with variable version strings.
"""
conf = config.Config("")
conf.setup_patterns()
content = 'pkg_check_modules(AVCODEC libavcodec${_avcodec_ver} libavutil$_avutil_ver)'
with tempfile.TemporaryDirectory() as tmpd:
with open(os.path.join(tmpd, 'fname'), 'w') as f:
f.write(content)
self.reqs.parse_cmake(os.path.join(tmpd, 'fname'), conf.cmake_modules, False)
self.assertEqual(self.reqs.buildreqs,
set(['pkgconfig(libavcodec)', 'pkgconfig(libavutil)']))
def test_parse_cmake_find_package(self):
"""
Test parse_cmake to ensure accurate handling of find_package.
"""
cmake_modules = {
"valid": "valid",
"valid_but_commented": "valid_but_commented",
"different_name": "another_name",
"qt6.module1": "qt6module1",
"qt6.module2": "qt6module2",
"kf6.module3": "kf6module3",
"kf6.module4": "kf6module4",
".module5": "namodule5",
".module6": "namodule6"
}
content = '''
find_package(valid)
#find_package(foo)
# find_package(valid_but_commented)
find_package(different_name)
find_package(Qt6 stuff
module1
module2)
find_package(KF6 stuff
module3
module4
)
find_package(NOT_HANDLED_NAMESPACE stuff
module5
module6
)
'''
with tempfile.TemporaryDirectory() as tmpd:
with open(os.path.join(tmpd, 'fname'), 'w') as f:
f.write(content)
self.reqs.parse_cmake(os.path.join(tmpd, 'fname'), cmake_modules, False)
self.assertEqual(self.reqs.buildreqs,
set(['valid',
'another_name',
'qt6module1',
'qt6module2',
'kf6module3',
'kf6module4',
'namodule5',
'namodule6']))
def test_r_desc_field_begin(self):
"""Test parsing of the first R description field."""
lines = [
"Field1: foo",
"Field2: bar",
"Field3: baz",
]
result = buildreq._get_desc_field("Field1", "\n".join(lines))
self.assertEqual(result, ["foo"])
def test_r_desc_field_middle(self):
"""Test parsing of an R description field with surrounding fields."""
lines = [
"Field1: foo",
"Field2: bar",
"Field3: baz",
]
result = buildreq._get_desc_field("Field2", "\n".join(lines))
self.assertEqual(result, ["bar"])
def test_r_desc_field_end(self):
"""Test parsing of the last R description field."""
lines = [
"Field1: foo",
"Field2: bar",
"Field3: baz",
]
result = buildreq._get_desc_field("Field3", "\n".join(lines))
self.assertEqual(result, ["baz"])
def test_r_desc_field_middle_multiple_lines(self):
"""Test parsing of a multi-line R description field, with surrounding fields."""
lines = [
"Field1: foo",
"Field2: bar1, bar2,",
" bar3, bar4",
"Field3: baz",
]
result = buildreq._get_desc_field("Field2", "\n".join(lines))
self.assertEqual(result, ["bar1", "bar2", "bar3", "bar4"])
def test_r_desc_field_end_multiple_lines(self):
"""Test parsing of the last R description field, consisting of multiple lines."""
lines = [
"Field1: foo",
"Field2: bar",
"Field3: baz1,",
" baz2",
]
result = buildreq._get_desc_field("Field3", "\n".join(lines))
self.assertEqual(result, ["baz1", "baz2"])
def test_r_desc_field_middle_one_per_line(self):
"""Test parsing of an R description field with one entry per line."""
lines = [
"Field1: foo",
"Field2:",
"bar1,",
"bar2",
"Field3: baz",
]
result = buildreq._get_desc_field("Field2", "\n".join(lines))
self.assertEqual(result, ["bar1", "bar2"])
def test_r_desc_field_trailing_whitespace(self):
"""Test parsing of an R description field with trailing whitespace."""
lines = [
"Field1: foo1, foo2 ",
]
result = buildreq._get_desc_field("Field1", "\n".join(lines))
self.assertEqual(result, ["foo1", "foo2"])
def test_r_desc_field_trailing_comma(self):
"""Test parsing of an R description field with trailing comma."""
lines = [
"Field1: foo1, foo2,",
]
result = buildreq._get_desc_field("Field1", "\n".join(lines))
self.assertEqual(result, ["foo1", "foo2"])
def test_r_desc_field_empty(self):
"""Test parsing of an R description field with an empty value."""
lines = [
"Field1:",
]
result = buildreq._get_desc_field("Field1", "\n".join(lines))
self.assertEqual(result, [])
def test_r_desc_field_missing(self):
"""Test parsing of an R description field that is missing."""
lines = [
"Field1: foo, bar",
]
result = buildreq._get_desc_field("Field2", "\n".join(lines))
self.assertEqual(result, [])
def test_parse_r_desc_depends(self):
"""Test parsing of R description Depends field."""
pkgs = ['R-pkg1']
open_name = 'buildreq.util.open_auto'
content = 'Depends: pkg1'
m_open = mock_open(read_data=content)
with patch(open_name, m_open):
self.reqs.parse_r_description('filename', pkgs)
self.assertTrue('R-pkg1' in self.reqs.buildreqs)
def test_parse_r_desc_imports(self):
"""Test parsing of an R description Imports field."""
pkgs = ['R-pkg2']
open_name = 'buildreq.util.open_auto'
content = 'Imports: pkg2'
m_open = mock_open(read_data=content)
with patch(open_name, m_open):
self.reqs.parse_r_description('filename', pkgs)
self.assertTrue('R-pkg2' in self.reqs.buildreqs)
def test_parse_r_desc_linkingto(self):
"""Test parsing of an R description LinkingTo field."""
pkgs = ['R-pkg3']
open_name = 'buildreq.util.open_auto'
content = 'LinkingTo: pkg3'
m_open = mock_open(read_data=content)
with patch(open_name, m_open):
self.reqs.parse_r_description('filename', pkgs)
self.assertTrue('R-pkg3' in self.reqs.buildreqs)
def test_parse_r_desc_multiple(self):
"""Test parsing of an R description file that captures multiple fields."""
pkgs = [
'R-pkg1',
'R-pkg2',
'R-pkg3',
'R-pkg4',
]
open_name = 'buildreq.util.open_auto'
content = [
'Field1: foo',
'Imports: pkg1, pkg2,',
' pkg3 ',
'LinkingTo: pkg4',
'FieldFoo: bar',
]
m_open = mock_open(read_data='\n'.join(content))
with patch(open_name, m_open):
self.reqs.parse_r_description('filename', pkgs)
self.assertFalse('R-foo' in self.reqs.buildreqs)
self.assertFalse('R-bar' in self.reqs.buildreqs)
self.assertTrue('R-pkg1' in self.reqs.buildreqs)
self.assertTrue('R-pkg2' in self.reqs.buildreqs)
self.assertTrue('R-pkg3' in self.reqs.buildreqs)
self.assertTrue('R-pkg4' in self.reqs.buildreqs)
def test_parse_r_desc_not_in_os(self):
"""Test parsing of an R description file with some non-OS packages."""
pkgs = [
'R-pkg1',
]
open_name = 'buildreq.util.open_auto'
content = [
'Imports: pkg1, pkg2',
'Depends: pkg3',
]
m_open = mock_open(read_data='\n'.join(content))
with patch(open_name, m_open):
self.reqs.parse_r_description('filename', pkgs)
self.assertTrue('R-pkg1' in self.reqs.buildreqs)
self.assertTrue('R-pkg1' in self.reqs.requires[None])
# Names absent from the os-packages list are also added, because the
# DESCRIPTION file is considered authoritative.
for pkg in ['R-pkg2', 'R-pkg3']:
self.assertTrue(pkg in self.reqs.buildreqs)
self.assertTrue(pkg in self.reqs.requires[None])
if __name__ == '__main__':
unittest.main(buffer=True)