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