• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

reactive-firewall-org / multicast / 16245996832

13 Jul 2025 05:13AM UTC coverage: 97.357%. Remained the same
16245996832

push

github

reactive-firewall
[RELEASE] Version `v2.0.9` (Stable)

127 of 133 branches covered (95.49%)

Branch coverage included in aggregate %.

154 of 157 new or added lines in 15 files covered. (98.09%)

30 existing lines in 4 files now uncovered.

2157 of 2213 relevant lines covered (97.47%)

6.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.41
/tests/test_usage.py
1
#! /usr/bin/env python3
2
# -*- coding: utf-8 -*-
3

4
# Python Test Repo Template
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://github.com/reactive-firewall/python-repo/blob/HEAD/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
"""
21
Tests of integration by usage.
22

23
        Caution: See details about Robust Imports documented in tests.context.
24

25
        Meta
26
        tests.test_usage.BasicIntegrationTestSuite
27

28
        Integration Tests - Fixtures:
29

30
                Test fixtures by importing test context.
31

32
                >>> import tests.test_usage as test_usage
33
                >>> import tests
34
                >>>
35

36
                >>> tests.test_usage.MulticastTestSuite #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
37
                <class...tests.test_usage.MulticastTestSuite...>
38
                >>>
39

40
                >>> tests.test_usage.BasicIntegrationTestSuite #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
41
                <class...tests.test_usage.BasicIntegrationTestSuite...>
42
                >>>
43

44
"""
45

46
__module__ = "tests"
4✔
47

48
try:
4✔
49
        try:
4✔
50
                import context
4✔
51
        except Exception as _root_cause:  # pragma: no branch
52
                del _root_cause  # skipcq - cleanup any error leaks early
53
                from . import context
54
        if not hasattr(context, '__name__') or not context.__name__:  # pragma: no branch
4✔
55
                raise ModuleNotFoundError("[CWE-758] Failed to import context") from None
56
        else:
57
                from collections import namedtuple
4✔
58
                from context import multicast  # pylint: disable=cyclic-import - skipcq: PYL-R0401
4✔
59
                from multicast import __main__  # pylint: disable=cyclic-import - skipcq: PYL-R0401
4✔
60
                from context import unittest
4✔
61
                import io
4✔
62
                from unittest.mock import patch
4✔
63
                from context import subprocess
4✔
64
                from context import Process
4✔
65
except Exception as _cause:
66
        raise ImportError("[CWE-758] Failed to import test context") from _cause
67

68

69
@context.markWithMetaTag("mat", "say", "hear")
4✔
70
class MulticastTestSuite(context.BasicUsageTestSuite):
4✔
71
        """
72
        A test suite for special Multicast usage scenarios.
73

74
        This test suite extends the BasicUsageTestSuite and focuses on testing various
75
        aspects of the multicast functionality, including error handling, command-line
76
        interface behavior, and basic send/receive operations.
77

78
        Methods:
79
        --------
80
        test_aborts_WHEN_calling_multicast_GIVEN_invalid_tools():
81
                Tests the behavior of the CLI tools when given invalid tool names.
82

83
        test_say_is_stable_WHEN_calling_multicast_GIVEN_say_tool():
84
                Verifies the stability of the 'SAY' command with various message arguments.
85

86
        test_recv_aborts_WHEN_calling_multicast_GIVEN_invalid_args():
87
                Checks if the 'RECV' command properly aborts when given invalid arguments.
88

89
        test_hear_aborts_WHEN_calling_multicast_GIVEN_invalid_args():
90
                Ensures the 'HEAR' command aborts correctly when provided with invalid arguments.
91

92
        test_hear_is_stable_WHEN_calling_multicast_GIVEN_invalid_tool():
93
                Tests the stability of the 'HEAR' command when given an invalid tool (--hex).
94

95
        test_noop_stable_WHEN_calling_multicast_GIVEN_noop_args():
96
                Verifies the stability of the 'NOOP' command.
97

98
        test_help_works_WHEN_calling_multicast_GIVEN_help_tool():
99
                Checks if the 'HELP' command functions correctly.
100

101
        test_hear_works_WHEN_say_works():
102
                Tests the basic send and receive functionality using 'SAY' and 'HEAR' commands.
103

104
        test_recv_Errors_WHEN_say_not_used():
105
                Verifies that 'RECV' command produces an error when 'SAY' is not used.
106

107
        Notes:
108
        ------
109
        - This test suite uses subprocess calls to test the multicast CLI interface.
110
        - Some tests involve multiprocessing to simulate concurrent operations.
111
        - Ensure proper network configuration for multicast tests to function correctly.
112

113
        Warnings:
114
        ---------
115
        - Some tests may require specific network conditions to pass successfully.
116
        - Failure in these tests may indicate issues with the multicast implementation
117
                or the testing environment rather than actual bugs in the code.
118
        """
119

120
        __module__ = "tests.test_usage"
4✔
121

122
        __name__ = "tests.test_usage.MulticastTestSuite"
4✔
123

124
        def test_aborts_WHEN_calling_multicast_GIVEN_invalid_tools(self):
4✔
125
                """Tests the impossible state for CLI tools given bad tools"""
126
                theResult = False
4✔
127
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(JUNK) == error")
4✔
128
                tst_dispatch = multicast.__main__.McastDispatch()
4✔
129
                test_junk_values = ["", "NoSuchTool", None]
4✔
130
                try:
4✔
131
                        for tst_in in test_junk_values:
4✔
132
                                (test_code, test_fixture) = tst_dispatch.useTool(tst_in)
4✔
133
                                self.assertEqual(type(test_code), type(True))
4✔
134
                                self.assertIsNone(test_fixture)
4✔
135
                                self.assertTupleEqual(
4✔
136
                                        tst_dispatch.useTool(tst_in),
137
                                        (False, None),  # skipcq: PTC-W0020  - This is test-code.
138
                                        fail_fixture
139
                                )
140
                        theResult = True
4✔
141
                except Exception as _cause:
142
                        context.debugtestError(_cause)
143
                        self.fail(fail_fixture)
144
                        theResult = False
145
                self.assertTrue(theResult, fail_fixture)
4✔
146

147
        def test_say_is_stable_WHEN_calling_multicast_GIVEN_say_tool(self):
4✔
148
                """
149
                Tests the message argument for expected syntax given simple args.
150

151
                First check that the --message argument requires a message value, or exits(2) as per CEP-8.
152
                Second check that providing the message value "test" is sufficient to succeed with exit(0).
153

154
                Rational of these tests are simple enough, the mis-use of the SAY sub-command should result
155
                in an argument error value of 2, due to misuse of shell/CLI builtin as per CEP-8, while a
156
                value of 0 should indicate success.
157
                """
158
                theResult = False
4✔
159
                fail_fixture = str(
160
                        "multicast.__main__.McastDispatch().useTool(SAY, message) != valid exit(0..3)"
161
                )
162
                try:
4✔
163
                        with self.assertRaises(SystemExit) as rtn_val_a:
4✔
164
                                _ = multicast.__main__.McastDispatch().doStep(["SAY", "--message"])
4✔
165
                        (tst_err_rslt_b, rtn_val_b) = multicast.__main__.McastDispatch().doStep(
4✔
166
                                ["SAY", "--message", "test"]
167
                        )
168
                        tst_err_rslt_a = rtn_val_a.exception.code
4✔
169
                        self.assertIsNotNone(rtn_val_a)
4✔
170
                        self.assertIsNotNone(rtn_val_b)
4✔
171
                        self.assertIsNotNone(tst_err_rslt_a)
4✔
172
                        self.assertIsNotNone(tst_err_rslt_b)
4✔
173
                        self.assertNotEqual(int(tst_err_rslt_a), int(0), str(rtn_val_a))
4✔
174
                        self.assertNotEqual(int(tst_err_rslt_a), int(1), str(rtn_val_a))
4✔
175
                        self.assertNotEqual(int(tst_err_rslt_b), int(1), str(rtn_val_b))
4✔
176
                        self.assertNotEqual(int(tst_err_rslt_b), int(2), str(rtn_val_b))
4✔
177
                        self.assertNotEqual(rtn_val_a, rtn_val_b)
4✔
178
                        self.assertNotEqual(tst_err_rslt_a, tst_err_rslt_b)
4✔
179
                        self.assertNotEqual(int(tst_err_rslt_b), int(tst_err_rslt_a))
4✔
180
                        self.assertNotEqual(int(tst_err_rslt_a), int(tst_err_rslt_b))
4✔
181
                        self.assertNotEqual(int(tst_err_rslt_b), int(3))
4✔
182
                        self.assertNotEqual(int(tst_err_rslt_a), int(3))
4✔
183
                        self.assertEqual(int(tst_err_rslt_a), int(2), str(rtn_val_a))
4✔
184
                        self.assertEqual(int(tst_err_rslt_b), int(0), str(rtn_val_b))
4✔
185
                        theResult = (int(tst_err_rslt_b) < int(tst_err_rslt_a))
4✔
186
                except Exception as _cause:
187
                        context.debugtestError(_cause)
188
                        self.fail(fail_fixture)
189
                        theResult = False
190
                self.assertTrue(theResult, fail_fixture)
4✔
191

192
        def test_recv_aborts_WHEN_calling_multicast_GIVEN_invalid_args(self):
4✔
193
                """Tests the message argument for failure given invalid input"""
194
                theResult = False
4✔
195
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(RECV, junk) != exit(1)")
196
                try:
4✔
197
                        with self.assertRaises(SystemExit) as rtn_val_c:
4✔
198
                                _ = multicast.__main__.McastDispatch().doStep(["RECV", "--port", "test"])
4✔
199
                        with self.assertRaises(SystemExit) as rtn_val_d:
4✔
200
                                _ = multicast.__main__.McastDispatch().doStep(
4✔
201
                                        ["RECV", "--port=test", "group=None"]
202
                                )
203
                        self.assertIsNotNone(rtn_val_c)
4✔
204
                        self.assertIsNotNone(rtn_val_d)
4✔
205
                        tst_err_rslt_c = rtn_val_c.exception.code
4✔
206
                        tst_err_rslt_d = rtn_val_d.exception.code
4✔
207
                        self.assertIsNotNone(tst_err_rslt_c)
4✔
208
                        self.assertIsNotNone(tst_err_rslt_d)
4✔
209
                        self.assertNotEqual(int(tst_err_rslt_c), int(0))
4✔
210
                        self.assertNotEqual(int(tst_err_rslt_c), int(1))
4✔
211
                        self.assertNotEqual(int(tst_err_rslt_d), int(1))
4✔
212
                        self.assertEqual(int(tst_err_rslt_c), int(2))
4✔
213
                        self.assertEqual(int(tst_err_rslt_d), int(2))
4✔
214
                        self.assertEqual(int(tst_err_rslt_d), int(tst_err_rslt_c))
4✔
215
                        self.assertEqual(int(tst_err_rslt_c), int(tst_err_rslt_d))
4✔
216
                        self.assertNotEqual(int(tst_err_rslt_d), int(3))
4✔
217
                        theResult = (int(tst_err_rslt_d) == int(tst_err_rslt_c))
4✔
218
                except Exception as _cause:
219
                        context.debugtestError(_cause)
220
                        self.fail(fail_fixture)
221
                        theResult = False
222
                self.assertTrue(theResult, fail_fixture)
4✔
223

224
        def test_hear_aborts_WHEN_calling_multicast_GIVEN_invalid_args(self):
4✔
225
                """Tests the message argument for failure given invalid input"""
226
                theResult = False
4✔
227
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(HEAR, junk) != exit(2)")
228
                try:
4✔
229
                        with self.assertRaises(SystemExit) as rtn_val_e:
4✔
230
                                _ = __main__.main(["HEAR", "--port", "test"])
4✔
231
                        with self.assertRaises(SystemExit) as rtn_val_f:
4✔
232
                                _ = __main__.main(["RECV", "--port", "test"])
4✔
233
                        self.assertIsNotNone(rtn_val_e)
4✔
234
                        self.assertIsNotNone(rtn_val_f)
4✔
235
                        tst_err_rslt_e = rtn_val_e.exception.code
4✔
236
                        tst_err_rslt_f = rtn_val_f.exception.code
4✔
237
                        self.assertIsNotNone(tst_err_rslt_e)
4✔
238
                        self.assertIsNotNone(tst_err_rslt_f)
4✔
239
                        self.assertNotEqual(int(tst_err_rslt_e), int(0))
4✔
240
                        self.assertNotEqual(int(tst_err_rslt_f), int(0))
4✔
241
                        self.assertNotEqual(int(tst_err_rslt_e), int(1))
4✔
242
                        self.assertNotEqual(int(tst_err_rslt_f), int(1))
4✔
243
                        self.assertEqual(int(tst_err_rslt_e), int(2), "CEP-8 Violation. REGRESSION in HEAR")
4✔
244
                        self.assertEqual(int(tst_err_rslt_f), int(2), "CEP-8 Violation. REGRESSION in RECV")
4✔
245
                        self.assertNotEqual(rtn_val_e, rtn_val_f)
4✔
246
                        self.assertNotEqual(int(tst_err_rslt_e), int(3), "Regression. 3 != 64")
4✔
247
                        self.assertNotEqual(int(tst_err_rslt_f), int(3), "Regression. 3 != 64")
4✔
248
                        self.assertEqual(int(tst_err_rslt_f), int(tst_err_rslt_e))
4✔
249
                        theResult = (int(tst_err_rslt_f) == int(tst_err_rslt_e))
4✔
250
                except Exception as _cause:
251
                        context.debugtestError(_cause)
252
                        self.fail(fail_fixture)
253
                        theResult = False
254
                self.assertTrue(theResult, fail_fixture)
4✔
255

256
        def test_hear_ignores_WHEN_calling_multicast_GIVEN_invalid_args(self):
4✔
257
                """Tests the group argument for new auto-default behavior given None."""
258
                theResult = False
4✔
259
                fail_fixture = str("multicast.__main__.main(HEAR, group=None) == ERROR")
4✔
260
                try:
4✔
261
                        (rtn_val_f, tst_err_rslt_f) = __main__.main(
4✔
262
                                ["HEAR", "--group", "None", "--iface=None"]
263
                        )
264
                        self.assertIsNotNone(rtn_val_f)
4✔
265
                        self.assertIsNotNone(tst_err_rslt_f)
4✔
266
                        self.assertNotEqual(int(tst_err_rslt_f[0]), int(1), "REGRESSION in JOIN")
4✔
267
                        self.assertNotEqual(int(tst_err_rslt_f[0]), int(70), "CEP-8 Violation.")
4✔
268
                        self.assertNotEqual(int(tst_err_rslt_f[0]), int(2), "CEP-8 Violation.")
4✔
269
                        self.assertNotEqual(int(tst_err_rslt_f[0]), int(3), "CEP-8 Violation.")
4✔
270
                        self.assertEqual(int(tst_err_rslt_f[0]), int(0), fail_fixture)
4✔
271
                        theResult = (int(tst_err_rslt_f[0]) == int(0))
4✔
272
                except Exception as _cause:
273
                        context.debugtestError(_cause)
274
                        self.fail(fail_fixture)
275
                        theResult = False
276
                self.assertTrue(theResult, fail_fixture)
4✔
277

278
        def test_hear_is_stable_WHEN_calling_multicast_GIVEN_invalid_tool(self):
4✔
279
                """Tests the hexdump argument for failure given future tools"""
280
                theResult = False
4✔
281
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(HEAR, hex) == error")
4✔
282
                try:
4✔
283
                        self.assertTupleEqual(
4✔
284
                                multicast.__main__.main(["HEAR", "--hex"]),
285
                                (70, (False, None))  # skipcq: PTC-W0020  - This is test-code.
286
                        )
287
                        theResult = True
4✔
288
                except Exception as _cause:
289
                        context.debugtestError(_cause)
290
                        self.fail(fail_fixture)
291
                        theResult = False
292
                self.assertTrue(theResult, fail_fixture)
4✔
293

294
        def test_noop_stable_WHEN_calling_multicast_GIVEN_noop_args(self):
4✔
295
                """Tests the NOOP state for multicast given bad input"""
296
                theResult = False
4✔
297
                fail_fixture = str("multicast.__main__.main(NOOP) == Error")
4✔
298
                try:
4✔
299
                        self.assertIsNotNone(multicast.__main__.main(["NOOP"]), fail_fixture)
4✔
300
                        self.assertIsNotNone(multicast.__main__.main(["NOOP"])[0])  # skipcq: PTC-W0020
4✔
301
                        self.assertTupleEqual(
4✔
302
                                multicast.__main__.main(["NOOP"]),
303
                                (0, (True, None)),  # skipcq: PTC-W0020  - This is test-code.
304
                        )
305
                        theResult = True
4✔
306
                except Exception as _cause:
307
                        context.debugtestError(_cause)
308
                        self.fail(fail_fixture)
309
                        theResult = False
310
                self.assertTrue(theResult, fail_fixture)
4✔
311

312
        def test_help_works_WHEN_calling_multicast_GIVEN_help_tool(self):
4✔
313
                """Tests the HELP argument for help usage"""
314
                theResult = False
4✔
315
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(HELP, []) == Empty")
4✔
316
                try:
4✔
317
                        with self.assertRaises(SystemExit) as rtn_val_h:
4✔
318
                                multicast.__main__.McastDispatch().doStep(["HELP"])
4✔
319
                        self.assertIsNotNone(rtn_val_h)
4✔
320
                        theResult = True
4✔
321
                except Exception as _cause:
322
                        context.debugtestError(_cause)
323
                        self.fail(fail_fixture)
324
                        theResult = False
325
                self.assertTrue(theResult, fail_fixture)
4✔
326

327
        def test_hear_works_WHEN_say_works(self):
4✔
328
                """Tests the basic send and recv test"""
329
                theResult = False
4✔
330
                fail_fixture = str("SAY --> HEAR == error")
4✔
331
                sub_fail_fixture = str("SAY X-> HEAR == Error X-> HEAR :: (Error in SAY)")
4✔
332
                try:
4✔
333
                        _fixture_SAY_args = [
4✔
334
                                "--port",
335
                                "59991",
336
                                "--group",
337
                                "'224.0.0.1'",
338
                                "--message",
339
                                "'test message'"
340
                        ]
341
                        _fixture_HEAR_args = [
4✔
342
                                "--port",
343
                                "59991",
344
                                "--groups",
345
                                "'224.0.0.1'""",
346
                                "--group",
347
                                "'224.0.0.1'"
348
                        ]
349
                        p = Process(
4✔
350
                                target=multicast.__main__.McastDispatch().doStep,
351
                                name="HEAR",
352
                                args=(["HEAR", _fixture_HEAR_args])
353
                        )
354
                        p.start()
4✔
355
                        try:
4✔
356
                                tst_fixture_sendDispatch = multicast.__main__.McastDispatch()
4✔
357
                                self.assertIsNotNone(
4✔
358
                                        tst_fixture_sendDispatch.doStep(["SAY", _fixture_SAY_args])
359
                                )
360
                                self.assertIsNotNone(
4✔
361
                                        tst_fixture_sendDispatch.doStep(["SAY", _fixture_SAY_args])
362
                                )
363
                                self.assertIsNotNone(
4✔
364
                                        tst_fixture_sendDispatch.doStep(["SAY", _fixture_SAY_args])
365
                                )
366
                        except Exception as _root_cause:
367
                                p.join()
368
                                raise unittest.SkipTest(sub_fail_fixture) from _root_cause
369
                        p.join()
4✔
370
                        self.assertIsNotNone(p.exitcode)
371
                        self.assertEqual(int(p.exitcode), int(0), f"Unexpected Exit-Code: {p.exitcode}.")
372
                        theResult = (int(p.exitcode) <= int(0))
373
                except unittest.SkipTest as baton:
×
374
                        raise unittest.SkipTest(sub_fail_fixture) from baton
×
375
                except Exception as _cause:
376
                        context.debugtestError(_cause)
377
                        self.fail(fail_fixture)
378
                        theResult = False
379
                self.assertTrue(theResult, fail_fixture)
4✔
380

381
        def test_hear_works_WHEN_fuzzed_and_say_works(self):
4✔
382
                """Tests the basic send and recv test. Skips if fuzzing broke SAY fixture."""
383
                theResult = False
4✔
384
                fail_fixture = str("SAY --> HEAR == error")
4✔
385
                _fixture_port_num = self._the_test_port
4✔
386
                try:
4✔
387
                        self.assertIsNotNone(_fixture_port_num)
4✔
388
                        self.assertEqual(type(_fixture_port_num), type(int(0)))
4✔
389
                        _fixture_SAY_args = [
4✔
390
                                "--port",
391
                                str(_fixture_port_num),
392
                                "--group",
393
                                "'224.0.0.1'",
394
                                "--message",
395
                                "'test message'"
396
                        ]
397
                        _fixture_HEAR_args = [
4✔
398
                                "HEAR",
399
                                "--port",
400
                                str(_fixture_port_num),
401
                                "--groups",
402
                                "'224.0.0.1'",
403
                                "--group",
404
                                "'224.0.0.1'"
405
                        ]
406
                        p = Process(
4✔
407
                                target=multicast.__main__.McastDispatch().doStep,
408
                                name="HEAR",
409
                                args=(["HEAR", _fixture_HEAR_args])
410
                        )
411
                        p.start()
4✔
412
                        try:
4✔
413
                                self.assertIsNotNone(
4✔
414
                                        multicast.__main__.McastDispatch().doStep(["SAY", _fixture_SAY_args])
415
                                )
416
                                self.assertIsNotNone(
4✔
417
                                        multicast.__main__.McastDispatch().doStep(["SAY", _fixture_SAY_args])
418
                                )
419
                                self.assertIsNotNone(
4✔
420
                                        multicast.__main__.McastDispatch().doStep(["SAY", _fixture_SAY_args])
421
                                )
422
                        except Exception as _root_cause:
423
                                p.join()
424
                                raise unittest.SkipTest(fail_fixture) from _root_cause
425
                        p.join()
4✔
426
                        self.assertIsNotNone(p.exitcode)
427
                        self.assertEqual(int(p.exitcode), int(0))
428
                        theResult = (int(p.exitcode) <= int(0))
429
                except unittest.SkipTest as baton:
×
430
                        raise unittest.SkipTest("Fuzzing broke SAY fixture.") from baton
×
431
                except Exception as _cause:
432
                        context.debugtestError(_cause)
433
                        self.skipTest(fail_fixture)
434
                        theResult = False
435
                self.assertTrue(theResult, fail_fixture)
4✔
436

437
        def test_say_works_WHEN_using_stdin(self):
4✔
438
                """Tests the basic send with streamed input test case."""
439
                theResult = False
4✔
440
                fail_fixture = str("STDIN --> SAY == error")
4✔
441
                _fixture_port_num = self._the_test_port
4✔
442
                try:
4✔
443
                        say = multicast.send.McastSAY()
4✔
444
                        self.assertIsNotNone(say)
4✔
445
                        self.assertIsNotNone(_fixture_port_num)
4✔
446
                        test_cases = [
4✔
447
                                "",  # Empty input
448
                                "Test message from stdin",  # Basic case
449
                                "A" * 1024,  # Large input
450
                                "Special chars: !@#$%^&*()",  # Special characters
451
                                "Unicode: 你好世界",  # Unicode
452
                                "HEAR\x00"  # Null byte injection
453
                        ]
454
                        for test_input in test_cases:
4✔
455
                                self.assertIsNotNone(test_input)
4✔
456
                                with patch('sys.stdin', io.StringIO(test_input)):
4✔
457
                                        result = say.doStep(data=["-"], group="224.0.0.1", port=_fixture_port_num)
4✔
458
                                        self.assertIsNotNone(result)
4✔
459
                                        # Verify the message was actually sent
460
                                        theResult = result[0] or False
4✔
461
                                        self.assertTrue(theResult)  # Assuming there's a success indicator
4✔
462
                except Exception as _cause:
463
                        context.debugtestError(_cause)
464
                        self.fail(fail_fixture)
465
                        theResult = False
466
                self.assertTrue(theResult, fail_fixture)
4✔
467

468
        def test_recv_Errors_WHEN_say_not_used(self):
4✔
469
                """Tests the basic noop recv test"""
470
                theResult = False
4✔
471
                fail_fixture = str("NOOP --> RECV != error")
4✔
472
                sub_fail_fixture = str("NOOP X-> RECV == Error X-> RECV :: (Error in NOOP)")
4✔
473
                try:
4✔
474
                        _fixture_RECV_args = [
4✔
475
                                "--port",
476
                                "59992",
477
                                "--groups",
478
                                "'224.0.0.1'",
479
                                "--group",
480
                                "'224.0.0.1'"
481
                        ]
482
                        p = Process(
4✔
483
                                target=multicast.__main__.McastDispatch().doStep,
484
                                name="NOHEAR",
485
                                args=(["RECV", _fixture_RECV_args])
486
                        )
487
                        p.start()
4✔
488
                        try:
4✔
489
                                test_cls = multicast.__main__.McastDispatch()
4✔
490
                                self.assertTupleEqual(
4✔
491
                                        test_cls.doStep(["NOOP", []]),
492
                                        (int(0), (True, None)),  # skipcq: PTC-W0020  - This is test-code.
493
                                        sub_fail_fixture
494
                                )
495
                        except Exception as _root_cause:
496
                                p.join()
497
                                raise unittest.SkipTest(sub_fail_fixture) from _root_cause
498
                        p.join()
4✔
499
                        self.assertIsNotNone(p.exitcode, fail_fixture)
500
                        self.assertEqual(int(p.exitcode), int(0), f"Unexpected Exit-Code: {p.exitcode}.")
501
                        theResult = (int(p.exitcode) <= int(0))
502
                except unittest.SkipTest as baton:
×
503
                        raise unittest.SkipTest(sub_fail_fixture) from baton
×
504
                except Exception as _cause:
505
                        context.debugtestError(_cause)
506
                        self.fail(fail_fixture)
507
                        theResult = False
508
                self.assertTrue(theResult, fail_fixture)
4✔
509

510

511
@context.markWithMetaTag("mat", "usage")
4✔
512
class BasicIntegrationTestSuite(context.BasicUsageTestSuite):
4✔
513
        """
514
        A test suite for basic functional integration tests of the multicast module.
515

516
        This class inherits from context.BasicUsageTestSuite and provides a set of
517
        test cases to verify the functionality of the multicast module's command-line
518
        interface and core features.
519

520
        The suite includes tests for:
521
        - Printing usage information when called with the help argument
522
        - Verifying command-specific help output
523
        - Comparing responses between absolute and implicit module calls
524
        - Checking version information output
525
        - Validating error handling for invalid inputs
526
        - Profiling and stability checks for the NOOP command
527

528
        Attributes:
529
                _thepython (str): Path to the Python interpreter used for testing.
530

531
        Methods:
532
                setUp(): Prepares the test environment before each test method is run.
533
                test_prints_usage_WHEN_called_GIVEN_help_argument(): Verifies help output.
534
                test_prints_usage_WHEN_called_GIVEN_cmd_and_help_argument(): Checks command-specific help.
535
                test_equivilant_response_WHEN_absolute_vs_implicit(): Compares module call methods.
536
                test_prints_version_WHEN_called_GIVEN_version_argument(): Validates version output.
537
                test_Usage_Error_WHEN_the_help_command_is_called(): Ensures correct help output.
538
                test_profile_WHEN_the_noop_command_is_called(): Profiles the NOOP command.
539
                test_stable_WHEN_the_noop_command_is_called(): Checks NOOP command stability.
540
                test_invalid_Error_WHEN_cli_called_GIVEN_bad_input(): Verifies error handling.
541

542
        Note:
543
                This test suite relies on the context module for utility functions and
544
                the subprocess module for executing Python commands. It uses various
545
                assertion methods to validate the expected behavior of the multicast module.
546

547
        Example:
548
                To run this test suite, use the unittest module's test runner:
549

550
                ```
551
                python -m unittest tests.test_usage.BasicIntegrationTestSuite
552
                ```
553
        """
554

555
        __module__ = "tests.test_usage"
4✔
556

557
        __name__ = "tests.test_usage.BasicIntegrationTestSuite"
4✔
558

559
        def setUp(self) -> None:
4✔
560
                """
561
                Set up the test environment before each test method is run.
562

563
                This method calls the superclass's setUp method to ensure that any
564
                necessary initialization is performed. It also checks if the
565
                `_thepython` attribute is None, and if so, it skips the test with
566
                a message indicating that there is no Python command to test with.
567

568
                Args:
569
                        None
570

571
                Returns:
572
                        None
573

574
                Raises:
575
                        unittest.SkipTest: If there is no Python command available for testing.
576
                """
577
                super(self.__class__, self).setUp()  # skipcq: PYL-E1003 - this is more polymorphic
4✔
578
                if (self._thepython is None):
4✔
UNCOV
579
                        self.skipTest(str("No python cmd to test with!"))
×
580

581
        def test_prints_usage_WHEN_called_GIVEN_help_argument(self):
4✔
582
                """Test case for multicast.__main__ help."""
583
                theResult = False
4✔
584
                fail_fixture = str("multicast.__main__(--help) == not helpful")
4✔
585
                try:
4✔
586
                        if (self._thepython is not None):
4✔
587
                                theOutputtxt = context.checkPythonCommand(
4✔
588
                                        [str(self._thepython), str("-m"), str("multicast"), str("--help")],
589
                                        stderr=subprocess.STDOUT
590
                                )
591
                                self.assertIn(str("usage:"), str(theOutputtxt))
4✔
592
                                if (str("usage:") in str(theOutputtxt)):
4✔
593
                                        theResult = True
4✔
594
                                else:
UNCOV
595
                                        theResult = False
×
596
                                        context.debugUnexpectedOutput(
×
597
                                                str("usage:"), str(theOutputtxt), self._thepython
598
                                        )
599
                except Exception as _cause:
600
                        context.debugtestError(_cause)
601
                        del _cause  # skipcq - cleanup any error leaks early
602
                        self.fail(fail_fixture)
603
                        theResult = False
604
                self.assertTrue(theResult, str("Could Not find usage from multicast --help"))
4✔
605

606
        def test_prints_usage_WHEN_called_GIVEN_cmd_and_help_argument(self):
4✔
607
                """Test case for multicast HEAR|RECV|SAY help."""
608
                theResult = None
4✔
609
                fail_fixture = str("multicast.__main__(--help) == not helpful")
4✔
610
                try:
4✔
611
                        if (self._thepython is not None):
4✔
612
                                for test_case in [".__main__", ""]:
4✔
613
                                        args = [
4✔
614
                                                str(self._thepython),
615
                                                str("-m"),
616
                                                str("multicast{}").format(str(test_case)),
617
                                                str("--help")
618
                                        ]
619
                                        theOutputtxt = context.checkPythonCommand(args, stderr=subprocess.STDOUT)
4✔
620
                                        self.assertIn(str("usage:"), str(theOutputtxt))
4✔
621
                                        if (str("usage:") in str(theOutputtxt)):
4✔
622
                                                theResult = ((theResult is None) or (theResult is True))
4✔
623
                                        else:
UNCOV
624
                                                theResult = False
×
UNCOV
625
                                                context.debugUnexpectedOutput(
×
626
                                                        str("usage:"), str(theOutputtxt), self._thepython
627
                                                )
628
                except Exception as _cause:
629
                        context.debugtestError(_cause)
630
                        del _cause  # skipcq - cleanup any error leaks early
631
                        self.fail(fail_fixture)
632
                        theResult = False
633
                self.assertTrue(theResult, str("Could Not find usage from multicast CMD --help"))
4✔
634

635
        def test_equivilant_response_WHEN_absolute_vs_implicit(self):
4✔
636
                """Test case for multicast vs multicast.__main__"""
637
                theResult = False
4✔
638
                try:
4✔
639
                        theExpectedText = context.checkPythonCommand(
4✔
640
                                [str(self._thepython), str("-m"), str("multicast.__main__")],
641
                                stderr=subprocess.STDOUT
642
                        )
643
                        self.assertIsNotNone(theExpectedText)
4✔
644
                        theOutputtxt = context.checkPythonCommand(
4✔
645
                                [str(self._thepython), str("-m"), str("multicast")], stderr=subprocess.STDOUT
646
                        )
647
                        self.assertIn(str(theExpectedText), str(theOutputtxt))
4✔
648
                        if (str(theExpectedText) in str(theOutputtxt)):
4✔
649
                                theResult = True
4✔
650
                        else:
UNCOV
651
                                theResult = False
×
UNCOV
652
                                context.debugUnexpectedOutput(
×
653
                                        str(theExpectedText), str(theOutputtxt), self._thepython
654
                                )
655
                except BaseException as _cause:
656
                        context.debugtestError(_cause)
657
                        del _cause  # skipcq - cleanup any error leaks early
658
                        theResult = False
659
                self.assertTrue(theResult, str("Could Not swap multicast for multicast.__main__"))
4✔
660

661
        def test_prints_version_WHEN_called_GIVEN_version_argument(self):
4✔
662
                """Test for result from --version argument: python -m multicast.* --version """
663
                theResult = False
4✔
664
                if (self._thepython is not None):
4✔
665
                        try:
4✔
666
                                for test_case in [".__main__", ""]:
4✔
667
                                        args = [
4✔
668
                                                str(self._thepython),
669
                                                str("-m"),
670
                                                str("multicast{}").format(str(test_case)),
671
                                                str("--version")
672
                                        ]
673
                                        theOutputtxt = context.checkPythonCommand(args, stderr=subprocess.STDOUT)
4✔
674
                                        context.check_exec_command_has_output(self, args)
4✔
675
                                        theResult = (theOutputtxt is not None)
4✔
676
                        except Exception as _cause:
677
                                context.debugtestError(_cause)
678
                                del _cause  # skipcq - cleanup any error leaks early
679
                                theResult = False
680
                self.assertTrue(theResult, str("Could Not find version from multicast --version"))
4✔
681

682
        def _validate_help_output(self, args: list) -> bool:
4✔
683
                """
684
                Helper method to validate help command output.
685

686
                Args:
687
                        args (list) -- List of command arguments to execute
688

689
                Returns:
690
                        bool: True if validation passes, False otherwise
691
                """
692
                usageText = "usage:"
4✔
693
                theOutputtxt = context.checkPythonCommand(args, stderr=subprocess.STDOUT)
4✔
694
                subResult = False
4✔
695
                try:
4✔
696
                        if isinstance(theOutputtxt, bytes):
4✔
UNCOV
697
                                theOutputtxt = theOutputtxt.decode('utf8')
×
698
                except UnicodeDecodeError:
699
                        theOutputtxt = str(repr(bytes(theOutputtxt)))
700
                self.assertIsNotNone(theOutputtxt)
4✔
701
                self.assertIn(str(usageText), str(theOutputtxt))
4✔
702
                if str(usageText) in str(theOutputtxt):
4✔
703
                        subResult = True
4✔
704
                else:
UNCOV
705
                        context.debugUnexpectedOutput(
×
706
                                str(usageText), str(theOutputtxt), self._thepython
707
                        )
708
                return subResult
4✔
709

710
        def test_Usage_Error_WHEN_the_help_command_is_called(self):
4✔
711
                """Test case for multicast* --help."""
712
                theResult = False
4✔
713
                fail_fixture = str("multicast --help == not helpful")
4✔
714
                try:
4✔
715
                        if (self._thepython is not None):
4✔
716
                                for test_case in [".__main__", ""]:
4✔
717
                                        args = [
4✔
718
                                                str(self._thepython),
719
                                                str("-m"),
720
                                                str("multicast{}").format(str(test_case)),
721
                                                str("--help")
722
                                        ]
723
                                        with self.subTest(args=args):
4✔
724
                                                if self._validate_help_output(args):
4✔
725
                                                        theResult = True
4✔
726
                except Exception as _cause:
727
                        context.debugtestError(_cause)
728
                        del _cause  # skipcq - cleanup any error leaks early
729
                        self.fail(fail_fixture)
730
                        theResult = False
731
                self.assertTrue(theResult, str("Could Not find usage from multicast --help"))
4✔
732

733
        def test_Usage_Error_WHEN_the_help_sub_command_is_called(self):
4✔
734
                """
735
                Test case for validating help output of multicast sub-commands.
736

737
                This test ensures that the help output is correct for various sub-commands
738
                (HEAR, RECV, SAY) in both daemon and non-daemon modes. It validates that
739
                each command combination provides appropriate usage information.
740

741
                Test fixtures use named tuples to organize:
742
                - mode: daemon/non-daemon mode
743
                - command: the sub-command being tested
744
                """
745
                theResult = False
4✔
746
                fail_fixture = str("multicast [HEAR|RECV] --help == not helpful")
4✔
747
                try:
4✔
748
                        TestCase = namedtuple("TestCase", ["mode", "command"])
4✔
749
                        inner_fixtures = [
4✔
750
                                TestCase(mode="--daemon {}", command="HEAR"),
751
                                TestCase(mode="{}", command="HEAR"),
752
                                TestCase(mode="--daemon {}", command="RECV"),
753
                                TestCase(mode="{}", command="RECV"),
754
                                TestCase(mode="{}", command="SAY"),
755
                                TestCase(mode="{}", command="NOOP")
756
                        ]
757
                        if (self._thepython is not None):
4✔
758
                                theResult = True
4✔
759
                                for test_case_o in [".__main__", ""]:
4✔
760
                                        for test_case_i in inner_fixtures:
4✔
761
                                                self.assertIsInstance(test_case_i, TestCase)
4✔
762
                                                args = [
4✔
763
                                                        str(self._thepython),
764
                                                        str("-m"),
765
                                                        str("multicast{}").format(str(test_case_o)),
766
                                                        str(test_case_i.mode).format(str(test_case_i.command)),
767
                                                        str("--help")
768
                                                ]
769
                                                with self.subTest(args=args):
4✔
770
                                                        if not self._validate_help_output(args):
4✔
UNCOV
771
                                                                theResult = False
×
772
                except Exception as _cause:
773
                        context.debugtestError(_cause)
774
                        del _cause  # skipcq - cleanup any error leaks early
775
                        self.fail(fail_fixture)
776
                        theResult = False
777
                self.assertTrue(theResult, str("Could Not find usage from multicast --help"))
4✔
778

779
        def test_profile_WHEN_the_noop_command_is_called(self):
4✔
780
                """Test case template for profiling"""
781
                theResult = False
4✔
782
                if (self._thepython is not None):
4✔
783
                        try:
4✔
784
                                for test_case in ["NOOP"]:
4✔
785
                                        args = [
4✔
786
                                                str(self._thepython),
787
                                                str("-m"),
788
                                                str("multicast"),
789
                                                str("{}").format(str(test_case))
790
                                        ]
791
                                        theOutputtxt = context.timePythonCommand(args, stderr=subprocess.STDOUT)
4✔
792
                                        # now test it
793
                                        try:
4✔
794
                                                if isinstance(theOutputtxt, bytes):
4✔
UNCOV
795
                                                        theOutputtxt = theOutputtxt.decode('utf8')
×
796
                                        except UnicodeDecodeError:
797
                                                theOutputtxt = str(repr(bytes(theOutputtxt)))
798
                                        # or simply:
799
                                        self.assertIsNotNone(theOutputtxt)
4✔
800
                                        theResult = True
4✔
801
                        except Exception as _cause:
802
                                context.debugtestError(_cause)
803
                                del _cause  # skipcq - cleanup any error leaks early
804
                                theResult = False
805
                assert theResult
4✔
806

807
        def test_stable_WHEN_the_noop_command_is_called(self):
4✔
808
                """Test case template for profiling"""
809
                theResult = False
4✔
810
                if (self._thepython is not None):
4✔
811
                        try:
4✔
812
                                for test_case in ["NOOP"]:
4✔
813
                                        args = [
4✔
814
                                                str(self._thepython),
815
                                                str("-m"),
816
                                                str("multicast"),
817
                                                str("{}").format(str(test_case))
818
                                        ]
819
                                        context.checkPythonFuzzing(args, stderr=None)
4✔
820
                                        # now test it
821
                                        theResult = True
4✔
822
                        except Exception as _cause:
823
                                context.debugtestError(_cause)
824
                                del _cause  # skipcq - cleanup any error leaks early
825
                                theResult = False
826
                self.assertTrue(theResult, str("Could Not handle multicast NOOP"))
4✔
827

828
        def test_invalid_Error_WHEN_cli_called_GIVEN_bad_input(self):
4✔
829
                """Test case template for invalid input to multicast CLI."""
830
                theResult = False
4✔
831
                if (self._thepython is not None):
4✔
832
                        try:
4✔
833
                                test_cases = [
834
                                        "BAdInPut",  # Basic invalid input
835
                                        int(1),  # Non-string input
836
                                        "exit",  # Reserved word
837
                                        "",  # Empty string
838
                                        " ",  # Whitespace
839
                                        "\t",  # Tab character
840
                                        "你好",  # Unicode
841
                                        "HEAR\x00",  # Null byte injection
842
                                        "SAY;ls"  # Command injection attempt
843
                                ]
844
                                for test_case in test_cases:
4✔
845
                                        args = [
4✔
846
                                                str(self._thepython),
847
                                                str("-m"),
848
                                                str("multicast"),
849
                                                str("{}").format(str(test_case))
850
                                        ]
851
                                        theOutputtxt = context.checkPythonCommand(args, stderr=subprocess.STDOUT)
4✔
852
                                        # or simply:
853
                                        if theOutputtxt:
4✔
854
                                                self.assertIsNotNone(theOutputtxt, f"Error with {str(test_case)}")
4✔
855
                                                self.assertIn(str("invalid choice:"), str(theOutputtxt))
4✔
856
                                                self.assertIn(repr(str(test_case)), str(theOutputtxt))
4✔
857
                                                theResult = True
4✔
858
                        except Exception as _cause:
859
                                context.debugtestError(_cause)
860
                                del _cause  # skipcq - cleanup any error leaks early
861
                                theResult = False
862
                self.assertTrue(theResult, str("Could Not handle negative inputs"))
4✔
863

864

865
if __name__ == '__main__':
866
        unittest.main()
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc