def test_multiple(self): part1 = multipart.MessagePart( entity_body=b"plain text version\r\n") part1.set_content_type("text/plain; charset=us-ascii") part2 = multipart.MessagePart( entity_body=b"RFC 1896 text/enriched version\r\n") part2.set_content_type("text/enriched") part3 = multipart.MessagePart( entity_body=b"fanciest version\r\n") part3.set_content_type("application/x-whatever") mtype = MediaType.from_str( "multipart/alternative; boundary=boundary42") mstream = multipart.MultipartSendWrapper(mtype, [part1, part2, part3]) self.assertTrue( mstream.read() == b"--boundary42\r\n" b"Content-Type: text/plain; charset=us-ascii\r\n" b"\r\n" b"plain text version\r\n" b"\r\n" b"--boundary42\r\n" b"Content-Type: text/enriched\r\n" b"\r\n" b"RFC 1896 text/enriched version\r\n" b"\r\n" b"--boundary42\r\n" b"Content-Type: application/x-whatever\r\n" b"\r\n" b"fanciest version\r\n" b"\r\n" b"--boundary42--")
def test_read_nonblocking(self): src = io.BytesIO(b"How are you?\n" * 10) src = MockBlockingByteReader(src, block_after=((10,))) part = multipart.MessagePart(entity_body=src) part.set_content_type("text/plain") mtype = MediaType.from_str( "multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p") mstream = multipart.MultipartSendWrapper(mtype, [part]) # non-blocking non-empty stream lines = [] line = [] blocks = 0 while True: c = mstream.read(1) if c: if c == b"\n": # end of line lines.append(b"".join(line)) line = [] else: line.append(c) elif c is None: blocks += 1 else: break # our mock blocking stream always returns None at least once self.assertTrue(blocks > 1, "non-blocking stream failed to stall") boundary = lines.index(b"\r") self.assertTrue(boundary > 0, lines) for line in lines[boundary + 1:boundary + 11]: self.assertTrue(line == b"How are you?") mstream.close()
def test_readlines_crlf(self): # Now repeat the exercise with maximal CRLF part = multipart.MessagePart(entity_body=b"\r\nHow are you?\r\n") part.set_content_type("text/plain") mtype = MediaType.from_str( "multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p") mstream = multipart.MultipartSendWrapper( mtype, [part], preamble=b"\r\nJust wanted to ask\r\n", epilogue=b"\r\nFine thanks!\r\n") lines = mstream.readlines() matches = [ b"\r\n", b"Just wanted to ask\r\n", b"\r\n", b"--gc0p4Jq0M2Yt08j34c0p\r\n", b"Content-Type: text/plain\r\n", b"\r\n", b"\r\n", b"How are you?\r\n", b"\r\n", b"--gc0p4Jq0M2Yt08j34c0p--\r\n", b"\r\n", b"Fine thanks!\r\n"] self.assertTrue(len(lines) == len(matches), lines) for line, match in zip(lines, matches): self.assertTrue(line == match, "Failed to match: %s" % match) mstream.close()
def test_content_transfer_encoding(self): part = multipart.MessagePart() # value is a single token, represented as a character string for token in ("7bit", "8bit", "binary", "quoted-printable", "base64", "x-custom", "BINARY"): part.set_content_transfer_encoding(token) self.assertTrue(part.get_header('Content-Transfer-Encoding') == token.encode('ascii')) self.assertTrue(is_text(part.get_content_transfer_encoding())) self.assertTrue(part.get_content_transfer_encoding() == token.lower()) # default is 7bit part.set_header('Content-Transfer-Encoding', None) self.assertTrue(part.get_content_transfer_encoding() == '7bit') # bad tokens should raise an error on set try: part.set_content_transfer_encoding("9:bit") self.fail("bad token in content-transfer-encoding (set)") except ValueError: pass part.set_header('Content-Transfer-Encoding', b"9:bit") # badly formed should be treated as an unrecognized value self.assertTrue(part.get_content_transfer_encoding() is None) # Any entity with an unrecognized Content-Transfer-Encoding must # be treated as if it has a Content-Type of # "application/octet-stream", regardless of what the # Content-Type header field actually says. self.assertTrue(part.get_content_type() == APPLICATION_OCTETSTREAM) part.set_content_type("text/plain") self.assertTrue(part.get_content_type() == APPLICATION_OCTETSTREAM) part.set_content_transfer_encoding("9bit") self.assertTrue(part.get_content_type() == APPLICATION_OCTETSTREAM)
def test_write(self): part = multipart.MessagePart(entity_body=b"How are you?") part.set_content_type("text/plain") mtype = MediaType.from_str( "multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p") mstream = multipart.MultipartSendWrapper(mtype, [part]) self.assertFalse(mstream.writable()) try: mstream.write(b"Hello") self.fail("MultipartSendWrapper.write") except IOError: pass mstream.close()
def test_nested(self): part_a = multipart.MessagePart(entity_body=b"Introduction") part_a.set_content_type("text/plain") part1 = multipart.MessagePart( entity_body=b"plain text version\r\n") part1.set_content_type("text/plain; charset=us-ascii") part2 = multipart.MessagePart( entity_body=b"RFC 1896 text/enriched version\r\n") part2.set_content_type("text/enriched") mtype = MediaType.from_str( 'multipart/alternative; boundary="---- next message ----"') mstream = multipart.MultipartSendWrapper(mtype, [part1, part2]) part_b = multipart.MessagePart(entity_body=mstream) part_b.set_content_type(mtype) mtype = MediaType.from_str( 'multipart/mixed; boundary="---- main boundary ----"') mstream = multipart.MultipartSendWrapper(mtype, [part_a, part_b]) result = mstream.read() self.assertTrue( result == b"------ main boundary ----\r\n" b'Content-Type: text/plain\r\n' b"\r\n" b"Introduction\r\n" b"------ main boundary ----\r\n" b"Content-Type: multipart/alternative; " b'boundary="---- next message ----"\r\n' b"\r\n" b"------ next message ----\r\n" b"Content-Type: text/plain; charset=us-ascii\r\n" b"\r\n" b"plain text version\r\n" b"\r\n" b"------ next message ----\r\n" b"Content-Type: text/enriched\r\n" b"\r\n" b"RFC 1896 text/enriched version\r\n" b"\r\n" b"------ next message ------\r\n" b"------ main boundary ------", repr(result))
def test_close(self): part = multipart.MessagePart() mtype = MediaType.from_str( "multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p") # pass in an iterable of MessageParts mstream = multipart.MultipartSendWrapper(mtype, [part]) self.assertFalse(mstream.closed) mstream.close() self.assertTrue(mstream.closed) try: mstream.read(1) self.fail("MultipartSendWrapper.read after close") except IOError: pass
def test_content_id(self): part = multipart.MessagePart() # value is a character string that must be a valid addr-spec # spaces are removed and ignored as per specification part.set_content_id(" content @ pyslet.org ") self.assertTrue(part.get_header('Content-ID') == b"<*****@*****.**>") self.assertTrue(is_text(part.get_content_id())) self.assertTrue(part.get_content_id() == "*****@*****.**") try: part.set_content_id("content:[email protected]") self.fail("bad localpart in content ID") except grammar.BadSyntax: pass part.set_header("Content-ID", b"content:[email protected]") self.assertTrue(part.get_content_id() is None)
def test_content_description(self): part = multipart.MessagePart() # any text, though non-ascii will be problematic 'the mechanism # specified in RFC 2047' is broken and not work implementing. we # treat this field as ASCII text or raw bytes with spaces trimmed part.set_content_description(" About my content ") self.assertTrue(part.get_header('Content-Description') == b"About my content") self.assertTrue(part.get_content_description() == b"About my content") try: part.set_content_description(ul("Caf\xe9")) self.fail("Content description should ASCII encode") except UnicodeError: pass # OK to pass raw bytes part.set_content_description(ul("Caf\xe9").encode('iso-8859-1')) self.assertTrue(part.get_header('Content-Description') == b"Caf\xe9") self.assertTrue(part.get_content_description() == b"Caf\xe9")
def test_constructor(self): part = multipart.MessagePart() mtype = MediaType.from_str( "multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p") # pass in an iterable of MessageParts and required mime type mstream = multipart.MultipartSendWrapper(mtype, [part]) try: mstream.fileno() self.fail("MultipartSendWrapper.fileno") except IOError: pass # flush does nothing but is callable mstream.flush() self.assertFalse(mstream.isatty()) self.assertTrue(mstream.readable()) mstream.close() # can add an optional preamble, epilogue and boundary mstream = multipart.MultipartSendWrapper( mtype, [part], preamble=b"Hello", epilogue=b"Goodbye")
def test_readline(self): part = multipart.MessagePart(entity_body=b"How are you?") part.set_content_type("text/plain") mtype = MediaType.from_str( "multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p") mstream = multipart.MultipartSendWrapper(mtype, [part]) # preamble is empty, straight into the boundary self.assertTrue( mstream.readline() == b"--gc0p4Jq0M2Yt08j34c0p\r\n") self.assertTrue( mstream.readline() == b"Content-Type: text/plain\r\n") # blank line self.assertTrue(mstream.readline() == b"\r\n") # body self.assertTrue(mstream.readline() == b"How are you?\r\n") # terminating boundary has NO CRLF self.assertTrue( mstream.readline() == b"--gc0p4Jq0M2Yt08j34c0p--")
def test_read(self): part = multipart.MessagePart(entity_body=b"How are you?") part.set_content_type("text/plain") mtype = MediaType.from_str( "multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p") mstream = multipart.MultipartSendWrapper( mtype, [part], preamble=b"Just wanted to ask\r\n...", epilogue=b"Fine\r\nthanks!") # blocking stream c = mstream.read(1) self.assertTrue(c == b"J") line = [] while c != b"\n": line.append(c) c = mstream.read(1) # won't return None self.assertTrue(len(c) == 1) self.assertTrue( b"".join(line) == b'Just wanted to ask\r') data = mstream.read() self.assertTrue(data.endswith(b"Fine\r\nthanks!"), data) self.assertTrue(mstream.read(1) == b"") mstream.close()
def test_readlines(self): # Now try with preamble and epilogue (no CRLF) part = multipart.MessagePart(entity_body=b"How are you?") part.set_content_type("text/plain") mtype = MediaType.from_str( "multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p") mstream = multipart.MultipartSendWrapper( mtype, [part], preamble=b"Just wanted to ask\r\n...", epilogue=b"Fine\r\nthanks!") lines = mstream.readlines() matches = [ b"Just wanted to ask\r\n", b"...\r\n", b"--gc0p4Jq0M2Yt08j34c0p\r\n", b"Content-Type: text/plain\r\n", b"\r\n", b"How are you?\r\n", b"--gc0p4Jq0M2Yt08j34c0p--\r\n", b"Fine\r\n", b"thanks!"] self.assertTrue(len(lines) == len(matches)) for line, match in zip(lines, matches): self.assertTrue(line == match, "Failed to match: %s" % match) mstream.close()
def test_constructor(self): part = multipart.MessagePart() self.assertTrue(isinstance(part, http.Message))