Skip to content

Commit 498ebba

Browse files
[MERGE] pull request #359 from reactive-firewall/coderabbitai/chat/fd193f5
📝 CodeRabbit Chat: Insert new content into tests/test_recv.py Signed-off-by: coderabbitai[bot] <[email protected]> Signed-off-by: reactive-firewall <[email protected]>
2 parents 9e75b77 + b2840c2 commit 498ebba

File tree

2 files changed

+180
-1
lines changed

2 files changed

+180
-1
lines changed

tests/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def loadDocstringsFromModule(module: types.ModuleType) -> TestSuite:
285285
"No doctests found in %s: %s", # lazy formatting to avoid PYL-W1203
286286
module.__name__,
287287
e, # log as just warning level, instead of exception (error), but still detailed.
288-
exec_info=True,
288+
exc_info=True,
289289
)
290290
except Exception:
291291
_LOGGER.exception(
@@ -350,6 +350,13 @@ def loadDocstringsFromModule(module: types.ModuleType) -> TestSuite:
350350
"security": [], # To be implemented
351351
}
352352

353+
try:
354+
from tests import test_recv
355+
depends.insert(11, test_recv)
356+
EXTRA_TESTS["coverage"].append(test_recv.McastRECVTestSuite)
357+
except Exception: # pragma: no branch
358+
_LOGGER.warning("Error loading optional debug tests", exc_info=True)
359+
353360
try:
354361
FUZZING_TESTS = {
355362
"slow": [

tests/test_recv.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#! /usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
# Multicast Python Module (Testing)
5+
# ..................................
6+
# Copyright (c) 2017-2025, Mr. Walls
7+
# ..................................
8+
# Licensed under MIT (the "License");
9+
# you may not use this file except in compliance with the License.
10+
# You may obtain a copy of the License at
11+
# ..........................................
12+
# https://www.github.com/reactive-firewall/multicast/LICENSE.md
13+
# ..........................................
14+
# Unless required by applicable law or agreed to in writing, software
15+
# distributed under the License is distributed on an "AS IS" BASIS,
16+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
# See the License for the specific language governing permissions and
18+
# limitations under the License.
19+
20+
"""Test module for multicast.recv functionality.
21+
22+
This module provides test cases for the recv module, focusing on the
23+
McastRECV.doStep method's branching logic for success/failure logging.
24+
"""
25+
26+
27+
__module__ = "tests"
28+
29+
30+
try:
31+
try:
32+
import context
33+
except Exception as _: # pragma: no branch
34+
del _ # skipcq - cleanup any error vars early
35+
from . import context
36+
if context.__name__ is None:
37+
raise ModuleNotFoundError("[CWE-758] Failed to import context") from None
38+
else:
39+
from context import sys
40+
from context import multicast # pylint: disable=cyclic-import - skipcq: PYL-R0401
41+
from context import unittest
42+
from unittest import mock
43+
import io
44+
except Exception as err:
45+
raise ImportError("[CWE-758] Failed to import test context") from err
46+
47+
48+
@context.markWithMetaTag("extra", "coverage")
49+
class McastRECVTestSuite(context.BasicUsageTestSuite):
50+
"""Test cases for McastRECV class doStep method."""
51+
52+
__module__ = "tests.test_recv"
53+
54+
def setUp(self):
55+
"""Set up test fixtures."""
56+
super(McastRECVTestSuite, self).setUp()
57+
self.recv_tool = multicast.recv.McastRECV()
58+
# Store original stdout for later restoration
59+
self.original_stdout = sys.stdout
60+
61+
def tearDown(self):
62+
"""Tear down test fixtures."""
63+
# Restore original stdout
64+
sys.stdout = self.original_stdout
65+
super(McastRECVTestSuite, self).tearDown()
66+
67+
@mock.patch('multicast.recv.module_logger')
68+
def test_doStep_with_response(self, mock_logger):
69+
"""Test case 1: Test doStep with successful response."""
70+
# Mock _hearstep to return a non-empty response
71+
with mock.patch.object(
72+
multicast.recv.McastRECV, '_hearstep', return_value='Test response'
73+
) as mock_hear:
74+
result, response = self.recv_tool.doStep(is_std=False)
75+
# Verify results
76+
self.assertTrue(result)
77+
self.assertEqual(response, 'Test response')
78+
# Verify logger called with success message
79+
mock_logger.info.assert_called_once_with("Success")
80+
# Verify _hearstep was called with expected defaults
81+
mock_hear.assert_called_once()
82+
83+
@mock.patch('multicast.recv.module_logger')
84+
def test_doStep_with_empty_response(self, mock_logger):
85+
"""Test case 2: Test doStep with empty response."""
86+
# Mock _hearstep to return an empty response
87+
with mock.patch.object(
88+
multicast.recv.McastRECV, '_hearstep', return_value=''
89+
) as mock_hear:
90+
result, response = self.recv_tool.doStep(is_std=False)
91+
# Verify results: expect a failure (False) and no response (None)
92+
self.assertFalse(result)
93+
self.assertIsNone(response)
94+
# Verify logger called with nothing received message
95+
mock_logger.debug.assert_any_call("Nothing Received.")
96+
# Verify _hearstep was called with expected defaults
97+
mock_hear.assert_called_once()
98+
99+
@mock.patch('multicast.recv.module_logger')
100+
def test_doStep_logging_sequence_success(self, mock_logger):
101+
"""Test case 3: Verify logging sequence for successful response."""
102+
# Mock _hearstep to return a non-empty response
103+
with mock.patch.object(
104+
multicast.recv.McastRECV, '_hearstep', return_value='Test response'
105+
):
106+
self.recv_tool.doStep(is_std=False)
107+
# Verify initial debug log and success log
108+
mock_logger.debug.assert_any_call("RECV")
109+
mock_logger.info.assert_called_once_with("Success")
110+
# Ensure that "Nothing Received" is not logged
111+
for call in mock_logger.debug.call_args_list:
112+
self.assertNotEqual(call[0][0], "Nothing Received.")
113+
114+
@mock.patch('multicast.recv.module_logger')
115+
def test_doStep_logging_sequence_empty(self, mock_logger):
116+
"""Test case 4: Verify logging sequence for empty response."""
117+
# Mock _hearstep to return an empty response
118+
with mock.patch.object(
119+
multicast.recv.McastRECV, '_hearstep', return_value=''
120+
):
121+
self.recv_tool.doStep(is_std=False)
122+
# Verify initial debug log and nothing received log
123+
mock_logger.debug.assert_any_call("RECV")
124+
mock_logger.debug.assert_any_call("Nothing Received.")
125+
# Verify that no success log was called
126+
mock_logger.info.assert_not_called()
127+
128+
@mock.patch('multicast.recv.module_logger')
129+
def test_doStep_console_output(self, mock_logger):
130+
"""Test case 5: Test console output when is_std is True with data."""
131+
# Capture printed output by redirecting stdout
132+
mock_stdout = io.StringIO()
133+
sys.stdout = mock_stdout
134+
# Mock _hearstep to return a non-empty response
135+
with mock.patch.object(
136+
multicast.recv.McastRECV, '_hearstep', return_value='Test response'
137+
):
138+
self.recv_tool.doStep(is_std=True)
139+
# Verify that the response is printed to console
140+
output = mock_stdout.getvalue()
141+
self.assertIn('Test response', output)
142+
# Verify that the logger recorded the intended debug message
143+
mock_logger.debug.assert_any_call("Will Print to Console.")
144+
145+
@mock.patch('multicast.recv.module_logger')
146+
def test_doStep_with_custom_parameters(self, mock_logger):
147+
"""Test case 6: Test doStep with custom parameters."""
148+
# Mock _hearstep to capture and return custom test output
149+
with mock.patch.object(
150+
multicast.recv.McastRECV, '_hearstep', return_value='Custom test'
151+
) as mock_hear:
152+
custom_group = "224.0.0.2"
153+
custom_port = 12345
154+
custom_iface = "lo"
155+
156+
self.recv_tool.doStep(
157+
groups=[custom_group],
158+
port=custom_port,
159+
iface=custom_iface,
160+
group=custom_group,
161+
is_std=False
162+
)
163+
# Verify _hearstep is called with custom parameters
164+
mock_hear.assert_called_once_with(
165+
[custom_group], custom_port, custom_iface, custom_group
166+
)
167+
# Verify that a success log is recorded for the custom parameters
168+
mock_logger.info.assert_called_once_with("Success")
169+
170+
171+
if __name__ == '__main__':
172+
unittest.main()

0 commit comments

Comments
 (0)