import unittest from _apple_support import SystemLog from test.support import is_apple from unittest.mock import Mock, call if not is_apple: raise unittest.SkipTest("Apple-specific") # Test redirection of stdout and stderr to the Apple system log. class TestAppleSystemLogOutput(unittest.TestCase): maxDiff = None def assert_writes(self, output): self.assertEqual( self.log_write.mock_calls, [ call(self.log_level, line) for line in output ] ) self.log_write.reset_mock() def setUp(self): self.log_write = Mock() self.log_level = 42 self.log = SystemLog(self.log_write, self.log_level, errors="replace") def test_repr(self): self.assertEqual(repr(self.log), "") self.assertEqual(repr(self.log.buffer), "") def test_log_config(self): self.assertIs(self.log.writable(), True) self.assertIs(self.log.readable(), False) self.assertEqual("UTF-8", self.log.encoding) self.assertEqual("replace", self.log.errors) self.assertIs(self.log.line_buffering, True) self.assertIs(self.log.write_through, False) def test_empty_str(self): self.log.write("") self.log.flush() self.assert_writes([]) def test_simple_str(self): self.log.write("hello world\n") self.assert_writes([b"hello world\n"]) def test_buffered_str(self): self.log.write("h") self.log.write("ello") self.log.write(" ") self.log.write("world\n") self.log.write("goodbye.") self.log.flush() self.assert_writes([b"hello world\n", b"goodbye."]) def test_manual_flush(self): self.log.write("Hello") self.assert_writes([]) self.log.write(" world\nHere for a while...\nGoodbye") self.assert_writes([b"Hello world\n", b"Here for a while...\n"]) self.log.write(" world\nHello again") self.assert_writes([b"Goodbye world\n"]) self.log.flush() self.assert_writes([b"Hello again"]) def test_non_ascii(self): # Spanish self.log.write("ol\u00e9\n") self.assert_writes([b"ol\xc3\xa9\n"]) # Chinese self.log.write("\u4e2d\u6587\n") self.assert_writes([b"\xe4\xb8\xad\xe6\x96\x87\n"]) # Printing Non-BMP emoji self.log.write("\U0001f600\n") self.assert_writes([b"\xf0\x9f\x98\x80\n"]) # Non-encodable surrogates are replaced self.log.write("\ud800\udc00\n") self.assert_writes([b"??\n"]) def test_modified_null(self): # Null characters are logged using "modified UTF-8". self.log.write("\u0000\n") self.assert_writes([b"\xc0\x80\n"]) self.log.write("a\u0000\n") self.assert_writes([b"a\xc0\x80\n"]) self.log.write("\u0000b\n") self.assert_writes([b"\xc0\x80b\n"]) self.log.write("a\u0000b\n") self.assert_writes([b"a\xc0\x80b\n"]) def test_nonstandard_str(self): # String subclasses are accepted, but they should be converted # to a standard str without calling any of their methods. class CustomStr(str): def splitlines(self, *args, **kwargs): raise AssertionError() def __len__(self): raise AssertionError() def __str__(self): raise AssertionError() self.log.write(CustomStr("custom\n")) self.assert_writes([b"custom\n"]) def test_non_str(self): # Non-string classes are not accepted. for obj in [b"", b"hello", None, 42]: with self.subTest(obj=obj): with self.assertRaisesRegex( TypeError, fr"write\(\) argument must be str, not " fr"{type(obj).__name__}" ): self.log.write(obj) def test_byteslike_in_buffer(self): # The underlying buffer *can* accept bytes-like objects self.log.buffer.write(bytearray(b"hello")) self.log.flush() self.log.buffer.write(b"") self.log.flush() self.log.buffer.write(b"goodbye") self.log.flush() self.assert_writes([b"hello", b"goodbye"]) def test_non_byteslike_in_buffer(self): for obj in ["hello", None, 42]: with self.subTest(obj=obj): with self.assertRaisesRegex( TypeError, fr"write\(\) argument must be bytes-like, not " fr"{type(obj).__name__}" ): self.log.buffer.write(obj)