generated from Nodarx/template
0250b5a847
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
126 lines
5.5 KiB
PHP
126 lines
5.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KTXT\ProviderImap\Tests\Unit;
|
|
|
|
use KTXM\ProviderImap\Client\Protocol\Command\Argument\FetchOptions;
|
|
use KTXM\ProviderImap\Client\Protocol\Parser\FetchMessageParser;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class FetchMessageParserTest extends TestCase
|
|
{
|
|
/** multipart/mixed ( multipart/alternative ( text/plain, text/html ), application/pdf ) */
|
|
private const MIXED_STRUCTURE = '((("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "7BIT" 5 1)'
|
|
. '("TEXT" "HTML" ("CHARSET" "UTF-8") NIL NIL "7BIT" 12 1) "ALTERNATIVE" ("BOUNDARY" "alt") NIL NIL)'
|
|
. '("APPLICATION" "PDF" ("NAME" "a.pdf") NIL NIL "BASE64" 100 NIL ("ATTACHMENT" ("FILENAME" "a.pdf")) NIL)'
|
|
. ' "MIXED" ("BOUNDARY" "mix") NIL NIL)';
|
|
|
|
private const ALTERNATIVE_PREFIX = "--mix\r\n"
|
|
. "Content-Type: multipart/alternative; boundary=alt\r\n\r\n"
|
|
. "--alt\r\nContent-Type: text/plain\r\n\r\nHello\r\n"
|
|
. "--alt\r\nContent-Type: text/html\r\n\r\n";
|
|
|
|
public function testBodyTextWithLimitRequestsPartialFetch(): void
|
|
{
|
|
$this->assertStringContainsString('BODY.PEEK[TEXT]<0.1024>', FetchOptions::message()->withBodyText(1024)->toCommand());
|
|
$this->assertStringContainsString('BODY.PEEK[TEXT]', FetchOptions::message()->withBodyText()->toCommand());
|
|
$this->assertStringNotContainsString('<0.', FetchOptions::message()->withBodyText()->toCommand());
|
|
}
|
|
|
|
public function testCompleteMultipartKeepsTextSectionsOnly(): void
|
|
{
|
|
$body = self::ALTERNATIVE_PREFIX . "<p>Hello</p>\r\n--alt--\r\n"
|
|
. "--mix\r\nContent-Type: application/pdf\r\nContent-Transfer-Encoding: base64\r\n\r\nJVBERi0=\r\n--mix--\r\n";
|
|
|
|
$message = FetchMessageParser::parse($this->fetchResponse(self::MIXED_STRUCTURE, 'BODY[TEXT]', $body));
|
|
|
|
$this->assertSame(['1.1' => 'Hello', '1.2' => '<p>Hello</p>'], $message->bodySections());
|
|
}
|
|
|
|
public function testPartialResponseWithOriginIsParsed(): void
|
|
{
|
|
$body = self::ALTERNATIVE_PREFIX . "<p>Hello</p>\r\n--alt--\r\n--mix--\r\n";
|
|
|
|
$message = FetchMessageParser::parse($this->fetchResponse(self::MIXED_STRUCTURE, 'BODY[TEXT]<0>', $body));
|
|
|
|
$this->assertSame(7, $message->uid());
|
|
$this->assertSame(['1.1' => 'Hello', '1.2' => '<p>Hello</p>'], $message->bodySections());
|
|
}
|
|
|
|
public function testBodyCutInsideNestedTextPartKeepsPrecedingAndPartialText(): void
|
|
{
|
|
$body = self::ALTERNATIVE_PREFIX . '<p>Hello wor';
|
|
|
|
$message = FetchMessageParser::parse($this->fetchResponse(self::MIXED_STRUCTURE, 'BODY[TEXT]<0>', $body));
|
|
|
|
$this->assertSame(['1.1' => 'Hello', '1.2' => '<p>Hello wor'], $message->bodySections());
|
|
}
|
|
|
|
public function testBodyCutInsideAttachmentHeadersDropsAttachment(): void
|
|
{
|
|
$body = self::ALTERNATIVE_PREFIX . "<p>Hello</p>\r\n--alt--\r\n--mix\r\nContent-Type: applic";
|
|
|
|
$message = FetchMessageParser::parse($this->fetchResponse(self::MIXED_STRUCTURE, 'BODY[TEXT]<0>', $body));
|
|
|
|
$this->assertSame(['1.1' => 'Hello', '1.2' => '<p>Hello</p>'], $message->bodySections());
|
|
}
|
|
|
|
public function testBodyCutInsideBase64TextPartDecodesCompleteQuanta(): void
|
|
{
|
|
$structure = '(("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "BASE64" 20 1)'
|
|
. '("APPLICATION" "PDF" NIL NIL NIL "BASE64" 100 NIL NIL NIL) "MIXED" ("BOUNDARY" "mix") NIL NIL)';
|
|
// "Hello world" = SGVsbG8gd29ybGQ= ; cut after "SGVsbG8gd29y" + 2 stray chars
|
|
$body = "--mix\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: base64\r\n\r\nSGVsbG8gd29yYm";
|
|
|
|
$message = FetchMessageParser::parse($this->fetchResponse($structure, 'BODY[TEXT]<0>', $body));
|
|
|
|
$this->assertSame(['1' => 'Hello wor'], $message->bodySections());
|
|
}
|
|
|
|
public function testTruncatedSectionsAreReported(): void
|
|
{
|
|
$complete = FetchMessageParser::parse($this->fetchResponse(
|
|
self::MIXED_STRUCTURE,
|
|
'BODY[TEXT]',
|
|
self::ALTERNATIVE_PREFIX . "<p>Hello</p>\r\n--alt--\r\n--mix--\r\n",
|
|
));
|
|
$cutInHtml = FetchMessageParser::parse($this->fetchResponse(
|
|
self::MIXED_STRUCTURE,
|
|
'BODY[TEXT]<0>',
|
|
self::ALTERNATIVE_PREFIX . '<p>Hello wor',
|
|
));
|
|
$cutInAttachment = FetchMessageParser::parse($this->fetchResponse(
|
|
self::MIXED_STRUCTURE,
|
|
'BODY[TEXT]<0>',
|
|
self::ALTERNATIVE_PREFIX . "<p>Hello</p>\r\n--alt--\r\n--mix\r\nContent-Type: application/pdf\r\n\r\nJVBE",
|
|
));
|
|
|
|
$this->assertSame([], $complete->truncatedSections());
|
|
$this->assertSame(['1.2'], $cutInHtml->truncatedSections());
|
|
$this->assertSame([], $cutInAttachment->truncatedSections());
|
|
}
|
|
|
|
public function testTruncatedSinglePartBodyIsReportedBySize(): void
|
|
{
|
|
$structure = '("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "7BIT" 11 1)';
|
|
|
|
$partial = FetchMessageParser::parse($this->fetchResponse($structure, 'BODY[TEXT]<0>', 'Hello'));
|
|
$complete = FetchMessageParser::parse($this->fetchResponse($structure, 'BODY[TEXT]', 'Hello world'));
|
|
|
|
$this->assertSame(['1'], $partial->truncatedSections());
|
|
$this->assertSame([], $complete->truncatedSections());
|
|
}
|
|
|
|
private function fetchResponse(string $bodyStructure, string $section, string $body): string
|
|
{
|
|
return sprintf(
|
|
"* 1 FETCH (UID 7 FLAGS () BODYSTRUCTURE %s %s {%d}\r\n%s)",
|
|
$bodyStructure,
|
|
$section,
|
|
strlen($body),
|
|
$body,
|
|
);
|
|
}
|
|
}
|