Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some tweaks to testing framework. #4594

Merged
merged 1 commit into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ NOTE: Python 3.6 support is deprecated and will be dropped in a future release.

RELEASE VERSION/DATE TO BE FILLED IN LATER

From John Doe:

- Whatever John Doe did.
From Mats Wichmann:
- Minor updates to test framework. The functional change is that
test.must_exist() and test.must_exist_one_of() now take an optional
'message' keyword argument which is passed on to fail_test() if
the test fails. The rest is cleanup and type annotations. Be more
careful that the returns from stderr() and stdout(), which *can*
return None, are not used without checking.


RELEASE 4.8.1 - Tue, 03 Sep 2024 17:22:20 -0700
Expand Down
107 changes: 60 additions & 47 deletions testing/framework/TestCmd.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# Copyright 2000-2024 Steven Knight
#
# This module is free software, and you may redistribute it and/or modify
# it under the same terms as Python itself, so long as this copyright message
# and disclaimer are retained in their original form.
#
# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#
# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# Python License: https://docs.python.org/3/license.html#psf-license

"""
A testing framework for commands and scripts.

Expand Down Expand Up @@ -276,22 +295,6 @@
TestCmd.where_is('foo', 'PATH1;PATH2', '.suffix3;.suffix4')
"""

# Copyright 2000-2010 Steven Knight
# This module is free software, and you may redistribute it and/or modify
# it under the same terms as Python itself, so long as this copyright message
# and disclaimer are retained in their original form.
#
# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#
# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

__author__ = "Steven Knight <knight at baldmt dot com>"
__revision__ = "TestCmd.py 1.3.D001 2010/06/03 12:58:27 knight"
__version__ = "1.3"
Expand Down Expand Up @@ -320,7 +323,7 @@
from collections import UserList, UserString
from pathlib import Path
from subprocess import PIPE, STDOUT
from typing import Optional
from typing import Callable, Dict, Optional, Union

IS_WINDOWS = sys.platform == 'win32'
IS_MACOS = sys.platform == 'darwin'
Expand Down Expand Up @@ -427,7 +430,13 @@ def clean_up_ninja_daemon(self, result_type) -> None:
shutil.rmtree(daemon_dir)


def fail_test(self=None, condition: bool=True, function=None, skip: int=0, message=None) -> None:
def fail_test(
self=None,
condition: bool = True,
function: Optional[Callable] = None,
skip: int = 0,
message: str = "",
) -> None:
"""Causes a test to exit with a fail.

Reports that the test FAILED and exits with a status of 1, unless
Expand Down Expand Up @@ -1047,37 +1056,33 @@ def __init__(
self.verbose_set(verbose)
self.combine = combine
self.universal_newlines = universal_newlines
self.process = None
self.process: Optional[Popen] = None
# Two layers of timeout: one at the test class instance level,
# one set on an individual start() call (usually via a run() call)
self.timeout = timeout
self.start_timeout = None
self.set_match_function(match, match_stdout, match_stderr)
self.set_diff_function(diff, diff_stdout, diff_stderr)
self._dirlist = []
self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
self._preserve: Dict[str, Union[str, bool]] = {
'pass_test': False,
'fail_test': False,
'no_result': False,
}
preserve_value = os.environ.get('PRESERVE', False)
if preserve_value not in [0, '0', 'False']:
self._preserve['pass_test'] = os.environ['PRESERVE']
self._preserve['fail_test'] = os.environ['PRESERVE']
self._preserve['no_result'] = os.environ['PRESERVE']
else:
try:
self._preserve['pass_test'] = os.environ['PRESERVE_PASS']
except KeyError:
pass
try:
self._preserve['fail_test'] = os.environ['PRESERVE_FAIL']
except KeyError:
pass
try:
self._preserve['no_result'] = os.environ['PRESERVE_NO_RESULT']
except KeyError:
pass
self._preserve['pass_test'] = os.environ.get('PRESERVE_PASS', False)
self._preserve['fail_test'] = os.environ.get('PRESERVE_FAIL', False)
self._preserve['no_result'] = os.environ.get('PRESERVE_NO_RESULT', False)
self._stdout = []
self._stderr = []
self.status = None
self.status: Optional[int] = None
self.condition = 'no_result'
self.workdir: Optional[str]
self.workdir_set(workdir)
self.subdir(subdir)

Expand Down Expand Up @@ -1144,8 +1149,8 @@ def cleanup(self, condition=None) -> None:
list = self._dirlist[:]
list.reverse()
for dir in list:
self.writable(dir, 1)
shutil.rmtree(dir, ignore_errors=1)
self.writable(dir, True)
shutil.rmtree(dir, ignore_errors=True)
self._dirlist = []

global _Cleanup
Expand Down Expand Up @@ -1242,16 +1247,24 @@ def diff_stdout(self, a, b, *args, **kw):

unified_diff = staticmethod(difflib.unified_diff)

def fail_test(self, condition: bool=True, function=None, skip: int=0, message=None) -> None:
def fail_test(
self,
condition: bool = True,
function: Optional[Callable] = None,
skip: int = 0,
message: str = "",
)-> None:
"""Cause the test to fail."""
if not condition:
return
self.condition = 'fail_test'
fail_test(self=self,
condition=condition,
function=function,
skip=skip,
message=message)
fail_test(
self=self,
condition=condition,
function=function,
skip=skip,
message=message
)

def interpreter_set(self, interpreter) -> None:
"""Set the program to be used to interpret the program
Expand Down Expand Up @@ -1338,7 +1351,7 @@ def preserve(self, *conditions) -> None:
if not conditions:
conditions = ('pass_test', 'fail_test', 'no_result')
for cond in conditions:
self._preserve[cond] = 1
self._preserve[cond] = True

def program_set(self, program) -> None:
"""Sets the executable program or script to be tested."""
Expand Down Expand Up @@ -1701,12 +1714,12 @@ def run(self, program=None,
if self.verbose >= 2:
write = sys.stdout.write
write('============ STATUS: %d\n' % self.status)
out = self.stdout()
out = self.stdout() or ""
bdbaddog marked this conversation as resolved.
Show resolved Hide resolved
if out or self.verbose >= 3:
write(f'============ BEGIN STDOUT (len={len(out)}):\n')
write(out)
write('============ END STDOUT\n')
err = self.stderr()
err = self.stderr() or ""
if err or self.verbose >= 3:
write(f'============ BEGIN STDERR (len={len(err)})\n')
write(err)
Expand Down Expand Up @@ -1985,7 +1998,7 @@ def do_chmod(fname) -> None:
# in the tree bottom-up, lest disabling read permission from
# the top down get in the way of being able to get at lower
# parts of the tree.
for dirpath, dirnames, filenames in os.walk(top, topdown=0):
for dirpath, dirnames, filenames in os.walk(top, topdown=False):
for name in dirnames + filenames:
do_chmod(os.path.join(dirpath, name))
do_chmod(top)
Expand Down Expand Up @@ -2036,7 +2049,7 @@ def do_chmod(fname) -> None:
do_chmod(top)
else:
do_chmod(top)
for dirpath, dirnames, filenames in os.walk(top, topdown=0):
for dirpath, dirnames, filenames in os.walk(top, topdown=False):
for name in dirnames + filenames:
do_chmod(os.path.join(dirpath, name))

Expand Down Expand Up @@ -2090,7 +2103,7 @@ def do_chmod(fname) -> None:
# in the tree bottom-up, lest disabling execute permission from
# the top down get in the way of being able to get at lower
# parts of the tree.
for dirpath, dirnames, filenames in os.walk(top, topdown=0):
for dirpath, dirnames, filenames in os.walk(top, topdown=False):
for name in dirnames + filenames:
do_chmod(os.path.join(dirpath, name))
do_chmod(top)
Expand Down
3 changes: 3 additions & 0 deletions testing/framework/TestCmdTests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python
#
# Copyright 2000-2010 Steven Knight
#
# This module is free software, and you may redistribute it and/or modify
# it under the same terms as Python itself, so long as this copyright message
# and disclaimer are retained in their original form.
Expand All @@ -15,6 +16,8 @@
# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# Python License: https://docs.python.org/3/license.html#psf-license

"""
Unit tests for the TestCmd.py module.
Expand Down
Loading
Loading