Skip to content

Commit a4574ae

Browse files
committed
Use assert(Not)Regex instead of assertTrue or assertFalse in tests
This makes the tests shorter and hence easier to read, avoids `re.compile` calls and manual failure message composing. In some cases `assert_multi_regex` could be used to avoid the explicit loops.
1 parent 3c13372 commit a4574ae

25 files changed

Lines changed: 528 additions & 936 deletions

easybuild/base/testing.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import difflib
3737
import os
3838
import pprint
39-
import re
4039
import sys
4140
from contextlib import contextmanager
4241
from io import StringIO
@@ -173,10 +172,7 @@ def assertErrorRegex(self, error, regex, call, *args, **kwargs):
173172
str_args = ', '.join(list(map(str, args)) + str_kwargs)
174173
self.fail("Expected errors with %s(%s) call should occur" % (call.__name__, str_args))
175174
except error as err:
176-
msg = self.convert_exception_to_str(err)
177-
if isinstance(regex, str):
178-
regex = re.compile(regex)
179-
self.assertTrue(regex.search(msg), "Pattern '%s' is found in '%s'" % (regex.pattern, msg))
175+
self.assertRegex(self.convert_exception_to_str(err), regex)
180176

181177
def mock_stdout(self, enable, force_tty=False):
182178
"""Enable/disable mocking stdout."""

test/framework/build_log.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ def test_easybuilderror(self):
6767
self.assertErrorRegex(EasyBuildError, 'BOOM', raise_easybuilderror, 'BOOM')
6868
logtxt = read_file(logfile)
6969

70-
log_re = re.compile(r"^fancyroot ::.* BOOM \(at .*:[0-9]+ in [a-z_]+\)$", re.M)
71-
self.assertTrue(log_re.match(logtxt), "%s matches %s" % (log_re.pattern, logtxt))
70+
self.assertRegex(logtxt, re.compile(r"^fancyroot ::.* BOOM \(at .*:[0-9]+ in [a-z_]+\)$", re.M))
7271

7372
# test formatting of message
7473
self.assertErrorRegex(EasyBuildError, 'BOOMBAF', raise_easybuilderror, 'BOOM%s', 'BAF')
@@ -154,8 +153,7 @@ def test_easybuildlog(self):
154153
r"fancyroot.test_easybuildlog \[ERROR\] :: .*EasyBuild encountered an exception \(at .* in .*\): oops",
155154
'',
156155
])
157-
logtxt_regex = re.compile(r'^%s' % expected_logtxt, re.M)
158-
self.assertTrue(logtxt_regex.search(logtxt), "Pattern '%s' found in %s" % (logtxt_regex.pattern, logtxt))
156+
self.assertRegex(logtxt, re.compile(r'^%s' % expected_logtxt, re.M))
159157

160158
self.assertErrorRegex(EasyBuildError, r"DEPRECATED \(since .*: kaput", log.deprecated, "kaput", older_ver)
161159
self.assertErrorRegex(EasyBuildError, r"DEPRECATED \(since .*: 2>1", log.deprecated, "2>1", '2.0', '1.0')
@@ -181,8 +179,7 @@ def test_easybuildlog(self):
181179
r"fancyroot.test_easybuildlog \[ERROR\] :: EasyBuild encountered an error \(at .* in .*\): foo baz baz",
182180
'',
183181
])
184-
logtxt_regex = re.compile(r'^%s' % expected_logtxt, re.M)
185-
self.assertTrue(logtxt_regex.search(logtxt), "Pattern '%s' found in %s" % (logtxt_regex.pattern, logtxt))
182+
self.assertRegex(logtxt, re.compile(r'^%s' % expected_logtxt, re.M))
186183

187184
write_file(tmplog, '')
188185
logToFile(tmplog, enable=True)
@@ -242,8 +239,7 @@ def test_log_levels(self):
242239
error_msg, deprecated_msg, warning_msg, info_msg, debug_msg,
243240
error_msg, deprecated_msg, warning_msg, info_msg, debug_msg, devel_msg,
244241
])
245-
logtxt_regex = re.compile(r'^%s' % expected_logtxt, re.M)
246-
self.assertTrue(logtxt_regex.search(logtxt), "Pattern '%s' found in %s" % (logtxt_regex.pattern, logtxt))
242+
self.assertRegex(logtxt, re.compile(r'^%s' % expected_logtxt, re.M))
247243

248244
def test_print_warning(self):
249245
"""Test print_warning"""

test/framework/config.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -598,33 +598,27 @@ def test_get_log_filename(self):
598598
tmpdir = tempfile.gettempdir()
599599

600600
res = get_log_filename('foo', '1.2.3')
601-
regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-[0-9]{8}\.[0-9]{6}\.log$'))
602-
self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res))
601+
self.assertRegex(res, re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-[0-9]{8}\.[0-9]{6}\.log$')))
603602

604603
res = get_log_filename('foo', '1.2.3', date='19700101')
605-
regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.[0-9]{6}\.log$'))
606-
self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res))
604+
self.assertRegex(res, re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.[0-9]{6}\.log$')))
607605

608606
res = get_log_filename('foo', '1.2.3', timestamp='094651')
609-
regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-[0-9]{8}\.094651\.log$'))
610-
self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res))
607+
self.assertRegex(res, re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-[0-9]{8}\.094651\.log$')))
611608

612609
res = get_log_filename('foo', '1.2.3', date='19700101', timestamp='094651')
613-
regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.log$'))
614-
self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res))
610+
self.assertRegex(res, re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.log$')))
615611

616612
# if log file already exists, numbers are added to the filename to obtain a new file path
617613
write_file(res, '')
618614
res = get_log_filename('foo', '1.2.3', date='19700101', timestamp='094651')
619-
regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.log\.1$'))
620-
self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res))
615+
self.assertRegex(res, re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.log\.1$')))
621616

622617
# adding salt ensures a unique filename (pretty much)
623618
prev_log_filenames = []
624-
for i in range(10):
619+
for _ in range(10):
625620
res = get_log_filename('foo', '1.2.3', date='19700101', timestamp='094651', add_salt=True)
626-
regex = re.compile(os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.[a-zA-Z]{5}\.log$'))
627-
self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res))
621+
self.assertRegex(res, os.path.join(tmpdir, r'easybuild-foo-1\.2\.3-19700101\.094651\.[a-zA-Z]{5}\.log$'))
628622
self.assertNotIn(res, prev_log_filenames)
629623
prev_log_filenames.append(res)
630624

@@ -676,9 +670,8 @@ def test_log_path(self):
676670

677671
# reconfigure with value for log directory that includes templates
678672
init_config(args=['--logfile-format=easybuild-%(name)s-%(version)s-%(date)s-%(time)s,log.txt'])
679-
regex = re.compile(r'^easybuild-foo-1\.2\.3-[0-9-]{8}-[0-9]{6}$')
680673
res = log_path(ec=ec)
681-
self.assertTrue(regex.match(res), "Pattern '%s' matches '%s'" % (regex.pattern, res))
674+
self.assertRegex(res, r'^easybuild-foo-1\.2\.3-[0-9-]{8}-[0-9]{6}$')
682675
self.assertEqual(log_file_format(), 'log.txt')
683676

684677
def test_get_build_log_path(self):

test/framework/containers.py

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,6 @@ def run_main(self, args, raise_error=True):
8484

8585
return stdout, stderr
8686

87-
def check_regexs(self, regexs, stdout):
88-
"""Helper function to check output of stdout."""
89-
for regex in regexs:
90-
regex = re.compile(regex, re.M)
91-
self.assertTrue(regex.search(stdout), "Pattern '%s' found in: %s" % (regex.pattern, stdout))
92-
9387
def test_end2end_singularity_recipe_config(self):
9488
"""End-to-end test for --containerize (recipe only), using --container-config."""
9589
test_ecs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs', 'test_ecs')
@@ -122,7 +116,7 @@ def test_end2end_singularity_recipe_config(self):
122116
self.assertErrorRegex(EasyBuildError, error_pattern, self.run_main, args, raise_error=True)
123117

124118
args[-1] = 'bootstrap=yum,osversion=7.6.1810'
125-
stdout, stderr = self.run_main(args, raise_error=True)
119+
self.run_main(args, raise_error=True)
126120

127121
txt = read_file(test_container_recipe)
128122
expected = '\n'.join([
@@ -137,8 +131,7 @@ def test_end2end_singularity_recipe_config(self):
137131
# when installing from scratch, a bunch of OS packages are installed too
138132
pkgs = ['epel-release', 'python', 'setuptools', 'Lmod', r'gcc-c\+\+', 'make', 'patch', 'tar']
139133
for pkg in pkgs:
140-
regex = re.compile(r"^yum install .*%s" % pkg, re.M)
141-
self.assertTrue(regex.search(txt), "Pattern '%s' found in: %s" % (regex.pattern, txt))
134+
self.assertRegex(txt, re.compile(r"^yum install .*%s" % pkg, re.M))
142135

143136
pip_patterns = [
144137
# EasyBuild is installed with pip3 by default
@@ -152,15 +145,13 @@ def test_end2end_singularity_recipe_config(self):
152145
r"if \[ ! -d /scratch \]; then mkdir -p /scratch",
153146
]
154147
eb_pattern = r"eb toy-0.0.eb --robot\s*$"
155-
for pattern in pip_patterns + post_commands_patterns + [eb_pattern]:
156-
regex = re.compile('^' + pattern, re.M)
157-
self.assertTrue(regex.search(txt), "Pattern '%s' found in: %s" % (regex.pattern, txt))
148+
self.assert_multi_regex(pip_patterns + post_commands_patterns + [eb_pattern], txt)
158149

159150
remove_file(test_container_recipe)
160151

161152
# can also specify a custom mirror URL
162153
args[-1] += ',mirrorurl=https://example.com'
163-
stdout, stderr = self.run_main(args, raise_error=True)
154+
self.run_main(args, raise_error=True)
164155

165156
txt = read_file(test_container_recipe)
166157
expected = '\n'.join([
@@ -213,10 +204,9 @@ def test_end2end_singularity_recipe_config(self):
213204

214205
# no OS packages are installed by default when starting from an existing image
215206
self.assertNotIn("yum install", txt)
216-
217-
for pattern in pip_patterns + post_commands_patterns + [eb_pattern]:
218-
regex = re.compile('^' + pattern, re.M)
219-
self.assertTrue(regex.search(txt), "Pattern '%s' found in: %s" % (regex.pattern, txt))
207+
self.assert_multi_regex(
208+
(f'^{pattern}' for pattern in pip_patterns + post_commands_patterns + [eb_pattern]),
209+
txt)
220210

221211
remove_file(test_container_recipe)
222212

@@ -226,12 +216,10 @@ def test_end2end_singularity_recipe_config(self):
226216
txt = read_file(test_container_recipe)
227217

228218
for pattern in pip_patterns:
229-
regex = re.compile('^' + pattern, re.M)
230-
self.assertFalse(regex.search(txt), "Pattern '%s' should not be found in: %s" % (regex.pattern, txt))
219+
self.assertNotRegex(txt, re.compile('^' + pattern, re.M))
231220

232221
for pattern in ["easy_install easybuild", eb_pattern]:
233-
regex = re.compile('^' + pattern, re.M)
234-
self.assertTrue(regex.search(txt), "Pattern '%s' should be found in: %s" % (regex.pattern, txt))
222+
self.assertRegex(txt, re.compile('^' + pattern, re.M))
235223

236224
remove_file(test_container_recipe)
237225

@@ -241,12 +229,10 @@ def test_end2end_singularity_recipe_config(self):
241229
txt = read_file(test_container_recipe)
242230

243231
for pattern in post_commands_patterns:
244-
regex = re.compile('^' + pattern, re.M)
245-
self.assertFalse(regex.search(txt), "Pattern '%s' should not be found in: %s" % (regex.pattern, txt))
232+
self.assertNotRegex(txt, re.compile('^' + pattern, re.M))
246233

247234
for pattern in ["id easybuild", eb_pattern]:
248-
regex = re.compile('^' + pattern, re.M)
249-
self.assertTrue(regex.search(txt), "Pattern '%s' should be found in: %s" % (regex.pattern, txt))
235+
self.assertRegex(txt, re.compile('^' + pattern, re.M))
250236

251237
remove_file(test_container_recipe)
252238

@@ -255,8 +241,7 @@ def test_end2end_singularity_recipe_config(self):
255241
stdout, stderr = self.run_main(args, raise_error=True)
256242
txt = read_file(test_container_recipe)
257243

258-
regex = re.compile(r"^eb toy-0.0.eb --robot --debug -l", re.M)
259-
self.assertTrue(regex.search(txt), "Pattern '%s' should be found in: %s" % (regex.pattern, txt))
244+
self.assertRegex(txt, re.compile(r"^eb toy-0.0.eb --robot --debug -l", re.M))
260245

261246
def test_end2end_singularity_image(self):
262247
"""End-to-end test for --containerize (recipe + image)."""
@@ -306,7 +291,7 @@ def test_end2end_singularity_image(self):
306291
r"^== Running 'sudo\s*\S*/singularity build\s*/.* /.*', you may need to enter your 'sudo' password...",
307292
r"^== Singularity image created at %s/containers/toy-0.0\.%s" % (self.test_prefix, ext),
308293
]
309-
self.check_regexs(regexs, stdout)
294+
self.assert_multi_regex(regexs, stdout)
310295

311296
self.assertExists(os.path.join(containerpath, 'toy-0.0.%s' % ext))
312297

@@ -327,7 +312,7 @@ def test_end2end_singularity_image(self):
327312
r"^== Running 'sudo\s*\S*/singularity build --writable /.* /.*', you may need to enter .*",
328313
r"^== Singularity image created at %s/containers/foo-bar\.img$" % self.test_prefix,
329314
]
330-
self.check_regexs(regexs, stdout)
315+
self.assert_multi_regex(regexs, stdout)
331316

332317
cont_img = os.path.join(containerpath, 'foo-bar.img')
333318
self.assertExists(cont_img)
@@ -347,21 +332,21 @@ def test_end2end_singularity_image(self):
347332
regexs.extend([
348333
"WARNING: overwriting existing container image at %s due to --force" % cont_img,
349334
])
350-
self.check_regexs(regexs, stdout)
335+
self.assert_multi_regex(regexs, stdout)
351336
self.assertExists(cont_img)
352337

353338
# also check behaviour under --extended-dry-run
354339
args.append('--extended-dry-run')
355340
stdout, stderr = self.run_main(args)
356341
self.assertFalse(stderr)
357-
self.check_regexs(regexs, stdout)
342+
self.assert_multi_regex(regexs, stdout)
358343

359344
# test use of --container-tmpdir
360345
args.append('--container-tmpdir=%s' % self.test_prefix)
361346
stdout, stderr = self.run_main(args)
362347
self.assertFalse(stderr)
363348
regexs[-3] = r"^== Running 'sudo\s*SINGULARITY_TMPDIR=%s \S*/singularity build .*" % self.test_prefix
364-
self.check_regexs(regexs, stdout)
349+
self.assert_multi_regex(regexs, stdout)
365350

366351
def test_end2end_dockerfile(self):
367352
test_ecs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs', 'test_ecs')
@@ -390,7 +375,7 @@ def test_end2end_dockerfile(self):
390375
stdout, stderr = self.run_main(base_args + ['--container-config=%s' % cont_base])
391376
self.assertFalse(stderr)
392377
regexs = ["^== Dockerfile definition file created at %s/containers/Dockerfile.toy-0.0" % self.test_prefix]
393-
self.check_regexs(regexs, stdout)
378+
self.assert_multi_regex(regexs, stdout)
394379
remove_file(os.path.join(self.test_prefix, 'containers', 'Dockerfile.toy-0.0'))
395380

396381
self.run_main(base_args + ['--container-config=centos:7'])
@@ -413,12 +398,10 @@ def test_end2end_dockerfile(self):
413398
"eb --robot toy-0.0.eb GCC-4.9.2.eb",
414399
"module load toy/0.0 GCC/4.9.2",
415400
]
416-
self.check_regexs(regexs, def_file)
401+
self.assert_multi_regex(regexs, def_file)
417402

418403
# there should be no leading/trailing whitespace included
419-
for pattern in [r'^\s+', r'\s+$']:
420-
regex = re.compile(pattern)
421-
self.assertFalse(regex.search(def_file), "Pattern '%s' should *not* be found in: %s" % (pattern, def_file))
404+
self.assert_multi_regex((r'^\s+', r'\s+$'), def_file, assert_true=False, flags=0)
422405

423406
def test_end2end_docker_image(self):
424407

@@ -462,12 +445,12 @@ def test_end2end_docker_image(self):
462445
r"^== Running 'sudo docker build -f .* -t .* \.', you may need to enter your 'sudo' password...",
463446
r"^== Docker image created at toy-0.0:latest",
464447
]
465-
self.check_regexs(regexs, stdout)
448+
self.assert_multi_regex(regexs, stdout)
466449

467450
args.extend(['--force', '--extended-dry-run'])
468451
stdout, stderr = self.run_main(args)
469452
self.assertFalse(stderr)
470-
self.check_regexs(regexs, stdout)
453+
self.assert_multi_regex(regexs, stdout)
471454

472455
def test_container_config_template_recipe(self):
473456
"""Test use of --container-config and --container-template-recipe."""
@@ -494,8 +477,7 @@ def test_container_config_template_recipe(self):
494477
stdout, stderr = self.run_main(args)
495478

496479
self.assertFalse(stderr)
497-
regex = re.compile("^== Singularity definition file created at .*/containers/Singularity.toy-0.0$")
498-
self.assertTrue(regex.match(stdout), "Stdout matches pattern '%s': %s" % (regex.pattern, stdout))
480+
self.assertRegex(stdout, "^== Singularity definition file created at .*/containers/Singularity.toy-0.0$")
499481

500482
expected = '\n'.join([
501483
"# this is just a test",

0 commit comments

Comments
 (0)