test_io.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Test cases for L{twisted.logger._io}.
  5. """
  6. from __future__ import print_function
  7. import sys
  8. from twisted.trial import unittest
  9. from .._levels import LogLevel
  10. from .._logger import Logger
  11. from .._observer import LogPublisher
  12. from .._io import LoggingFile
  13. class LoggingFileTests(unittest.TestCase):
  14. """
  15. Tests for L{LoggingFile}.
  16. """
  17. def setUp(self):
  18. """
  19. Create a logger for test L{LoggingFile} instances to use.
  20. """
  21. self.publisher = LogPublisher()
  22. self.logger = Logger(observer=self.publisher)
  23. def test_softspace(self):
  24. """
  25. L{LoggingFile.softspace} is 0.
  26. """
  27. self.assertEqual(LoggingFile.softspace, 0)
  28. def test_readOnlyAttributes(self):
  29. """
  30. Some L{LoggingFile} attributes are read-only.
  31. """
  32. f = LoggingFile(self.logger)
  33. self.assertRaises(AttributeError, setattr, f, "closed", True)
  34. self.assertRaises(AttributeError, setattr, f, "encoding", "utf-8")
  35. self.assertRaises(AttributeError, setattr, f, "mode", "r")
  36. self.assertRaises(AttributeError, setattr, f, "newlines", ["\n"])
  37. self.assertRaises(AttributeError, setattr, f, "name", "foo")
  38. def test_unsupportedMethods(self):
  39. """
  40. Some L{LoggingFile} methods are unsupported.
  41. """
  42. f = LoggingFile(self.logger)
  43. self.assertRaises(IOError, f.read)
  44. self.assertRaises(IOError, f.next)
  45. self.assertRaises(IOError, f.readline)
  46. self.assertRaises(IOError, f.readlines)
  47. self.assertRaises(IOError, f.xreadlines)
  48. self.assertRaises(IOError, f.seek)
  49. self.assertRaises(IOError, f.tell)
  50. self.assertRaises(IOError, f.truncate)
  51. def test_level(self):
  52. """
  53. Default level is L{LogLevel.info} if not set.
  54. """
  55. f = LoggingFile(self.logger)
  56. self.assertEqual(f.level, LogLevel.info)
  57. f = LoggingFile(self.logger, level=LogLevel.error)
  58. self.assertEqual(f.level, LogLevel.error)
  59. def test_encoding(self):
  60. """
  61. Default encoding is C{sys.getdefaultencoding()} if not set.
  62. """
  63. f = LoggingFile(self.logger)
  64. self.assertEqual(f.encoding, sys.getdefaultencoding())
  65. f = LoggingFile(self.logger, encoding="utf-8")
  66. self.assertEqual(f.encoding, "utf-8")
  67. def test_mode(self):
  68. """
  69. Reported mode is C{"w"}.
  70. """
  71. f = LoggingFile(self.logger)
  72. self.assertEqual(f.mode, "w")
  73. def test_newlines(self):
  74. """
  75. The C{newlines} attribute is L{None}.
  76. """
  77. f = LoggingFile(self.logger)
  78. self.assertIsNone(f.newlines)
  79. def test_name(self):
  80. """
  81. The C{name} attribute is fixed.
  82. """
  83. f = LoggingFile(self.logger)
  84. self.assertEqual(
  85. f.name,
  86. "<LoggingFile twisted.logger.test.test_io#info>"
  87. )
  88. def test_close(self):
  89. """
  90. L{LoggingFile.close} closes the file.
  91. """
  92. f = LoggingFile(self.logger)
  93. f.close()
  94. self.assertTrue(f.closed)
  95. self.assertRaises(ValueError, f.write, "Hello")
  96. def test_flush(self):
  97. """
  98. L{LoggingFile.flush} does nothing.
  99. """
  100. f = LoggingFile(self.logger)
  101. f.flush()
  102. def test_fileno(self):
  103. """
  104. L{LoggingFile.fileno} returns C{-1}.
  105. """
  106. f = LoggingFile(self.logger)
  107. self.assertEqual(f.fileno(), -1)
  108. def test_isatty(self):
  109. """
  110. L{LoggingFile.isatty} returns C{False}.
  111. """
  112. f = LoggingFile(self.logger)
  113. self.assertFalse(f.isatty())
  114. def test_writeBuffering(self):
  115. """
  116. Writing buffers correctly.
  117. """
  118. f = self.observedFile()
  119. f.write("Hello")
  120. self.assertEqual(f.messages, [])
  121. f.write(", world!\n")
  122. self.assertEqual(f.messages, [u"Hello, world!"])
  123. f.write("It's nice to meet you.\n\nIndeed.")
  124. self.assertEqual(
  125. f.messages,
  126. [
  127. u"Hello, world!",
  128. u"It's nice to meet you.",
  129. u"",
  130. ]
  131. )
  132. def test_writeBytesDecoded(self):
  133. """
  134. Bytes are decoded to unicode.
  135. """
  136. f = self.observedFile(encoding="utf-8")
  137. f.write(b"Hello, Mr. S\xc3\xa1nchez\n")
  138. self.assertEqual(f.messages, [u"Hello, Mr. S\xe1nchez"])
  139. def test_writeUnicode(self):
  140. """
  141. Unicode is unmodified.
  142. """
  143. f = self.observedFile(encoding="utf-8")
  144. f.write(u"Hello, Mr. S\xe1nchez\n")
  145. self.assertEqual(f.messages, [u"Hello, Mr. S\xe1nchez"])
  146. def test_writeLevel(self):
  147. """
  148. Log level is emitted properly.
  149. """
  150. f = self.observedFile()
  151. f.write("Hello\n")
  152. self.assertEqual(len(f.events), 1)
  153. self.assertEqual(f.events[0]["log_level"], LogLevel.info)
  154. f = self.observedFile(level=LogLevel.error)
  155. f.write("Hello\n")
  156. self.assertEqual(len(f.events), 1)
  157. self.assertEqual(f.events[0]["log_level"], LogLevel.error)
  158. def test_writeFormat(self):
  159. """
  160. Log format is C{u"{message}"}.
  161. """
  162. f = self.observedFile()
  163. f.write("Hello\n")
  164. self.assertEqual(len(f.events), 1)
  165. self.assertEqual(f.events[0]["log_format"], u"{log_io}")
  166. def test_writelinesBuffering(self):
  167. """
  168. C{writelines} does not add newlines.
  169. """
  170. # Note this is different behavior than t.p.log.StdioOnnaStick.
  171. f = self.observedFile()
  172. f.writelines(("Hello", ", ", ""))
  173. self.assertEqual(f.messages, [])
  174. f.writelines(("world!\n",))
  175. self.assertEqual(f.messages, [u"Hello, world!"])
  176. f.writelines(("It's nice to meet you.\n\n", "Indeed."))
  177. self.assertEqual(
  178. f.messages,
  179. [
  180. u"Hello, world!",
  181. u"It's nice to meet you.",
  182. u"",
  183. ]
  184. )
  185. def test_print(self):
  186. """
  187. L{LoggingFile} can replace L{sys.stdout}.
  188. """
  189. f = self.observedFile()
  190. self.patch(sys, "stdout", f)
  191. print("Hello,", end=" ")
  192. print("world.")
  193. self.assertEqual(f.messages, [u"Hello, world."])
  194. def observedFile(self, **kwargs):
  195. """
  196. Construct a L{LoggingFile} with a built-in observer.
  197. @param kwargs: keyword arguments for the L{LoggingFile}.
  198. @type kwargs: L{dict}
  199. @return: a L{LoggingFile} with an observer that appends received
  200. events into the file's C{events} attribute (a L{list}) and
  201. event messages into the file's C{messages} attribute (a L{list}).
  202. @rtype: L{LoggingFile}
  203. """
  204. def observer(event):
  205. f.events.append(event)
  206. if "log_io" in event:
  207. f.messages.append(event["log_io"])
  208. log = Logger(observer=observer)
  209. f = LoggingFile(logger=log, **kwargs)
  210. f.events = []
  211. f.messages = []
  212. return f