diff --git a/skbase/testing/test_all_objects.py b/skbase/testing/test_all_objects.py index d8a715e1..bd12f7a7 100644 --- a/skbase/testing/test_all_objects.py +++ b/skbase/testing/test_all_objects.py @@ -342,6 +342,7 @@ def run_tests( """ from _pytest.outcomes import Skipped + from skbase.utils.stderr_mute import StderrMute from skbase.utils.stdout_mute import StdoutMute tests_to_run = self._check_none_str_or_list_of_str( @@ -464,7 +465,10 @@ def print_if_verbose(msg): print_if_verbose(f"{key}") try: - with StdoutMute(active=verbose < 2): + with ( + StdoutMute(active=verbose < 2), + StderrMute(active=verbose < 2), + ): test_fun(**deepcopy(args)) results[key] = "PASSED" print_if_verbose("PASSED") @@ -541,7 +545,7 @@ def _check_none_str_or_list_of_str(obj, var_name="obj"): obj = [obj] if not isinstance(obj, list): raise ValueError(msg) - if not np.all(isinstance(x, str) for x in obj): + if not np.all([isinstance(x, str) for x in obj]): raise ValueError(msg) return obj @@ -715,12 +719,12 @@ def test_create_test_instances_and_names(self, object_class): f"found {type(names)}" ) - assert np.all(isinstance(est, object_class) for est in objects), ( + assert np.all([isinstance(est, object_class) for est in objects]), ( "list elements of first return returned by create_test_instances_and_names " "all must be an instance of the class" ) - assert np.all(isinstance(name, names) for name in names), ( + assert np.all([isinstance(name, str) for name in names]), ( "list elements of second return returned by create_test_instances_and_names" " all must be strings" ) diff --git a/skbase/testing/tests/__init__.py b/skbase/testing/tests/__init__.py new file mode 100644 index 00000000..3b6c2e93 --- /dev/null +++ b/skbase/testing/tests/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +"""Tests for the skbase testing module.""" diff --git a/skbase/testing/tests/test_quicktester.py b/skbase/testing/tests/test_quicktester.py new file mode 100644 index 00000000..eecc5b14 --- /dev/null +++ b/skbase/testing/tests/test_quicktester.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +"""Regression tests for QuickTester input checks and output muting.""" + +import sys +from typing import List + +import pytest + +from skbase.testing import BaseFixtureGenerator, QuickTester +from skbase.tests.conftest import Parent + +__author__: List[str] = ["yash-sangwan"] + + +class _NoisyTester(BaseFixtureGenerator, QuickTester): + """Minimal test class that writes to both output streams.""" + + def test_writes_to_streams(self, object_class): + """Write a marker to stdout and to stderr.""" + sys.stdout.write("stdout-marker") + sys.stderr.write("stderr-marker") + + +@pytest.mark.parametrize("bad", [42, ["a", 5], {"a": 1}]) +def test_check_none_str_or_list_of_str_rejects_invalid(bad): + """Invalid input raises; a generator passed to np.all would never raise.""" + with pytest.raises(ValueError, match="must be None, str, or list of str"): + QuickTester._check_none_str_or_list_of_str(bad, var_name="x") + + +@pytest.mark.parametrize( + "good, expected", [(None, None), ("a", ["a"]), (["a", "b"], ["a", "b"])] +) +def test_check_none_str_or_list_of_str_accepts_valid(good, expected): + """Valid input is returned, coerced to list of str.""" + assert QuickTester._check_none_str_or_list_of_str(good, var_name="x") == expected + + +@pytest.mark.parametrize("verbose, muted", [(0, True), (2, False)]) +def test_run_tests_mutes_stdout_and_stderr(capsys, verbose, muted): + """Both streams are muted below verbose=2, and both are shown at verbose=2.""" + _NoisyTester().run_tests( + Parent, tests_to_run="test_writes_to_streams", verbose=verbose + ) + captured = capsys.readouterr() + assert ("stdout-marker" not in captured.out) is muted + assert ("stderr-marker" not in captured.err) is muted