test_quopri.py 7.3 KB

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