| # Copyright 2026 The Fuchsia Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| """Unit tests for logging_utils module.""" | |
| import io | |
| import logging | |
| import tempfile | |
| import unittest | |
| from unittest import mock | |
| import logging_utils | |
| class LoggingUtilsTest(unittest.TestCase): | |
| """Unit tests for logging_utils module.""" | |
| def test_supports_color_true_when_tty(self) -> None: | |
| mock_stream = mock.MagicMock() | |
| mock_stream.isatty.return_value = True | |
| with mock.patch.dict("os.environ", {"TERM": "xterm"}, clear=True): | |
| self.assertTrue(logging_utils.supports_color(mock_stream)) | |
| def test_supports_color_false_when_no_tty(self) -> None: | |
| mock_stream = mock.MagicMock() | |
| mock_stream.isatty.return_value = False | |
| with mock.patch.dict("os.environ", {"TERM": "xterm"}, clear=True): | |
| self.assertFalse(logging_utils.supports_color(mock_stream)) | |
| def test_supports_color_false_with_no_color_env(self) -> None: | |
| mock_stream = mock.MagicMock() | |
| mock_stream.isatty.return_value = True | |
| with mock.patch.dict("os.environ", {"NO_COLOR": "1"}): | |
| self.assertFalse(logging_utils.supports_color(mock_stream)) | |
| def test_supports_color_false_with_dumb_term(self) -> None: | |
| mock_stream = mock.MagicMock() | |
| mock_stream.isatty.return_value = True | |
| with mock.patch.dict("os.environ", {"TERM": "dumb"}): | |
| self.assertFalse(logging_utils.supports_color(mock_stream)) | |
| def test_supports_color_true_with_force_color(self) -> None: | |
| mock_stream = mock.MagicMock() | |
| mock_stream.isatty.return_value = False | |
| with mock.patch.dict("os.environ", {"FORCE_COLOR": "1"}, clear=True): | |
| self.assertTrue(logging_utils.supports_color(mock_stream)) | |
| def test_supports_color_true_with_clicolor_force(self) -> None: | |
| mock_stream = mock.MagicMock() | |
| mock_stream.isatty.return_value = False | |
| with mock.patch.dict("os.environ", {"CLICOLOR_FORCE": "1"}, clear=True): | |
| self.assertTrue(logging_utils.supports_color(mock_stream)) | |
| def test_supports_color_true_with_fuchsia_fx_test_run(self) -> None: | |
| mock_stream = mock.MagicMock() | |
| mock_stream.isatty.return_value = False | |
| with mock.patch.dict( | |
| "os.environ", {"FUCHSIA_FX_TEST_RUN": "1"}, clear=True | |
| ): | |
| self.assertTrue(logging_utils.supports_color(mock_stream)) | |
| def test_colored_formatter_without_color(self) -> None: | |
| formatter = logging_utils.ColoredFormatter( | |
| "%(levelname)s %(message)s", | |
| prefix="[MOCK_PREFIX] ", | |
| use_color=False, | |
| ) | |
| record = logging.LogRecord( | |
| name="test", | |
| level=logging.INFO, | |
| pathname="test.py", | |
| lineno=1, | |
| msg="[Test] test_case PASS [ret: 0]", | |
| args=(), | |
| exc_info=None, | |
| ) | |
| output = formatter.format(record) | |
| self.assertEqual( | |
| output, "[MOCK_PREFIX] INFO [Test] test_case PASS [ret: 0]" | |
| ) | |
| def test_colored_formatter_with_color_results(self) -> None: | |
| formatter = logging_utils.ColoredFormatter( | |
| "[MOCK_PREFIX] %(levelname)s %(message)s", | |
| use_color=True, | |
| ) | |
| for result in ("PASS", "FAIL", "ERROR", "SKIP"): | |
| record = logging.LogRecord( | |
| name="test", | |
| level=logging.INFO, | |
| pathname="test.py", | |
| lineno=1, | |
| msg=f"[Test] test_case {result}", | |
| args=(), | |
| exc_info=None, | |
| ) | |
| output = formatter.format(record) | |
| self.assertIn("\033[", output) | |
| self.assertIn(result, output) | |
| # Ensure levelname was restored on the record | |
| self.assertEqual(record.levelname, "INFO") | |
| def test_colored_formatter_return_codes(self) -> None: | |
| formatter = logging_utils.ColoredFormatter( | |
| "%(message)s", | |
| use_color=True, | |
| ) | |
| # Success code (0) | |
| record_pass = logging.LogRecord( | |
| name="test", | |
| level=logging.INFO, | |
| pathname="test.py", | |
| lineno=1, | |
| msg="Completed: test_case PASS [ret: 0]", | |
| args=(), | |
| exc_info=None, | |
| ) | |
| out_pass = formatter.format(record_pass) | |
| self.assertIn("ret: 0", out_pass) | |
| self.assertIn("\033[32mret: 0", out_pass) # Green | |
| # Failure code (1) | |
| record_fail = logging.LogRecord( | |
| name="test", | |
| level=logging.ERROR, | |
| pathname="test.py", | |
| lineno=1, | |
| msg="Completed: test_case FAIL [ret: 1]", | |
| args=(), | |
| exc_info=None, | |
| ) | |
| out_fail = formatter.format(record_fail) | |
| self.assertIn("ret: 1", out_fail) | |
| self.assertIn("\033[31mret: 1", out_fail) # Red | |
| def test_colored_formatter_target_names(self) -> None: | |
| formatter = logging_utils.ColoredFormatter( | |
| "%(message)s", | |
| use_color=True, | |
| ) | |
| record = logging.LogRecord( | |
| name="test", | |
| level=logging.INFO, | |
| pathname="test.py", | |
| lineno=1, | |
| msg="Connecting to fuchsia-1a7d-1303-a909 and fuchsia-emulator", | |
| args=(), | |
| exc_info=None, | |
| ) | |
| out = formatter.format(record) | |
| self.assertIn("\033[36mfuchsia-1a7d-1303-a909\033[0m", out) | |
| self.assertIn("\033[36mfuchsia-emulator\033[0m", out) | |
| def test_colorize_logger_preserves_file_handler(self) -> None: | |
| test_logger = logging.Logger("test_logger") | |
| stream = io.StringIO() | |
| stream_handler = logging.StreamHandler(stream) | |
| test_logger.addHandler(stream_handler) | |
| with tempfile.NamedTemporaryFile() as tmp_file: | |
| file_handler = logging.FileHandler(tmp_file.name) | |
| original_file_formatter = logging.Formatter("%(message)s") | |
| file_handler.setFormatter(original_file_formatter) | |
| test_logger.addHandler(file_handler) | |
| logging_utils.colorize_logger(test_logger, prefix="PREFIX") | |
| # Stream handler should be colorized | |
| self.assertIsInstance( | |
| stream_handler.formatter, logging_utils.ColoredFormatter | |
| ) | |
| # File handler should remain un-colorized | |
| self.assertIs(file_handler.formatter, original_file_formatter) | |
| self.assertNotIsInstance( | |
| file_handler.formatter, logging_utils.ColoredFormatter | |
| ) | |
| def test_colored_formatter_with_color_and_prefix(self) -> None: | |
| formatter = logging_utils.ColoredFormatter( | |
| "%(levelname)s %(message)s", | |
| prefix="[MY_PREFIX] ", | |
| use_color=True, | |
| ) | |
| record = logging.LogRecord( | |
| name="test", | |
| level=logging.INFO, | |
| pathname="test.py", | |
| lineno=1, | |
| msg="hello", | |
| args=(), | |
| exc_info=None, | |
| ) | |
| output = formatter.format(record) | |
| self.assertTrue(output.startswith("[MY_PREFIX] ")) | |
| self.assertIn("hello", output) | |
| if __name__ == "__main__": | |
| unittest.main() |