test_uu.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. """
  2. Tests for uu module.
  3. Nick Mathewson
  4. """
  5. import unittest
  6. from test.support import os_helper, warnings_helper
  7. uu = warnings_helper.import_deprecated("uu")
  8. import os
  9. import stat
  10. import sys
  11. import io
  12. plaintext = b"The symbols on top of your keyboard are !@#$%^&*()_+|~\n"
  13. encodedtext = b"""\
  14. M5&AE('-Y;6)O;',@;VX@=&]P(&]F('EO=7(@:V5Y8F]A<F0@87)E("% (R0E
  15. *7B8J*"E?*WQ^"@ """
  16. # Stolen from io.py
  17. class FakeIO(io.TextIOWrapper):
  18. """Text I/O implementation using an in-memory buffer.
  19. Can be a used as a drop-in replacement for sys.stdin and sys.stdout.
  20. """
  21. # XXX This is really slow, but fully functional
  22. def __init__(self, initial_value="", encoding="utf-8",
  23. errors="strict", newline="\n"):
  24. super(FakeIO, self).__init__(io.BytesIO(),
  25. encoding=encoding,
  26. errors=errors,
  27. newline=newline)
  28. self._encoding = encoding
  29. self._errors = errors
  30. if initial_value:
  31. if not isinstance(initial_value, str):
  32. initial_value = str(initial_value)
  33. self.write(initial_value)
  34. self.seek(0)
  35. def getvalue(self):
  36. self.flush()
  37. return self.buffer.getvalue().decode(self._encoding, self._errors)
  38. def encodedtextwrapped(mode, filename, backtick=False):
  39. if backtick:
  40. res = (bytes("begin %03o %s\n" % (mode, filename), "ascii") +
  41. encodedtext.replace(b' ', b'`') + b"\n`\nend\n")
  42. else:
  43. res = (bytes("begin %03o %s\n" % (mode, filename), "ascii") +
  44. encodedtext + b"\n \nend\n")
  45. return res
  46. class UUTest(unittest.TestCase):
  47. def test_encode(self):
  48. inp = io.BytesIO(plaintext)
  49. out = io.BytesIO()
  50. uu.encode(inp, out, "t1")
  51. self.assertEqual(out.getvalue(), encodedtextwrapped(0o666, "t1"))
  52. inp = io.BytesIO(plaintext)
  53. out = io.BytesIO()
  54. uu.encode(inp, out, "t1", 0o644)
  55. self.assertEqual(out.getvalue(), encodedtextwrapped(0o644, "t1"))
  56. inp = io.BytesIO(plaintext)
  57. out = io.BytesIO()
  58. uu.encode(inp, out, "t1", backtick=True)
  59. self.assertEqual(out.getvalue(), encodedtextwrapped(0o666, "t1", True))
  60. with self.assertRaises(TypeError):
  61. uu.encode(inp, out, "t1", 0o644, True)
  62. @os_helper.skip_unless_working_chmod
  63. def test_decode(self):
  64. for backtick in True, False:
  65. inp = io.BytesIO(encodedtextwrapped(0o666, "t1", backtick=backtick))
  66. out = io.BytesIO()
  67. uu.decode(inp, out)
  68. self.assertEqual(out.getvalue(), plaintext)
  69. inp = io.BytesIO(
  70. b"UUencoded files may contain many lines,\n" +
  71. b"even some that have 'begin' in them.\n" +
  72. encodedtextwrapped(0o666, "t1", backtick=backtick)
  73. )
  74. out = io.BytesIO()
  75. uu.decode(inp, out)
  76. self.assertEqual(out.getvalue(), plaintext)
  77. def test_truncatedinput(self):
  78. inp = io.BytesIO(b"begin 644 t1\n" + encodedtext)
  79. out = io.BytesIO()
  80. try:
  81. uu.decode(inp, out)
  82. self.fail("No exception raised")
  83. except uu.Error as e:
  84. self.assertEqual(str(e), "Truncated input file")
  85. def test_missingbegin(self):
  86. inp = io.BytesIO(b"")
  87. out = io.BytesIO()
  88. try:
  89. uu.decode(inp, out)
  90. self.fail("No exception raised")
  91. except uu.Error as e:
  92. self.assertEqual(str(e), "No valid begin line found in input file")
  93. def test_garbage_padding(self):
  94. # Issue #22406
  95. encodedtext1 = (
  96. b"begin 644 file\n"
  97. # length 1; bits 001100 111111 111111 111111
  98. b"\x21\x2C\x5F\x5F\x5F\n"
  99. b"\x20\n"
  100. b"end\n"
  101. )
  102. encodedtext2 = (
  103. b"begin 644 file\n"
  104. # length 1; bits 001100 111111 111111 111111
  105. b"\x21\x2C\x5F\x5F\x5F\n"
  106. b"\x60\n"
  107. b"end\n"
  108. )
  109. plaintext = b"\x33" # 00110011
  110. for encodedtext in encodedtext1, encodedtext2:
  111. with self.subTest("uu.decode()"):
  112. inp = io.BytesIO(encodedtext)
  113. out = io.BytesIO()
  114. uu.decode(inp, out, quiet=True)
  115. self.assertEqual(out.getvalue(), plaintext)
  116. with self.subTest("uu_codec"):
  117. import codecs
  118. decoded = codecs.decode(encodedtext, "uu_codec")
  119. self.assertEqual(decoded, plaintext)
  120. def test_newlines_escaped(self):
  121. # Test newlines are escaped with uu.encode
  122. inp = io.BytesIO(plaintext)
  123. out = io.BytesIO()
  124. filename = "test.txt\n\roverflow.txt"
  125. safefilename = b"test.txt\\n\\roverflow.txt"
  126. uu.encode(inp, out, filename)
  127. self.assertIn(safefilename, out.getvalue())
  128. class UUStdIOTest(unittest.TestCase):
  129. def setUp(self):
  130. self.stdin = sys.stdin
  131. self.stdout = sys.stdout
  132. def tearDown(self):
  133. sys.stdin = self.stdin
  134. sys.stdout = self.stdout
  135. def test_encode(self):
  136. sys.stdin = FakeIO(plaintext.decode("ascii"))
  137. sys.stdout = FakeIO()
  138. uu.encode("-", "-", "t1", 0o666)
  139. self.assertEqual(sys.stdout.getvalue(),
  140. encodedtextwrapped(0o666, "t1").decode("ascii"))
  141. def test_decode(self):
  142. sys.stdin = FakeIO(encodedtextwrapped(0o666, "t1").decode("ascii"))
  143. sys.stdout = FakeIO()
  144. uu.decode("-", "-")
  145. stdout = sys.stdout
  146. sys.stdout = self.stdout
  147. sys.stdin = self.stdin
  148. self.assertEqual(stdout.getvalue(), plaintext.decode("ascii"))
  149. class UUFileTest(unittest.TestCase):
  150. def setUp(self):
  151. # uu.encode() supports only ASCII file names
  152. self.tmpin = os_helper.TESTFN_ASCII + "i"
  153. self.tmpout = os_helper.TESTFN_ASCII + "o"
  154. self.addCleanup(os_helper.unlink, self.tmpin)
  155. self.addCleanup(os_helper.unlink, self.tmpout)
  156. def test_encode(self):
  157. with open(self.tmpin, 'wb') as fin:
  158. fin.write(plaintext)
  159. with open(self.tmpin, 'rb') as fin:
  160. with open(self.tmpout, 'wb') as fout:
  161. uu.encode(fin, fout, self.tmpin, mode=0o644)
  162. with open(self.tmpout, 'rb') as fout:
  163. s = fout.read()
  164. self.assertEqual(s, encodedtextwrapped(0o644, self.tmpin))
  165. # in_file and out_file as filenames
  166. uu.encode(self.tmpin, self.tmpout, self.tmpin, mode=0o644)
  167. with open(self.tmpout, 'rb') as fout:
  168. s = fout.read()
  169. self.assertEqual(s, encodedtextwrapped(0o644, self.tmpin))
  170. # decode() calls chmod()
  171. @os_helper.skip_unless_working_chmod
  172. def test_decode(self):
  173. with open(self.tmpin, 'wb') as f:
  174. f.write(encodedtextwrapped(0o644, self.tmpout))
  175. with open(self.tmpin, 'rb') as f:
  176. uu.decode(f)
  177. with open(self.tmpout, 'rb') as f:
  178. s = f.read()
  179. self.assertEqual(s, plaintext)
  180. # XXX is there an xp way to verify the mode?
  181. @os_helper.skip_unless_working_chmod
  182. def test_decode_filename(self):
  183. with open(self.tmpin, 'wb') as f:
  184. f.write(encodedtextwrapped(0o644, self.tmpout))
  185. uu.decode(self.tmpin)
  186. with open(self.tmpout, 'rb') as f:
  187. s = f.read()
  188. self.assertEqual(s, plaintext)
  189. @os_helper.skip_unless_working_chmod
  190. def test_decodetwice(self):
  191. # Verify that decode() will refuse to overwrite an existing file
  192. with open(self.tmpin, 'wb') as f:
  193. f.write(encodedtextwrapped(0o644, self.tmpout))
  194. with open(self.tmpin, 'rb') as f:
  195. uu.decode(f)
  196. with open(self.tmpin, 'rb') as f:
  197. self.assertRaises(uu.Error, uu.decode, f)
  198. @os_helper.skip_unless_working_chmod
  199. def test_decode_mode(self):
  200. # Verify that decode() will set the given mode for the out_file
  201. expected_mode = 0o444
  202. with open(self.tmpin, 'wb') as f:
  203. f.write(encodedtextwrapped(expected_mode, self.tmpout))
  204. # make file writable again, so it can be removed (Windows only)
  205. self.addCleanup(os.chmod, self.tmpout, expected_mode | stat.S_IWRITE)
  206. with open(self.tmpin, 'rb') as f:
  207. uu.decode(f)
  208. self.assertEqual(
  209. stat.S_IMODE(os.stat(self.tmpout).st_mode),
  210. expected_mode
  211. )
  212. if __name__=="__main__":
  213. unittest.main()