# Copyright (C) 2023 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Unit test for repo_logging module.""" import contextlib import io import logging import unittest from unittest import mock from color import SetDefaultColoring from error import RepoExitError from repo_logging import RepoLogger class TestRepoLogger(unittest.TestCase): @mock.patch.object(RepoLogger, "error") def test_log_aggregated_errors_logs_aggregated_errors(self, mock_error): """Test if log_aggregated_errors logs a list of aggregated errors.""" logger = RepoLogger(__name__) logger.log_aggregated_errors( RepoExitError( aggregate_errors=[ Exception("foo"), Exception("bar"), Exception("baz"), Exception("hello"), Exception("world"), Exception("test"), ] ) ) mock_error.assert_has_calls( [ mock.call("=" * 80), mock.call( "Repo command failed due to the following `%s` errors:", "RepoExitError", ), mock.call("foo\nbar\nbaz\nhello\nworld"), mock.call("+%d additional errors...", 1), ] ) @mock.patch.object(RepoLogger, "error") def test_log_aggregated_errors_logs_single_error(self, mock_error): """Test if log_aggregated_errors logs empty aggregated_errors.""" logger = RepoLogger(__name__) logger.log_aggregated_errors(RepoExitError()) mock_error.assert_has_calls( [ mock.call("=" * 80), mock.call("Repo command failed: %s", "RepoExitError"), ] ) def test_log_with_format_string(self): """Test different log levels with format strings.""" # Set color output to "always" for consistent test results. # This ensures the logger's behavior is uniform across different # environments and git configurations. SetDefaultColoring("always") # Regex pattern to match optional ANSI color codes. # \033 - Escape character # \[ - Opening square bracket # [0-9;]* - Zero or more digits or semicolons # m - Ending 'm' character # ? - Makes the entire group optional opt_color = r"(\033\[[0-9;]*m)?" for level in (logging.INFO, logging.WARN, logging.ERROR): name = logging.getLevelName(level) with self.subTest(level=level, name=name): output = io.StringIO() with contextlib.redirect_stderr(output): logger = RepoLogger(__name__) logger.log(level, "%s", "100% pass") self.assertRegex( output.getvalue().strip(), f"^{opt_color}100% pass{opt_color}$", f"failed for level {name}", )