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