diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 70b6592c4..ae1a80c50 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -392,7 +392,9 @@ class LoggingPlugin(object): config, "log_file_date_format", "log_date_format" ) # Each pytest runtests session will write to a clean logfile - self.log_file_handler = logging.FileHandler(log_file, mode="w") + self.log_file_handler = logging.FileHandler( + log_file, mode="w", encoding="UTF-8" + ) log_file_formatter = logging.Formatter( log_file_format, datefmt=log_file_date_format ) diff --git a/testing/logging/test_reporting.py b/testing/logging/test_reporting.py index 0a8a58506..0bd12f0a3 100644 --- a/testing/logging/test_reporting.py +++ b/testing/logging/test_reporting.py @@ -827,6 +827,40 @@ def test_log_file_ini_level(testdir): assert "This log message won't be shown" not in contents +def test_log_file_unicode(testdir): + log_file = testdir.tmpdir.join("pytest.log").strpath + + testdir.makeini( + """ + [pytest] + log_file={} + log_file_level = INFO + """.format( + log_file + ) + ) + testdir.makepyfile( + """ + import logging + def test_log_file(): + logging.getLogger('catchlog').info("Normal message") + logging.getLogger('catchlog').info("\u251c") + logging.getLogger('catchlog').info("Another normal message") + """ + ) + + result = testdir.runpytest() + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + assert os.path.isfile(log_file) + with open(log_file, encoding="utf-8") as rfh: + contents = rfh.read() + assert "Normal message" in contents + assert "\u251c" in contents + assert "Another normal message" in contents + + @pytest.mark.parametrize("has_capture_manager", [True, False]) def test_live_logging_suspends_capture(has_capture_manager, request): """Test that capture manager is suspended when we emitting messages for live logging.