Skip to content

Improved Doctest loading #290

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

Merged
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
5 changes: 4 additions & 1 deletion multicast/hear.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,14 @@ def handle(self):

Testcase 3: `handle` requires valid requests or ignores input.

>>> handler.request = ("The Test", multicast.genSocket())
>>> tst_fixture_sock = multicast.genSocket()
>>> handler.request = ("The Test", tst_fixture_sock)
>>> handler.client_address = ("224.0.1.2", 51234)
>>> handler.handle() is None
True
>>>
>>> multicast.endSocket(tst_fixture_sock)
>>>
"""
(data, sock) = self.request
if data is None or not sock:
Expand Down
34 changes: 28 additions & 6 deletions multicast/recv.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@ def joinstep(groups, port, iface=None, bind_group=None, isock=None):
>>>

Testcase 1: Stability testing.
A: Verify the multicast.recv module is properly initialized.
B: Verify the joinstep function exists and has the expected type.
C: Test socket creation with no groups (default behavior).
D: Test socket creation with a specified multicast group.
E: Test socket creation with a multicast group and binding to that group.
F: Test socket creation using an existing socket handle.

>>> import multicast
>>>
Expand All @@ -243,20 +249,36 @@ def joinstep(groups, port, iface=None, bind_group=None, isock=None):
False
>>> type(multicast.recv.joinstep)
<class 'function'>
>>> multicast.recv.joinstep(None, 59991) #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket...>
>>> tst_sk = multicast.recv.joinstep(None, 59991)
>>> tst_sk #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket...laddr=...>
>>> multicast.endSocket(tst_sk)
>>> tst_sk #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket [closed]...>
>>> tst_fxtr = multicast._MCAST_DEFAULT_GROUP
>>> multicast.recv.joinstep([tst_fxtr], 59991) #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
>>> tst_sk_2 = multicast.recv.joinstep([tst_fxtr], 59991)
>>> tst_sk_2 #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket...>
>>> multicast.recv.joinstep(
>>> multicast.endSocket(tst_sk_2)
>>> tst_sk_2 #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket [closed]...>
>>> tst_sk_3 = multicast.recv.joinstep(
... [tst_fxtr], 59991, None, tst_fxtr
... ) #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
>>> tst_sk_3 #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket...>
>>> multicast.endSocket(tst_sk_3)
>>> tst_sk_3 #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket [closed]...>
>>> sk_fxtr = multicast.genSocket()
>>> multicast.recv.joinstep(
>>> tst_sk_4 = multicast.recv.joinstep(
... [tst_fxtr], 59991, None, tst_fxtr, sk_fxtr
... ) #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
... )
>>> tst_sk_4 #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket...>
>>> multicast.endSocket(tst_sk_4)
>>> tst_sk_4 #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
<socket.socket [closed]...>
>>> sk_fxtr.close()
>>>

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
# setuptools - MIT license
setuptools>=75.0
# virtualenv - MIT license
#virtualenv>=15.0.1
#virtualenv>=20.26.6
# pip - MIT license
pip>=24.3.1
# build - MIT license
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ testing =
pytest-enabler >= 1.0.1
# local
flake8 >= 5.0
virtualenv >= 20.26.5
virtualenv >= 20.26.6
wheel >= 0.44.0
pip >= 24.3.1
pytest-cov >= 4.0.0; \
Expand Down
62 changes: 61 additions & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,60 @@


def loadDocstringsFromModule(module):
"""
Load and return a test suite containing doctests from the specified module.

This function attempts to import the `doctest` module and uses it to find
and load all doctests defined in the provided module. If the module is
valid and contains doctests, a `unittest.TestSuite` object is returned
containing those tests. If no doctests are found or if an error occurs
during the loading process, appropriate messages are printed to the
console.

Notes:
- The function checks if the `doctest` module is already imported to
avoid unnecessary imports.
- The `DocTestFinder` is configured with the following options:
- `verbose=True`: Enables verbose output for the test discovery.
- `recurse=True`: Allows the finder to search for doctests in
nested functions and classes.
- `exclude_empty=True`: Excludes empty doctests from the results.
- If no doctests are found in the specified module, a message is printed
indicating that no tests were found.
- Any other exceptions encountered during the loading process are caught
and printed to the console.

See Also:
- get_test_suite: Function that uses `loadDocstringsFromModule` to build test suites
- load_tests: Function that loads both regular tests and doctests

Args:
module (module) -- The Python module from which to load doctests. This should be a
valid module object that has been imported. If the module is None,
the function will return None.

Returns:
(unittest.TestSuite or None) -- A `unittest.TestSuite` object containing the
doctests found in the specified module. If the module is None,
the function returns None.

Raises:
ImportError
If the `doctest` module fails to import, an ImportError is raised
with a message indicating the failure.

Meta-Testing:

>>> import multicast
>>> suite = loadDocstringsFromModule(multicast) #doctest: +ELLIPSIS
Finding tests in multicast...
>>> if suite:
... print(f"Loaded {len(suite._tests)} doctests from "
... f"{multicast.__name__}") # doctest: +ELLIPSIS
Loaded ... doctests from ...
>>>

"""
if not module:
return None
try:
Expand All @@ -172,7 +226,13 @@ def loadDocstringsFromModule(module):
raise ImportError("[CWE-440] doctest Failed to import.") from _cause
finder = doctest.DocTestFinder(verbose=True, recurse=True, exclude_empty=True)
doc_suite = unittest.TestSuite()
doc_suite.addTests(doctest.DocTestSuite(module=module, test_finder=finder))
try:
doc_suite.addTests(doctest.DocTestSuite(module=module, test_finder=finder))
except ValueError as e:
# ValueError is raised when no tests are found
print(f"No doctests found in {module.__name__}: {e}")
except Exception as e:
print(f"Error loading doctests from {module.__name__}: {e}")
return doc_suite


Expand Down
2 changes: 1 addition & 1 deletion tests/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# setuptools - MIT license
setuptools>=75.0
# virtualenv - MIT license
virtualenv>=20.0
virtualenv>=20.26.6
# pgpy - BSD 3-Clause licensed
#pgpy>=0.4.1
# tox - MIT license
Expand Down
Loading