|
1 from test import test_support |
|
2 import unittest |
|
3 |
|
4 import sys, os, cStringIO, subprocess |
|
5 import quopri |
|
6 |
|
7 |
|
8 |
|
9 ENCSAMPLE = """\ |
|
10 Here'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 |
|
24 characters... have fun! |
|
25 """ |
|
26 |
|
27 # First line ends with a space |
|
28 DECSAMPLE = "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 |
|
43 characters... have fun! |
|
44 """ |
|
45 |
|
46 |
|
47 def 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 |
|
65 class 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= |
|
90 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'''), |
|
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= |
|
99 zz'''), |
|
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= |
|
104 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''), |
|
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 |
|
110 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz''', |
|
111 '''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy= |
|
112 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy |
|
113 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''), |
|
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.assert_(quopri.encodestring(p) == e) |
|
134 |
|
135 @withpythonimplementation |
|
136 def test_decodestring(self): |
|
137 for p, e in self.STRINGS: |
|
138 self.assert_(quopri.decodestring(e) == p) |
|
139 |
|
140 @withpythonimplementation |
|
141 def test_idempotent_string(self): |
|
142 for p, e in self.STRINGS: |
|
143 self.assert_(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.assert_(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.assert_(outfp.getvalue() == p) |
|
160 |
|
161 @withpythonimplementation |
|
162 def test_embedded_ws(self): |
|
163 for p, e in self.ESTRINGS: |
|
164 self.assert_(quopri.encodestring(p, quotetabs=True) == e) |
|
165 self.assert_(quopri.decodestring(e) == p) |
|
166 |
|
167 @withpythonimplementation |
|
168 def test_encode_header(self): |
|
169 for p, e in self.HSTRINGS: |
|
170 self.assert_(quopri.encodestring(p, header=True) == e) |
|
171 |
|
172 @withpythonimplementation |
|
173 def test_decode_header(self): |
|
174 for p, e in self.HSTRINGS: |
|
175 self.assert_(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 cout, cerr = process.communicate(p) |
|
182 # On Windows, Python will output the result to stdout using |
|
183 # CRLF, as the mode of stdout is text mode. To compare this |
|
184 # with the expected result, we need to do a line-by-line comparison. |
|
185 self.assert_(cout.splitlines() == e.splitlines()) |
|
186 |
|
187 def test_scriptdecode(self): |
|
188 (p, e) = self.STRINGS[-1] |
|
189 process = subprocess.Popen([sys.executable, "-mquopri", "-d"], |
|
190 stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
|
191 cout, cerr = process.communicate(e) |
|
192 self.assert_(cout.splitlines() == p.splitlines()) |
|
193 |
|
194 def test_main(): |
|
195 test_support.run_unittest(QuopriTestCase) |
|
196 |
|
197 |
|
198 if __name__ == "__main__": |
|
199 test_main() |