156 lines
4.7 KiB
Python
156 lines
4.7 KiB
Python
import unittest
|
|
from _apple_support import SystemLog
|
|
from test.support import is_apple_mobile
|
|
from unittest.mock import Mock, call
|
|
|
|
if not is_apple_mobile:
|
|
raise unittest.SkipTest("iOS-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), "<SystemLog (level 42)>")
|
|
self.assertEqual(repr(self.log.buffer), "<LogStream (level 42)>")
|
|
|
|
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)
|