blob: 715544c8a9669d56f5087a6487d1dad9414be4da [file] [log] [blame]
Barry Warsaw70697632001-06-19 19:08:13 +00001import unittest
2
Berker Peksag1e8ee9b2016-04-24 07:31:42 +03003import sys, io, subprocess
Walter Dörwaldb1975432005-12-14 23:32:22 +00004import quopri
Barry Warsaw70697632001-06-19 19:08:13 +00005
6
Tim Peters87cc0c32001-07-21 01:41:30 +00007
Martin v. Löwisc582bfc2007-07-28 17:52:25 +00008ENCSAMPLE = b"""\
Barry Warsaw70697632001-06-19 19:08:13 +00009Here's a bunch of special=20
10
11=A1=A2=A3=A4=A5=A6=A7=A8=A9
12=AA=AB=AC=AD=AE=AF=B0=B1=B2=B3
13=B4=B5=B6=B7=B8=B9=BA=BB=BC=BD=BE
14=BF=C0=C1=C2=C3=C4=C5=C6
15=C7=C8=C9=CA=CB=CC=CD=CE=CF
16=D0=D1=D2=D3=D4=D5=D6=D7
17=D8=D9=DA=DB=DC=DD=DE=DF
18=E0=E1=E2=E3=E4=E5=E6=E7
19=E8=E9=EA=EB=EC=ED=EE=EF
20=F0=F1=F2=F3=F4=F5=F6=F7
21=F8=F9=FA=FB=FC=FD=FE=FF
22
23characters... have fun!
24"""
25
26# First line ends with a space
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000027DECSAMPLE = b"Here's a bunch of special \n" + \
28b"""\
Barry Warsaw70697632001-06-19 19:08:13 +000029
Tim Peterse8613652001-08-03 20:40:18 +000030\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9
31\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3
32\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe
33\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6
34\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf
35\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7
36\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf
37\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7
38\xe8\xe9\xea\xeb\xec\xed\xee\xef
39\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7
40\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff
Barry Warsaw70697632001-06-19 19:08:13 +000041
42characters... have fun!
43"""
44
45
Walter Dörwaldb1975432005-12-14 23:32:22 +000046def withpythonimplementation(testfunc):
47 def newtest(self):
48 # Test default implementation
49 testfunc(self)
50 # Test Python implementation
51 if quopri.b2a_qp is not None or quopri.a2b_qp is not None:
52 oldencode = quopri.b2a_qp
53 olddecode = quopri.a2b_qp
54 try:
55 quopri.b2a_qp = None
56 quopri.a2b_qp = None
57 testfunc(self)
58 finally:
59 quopri.b2a_qp = oldencode
60 quopri.a2b_qp = olddecode
61 newtest.__name__ = testfunc.__name__
62 return newtest
Tim Peters87cc0c32001-07-21 01:41:30 +000063
Barry Warsaw70697632001-06-19 19:08:13 +000064class QuopriTestCase(unittest.TestCase):
65 # Each entry is a tuple of (plaintext, encoded string). These strings are
66 # used in the "quotetabs=0" tests.
67 STRINGS = (
68 # Some normal strings
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000069 (b'hello', b'hello'),
70 (b'''hello
Barry Warsaw70697632001-06-19 19:08:13 +000071 there
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000072 world''', b'''hello
Barry Warsaw70697632001-06-19 19:08:13 +000073 there
74 world'''),
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000075 (b'''hello
Barry Warsaw70697632001-06-19 19:08:13 +000076 there
77 world
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000078''', b'''hello
Barry Warsaw70697632001-06-19 19:08:13 +000079 there
80 world
81'''),
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000082 (b'\201\202\203', b'=81=82=83'),
Barry Warsaw70697632001-06-19 19:08:13 +000083 # Add some trailing MUST QUOTE strings
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000084 (b'hello ', b'hello=20'),
85 (b'hello\t', b'hello=09'),
Barry Warsaw7599a3f2001-06-19 22:48:42 +000086 # Some long lines. First, a single line of 108 characters
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000087 (b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\xd8\xd9\xda\xdb\xdc\xdd\xde\xdfxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
88 b'''xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=D8=D9=DA=DB=DC=DD=DE=DFx=
Barry Warsaw7599a3f2001-06-19 22:48:42 +000089xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'''),
90 # A line of exactly 76 characters, no soft line break should be needed
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000091 (b'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy',
92 b'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'),
Barry Warsaw7599a3f2001-06-19 22:48:42 +000093 # A line of 77 characters, forcing a soft line break at position 75,
94 # and a second line of exactly 2 characters (because the soft line
95 # break `=' sign counts against the line length limit).
Martin v. Löwisc582bfc2007-07-28 17:52:25 +000096 (b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
97 b'''zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=
Barry Warsaw7599a3f2001-06-19 22:48:42 +000098zz'''),
99 # A line of 151 characters, forcing a soft line break at position 75,
100 # with a second line of exactly 76 characters and no trailing =
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000101 (b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
102 b'''zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=
Barry Warsaw7599a3f2001-06-19 22:48:42 +0000103zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''),
104 # A string containing a hard line break, but which the first line is
105 # 151 characters and the second line is exactly 76 characters. This
106 # should leave us with three lines, the first which has a soft line
107 # break, and which the second and third do not.
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000108 (b'''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
Barry Warsaw7599a3f2001-06-19 22:48:42 +0000109zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz''',
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000110 b'''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy=
Barry Warsaw7599a3f2001-06-19 22:48:42 +0000111yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
112zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''),
113 # Now some really complex stuff ;)
Barry Warsaw70697632001-06-19 19:08:13 +0000114 (DECSAMPLE, ENCSAMPLE),
115 )
116
117 # These are used in the "quotetabs=1" tests.
118 ESTRINGS = (
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000119 (b'hello world', b'hello=20world'),
120 (b'hello\tworld', b'hello=09world'),
Barry Warsaw70697632001-06-19 19:08:13 +0000121 )
Tim Peters87cc0c32001-07-21 01:41:30 +0000122
Martin v. Löwis16dc7f42001-09-30 20:32:11 +0000123 # These are used in the "header=1" tests.
124 HSTRINGS = (
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000125 (b'hello world', b'hello_world'),
126 (b'hello_world', b'hello=5Fworld'),
Martin v. Löwis16dc7f42001-09-30 20:32:11 +0000127 )
128
Walter Dörwaldb1975432005-12-14 23:32:22 +0000129 @withpythonimplementation
Barry Warsaw70697632001-06-19 19:08:13 +0000130 def test_encodestring(self):
131 for p, e in self.STRINGS:
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000132 self.assertEqual(quopri.encodestring(p), e)
Tim Peters87cc0c32001-07-21 01:41:30 +0000133
Walter Dörwaldb1975432005-12-14 23:32:22 +0000134 @withpythonimplementation
Barry Warsaw70697632001-06-19 19:08:13 +0000135 def test_decodestring(self):
136 for p, e in self.STRINGS:
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000137 self.assertEqual(quopri.decodestring(e), p)
Tim Peters87cc0c32001-07-21 01:41:30 +0000138
Walter Dörwaldb1975432005-12-14 23:32:22 +0000139 @withpythonimplementation
Guido van Rossume173c072015-04-11 17:44:01 -0400140 def test_decodestring_double_equals(self):
141 # Issue 21511 - Ensure that byte string is compared to byte string
142 # instead of int byte value
143 decoded_value, encoded_value = (b"123=four", b"123==four")
144 self.assertEqual(quopri.decodestring(encoded_value), decoded_value)
145
146 @withpythonimplementation
Barry Warsaw70697632001-06-19 19:08:13 +0000147 def test_idempotent_string(self):
148 for p, e in self.STRINGS:
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000149 self.assertEqual(quopri.decodestring(quopri.encodestring(e)), e)
Barry Warsaw70697632001-06-19 19:08:13 +0000150
Walter Dörwaldb1975432005-12-14 23:32:22 +0000151 @withpythonimplementation
Barry Warsaw70697632001-06-19 19:08:13 +0000152 def test_encode(self):
153 for p, e in self.STRINGS:
Martin v. Löwis48f4cf92007-07-28 17:58:14 +0000154 infp = io.BytesIO(p)
155 outfp = io.BytesIO()
Walter Dörwaldb1975432005-12-14 23:32:22 +0000156 quopri.encode(infp, outfp, quotetabs=False)
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000157 self.assertEqual(outfp.getvalue(), e)
Barry Warsaw70697632001-06-19 19:08:13 +0000158
Walter Dörwaldb1975432005-12-14 23:32:22 +0000159 @withpythonimplementation
Barry Warsaw70697632001-06-19 19:08:13 +0000160 def test_decode(self):
161 for p, e in self.STRINGS:
Martin v. Löwis48f4cf92007-07-28 17:58:14 +0000162 infp = io.BytesIO(e)
163 outfp = io.BytesIO()
Walter Dörwaldb1975432005-12-14 23:32:22 +0000164 quopri.decode(infp, outfp)
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000165 self.assertEqual(outfp.getvalue(), p)
Barry Warsaw70697632001-06-19 19:08:13 +0000166
Walter Dörwaldb1975432005-12-14 23:32:22 +0000167 @withpythonimplementation
Barry Warsaw70697632001-06-19 19:08:13 +0000168 def test_embedded_ws(self):
169 for p, e in self.ESTRINGS:
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000170 self.assertEqual(quopri.encodestring(p, quotetabs=True), e)
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000171 self.assertEqual(quopri.decodestring(e), p)
Barry Warsaw70697632001-06-19 19:08:13 +0000172
Walter Dörwaldb1975432005-12-14 23:32:22 +0000173 @withpythonimplementation
Martin v. Löwis16dc7f42001-09-30 20:32:11 +0000174 def test_encode_header(self):
175 for p, e in self.HSTRINGS:
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000176 self.assertEqual(quopri.encodestring(p, header=True), e)
Martin v. Löwis16dc7f42001-09-30 20:32:11 +0000177
Walter Dörwaldb1975432005-12-14 23:32:22 +0000178 @withpythonimplementation
Martin v. Löwis16dc7f42001-09-30 20:32:11 +0000179 def test_decode_header(self):
180 for p, e in self.HSTRINGS:
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000181 self.assertEqual(quopri.decodestring(e, header=True), p)
Tim Peters87cc0c32001-07-21 01:41:30 +0000182
Walter Dörwald3b287702005-12-15 20:17:20 +0000183 def test_scriptencode(self):
Tim Peters536cf992005-12-25 23:18:31 +0000184 (p, e) = self.STRINGS[-1]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000185 process = subprocess.Popen([sys.executable, "-mquopri"],
186 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
Brian Curtinab747a72010-11-05 15:40:27 +0000187 self.addCleanup(process.stdout.close)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000188 cout, cerr = process.communicate(p)
189 # On Windows, Python will output the result to stdout using
190 # CRLF, as the mode of stdout is text mode. To compare this
191 # with the expected result, we need to do a line-by-line comparison.
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000192 cout = cout.decode('latin-1').splitlines()
193 e = e.decode('latin-1').splitlines()
194 assert len(cout)==len(e)
195 for i in range(len(cout)):
196 self.assertEqual(cout[i], e[i])
197 self.assertEqual(cout, e)
Walter Dörwald3b287702005-12-15 20:17:20 +0000198
199 def test_scriptdecode(self):
Tim Peters536cf992005-12-25 23:18:31 +0000200 (p, e) = self.STRINGS[-1]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000201 process = subprocess.Popen([sys.executable, "-mquopri", "-d"],
202 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
Brian Curtinab747a72010-11-05 15:40:27 +0000203 self.addCleanup(process.stdout.close)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000204 cout, cerr = process.communicate(e)
Martin v. Löwisc582bfc2007-07-28 17:52:25 +0000205 cout = cout.decode('latin-1')
206 p = p.decode('latin-1')
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000207 self.assertEqual(cout.splitlines(), p.splitlines())
Walter Dörwald3b287702005-12-15 20:17:20 +0000208
Fred Drake2e2be372001-09-20 21:33:42 +0000209if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500210 unittest.main()