import copy import os import unittest from collections import OrderedDict from unittest.mock import MagicMock, Mock, patch import build import config import files import tarball # Stores all test cases for dynamic tests. # In order to add more tests just add more elements to the lists provided below. CONTENT_PECL = [ 'package.xml', 'common-prefix/', 'common-prefix/md5/', 'common-prefix/md5/CMakeLists.txt', 'common-prefix/md5/md5.h', 'common-prefix/md5/md5hl.c', 'common-prefix/md5/md5cmp.c', 'common-prefix/md5/md5.c', 'common-prefix/md5/Makefile.am', 'common-prefix/md5/Makefile.in', 'common-prefix/jerror.c', 'common-prefix/sharedlib/', 'common-prefix/sharedlib/CMakeLists.txt', 'common-prefix/turbojpeg-mapfile', 'common-prefix/jdpostct.c', 'common-prefix/turbojpeg-jni.c', ] CONTENT_PREFIX = [ 'common-prefix/', 'common-prefix/md5/', 'common-prefix/md5/CMakeLists.txt', 'common-prefix/md5/md5.h', 'common-prefix/md5/md5hl.c', 'common-prefix/md5/md5cmp.c', 'common-prefix/md5/md5.c', 'common-prefix/md5/Makefile.am', 'common-prefix/md5/Makefile.in', 'common-prefix/jerror.c', 'common-prefix/sharedlib/', 'common-prefix/sharedlib/CMakeLists.txt', 'common-prefix/turbojpeg-mapfile', 'common-prefix/jdpostct.c', 'common-prefix/turbojpeg-jni.c', ] CONTENT_SUBDIR = [ 'dir1/', 'dir1/md5/', 'dir1/md5/CMakeLists.txt', 'dir1/md5/md5.h', 'dir1/md5/md5hl.c', 'dir1/md5/md5cmp.c', 'dir1/md5/md5.c', 'dir1/md5/Makefile.am', 'dir1/md5/Makefile.in', 'dir2/', 'dir2/jerror.c', 'dir2/sharedlib/', 'dir2/sharedlib/CMakeLists.txt', 'dir2/turbojpeg-mapfile', 'dir2/jdpostct.c', 'dir2/turbojpeg-jni.c', 'file.c' ] # Input for tarball.Source class tests. # Structure: (url, destination, path, fake-content, source_type, prefix, subddir) SRC_CREATION = [ ("https://example/src-PECL.tar", "", "/tmp/src-PECL.tar", CONTENT_PECL, "tar", "common-prefix", None), ("https://example/src-non-PECL.tar", "", "/tmp/src-non-PECL.tar", CONTENT_PECL, "tar", "", "src-non-PECL"), ("https://example/src-prefix.zip", "", "/tmp/src-prefix.zip", CONTENT_PREFIX, "zip", "common-prefix", None), ("https://example/src-subdir.zip", "", "/tmp/src-subdir.zip", CONTENT_SUBDIR, "zip", "", "src-subdir"), ("https://example/src-prefix.tar", "", "/tmp/src-prefix.tar", CONTENT_PREFIX, "tar", "common-prefix", None), ("https://example/src-subdir.tar", "", "/tmp/src-subdir.tar", CONTENT_SUBDIR, "tar", "", "src-subdir"), ("https://example/src-no-extractable.tar", ":", "/tmp/src-no-extractable.tar", None, None, None, None), ] class MockSrcFile(): """Mock class for zipfile and tarfile.""" def __init__(self, path, mode): self.name = path self.mode = mode def __enter__(self): return self def __exit__(self, exc_type, exc_val, traceback): return False @classmethod def set_content(cls, content): # deep copy because the content is modified by Source cls.content = copy.deepcopy(content) def getnames(self): return self.content def namelist(self): return self.content def source_test_generator(url, destination, path, content, src_type, prefix, subdir): """Create test for tarball.Source class using generator template.""" @patch('tarball.tarfile.open', MockSrcFile) @patch('tarball.zipfile.ZipFile', MockSrcFile) @patch('tarball.tarfile.is_tarfile', Mock(return_value=True)) @patch('tarball.zipfile.is_zipfile', Mock(return_value=True)) def generator(self): """Test template.""" # Set fake content MockSrcFile.set_content(content) if os.path.basename(path) in ['src-PECL.tar']: src = tarball.Source(url, destination, path, 'phpize') else: src = tarball.Source(url, destination, path) self.assertEqual(src.type, src_type) self.assertEqual(src.prefix, prefix, f"fail for: {url}") self.assertEqual(src.subdir, subdir) return generator def name_and_version_test_generator(url, name, version): """Create test for tarball.name_and_version method.""" def generator(self): """Test template.""" conf = config.Config('/download/path') conf.parse_config_versions = Mock(return_value={}) # Test four different name/version states for tarball.Content, each in # a subtest. Test failures will print these state numbers for easy # identification: # 0 - no state # 1 - name only # 2 - version only # 3 - name and version for state in range(4): with self.subTest(state=state): name_arg = "" version_arg = "" if state == 1 or state == 3: name_arg = f"state.{name}" if state == 2 or state == 3: version_arg = f"state.{version}" content = tarball.Content(url, name_arg, version_arg, [], conf, '/tmp') content.config = conf pkg = build.Build() mgr = files.FileManager(conf, pkg) content.name_and_version(mgr) name_cmp = name version_cmp = version if state == 1 or state == 3: name_cmp = name_arg if state == 2 or state == 3: version_cmp = version_arg self.assertEqual(name_cmp, content.name) self.assertEqual(version_cmp, content.version) # redo without args and verify giturl is set correctly content.name = "" content.version = "" content.name_and_version(Mock()) if "github.com" in url: self.assertRegex(content.giturl, r"https://github.com/[^/]+/" + content.repo + ".git") return generator def create_dynamic_tests(): """Create dynamic tests based on content in lists and packageulrs file.""" # Create tests for tarball.Source class. for url, dest, path, content, src_type, prefix, subdir in SRC_CREATION: test_name = 'test_src_{}'.format(url) test = source_test_generator(url, dest, path, content, src_type, prefix, subdir) setattr(TestTarball, test_name, test) # Create tests for tarball.name_and_version method. with open('tests/packageurls', 'r') as pkgurls: for urlline in pkgurls.read().split('\n'): if not urlline or urlline.startswith('#'): continue (url, name, version) = urlline.split(',') test_name = 'test_name_ver_{}'.format(url) test = name_and_version_test_generator(url, name, version) setattr(TestTarball, test_name, test) class TestTarball(unittest.TestCase): """Main testing class for tarball.py. This class would contain all static tests and dynamic tests for tarball.py """ def setUp(self): """Set up default values before start test.""" # Set strenght to 0 so it can be updated during tests conf = config.Config('/download/path') self.content = tarball.Content('', '', '', [], conf, '/tmp') conf.content = self.content @patch('tarball.os.path.isfile', Mock(return_value=True)) def test_set_gcov(self): """Test for tarball.set_gcov method.""" # Set up input values self.content.name = 'test' self.content.set_gcov() self.assertEqual(self.content.gcov_file, 'test.gcov') @patch('tarball.Source.set_prefix', Mock()) @patch('tarball.Source.extract', Mock()) def test_extract_sources(self): """Test for Content extract_sources method.""" # Set up input values main_src = tarball.Source('https://example1.tar', '', '/tmp') arch1_src = tarball.Source('https://example2.tar', '', '/tmp') arch2_src = tarball.Source('https://example3.tar', ':', '/tmp') arch3_src = tarball.Source('https://example4.tar', '', '/tmp') archives_src = [arch1_src, arch2_src, arch3_src] self.content.extract_sources(main_src, archives_src) # Sources with destination=':' should not be extracted, so method # should be called only 3 times. self.assertEqual(tarball.Source.extract.call_count, 3) # Create dynamic tests based on config file create_dynamic_tests() if __name__ == '__main__': unittest.main(buffer=True)