first line ends with a space decsample bhere s a bunch of special n b xa1xa2xa3xa4xa5xa6xa7xa8xa9 xaaxabxacxadxaexafxb0xb1xb2xb3 xb4xb5xb6xb7xb8xb9xbaxbbxbcxbdxbe xbfxc0xc1xc2xc3xc4xc5xc6 xc7xc8xc9xcaxcbxccxcdxcexcf xd0xd1xd2xd3xd4xd5xd6xd7 xd8xd9xdaxdbxdcxddxdexdf xe0xe1xe2xe3xe4xe5xe6xe7 xe8xe9xeaxebxecxedxeexef xf0xf1xf2xf3xf4xf5xf6xf7 xf8xf9xfaxfbxfcxfdxfexff characters have fun test default implementation test python implementation each entry is a tuple of plaintext encoded string these strings are used in the quotetabs0 tests some normal strings b hello there world add some trailing must quote strings some long lines first a single line of 108 characters a line of exactly 76 characters no soft line break should be needed a line of 77 characters forcing a soft line break at position 75 and a second line of exactly 2 characters because the soft line break sign counts against the line length limit a line of 151 characters forcing a soft line break at position 75 with a second line of exactly 76 characters and no trailing a string containing a hard line break but which the first line is 151 characters and the second line is exactly 76 characters this should leave us with three lines the first which has a soft line break and which the second and third do not now some really complex stuff these are used in the quotetabs1 tests these are used in the header1 tests issue 21511 ensure that byte string is compared to byte string instead of int byte value on windows python will output the result to stdout using crlf as the mode of stdout is text mode to compare this with the expected result we need to do a linebyline comparison here s a bunch of special 20 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff characters have fun first line ends with a space xa1 xa2 xa3 xa4 xa5 xa6 xa7 xa8 xa9 xaa xab xac xad xae xaf xb0 xb1 xb2 xb3 xb4 xb5 xb6 xb7 xb8 xb9 xba xbb xbc xbd xbe xbf xc0 xc1 xc2 xc3 xc4 xc5 xc6 xc7 xc8 xc9 xca xcb xcc xcd xce xcf xd0 xd1 xd2 xd3 xd4 xd5 xd6 xd7 xd8 xd9 xda xdb xdc xdd xde xdf xe0 xe1 xe2 xe3 xe4 xe5 xe6 xe7 xe8 xe9 xea xeb xec xed xee xef xf0 xf1 xf2 xf3 xf4 xf5 xf6 xf7 xf8 xf9 xfa xfb xfc xfd xfe xff characters have fun test default implementation test python implementation each entry is a tuple of plaintext encoded string these strings are used in the quotetabs 0 tests some normal strings hello there world hello there world hello there world hello there world add some trailing must quote strings some long lines first a single line of 108 characters xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx d8 d9 da db dc dd de dfx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx a line of exactly 76 characters no soft line break should be needed a line of 77 characters forcing a soft line break at position 75 and a second line of exactly 2 characters because the soft line break sign counts against the line length limit zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz zz a line of 151 characters forcing a soft line break at position 75 with a second line of exactly 76 characters and no trailing zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz a string containing a hard line break but which the first line is 151 characters and the second line is exactly 76 characters this should leave us with three lines the first which has a soft line break and which the second and third do not yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz now some really complex stuff these are used in the quotetabs 1 tests these are used in the header 1 tests issue 21511 ensure that byte string is compared to byte string instead of int byte value on windows python will output the result to stdout using crlf as the mode of stdout is text mode to compare this with the expected result we need to do a line by line comparison
import unittest

import sys, io, subprocess
import quopri

from test import support


ENCSAMPLE = b


DECSAMPLE = b"Here's a bunch of special \n" + \
b


def withpythonimplementation(testfunc):
    def newtest(self):
        
        testfunc(self)
        
        if quopri.b2a_qp is not None or quopri.a2b_qp is not None:
            oldencode = quopri.b2a_qp
            olddecode = quopri.a2b_qp
            try:
                quopri.b2a_qp = None
                quopri.a2b_qp = None
                testfunc(self)
            finally:
                quopri.b2a_qp = oldencode
                quopri.a2b_qp = olddecode
    newtest.__name__ = testfunc.__name__
    return newtest

class QuopriTestCase(unittest.TestCase):
    
    
    STRINGS = (
        
        (b'hello', b'hello'),
        (b, b),
        (b, b),
        (b'\201\202\203', b'=81=82=83'),
        
        (b'hello ', b'hello=20'),
        (b'hello\t', b'hello=09'),
        
        (b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\xd8\xd9\xda\xdb\xdc\xdd\xde\xdfxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
         b),
        
        (b'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy',
        b'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'),
        
        
        
        (b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
         b),
        
        
        (b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
         b),
        
        
        
        
        (b,
         b),
        
        (DECSAMPLE, ENCSAMPLE),
        )

    
    ESTRINGS = (
        (b'hello world', b'hello=20world'),
        (b'hello\tworld', b'hello=09world'),
        )

    
    HSTRINGS = (
        (b'hello world', b'hello_world'),
        (b'hello_world', b'hello=5Fworld'),
        )

    @withpythonimplementation
    def test_encodestring(self):
        for p, e in self.STRINGS:
            self.assertEqual(quopri.encodestring(p), e)

    @withpythonimplementation
    def test_decodestring(self):
        for p, e in self.STRINGS:
            self.assertEqual(quopri.decodestring(e), p)

    @withpythonimplementation
    def test_decodestring_double_equals(self):
        
        
        decoded_value, encoded_value = (b"123=four", b"123==four")
        self.assertEqual(quopri.decodestring(encoded_value), decoded_value)

    @withpythonimplementation
    def test_idempotent_string(self):
        for p, e in self.STRINGS:
            self.assertEqual(quopri.decodestring(quopri.encodestring(e)), e)

    @withpythonimplementation
    def test_encode(self):
        for p, e in self.STRINGS:
            infp = io.BytesIO(p)
            outfp = io.BytesIO()
            quopri.encode(infp, outfp, quotetabs=False)
            self.assertEqual(outfp.getvalue(), e)

    @withpythonimplementation
    def test_decode(self):
        for p, e in self.STRINGS:
            infp = io.BytesIO(e)
            outfp = io.BytesIO()
            quopri.decode(infp, outfp)
            self.assertEqual(outfp.getvalue(), p)

    @withpythonimplementation
    def test_embedded_ws(self):
        for p, e in self.ESTRINGS:
            self.assertEqual(quopri.encodestring(p, quotetabs=True), e)
            self.assertEqual(quopri.decodestring(e), p)

    @withpythonimplementation
    def test_encode_header(self):
        for p, e in self.HSTRINGS:
            self.assertEqual(quopri.encodestring(p, header=True), e)

    @withpythonimplementation
    def test_decode_header(self):
        for p, e in self.HSTRINGS:
            self.assertEqual(quopri.decodestring(e, header=True), p)

    @support.requires_subprocess()
    def test_scriptencode(self):
        (p, e) = self.STRINGS[-1]
        process = subprocess.Popen([sys.executable, "-mquopri"],
                                   stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        self.addCleanup(process.stdout.close)
        cout, cerr = process.communicate(p)
        
        
        
        cout = cout.decode('latin-1').splitlines()
        e = e.decode('latin-1').splitlines()
        assert len(cout)==len(e)
        for i in range(len(cout)):
            self.assertEqual(cout[i], e[i])
        self.assertEqual(cout, e)

    @support.requires_subprocess()
    def test_scriptdecode(self):
        (p, e) = self.STRINGS[-1]
        process = subprocess.Popen([sys.executable, "-mquopri", "-d"],
                                   stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        self.addCleanup(process.stdout.close)
        cout, cerr = process.communicate(e)
        cout = cout.decode('latin-1')
        p = p.decode('latin-1')
        self.assertEqual(cout.splitlines(), p.splitlines())

if __name__ == "__main__":
    unittest.main()