diff --git a/test/framework/build_log.py b/test/framework/build_log.py index 47687426c1..aa4d699082 100644 --- a/test/framework/build_log.py +++ b/test/framework/build_log.py @@ -67,8 +67,7 @@ def test_easybuilderror(self): self.assertErrorRegex(EasyBuildError, 'BOOM', raise_easybuilderror, 'BOOM') logtxt = read_file(logfile) - log_re = re.compile(r"^fancyroot ::.* BOOM \(at .*:[0-9]+ in [a-z_]+\)$", re.M) - self.assertTrue(log_re.match(logtxt), "%s matches %s" % (log_re.pattern, logtxt)) + self.assertRegex(logtxt, re.compile(r"^fancyroot ::.* BOOM \(at .*:[0-9]+ in [a-z_]+\)$", re.M)) # test formatting of message self.assertErrorRegex(EasyBuildError, 'BOOMBAF', raise_easybuilderror, 'BOOM%s', 'BAF') @@ -93,7 +92,7 @@ def test_easybuilderror(self): r'\s+easybuild/tools/filetools\.py:\d+ in read_file', r'\s+easybuild/framework/easyconfig/tweak\.py:\d+ in tweak_one', r'\s+easybuild/base/testing\.py:\d+ in assertErrorRegex', - )), re.M) + ))) def test_easybuildlog(self): """Tests for EasyBuildLog.""" @@ -153,8 +152,7 @@ def test_easybuildlog(self): r"fancyroot.test_easybuildlog \[ERROR\] :: .*EasyBuild encountered an exception \(at .* in .*\): oops", '', ]) - logtxt_regex = re.compile(r'^%s' % expected_logtxt, re.M) - self.assertTrue(logtxt_regex.search(logtxt), "Pattern '%s' found in %s" % (logtxt_regex.pattern, logtxt)) + self.assertRegex(logtxt, rf'^{expected_logtxt}') self.assertErrorRegex(EasyBuildError, r"DEPRECATED \(since .*: kaput", log.deprecated, "kaput", older_ver) self.assertErrorRegex(EasyBuildError, r"DEPRECATED \(since .*: 2>1", log.deprecated, "2>1", '2.0', '1.0') @@ -180,8 +178,7 @@ def test_easybuildlog(self): r"fancyroot.test_easybuildlog \[ERROR\] :: EasyBuild encountered an error \(at .* in .*\): foo baz baz", '', ]) - logtxt_regex = re.compile(r'^%s' % expected_logtxt, re.M) - self.assertTrue(logtxt_regex.search(logtxt), "Pattern '%s' found in %s" % (logtxt_regex.pattern, logtxt)) + self.assertRegex(logtxt, rf'^{expected_logtxt}') write_file(tmplog, '') logToFile(tmplog, enable=True) @@ -239,8 +236,7 @@ def test_log_levels(self): error_msg, deprecated_msg, warning_msg, info_msg, debug_msg, error_msg, deprecated_msg, warning_msg, info_msg, debug_msg, devel_msg, ]) - logtxt_regex = re.compile(r'^%s' % expected_logtxt, re.M) - self.assertTrue(logtxt_regex.search(logtxt), "Pattern '%s' found in %s" % (logtxt_regex.pattern, logtxt)) + self.assertRegex(logtxt, rf'^{expected_logtxt}') def test_print_warning(self): """Test print_warning""" diff --git a/test/framework/config.py b/test/framework/config.py index 03d7c3fbf3..a621a5c0f7 100644 --- a/test/framework/config.py +++ b/test/framework/config.py @@ -29,7 +29,6 @@ @author: Stijn De Weirdt (Ghent University) """ import os -import re import shutil import sys import tempfile @@ -598,33 +597,27 @@ def test_get_log_filename(self): tmpdir = tempfile.gettempdir() res = get_log_filename('foo', '1.2.3') - regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-[0-9]{8}\.[0-9]{6}\.log$')) - self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res)) + self.assertRegex(res, os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-[0-9]{8}\.[0-9]{6}\.log$')) res = get_log_filename('foo', '1.2.3', date='19700101') - regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.[0-9]{6}\.log$')) - self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res)) + self.assertRegex(res, os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.[0-9]{6}\.log$')) res = get_log_filename('foo', '1.2.3', timestamp='094651') - regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-[0-9]{8}\.094651\.log$')) - self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res)) + self.assertRegex(res, os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-[0-9]{8}\.094651\.log$')) res = get_log_filename('foo', '1.2.3', date='19700101', timestamp='094651') - regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.log$')) - self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res)) + self.assertRegex(res, os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.log$')) # if log file already exists, numbers are added to the filename to obtain a new file path write_file(res, '') res = get_log_filename('foo', '1.2.3', date='19700101', timestamp='094651') - regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.log\.1$')) - self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res)) + self.assertRegex(res, os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.log\.1$')) # adding salt ensures a unique filename (pretty much) prev_log_filenames = [] - for i in range(10): + for _ in range(10): res = get_log_filename('foo', '1.2.3', date='19700101', timestamp='094651', add_salt=True) - regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.[a-zA-Z]{5}\.log$')) - self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res)) + self.assertRegex(res, os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.[a-zA-Z]{5}\.log$')) self.assertNotIn(res, prev_log_filenames) prev_log_filenames.append(res) @@ -676,9 +669,8 @@ def test_log_path(self): # reconfigure with value for log directory that includes templates init_config(args=['--logfile-format=easybuild-%(name)s-%(version)s-%(date)s-%(time)s,log.txt']) - regex = re.compile(r'^easybuild-foo-1\.2\.3-[0-9-]{8}-[0-9]{6}$') res = log_path(ec=ec) - self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res)) + self.assertRegex(res, r'^easybuild-foo-1\.2\.3-[0-9-]{8}-[0-9]{6}$') self.assertEqual(log_file_format(), 'log.txt') def test_get_build_log_path(self): diff --git a/test/framework/containers.py b/test/framework/containers.py index 1c47ccfc45..69259db758 100644 --- a/test/framework/containers.py +++ b/test/framework/containers.py @@ -405,9 +405,7 @@ def test_end2end_dockerfile(self): self.check_regexs(regexs, def_file) # there should be no leading/trailing whitespace included - for pattern in [r'^\s+', r'\s+$']: - regex = re.compile(pattern) - self.assertFalse(regex.search(def_file), "Pattern '%s' should *not* be found in: %s" % (pattern, def_file)) + self.assert_multi_regex((r'^\s+', r'\s+$'), def_file, assert_match=False, multi_line=False) def test_end2end_docker_image(self): diff --git a/test/framework/easyblock.py b/test/framework/easyblock.py index ee28246b21..37e0b28019 100644 --- a/test/framework/easyblock.py +++ b/test/framework/easyblock.py @@ -782,7 +782,7 @@ def test_make_module_req(self): r"^prepend[-_]path.*CPATH.*root.*include/bar.*", r"^prepend[-_]path.*TEST_VAR.*root.*baz", ] - self.assert_multi_regex(non_expected_patterns, txt, assert_true=False) + self.assert_multi_regex(non_expected_patterns, txt, assert_match=False) # cleanup eb.close_log() diff --git a/test/framework/general.py b/test/framework/general.py index 857f55d74b..5a962576a5 100644 --- a/test/framework/general.py +++ b/test/framework/general.py @@ -28,7 +28,6 @@ @author: Kenneth hoste (Ghent University) """ import os -import re import sys from test.framework.utilities import EnhancedTestCase, TestLoaderFiltered from unittest import TextTestRunner @@ -49,9 +48,9 @@ def test_error_reporting(self): easybuild_loc = os.path.dirname(os.path.dirname(os.path.abspath(easybuild.framework.__file__))) log_method_regexes = [ - re.compile(r"log\.error\("), - re.compile(r"log\.exception\("), - re.compile(r"log\.raiseException\("), + r"log\.error\(", + r"log\.exception\(", + r"log\.raiseException\(", ] for dirpath, _, filenames in os.walk(easybuild_loc): @@ -61,7 +60,7 @@ def test_error_reporting(self): path = os.path.join(dirpath, filename) txt = read_file(path) for regex in log_method_regexes: - self.assertFalse(regex.search(txt), "No match for '%s' in %s" % (regex.pattern, path)) + self.assertNotRegex(txt, regex) def test_only_if_module_is_available(self): """Test only_if_module_is_available decorator.""" @@ -106,10 +105,10 @@ def test_docstrings(self): # easybuild.framework.__file__ provides location to /easybuild/framework/__init__.py easybuild_loc = os.path.dirname(os.path.dirname(os.path.abspath(easybuild.framework.__file__))) - docstring_regexes = [ - re.compile("@author"), - re.compile("@param"), - re.compile("@return"), + docstring_patterns = [ + "@author", + "@param", + "@return", ] for dirpath, _, filenames in os.walk(easybuild_loc): @@ -120,8 +119,8 @@ def test_docstrings(self): path = os.path.join(dirpath, filename) txt = read_file(path) - for regex in docstring_regexes: - self.assertFalse(regex.search(txt), "No match for '%s' in %s" % (regex.pattern, path)) + for pattern in docstring_patterns: + self.assertNotIn(pattern, txt) def test_import_available_modules(self): """Test for import_available_modules function.""" diff --git a/test/framework/module_generator.py b/test/framework/module_generator.py index 0a42c214da..655a24be0f 100644 --- a/test/framework/module_generator.py +++ b/test/framework/module_generator.py @@ -830,9 +830,7 @@ def test_module_extensions(self): r'\s*extensions\("bar/0.0,barbar/1.2,toy/0.0,ulimit"\)\nend$', ] - for pattern in patterns: - regex = re.compile(pattern, re.M) - self.assertTrue(regex.search(desc), "Pattern '%s' found in: %s" % (regex.pattern, desc)) + self.assert_multi_regex(patterns, desc) # check if the extensions is missing if there are no extensions test_ec = os.path.join(test_dir, 'easyconfigs', 'test_ecs', 't', 'toy', 'toy-0.0-test.eb') @@ -847,7 +845,7 @@ def test_module_extensions(self): else: pattern = r"\s*extensions\(" - self.assertFalse(re.search(pattern, desc), "No extensions found in: %s" % desc) + self.assertNotRegex(pattern, desc) # check if the extensions is missing if 'module_extensions' is disabled init_config(build_options={'module_extensions': False}) @@ -858,9 +856,7 @@ def test_module_extensions(self): modgen = self.MODULE_GENERATOR_CLASS(eb) desc = modgen.get_description() - for pattern in patterns: - regex = re.compile(pattern, re.M) - self.assertFalse(regex.search(desc), "Pattern '%s' not found in: %s" % (regex.pattern, desc)) + self.assert_multi_regex(patterns, desc, assert_match=False) def test_module_extensions_extension_name(self): """Test that the 'extension_name' easyconfig parameter is included in the 'extensions' statement.""" diff --git a/test/framework/options.py b/test/framework/options.py index 8c9c037ef0..e849d08b98 100644 --- a/test/framework/options.py +++ b/test/framework/options.py @@ -1847,7 +1847,7 @@ def test_try_toolchain_mapping(self): r"^ \* \[.\] .*-gompi-2018a", r"^ \* \[.\] .*-GCC.*6\.4\.0", ] - self.assert_multi_regex(anti_patterns, outtxt, assert_true=False) + self.assert_multi_regex(anti_patterns, outtxt, assert_match=False) def test_try_update_deps(self): """Test for --try-update-deps.""" @@ -3233,7 +3233,7 @@ def run_and_assert(args, words_expected=None, words_unexpected=None): if words_expected is not None: self.assert_multi_regex(words_expected, stdout) if words_unexpected is not None: - self.assert_multi_regex(words_unexpected, stdout, assert_true=False) + self.assert_multi_regex(words_unexpected, stdout, assert_match=False) # A: simple direct case (all is logged because passed directly via EasyBuild configuration options) args = list(common_args) @@ -3343,7 +3343,7 @@ def toy(extra_args=None): test_report_txt = toy() self.assertIn(test_var_secret_ondemand, test_report_txt) self.assertIn(test_var_public, test_report_txt) - self.assert_multi_regex([test_var_secret_always, test_var_secret_always2], test_report_txt, assert_true=False) + self.assert_multi_regex([test_var_secret_always, test_var_secret_always2], test_report_txt, assert_match=False) # filter out env vars that match specified regex pattern filter_arg = "--test-report-env-filter=.*_IS_A_CUSTOM_ENV_VAR_FOR_EASYBUILD" @@ -3353,7 +3353,7 @@ def toy(extra_args=None): test_var_secret_always, test_var_secret_always2, ] - self.assert_multi_regex(regexs, test_report_txt, assert_true=False) + self.assert_multi_regex(regexs, test_report_txt, assert_match=False) # make sure that used filter is reported correctly in test report filter_arg_regex = r"--test-report-env-filter='.\*_IS_A_CUSTOM_ENV_VAR_FOR_EASYBUILD'" self.assertRegex(test_report_txt, filter_arg_regex) @@ -4458,7 +4458,7 @@ def test_extended_dry_run(self): self.assert_multi_regex(msg_regexs, stdout) # no ignored errors should occur - self.assert_multi_regex([ignoring_error_regex, ignored_error_regex], stdout, assert_true=False) + self.assert_multi_regex([ignoring_error_regex, ignored_error_regex], stdout, assert_match=False) def test_last_log(self): """Test --last-log.""" @@ -4908,7 +4908,7 @@ def test_github_new_update_pr(self): r"# Build statistics", r"buildstats\s*=", ] - self.assert_multi_regex(regexs, txt, assert_true=False) + self.assert_multi_regex(regexs, txt, assert_match=False) def test_github_new_pr_warning_missing_patch(self): """Test warning printed by --new-pr (dry run only) when a specified patch file could not be found.""" @@ -5797,7 +5797,7 @@ def test_debug_module_cmds(self): self.modtool.load(['GCC/4.6.3']) logtxt = read_file(self.logfile) self.assertRegex(logtxt, "Running .*\n.*load GCC/4.6.3") - self.assert_multi_regex(patterns, logtxt, assert_true=enable) + self.assert_multi_regex(patterns, logtxt, assert_match=enable) self.modtool.purge() def test_use_color(self): diff --git a/test/framework/package.py b/test/framework/package.py index 7a1326b12a..4c662364e9 100644 --- a/test/framework/package.py +++ b/test/framework/package.py @@ -232,16 +232,12 @@ def test_package(self): self.assertTrue(os.path.isfile(pkgfile), "Found %s" % pkgfile) # check whether extra packaging options were passed down - regex = re.compile("^got an unhandled option: --foo bar$", re.M) - self.assertTrue(regex.search(fpm_output), "Pattern '%s' found in: %s" % (regex.pattern, fpm_output)) + self.assertRegex(fpm_output, re.compile("^got an unhandled option: --foo bar$", re.M)) pkgtxt = read_file(pkgfile) - pkgtxt_regex = re.compile("STARTCONTENTS of installdir %s" % easyblock.installdir) - self.assertTrue(pkgtxt_regex.search(pkgtxt), "Pattern '%s' found in: %s" % (pkgtxt_regex.pattern, pkgtxt)) + self.assertIn("STARTCONTENTS of installdir %s" % easyblock.installdir, pkgtxt) - no_logfiles_regex = re.compile(r'STARTCONTENTS.*\.(log|md)$.*ENDCONTENTS', re.DOTALL | re.MULTILINE) - res = no_logfiles_regex.search(pkgtxt) - self.assertFalse(res, "Pattern not '%s' found in: %s" % (no_logfiles_regex.pattern, pkgtxt)) + self.assertNotRegex(pkgtxt, re.compile(r'STARTCONTENTS.*\.(log|md)$.*ENDCONTENTS', re.DOTALL | re.M)) toy_txt = read_file(os.path.join(TEST_ECS_DIR, 't', 'toy', 'toy-0.0-gompi-2018a-test.eb')) replace_str = '''description = """Toy C program, 100% toy. Now with `backticks'\n''' @@ -250,8 +246,7 @@ def test_package(self): toy_file = os.path.join(self.test_prefix, 'toy-test-description.eb') write_file(toy_file, toy_txt) - regex = re.compile(r"""`backticks'""") - self.assertTrue(regex.search(toy_txt), "Pattern '%s' found in: %s" % (regex.pattern, toy_txt)) + self.assertRegex(toy_txt, r"""`backticks'""") ec_desc = EasyConfig(toy_file, validate=False) easyblock_desc = EB_toy(ec_desc) easyblock_desc.run_all_steps(False) @@ -259,10 +254,8 @@ def test_package(self): pkgfile = os.path.join(pkgdir, 'toy-0.0-gompi-2018a-test-eb-%s.1.rpm' % EASYBUILD_VERSION) self.assertTrue(os.path.isfile(pkgfile)) pkgtxt = read_file(pkgfile) - regex_pkg = re.compile(r"""DESCRIPTION:.*`backticks'.*""") - self.assertTrue(regex_pkg.search(pkgtxt), "Pattern '%s' not found in: %s" % (regex_pkg.pattern, pkgtxt)) - regex_pkg = re.compile(r"""DESCRIPTION:.*\nand newlines""", re.MULTILINE) - self.assertTrue(regex_pkg.search(pkgtxt), "Pattern '%s' not found in: %s" % (regex_pkg.pattern, pkgtxt)) + self.assertRegex(pkgtxt, r"""DESCRIPTION:.*`backticks'.*""") + self.assertRegex(pkgtxt, r"""DESCRIPTION:.*\nand newlines""") def suite(loader=None): diff --git a/test/framework/utilities.py b/test/framework/utilities.py index ff9d4372d3..2257b93136 100644 --- a/test/framework/utilities.py +++ b/test/framework/utilities.py @@ -39,6 +39,7 @@ from contextlib import contextmanager from importlib import reload from pathlib import Path +from typing import List, Pattern, Union from test.framework import TEST_DIR, TEST_ECS_DIR, TEST_MODULES_DIR from easybuild.base import fancylogger @@ -449,11 +450,18 @@ def setup_categorized_hmns_modules(self): line) sys.stdout.write(line) - def assert_multi_regex(self, regexs, txt, assert_true=True, flags=re.M): - """Helper function to assert presence/absence of list of regex patterns in a text""" + def assert_multi_regex(self, regexs: List[Union[str, Pattern]], txt: str, + assert_match: bool = True, multi_line: bool = True) -> None: + """Helper function to assert presence/absence of list of regex patterns in a text + param: regexs: list of regex patterns to check for + param: txt: text to check for regex patterns + param: assert_match: Whether all regex patterns should match or not match + param: multi_line: if False, match ^/$ only at the beginning/end of the whole string + """ for regex in regexs: - regex = re.compile(regex, flags) - if assert_true: + if multi_line: + regex = re.compile(regex, re.M) + if assert_match: self.assertRegex(txt, regex) else: self.assertNotRegex(txt, regex)