1from test import test_support 2import unittest 3 4import sys, cStringIO, subprocess 5import quopri 6 7 8 9ENCSAMPLE = """\ 10Here's a bunch of special=20 11 12=A1=A2=A3=A4=A5=A6=A7=A8=A9 13=AA=AB=AC=AD=AE=AF=B0=B1=B2=B3 14=B4=B5=B6=B7=B8=B9=BA=BB=BC=BD=BE 15=BF=C0=C1=C2=C3=C4=C5=C6 16=C7=C8=C9=CA=CB=CC=CD=CE=CF 17=D0=D1=D2=D3=D4=D5=D6=D7 18=D8=D9=DA=DB=DC=DD=DE=DF 19=E0=E1=E2=E3=E4=E5=E6=E7 20=E8=E9=EA=EB=EC=ED=EE=EF 21=F0=F1=F2=F3=F4=F5=F6=F7 22=F8=F9=FA=FB=FC=FD=FE=FF 23 24characters... have fun! 25""" 26 27# First line ends with a space 28DECSAMPLE = "Here's a bunch of special \n" + \ 29"""\ 30 31\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9 32\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3 33\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe 34\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6 35\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf 36\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7 37\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf 38\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7 39\xe8\xe9\xea\xeb\xec\xed\xee\xef 40\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7 41\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff 42 43characters... have fun! 44""" 45 46 47def withpythonimplementation(testfunc): 48 def newtest(self): 49 # Test default implementation 50 testfunc(self) 51 # Test Python implementation 52 if quopri.b2a_qp is not None or quopri.a2b_qp is not None: 53 oldencode = quopri.b2a_qp 54 olddecode = quopri.a2b_qp 55 try: 56 quopri.b2a_qp = None 57 quopri.a2b_qp = None 58 testfunc(self) 59 finally: 60 quopri.b2a_qp = oldencode 61 quopri.a2b_qp = olddecode 62 newtest.__name__ = testfunc.__name__ 63 return newtest 64 65class QuopriTestCase(unittest.TestCase): 66 # Each entry is a tuple of (plaintext, encoded string). These strings are 67 # used in the "quotetabs=0" tests. 68 STRINGS = ( 69 # Some normal strings 70 ('hello', 'hello'), 71 ('''hello 72 there 73 world''', '''hello 74 there 75 world'''), 76 ('''hello 77 there 78 world 79''', '''hello 80 there 81 world 82'''), 83 ('\201\202\203', '=81=82=83'), 84 # Add some trailing MUST QUOTE strings 85 ('hello ', 'hello=20'), 86 ('hello\t', 'hello=09'), 87 # Some long lines. First, a single line of 108 characters 88 ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\xd8\xd9\xda\xdb\xdc\xdd\xde\xdfxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 89 '''xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=D8=D9=DA=DB=DC=DD=DE=DFx= 90xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'''), 91 # A line of exactly 76 characters, no soft line break should be needed 92 ('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy', 93 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'), 94 # A line of 77 characters, forcing a soft line break at position 75, 95 # and a second line of exactly 2 characters (because the soft line 96 # break `=' sign counts against the line length limit). 97 ('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz', 98 '''zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz= 99zz'''), 100 # A line of 151 characters, forcing a soft line break at position 75, 101 # with a second line of exactly 76 characters and no trailing = 102 ('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz', 103 '''zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz= 104zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''), 105 # A string containing a hard line break, but which the first line is 106 # 151 characters and the second line is exactly 76 characters. This 107 # should leave us with three lines, the first which has a soft line 108 # break, and which the second and third do not. 109 ('''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 110zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz''', 111 '''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy= 112yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 113zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''), 114 # Now some really complex stuff ;) 115 (DECSAMPLE, ENCSAMPLE), 116 ) 117 118 # These are used in the "quotetabs=1" tests. 119 ESTRINGS = ( 120 ('hello world', 'hello=20world'), 121 ('hello\tworld', 'hello=09world'), 122 ) 123 124 # These are used in the "header=1" tests. 125 HSTRINGS = ( 126 ('hello world', 'hello_world'), 127 ('hello_world', 'hello=5Fworld'), 128 ) 129 130 @withpythonimplementation 131 def test_encodestring(self): 132 for p, e in self.STRINGS: 133 self.assertTrue(quopri.encodestring(p) == e) 134 135 @withpythonimplementation 136 def test_decodestring(self): 137 for p, e in self.STRINGS: 138 self.assertTrue(quopri.decodestring(e) == p) 139 140 @withpythonimplementation 141 def test_idempotent_string(self): 142 for p, e in self.STRINGS: 143 self.assertTrue(quopri.decodestring(quopri.encodestring(e)) == e) 144 145 @withpythonimplementation 146 def test_encode(self): 147 for p, e in self.STRINGS: 148 infp = cStringIO.StringIO(p) 149 outfp = cStringIO.StringIO() 150 quopri.encode(infp, outfp, quotetabs=False) 151 self.assertTrue(outfp.getvalue() == e) 152 153 @withpythonimplementation 154 def test_decode(self): 155 for p, e in self.STRINGS: 156 infp = cStringIO.StringIO(e) 157 outfp = cStringIO.StringIO() 158 quopri.decode(infp, outfp) 159 self.assertTrue(outfp.getvalue() == p) 160 161 @withpythonimplementation 162 def test_embedded_ws(self): 163 for p, e in self.ESTRINGS: 164 self.assertTrue(quopri.encodestring(p, quotetabs=True) == e) 165 self.assertTrue(quopri.decodestring(e) == p) 166 167 @withpythonimplementation 168 def test_encode_header(self): 169 for p, e in self.HSTRINGS: 170 self.assertTrue(quopri.encodestring(p, header=True) == e) 171 172 @withpythonimplementation 173 def test_decode_header(self): 174 for p, e in self.HSTRINGS: 175 self.assertTrue(quopri.decodestring(e, header=True) == p) 176 177 def test_scriptencode(self): 178 (p, e) = self.STRINGS[-1] 179 process = subprocess.Popen([sys.executable, "-mquopri"], 180 stdin=subprocess.PIPE, stdout=subprocess.PIPE) 181 self.addCleanup(process.stdout.close) 182 cout, cerr = process.communicate(p) 183 # On Windows, Python will output the result to stdout using 184 # CRLF, as the mode of stdout is text mode. To compare this 185 # with the expected result, we need to do a line-by-line comparison. 186 self.assertEqual(cout.splitlines(), e.splitlines()) 187 188 def test_scriptdecode(self): 189 (p, e) = self.STRINGS[-1] 190 process = subprocess.Popen([sys.executable, "-mquopri", "-d"], 191 stdin=subprocess.PIPE, stdout=subprocess.PIPE) 192 self.addCleanup(process.stdout.close) 193 cout, cerr = process.communicate(e) 194 self.assertEqual(cout.splitlines(), p.splitlines()) 195 196def test_main(): 197 test_support.run_unittest(QuopriTestCase) 198 199 200if __name__ == "__main__": 201 test_main() 202