diff --git a/src/PhpImap/Imap.php b/src/PhpImap/Imap.php index d4ab5018..3762410f 100644 --- a/src/PhpImap/Imap.php +++ b/src/PhpImap/Imap.php @@ -813,12 +813,16 @@ public static function search( $imap_stream, string $criteria, int $options = SE_FREE, - string $charset = null + string $charset = null, + bool $encodeCriteriaAsUtf7Imap = false ): array { \imap_errors(); // flush errors $imap_stream = static::EnsureConnection($imap_stream, __METHOD__, 1); - $criteria = static::encodeStringToUtf7Imap($criteria); + + if ($encodeCriteriaAsUtf7Imap) { + $criteria = static::encodeStringToUtf7Imap($criteria); + } if (\is_string($charset)) { $result = \imap_search( diff --git a/tests/unit/AbstractLiveMailboxTest.php b/tests/unit/AbstractLiveMailboxTest.php index ff21ea5f..d1b25d69 100644 --- a/tests/unit/AbstractLiveMailboxTest.php +++ b/tests/unit/AbstractLiveMailboxTest.php @@ -10,8 +10,10 @@ namespace PhpImap; +use Generator; use ParagonIE\HiddenString\HiddenString; use PHPUnit\Framework\TestCase; +use Throwable; /** * @psalm-type MAILBOX_ARGS = array{ @@ -21,6 +23,17 @@ * 3:string, * 4?:string * } + * @psalm-type COMPOSE_ENVELOPE = array{ + * subject?:string + * } + * @psalm-type COMPOSE_BODY = list */ abstract class AbstractLiveMailboxTest extends TestCase { @@ -44,6 +57,138 @@ public function MailBoxProvider(): array return $sets; } + /** + * @psalm-return Generator + */ + public function ComposeProvider(): Generator + { + yield from []; + } + + /** + * @psalm-return Generator + */ + public function AppendProvider(): Generator + { + foreach ($this->MailBoxProvider() as $mailbox_args) { + foreach ($this->ComposeProvider() as $compose_args) { + [$envelope, $body, $expected_compose_result] = $compose_args; + + yield [$mailbox_args, $envelope, $body, $expected_compose_result, false]; + } + + foreach ($this->ComposeProvider() as $compose_args) { + [$envelope, $body, $expected_compose_result] = $compose_args; + + yield [$mailbox_args, $envelope, $body, $expected_compose_result, true]; + } + } + } + + /** + * @dataProvider AppendProvider + * + * @group live + * + * @depends testGetImapStream + * @depends testMailCompose + * + * @psalm-param MAILBOX_ARGS $mailbox_args + * @psalm-param COMPOSE_ENVELOPE $envelope + * @psalm-param COMPOSE_BODY $body + */ + public function testAppend( + array $mailbox_args, + array $envelope, + array $body, + string $_expected_compose_result, + bool $pre_compose + ): void { + if ($this->MaybeSkipAppendTest($envelope)) { + return; + } + + list($search_criteria) = $this->SubjectSearchCriteriaAndSubject($envelope); + + list($mailbox, $remove_mailbox, $path) = $this->getMailboxFromArgs( + $mailbox_args + ); + + /** @var Throwable|null */ + $exception = null; + + $mailboxDeleted = false; + + try { + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 0, + $search, + ( + 'If a subject was found,'. + ' then the message is insufficiently unique to assert that'. + ' a newly-appended message was actually created.' + ) + ); + + $message = [$envelope, $body]; + + if ($pre_compose) { + $message = Imap::mail_compose($envelope, $body); + } + + $mailbox->appendMessageToMailbox($message); + + $search = $mailbox->searchMailbox($search_criteria); + + $this->assertCount( + 1, + $search, + ( + 'If a subject was not found, '. + ' then Mailbox::appendMessageToMailbox() failed'. + ' despite not throwing an exception.' + ) + ); + + $mailbox->deleteMail($search[0]); + + $mailbox->expungeDeletedMails(); + + $mailbox->switchMailbox($path->getString()); + $mailbox->deleteMailbox($remove_mailbox); + $mailboxDeleted = true; + + $this->assertCount( + 0, + $mailbox->searchMailbox($search_criteria), + ( + 'If a subject was found,'. + ' then the message is was not expunged as requested.' + ) + ); + } catch (Throwable $ex) { + $exception = $ex; + } finally { + $mailbox->switchMailbox($path->getString()); + if (!$mailboxDeleted) { + $mailbox->deleteMailbox($remove_mailbox); + } + $mailbox->disconnect(); + } + + if (null !== $exception) { + throw $exception; + } + } + /** * Get instance of Mailbox, pre-set to a random mailbox. * @@ -106,4 +251,17 @@ protected function SubjectSearchCriteriaAndSubject(array $envelope): array /** @psalm-var array{0:string, 1:string} */ return [$search_criteria, (string) $subject]; } + + protected function MaybeSkipAppendTest(array $envelope): bool + { + if (!isset($envelope['subject'])) { + $this->markTestSkipped( + 'Cannot search for message by subject, no subject specified!' + ); + + return true; + } + + return false; + } } diff --git a/tests/unit/LiveMailboxIssue250Test.php b/tests/unit/LiveMailboxIssue250Test.php new file mode 100644 index 00000000..b80ad7fb --- /dev/null +++ b/tests/unit/LiveMailboxIssue250Test.php @@ -0,0 +1,89 @@ + + */ +class LiveMailboxIssue250Test extends AbstractLiveMailboxTest +{ + /** + * @psalm-return Generator + */ + public function ComposeProvider(): Generator + { + $random_subject = 'barbushin/php-imap#250 测试: '.\bin2hex(\random_bytes(16)); + + yield [ + ['subject' => $random_subject], + [ + [ + 'type' => TYPETEXT, + 'contents.data' => 'test', + ], + ], + ( + 'Subject: '.$random_subject."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: TEXT/PLAIN; CHARSET=US-ASCII'."\r\n". + "\r\n". + 'test'."\r\n" + ), + ]; + } + + /** + * @dataProvider AppendProvider + * + * @group live + * @group live-issue-250 + * + * @psalm-param MAILBOX_ARGS $mailbox_args + * @psalm-param COMPOSE_ENVELOPE $envelope + * @psalm-param COMPOSE_BODY $body + */ + public function testAppend( + array $mailbox_args, + array $envelope, + array $body, + string $expected_compose_result, + bool $pre_compose + ): void { + parent::testAppend( + $mailbox_args, + $envelope, + $body, + $expected_compose_result, + $pre_compose + ); + } +} diff --git a/tests/unit/LiveMailboxTest.php b/tests/unit/LiveMailboxTest.php index b548d91d..ee39b4e6 100644 --- a/tests/unit/LiveMailboxTest.php +++ b/tests/unit/LiveMailboxTest.php @@ -12,10 +12,10 @@ use function date; use const ENCBASE64; -use Exception; use Generator; use ParagonIE\HiddenString\HiddenString; use const SORTARRIVAL; +use Throwable; use const TYPEAPPLICATION; use const TYPEMULTIPART; use const TYPETEXT; @@ -66,7 +66,7 @@ public function testGetImapStream(HiddenString $imapPath, HiddenString $login, H $serverEncoding ); - /** @var Exception|null */ + /** @var Throwable|null */ $exception = null; try { @@ -129,7 +129,7 @@ public function testGetImapStream(HiddenString $imapPath, HiddenString $login, H $this->assertSame($check->Nmsgs, $mailbox->countMails(), 'Mailbox::checkMailbox()->Nmsgs did not match Mailbox::countMails()!'); } - } catch (Exception $ex) { + } catch (Throwable $ex) { $exception = $ex; } finally { $mailbox->switchMailbox($imapPath->getString()); @@ -314,110 +314,6 @@ public function testMailCompose(array $envelope, array $body, string $expected_r $this->assertSame($expected_result, $actual_result); } - /** - * @psalm-return Generator - */ - public function AppendProvider(): Generator - { - foreach ($this->MailBoxProvider() as $mailbox_args) { - foreach ($this->ComposeProvider() as $compose_args) { - [$envelope, $body, $expected_compose_result] = $compose_args; - - yield [$mailbox_args, $envelope, $body, $expected_compose_result, false]; - } - - foreach ($this->ComposeProvider() as $compose_args) { - [$envelope, $body, $expected_compose_result] = $compose_args; - - yield [$mailbox_args, $envelope, $body, $expected_compose_result, true]; - } - } - } - - /** - * @dataProvider AppendProvider - * - * @group live - * - * @depends testGetImapStream - * @depends testMailCompose - * - * @psalm-param MAILBOX_ARGS $mailbox_args - * @psalm-param COMPOSE_ENVELOPE $envelope - * @psalm-param COMPOSE_BODY $body - */ - public function testAppend( - array $mailbox_args, - array $envelope, - array $body, - string $_expected_compose_result, - bool $pre_compose - ): void { - if ($this->MaybeSkipAppendTest($envelope)) { - return; - } - - list($search_criteria) = $this->SubjectSearchCriteriaAndSubject($envelope); - - list($mailbox, $remove_mailbox, $path) = $this->getMailboxFromArgs( - $mailbox_args - ); - - $search = $mailbox->searchMailbox($search_criteria); - - $this->assertCount( - 0, - $search, - ( - 'If a subject was found,'. - ' then the message is insufficiently unique to assert that'. - ' a newly-appended message was actually created.' - ) - ); - - $message = [$envelope, $body]; - - if ($pre_compose) { - $message = Imap::mail_compose($envelope, $body); - } - - $mailbox->appendMessageToMailbox($message); - - $search = $mailbox->searchMailbox($search_criteria); - - $this->assertCount( - 1, - $search, - ( - 'If a subject was not found, '. - ' then Mailbox::appendMessageToMailbox() failed'. - ' despite not throwing an exception.' - ) - ); - - $mailbox->deleteMail($search[0]); - - $mailbox->expungeDeletedMails(); - - $mailbox->switchMailbox($path->getString()); - $mailbox->deleteMailbox($remove_mailbox); - - $this->assertCount( - 0, - $mailbox->searchMailbox($search_criteria), - ( - 'If a subject was found,'. - ' then the message is was not expunged as requested.' - ) - ); - } - /** * @dataProvider AppendProvider * @@ -750,19 +646,6 @@ public function testAppendRetrievalMatchesExpected( ); } - protected function MaybeSkipAppendTest(array $envelope): bool - { - if (!isset($envelope['subject'])) { - $this->markTestSkipped( - 'Cannot search for message by subject, no subject specified!' - ); - - return true; - } - - return false; - } - /** * @param string $expected_result * @param string $actual_result