1
0

提交代码

This commit is contained in:
2020-08-06 14:50:07 +08:00
parent 9d0d5f4be9
commit d7a848c824
11299 changed files with 1321854 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mime\Tests\Header;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\Header\DateHeader;
class DateHeaderTest extends TestCase
{
/* --
The following tests refer to RFC 2822, section 3.6.1 and 3.3.
*/
public function testGetDateTime()
{
$header = new DateHeader('Date', $dateTime = new \DateTimeImmutable());
$this->assertSame($dateTime, $header->getDateTime());
}
public function testDateTimeCanBeSetBySetter()
{
$header = new DateHeader('Date', new \DateTimeImmutable());
$header->setDateTime($dateTime = new \DateTimeImmutable());
$this->assertSame($dateTime, $header->getDateTime());
}
public function testDateTimeIsConvertedToImmutable()
{
$dateTime = new \DateTime();
$header = new DateHeader('Date', $dateTime);
$this->assertInstanceOf('DateTimeImmutable', $header->getDateTime());
$this->assertEquals($dateTime->getTimestamp(), $header->getDateTime()->getTimestamp());
$this->assertEquals($dateTime->getTimezone(), $header->getDateTime()->getTimezone());
}
public function testDateTimeIsImmutable()
{
$header = new DateHeader('Date', $dateTime = new \DateTime('2000-01-01 12:00:00 Europe/Berlin'));
$dateTime->setDate(2002, 2, 2);
$this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getDateTime()->format('r'));
$this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getBodyAsString());
}
public function testDateTimeIsConvertedToRfc2822Date()
{
$header = new DateHeader('Date', $dateTime = new \DateTimeImmutable('2000-01-01 12:00:00 Europe/Berlin'));
$header->setDateTime($dateTime);
$this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getBodyAsString());
}
public function testSetBody()
{
$header = new DateHeader('Date', $dateTime = new \DateTimeImmutable());
$header->setBody($dateTime);
$this->assertEquals($dateTime->format('r'), $header->getBodyAsString());
}
public function testGetBody()
{
$header = new DateHeader('Date', $dateTime = new \DateTimeImmutable());
$header->setDateTime($dateTime);
$this->assertEquals($dateTime, $header->getBody());
}
public function testToString()
{
$header = new DateHeader('Date', $dateTime = new \DateTimeImmutable('2000-01-01 12:00:00 Europe/Berlin'));
$header->setDateTime($dateTime);
$this->assertEquals('Date: Sat, 01 Jan 2000 12:00:00 +0100', $header->toString());
}
}

View File

@@ -0,0 +1,245 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mime\Tests\Header;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Header\Headers;
use Symfony\Component\Mime\Header\IdentificationHeader;
use Symfony\Component\Mime\Header\MailboxListHeader;
use Symfony\Component\Mime\Header\UnstructuredHeader;
class HeadersTest extends TestCase
{
public function testAddMailboxListHeaderDelegatesToFactory()
{
$headers = new Headers();
$headers->addMailboxListHeader('From', ['person@domain']);
$this->assertNotNull($headers->get('From'));
}
public function testAddDateHeaderDelegatesToFactory()
{
$dateTime = new \DateTimeImmutable();
$headers = new Headers();
$headers->addDateHeader('Date', $dateTime);
$this->assertNotNull($headers->get('Date'));
}
public function testAddTextHeaderDelegatesToFactory()
{
$headers = new Headers();
$headers->addTextHeader('Subject', 'some text');
$this->assertNotNull($headers->get('Subject'));
}
public function testAddParameterizedHeaderDelegatesToFactory()
{
$headers = new Headers();
$headers->addParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']);
$this->assertNotNull($headers->get('Content-Type'));
}
public function testAddIdHeaderDelegatesToFactory()
{
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$this->assertNotNull($headers->get('Message-ID'));
}
public function testAddPathHeaderDelegatesToFactory()
{
$headers = new Headers();
$headers->addPathHeader('Return-Path', 'some@path');
$this->assertNotNull($headers->get('Return-Path'));
}
public function testHasReturnsFalseWhenNoHeaders()
{
$headers = new Headers();
$this->assertFalse($headers->has('Some-Header'));
}
public function testAddedMailboxListHeaderIsSeenByHas()
{
$headers = new Headers();
$headers->addMailboxListHeader('From', ['person@domain']);
$this->assertTrue($headers->has('From'));
}
public function testAddedDateHeaderIsSeenByHas()
{
$dateTime = new \DateTimeImmutable();
$headers = new Headers();
$headers->addDateHeader('Date', $dateTime);
$this->assertTrue($headers->has('Date'));
}
public function testAddedTextHeaderIsSeenByHas()
{
$headers = new Headers();
$headers->addTextHeader('Subject', 'some text');
$this->assertTrue($headers->has('Subject'));
}
public function testAddedParameterizedHeaderIsSeenByHas()
{
$headers = new Headers();
$headers->addParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']);
$this->assertTrue($headers->has('Content-Type'));
}
public function testAddedIdHeaderIsSeenByHas()
{
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$this->assertTrue($headers->has('Message-ID'));
}
public function testAddedPathHeaderIsSeenByHas()
{
$headers = new Headers();
$headers->addPathHeader('Return-Path', 'some@path');
$this->assertTrue($headers->has('Return-Path'));
}
public function testNewlySetHeaderIsSeenByHas()
{
$headers = new Headers();
$headers->add(new UnstructuredHeader('X-Foo', 'bar'));
$this->assertTrue($headers->has('X-Foo'));
}
public function testHasCanDistinguishMultipleHeaders()
{
$headers = new Headers();
$headers->addTextHeader('X-Test', 'some@id');
$headers->addTextHeader('X-Test', 'other@id');
$this->assertTrue($headers->has('X-Test'));
}
public function testGet()
{
$header = new IdentificationHeader('Message-ID', 'some@id');
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$this->assertEquals($header->toString(), $headers->get('Message-ID')->toString());
}
public function testGetReturnsNullIfHeaderNotSet()
{
$headers = new Headers();
$this->assertNull($headers->get('Message-ID'));
}
public function testAllReturnsAllHeadersMatchingName()
{
$header0 = new UnstructuredHeader('X-Test', 'some@id');
$header1 = new UnstructuredHeader('X-Test', 'other@id');
$header2 = new UnstructuredHeader('X-Test', 'more@id');
$headers = new Headers();
$headers->addTextHeader('X-Test', 'some@id');
$headers->addTextHeader('X-Test', 'other@id');
$headers->addTextHeader('X-Test', 'more@id');
$this->assertEquals([$header0, $header1, $header2], iterator_to_array($headers->all('X-Test')));
}
public function testAllReturnsAllHeadersIfNoArguments()
{
$header0 = new IdentificationHeader('Message-ID', 'some@id');
$header1 = new UnstructuredHeader('Subject', 'thing');
$header2 = new MailboxListHeader('To', [new Address('person@example.org')]);
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$headers->addTextHeader('Subject', 'thing');
$headers->addMailboxListHeader('To', [new Address('person@example.org')]);
$this->assertEquals(['message-id' => $header0, 'subject' => $header1, 'to' => $header2], iterator_to_array($headers->all()));
}
public function testAllReturnsEmptyArrayIfNoneSet()
{
$headers = new Headers();
$this->assertEquals([], iterator_to_array($headers->all('Received')));
}
public function testRemoveRemovesAllHeadersWithName()
{
$header0 = new UnstructuredHeader('X-Test', 'some@id');
$header1 = new UnstructuredHeader('X-Test', 'other@id');
$headers = new Headers();
$headers->addIdHeader('X-Test', 'some@id');
$headers->addIdHeader('X-Test', 'other@id');
$headers->remove('X-Test');
$this->assertFalse($headers->has('X-Test'));
$this->assertFalse($headers->has('X-Test'));
}
public function testHasIsNotCaseSensitive()
{
$header = new IdentificationHeader('Message-ID', 'some@id');
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$this->assertTrue($headers->has('message-id'));
}
public function testGetIsNotCaseSensitive()
{
$header = new IdentificationHeader('Message-ID', 'some@id');
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$this->assertEquals($header, $headers->get('message-id'));
}
public function testAllIsNotCaseSensitive()
{
$header = new IdentificationHeader('Message-ID', 'some@id');
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$this->assertEquals([$header], iterator_to_array($headers->all('message-id')));
}
public function testRemoveIsNotCaseSensitive()
{
$header = new IdentificationHeader('Message-ID', 'some@id');
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$headers->remove('message-id');
$this->assertFalse($headers->has('Message-ID'));
}
public function testToStringJoinsHeadersTogether()
{
$headers = new Headers();
$headers->addTextHeader('Foo', 'bar');
$headers->addTextHeader('Zip', 'buttons');
$this->assertEquals("Foo: bar\r\nZip: buttons\r\n", $headers->toString());
}
public function testHeadersWithoutBodiesAreNotDisplayed()
{
$headers = new Headers();
$headers->addTextHeader('Foo', 'bar');
$headers->addTextHeader('Zip', '');
$this->assertEquals("Foo: bar\r\n", $headers->toString());
}
public function testToArray()
{
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$headers->addTextHeader('Foo', str_repeat('a', 60).pack('C', 0x8F));
$this->assertEquals([
'Message-ID: <some@id>',
"Foo: =?utf-8?Q?aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?=\r\n =?utf-8?Q?aaaa?=",
], $headers->toArray());
}
}

View File

@@ -0,0 +1,173 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mime\Tests\Header;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\Header\IdentificationHeader;
class IdentificationHeaderTest extends TestCase
{
public function testValueMatchesMsgIdSpec()
{
/* -- RFC 2822, 3.6.4.
message-id = "Message-ID:" msg-id CRLF
in-reply-to = "In-Reply-To:" 1*msg-id CRLF
references = "References:" 1*msg-id CRLF
msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
id-left = dot-atom-text / no-fold-quote / obs-id-left
id-right = dot-atom-text / no-fold-literal / obs-id-right
no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE
no-fold-literal = "[" *(dtext / quoted-pair) "]"
*/
$header = new IdentificationHeader('Message-ID', 'id-left@id-right');
$this->assertEquals('<id-left@id-right>', $header->getBodyAsString());
}
public function testIdCanBeRetrievedVerbatim()
{
$header = new IdentificationHeader('Message-ID', 'id-left@id-right');
$this->assertEquals('id-left@id-right', $header->getId());
}
public function testMultipleIdsCanBeSet()
{
$header = new IdentificationHeader('References', 'c@d');
$header->setIds(['a@b', 'x@y']);
$this->assertEquals(['a@b', 'x@y'], $header->getIds());
}
public function testSettingMultipleIdsProducesAListValue()
{
/* -- RFC 2822, 3.6.4.
The "References:" and "In-Reply-To:" field each contain one or more
unique message identifiers, optionally separated by CFWS.
.. SNIP ..
in-reply-to = "In-Reply-To:" 1*msg-id CRLF
references = "References:" 1*msg-id CRLF
*/
$header = new IdentificationHeader('References', ['a@b', 'x@y']);
$this->assertEquals('<a@b> <x@y>', $header->getBodyAsString());
}
public function testIdLeftCanBeQuoted()
{
/* -- RFC 2822, 3.6.4.
id-left = dot-atom-text / no-fold-quote / obs-id-left
*/
$header = new IdentificationHeader('References', '"ab"@c');
$this->assertEquals('"ab"@c', $header->getId());
$this->assertEquals('<"ab"@c>', $header->getBodyAsString());
}
public function testIdLeftCanContainAnglesAsQuotedPairs()
{
/* -- RFC 2822, 3.6.4.
no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE
*/
$header = new IdentificationHeader('References', '"a\\<\\>b"@c');
$this->assertEquals('"a\\<\\>b"@c', $header->getId());
$this->assertEquals('<"a\\<\\>b"@c>', $header->getBodyAsString());
}
public function testIdLeftCanBeDotAtom()
{
$header = new IdentificationHeader('References', 'a.b+&%$.c@d');
$this->assertEquals('a.b+&%$.c@d', $header->getId());
$this->assertEquals('<a.b+&%$.c@d>', $header->getBodyAsString());
}
public function testInvalidIdLeftThrowsException()
{
$this->expectException('Exception');
$this->expectExceptionMessage('Email "a b c@d" does not comply with addr-spec of RFC 2822.');
$header = new IdentificationHeader('References', 'a b c@d');
}
public function testIdRightCanBeDotAtom()
{
/* -- RFC 2822, 3.6.4.
id-right = dot-atom-text / no-fold-literal / obs-id-right
*/
$header = new IdentificationHeader('References', 'a@b.c+&%$.d');
$this->assertEquals('a@b.c+&%$.d', $header->getId());
$this->assertEquals('<a@b.c+&%$.d>', $header->getBodyAsString());
}
public function testIdRightCanBeLiteral()
{
/* -- RFC 2822, 3.6.4.
no-fold-literal = "[" *(dtext / quoted-pair) "]"
*/
$header = new IdentificationHeader('References', 'a@[1.2.3.4]');
$this->assertEquals('a@[1.2.3.4]', $header->getId());
$this->assertEquals('<a@[1.2.3.4]>', $header->getBodyAsString());
}
public function testIdRigthIsIdnEncoded()
{
$header = new IdentificationHeader('References', 'a@ä');
$this->assertEquals('a@ä', $header->getId());
$this->assertEquals('<a@xn--4ca>', $header->getBodyAsString());
}
public function testInvalidIdRightThrowsException()
{
$this->expectException('Exception');
$this->expectExceptionMessage('Email "a@b c d" does not comply with addr-spec of RFC 2822.');
$header = new IdentificationHeader('References', 'a@b c d');
}
public function testMissingAtSignThrowsException()
{
$this->expectException('Exception');
$this->expectExceptionMessage('Email "abc" does not comply with addr-spec of RFC 2822.');
/* -- RFC 2822, 3.6.4.
msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
*/
$header = new IdentificationHeader('References', 'abc');
}
public function testSetBody()
{
$header = new IdentificationHeader('Message-ID', 'c@d');
$header->setBody('a@b');
$this->assertEquals(['a@b'], $header->getIds());
}
public function testGetBody()
{
$header = new IdentificationHeader('Message-ID', 'a@b');
$this->assertEquals(['a@b'], $header->getBody());
}
public function testStringValue()
{
$header = new IdentificationHeader('References', ['a@b', 'x@y']);
$this->assertEquals('References: <a@b> <x@y>', $header->toString());
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mime\Tests\Header;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Header\MailboxHeader;
use Symfony\Component\Mime\NamedAddress;
class MailboxHeaderTest extends TestCase
{
public function testConstructor()
{
$header = new MailboxHeader('Sender', $address = new Address('fabien@symfony.com'));
$this->assertEquals($address, $header->getAddress());
$this->assertEquals($address, $header->getBody());
}
public function testAddress()
{
$header = new MailboxHeader('Sender', new Address('fabien@symfony.com'));
$header->setBody($address = new Address('helene@symfony.com'));
$this->assertEquals($address, $header->getAddress());
$this->assertEquals($address, $header->getBody());
$header->setAddress($address = new Address('thomas@symfony.com'));
$this->assertEquals($address, $header->getAddress());
$this->assertEquals($address, $header->getBody());
}
public function testgetBodyAsString()
{
$header = new MailboxHeader('Sender', new Address('fabien@symfony.com'));
$this->assertEquals('fabien@symfony.com', $header->getBodyAsString());
$header->setAddress(new Address('fabien@sïmfony.com'));
$this->assertEquals('fabien@xn--smfony-iwa.com', $header->getBodyAsString());
$header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier'));
$this->assertEquals('Fabien Potencier <fabien@symfony.com>', $header->getBodyAsString());
$header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier, "from Symfony"'));
$this->assertEquals('"Fabien Potencier, \"from Symfony\"" <fabien@symfony.com>', $header->getBodyAsString());
$header = new MailboxHeader('From', new NamedAddress('fabien@symfony.com', 'Fabien Potencier, \\escaped\\'));
$this->assertEquals('"Fabien Potencier, \\\\escaped\\\\" <fabien@symfony.com>', $header->getBodyAsString());
$name = 'P'.pack('C', 0x8F).'tencier';
$header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien '.$name));
$header->setCharset('iso-8859-1');
$this->assertEquals('Fabien =?'.$header->getCharset().'?Q?P=8Ftencier?= <fabien@symfony.com>', $header->getBodyAsString());
}
public function testUtf8CharsInLocalPartThrows()
{
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
$header = new MailboxHeader('Sender', new Address('fabïen@symfony.com'));
$header->getBodyAsString();
}
public function testToString()
{
$header = new MailboxHeader('Sender', new Address('fabien@symfony.com'));
$this->assertEquals('Sender: fabien@symfony.com', $header->toString());
$header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier'));
$this->assertEquals('Sender: Fabien Potencier <fabien@symfony.com>', $header->toString());
}
}

View File

@@ -0,0 +1,131 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mime\Tests\Header;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Header\MailboxListHeader;
use Symfony\Component\Mime\NamedAddress;
class MailboxListHeaderTest extends TestCase
{
// RFC 2822, 3.6.2 for all tests
public function testMailboxIsSetForAddress()
{
$header = new MailboxListHeader('From', [new Address('chris@swiftmailer.org')]);
$this->assertEquals(['chris@swiftmailer.org'], $header->getAddressStrings());
}
public function testMailboxIsRenderedForNameAddress()
{
$header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn')]);
$this->assertEquals(['Chris Corbyn <chris@swiftmailer.org>'], $header->getAddressStrings());
}
public function testAddressCanBeReturnedForAddress()
{
$header = new MailboxListHeader('From', $addresses = [new Address('chris@swiftmailer.org')]);
$this->assertEquals($addresses, $header->getAddresses());
}
public function testQuotesInNameAreQuoted()
{
$header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, "DHE"')]);
$this->assertEquals(['"Chris Corbyn, \"DHE\"" <chris@swiftmailer.org>'], $header->getAddressStrings());
}
public function testEscapeCharsInNameAreQuoted()
{
$header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, \\escaped\\')]);
$this->assertEquals(['"Chris Corbyn, \\\\escaped\\\\" <chris@swiftmailer.org>'], $header->getAddressStrings());
}
public function testUtf8CharsInDomainAreIdnEncoded()
{
$header = new MailboxListHeader('From', [new NamedAddress('chris@swïftmailer.org', 'Chris Corbyn')]);
$this->assertEquals(['Chris Corbyn <chris@xn--swftmailer-78a.org>'], $header->getAddressStrings());
}
public function testUtf8CharsInLocalPartThrows()
{
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
$header = new MailboxListHeader('From', [new NamedAddress('chrïs@swiftmailer.org', 'Chris Corbyn')]);
$header->getAddressStrings();
}
public function testGetMailboxesReturnsNameValuePairs()
{
$header = new MailboxListHeader('From', $addresses = [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, DHE')]);
$this->assertEquals($addresses, $header->getAddresses());
}
public function testMultipleAddressesAsMailboxStrings()
{
$header = new MailboxListHeader('From', [new Address('chris@swiftmailer.org'), new Address('mark@swiftmailer.org')]);
$this->assertEquals(['chris@swiftmailer.org', 'mark@swiftmailer.org'], $header->getAddressStrings());
}
public function testNameIsEncodedIfNonAscii()
{
$name = 'C'.pack('C', 0x8F).'rbyn';
$header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris '.$name)]);
$header->setCharset('iso-8859-1');
$addresses = $header->getAddressStrings();
$this->assertEquals('Chris =?'.$header->getCharset().'?Q?C=8Frbyn?= <chris@swiftmailer.org>', array_shift($addresses));
}
public function testEncodingLineLengthCalculations()
{
/* -- RFC 2047, 2.
An 'encoded-word' may not be more than 75 characters long, including
'charset', 'encoding', 'encoded-text', and delimiters.
*/
$name = 'C'.pack('C', 0x8F).'rbyn';
$header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris '.$name)]);
$header->setCharset('iso-8859-1');
$addresses = $header->getAddressStrings();
$this->assertEquals('Chris =?'.$header->getCharset().'?Q?C=8Frbyn?= <chris@swiftmailer.org>', array_shift($addresses));
}
public function testGetValueReturnsMailboxStringValue()
{
$header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn')]);
$this->assertEquals('Chris Corbyn <chris@swiftmailer.org>', $header->getBodyAsString());
}
public function testGetValueReturnsMailboxStringValueForMultipleMailboxes()
{
$header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn'), new NamedAddress('mark@swiftmailer.org', 'Mark Corbyn')]);
$this->assertEquals('Chris Corbyn <chris@swiftmailer.org>, Mark Corbyn <mark@swiftmailer.org>', $header->getBodyAsString());
}
public function testSetBody()
{
$header = new MailboxListHeader('From', []);
$header->setBody($addresses = [new Address('chris@swiftmailer.org')]);
$this->assertEquals($addresses, $header->getAddresses());
}
public function testGetBody()
{
$header = new MailboxListHeader('From', $addresses = [new Address('chris@swiftmailer.org')]);
$this->assertEquals($addresses, $header->getBody());
}
public function testToString()
{
$header = new MailboxListHeader('From', [new NamedAddress('chris@example.org', 'Chris Corbyn'), new NamedAddress('mark@example.org', 'Mark Corbyn')]);
$this->assertEquals('From: Chris Corbyn <chris@example.org>, Mark Corbyn <mark@example.org>', $header->toString());
}
}

View File

@@ -0,0 +1,295 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mime\Tests\Header;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\Header\ParameterizedHeader;
class ParameterizedHeaderTest extends TestCase
{
private $charset = 'utf-8';
private $lang = 'en-us';
public function testValueIsReturnedVerbatim()
{
$header = new ParameterizedHeader('Content-Type', 'text/plain');
$this->assertEquals('text/plain', $header->getValue());
}
public function testParametersAreAppended()
{
/* -- RFC 2045, 5.1
parameter := attribute "=" value
attribute := token
; Matching of attributes
; is ALWAYS case-insensitive.
value := token / quoted-string
token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
or tspecials>
tspecials := "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "\" / <">
"/" / "[" / "]" / "?" / "="
; Must be in quoted-string,
; to use within parameter values
*/
$header = new ParameterizedHeader('Content-Type', 'text/plain');
$header->setParameters(['charset' => 'utf-8']);
$this->assertEquals('text/plain; charset=utf-8', $header->getBodyAsString());
}
public function testSpaceInParamResultsInQuotedString()
{
$header = new ParameterizedHeader('Content-Type', 'attachment');
$header->setParameters(['filename' => 'my file.txt']);
$this->assertEquals('attachment; filename="my file.txt"', $header->getBodyAsString());
}
public function testLongParamsAreBrokenIntoMultipleAttributeStrings()
{
/* -- RFC 2231, 3.
The asterisk character ("*") followed
by a decimal count is employed to indicate that multiple parameters
are being used to encapsulate a single parameter value. The count
starts at 0 and increments by 1 for each subsequent section of the
parameter value. Decimal values are used and neither leading zeroes
nor gaps in the sequence are allowed.
The original parameter value is recovered by concatenating the
various sections of the parameter, in order. For example, the
content-type field
Content-Type: message/external-body; access-type=URL;
URL*0="ftp://";
URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"
is semantically identical to
Content-Type: message/external-body; access-type=URL;
URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"
Note that quotes around parameter values are part of the value
syntax; they are NOT part of the value itself. Furthermore, it is
explicitly permitted to have a mixture of quoted and unquoted
continuation fields.
*/
$value = str_repeat('a', 180);
$header = new ParameterizedHeader('Content-Disposition', 'attachment');
$header->setParameters(['filename' => $value]);
$this->assertEquals(
'attachment; '.
'filename*0*=utf-8\'\''.str_repeat('a', 60).";\r\n ".
'filename*1*='.str_repeat('a', 60).";\r\n ".
'filename*2*='.str_repeat('a', 60),
$header->getBodyAsString()
);
}
public function testEncodedParamDataIncludesCharsetAndLanguage()
{
/* -- RFC 2231, 4.
Asterisks ("*") are reused to provide the indicator that language and
character set information is present and encoding is being used. A
single quote ("'") is used to delimit the character set and language
information at the beginning of the parameter value. Percent signs
("%") are used as the encoding flag, which agrees with RFC 2047.
Specifically, an asterisk at the end of a parameter name acts as an
indicator that character set and language information may appear at
the beginning of the parameter value. A single quote is used to
separate the character set, language, and actual value information in
the parameter value string, and an percent sign is used to flag
octets encoded in hexadecimal. For example:
Content-Type: application/x-stuff;
title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A
Note that it is perfectly permissible to leave either the character
set or language field blank. Note also that the single quote
delimiters MUST be present even when one of the field values is
omitted.
*/
$value = str_repeat('a', 20).pack('C', 0x8F).str_repeat('a', 10);
$header = new ParameterizedHeader('Content-Disposition', 'attachment');
$header->setCharset('iso-8859-1');
$header->setValue('attachment');
$header->setParameters(['filename' => $value]);
$header->setLanguage($this->lang);
$this->assertEquals(
'attachment; filename*='.$header->getCharset()."'".$this->lang."'".
str_repeat('a', 20).'%8F'.str_repeat('a', 10),
$header->getBodyAsString()
);
}
public function testMultipleEncodedParamLinesAreFormattedCorrectly()
{
/* -- RFC 2231, 4.1.
Character set and language information may be combined with the
parameter continuation mechanism. For example:
Content-Type: application/x-stuff
title*0*=us-ascii'en'This%20is%20even%20more%20
title*1*=%2A%2A%2Afun%2A%2A%2A%20
title*2="isn't it!"
Note that:
(1) Language and character set information only appear at
the beginning of a given parameter value.
(2) Continuations do not provide a facility for using more
than one character set or language in the same
parameter value.
(3) A value presented using multiple continuations may
contain a mixture of encoded and unencoded segments.
(4) The first segment of a continuation MUST be encoded if
language and character set information are given.
(5) If the first segment of a continued parameter value is
encoded the language and character set field delimiters
MUST be present even when the fields are left blank.
*/
$value = str_repeat('a', 20).pack('C', 0x8F).str_repeat('a', 60);
$header = new ParameterizedHeader('Content-Disposition', 'attachment');
$header->setValue('attachment');
$header->setCharset('utf-6');
$header->setParameters(['filename' => $value]);
$header->setLanguage($this->lang);
$this->assertEquals(
'attachment; filename*0*='.$header->getCharset()."'".$this->lang."'".
str_repeat('a', 20).'%8F'.str_repeat('a', 23).";\r\n ".
'filename*1*='.str_repeat('a', 37),
$header->getBodyAsString()
);
}
public function testToString()
{
$header = new ParameterizedHeader('Content-Type', 'text/html');
$header->setParameters(['charset' => 'utf-8']);
$this->assertEquals('Content-Type: text/html; charset=utf-8', $header->toString());
}
public function testValueCanBeEncodedIfNonAscii()
{
$value = 'fo'.pack('C', 0x8F).'bar';
$header = new ParameterizedHeader('X-Foo', $value);
$header->setCharset('iso-8859-1');
$header->setParameters(['lookslike' => 'foobar']);
$this->assertEquals('X-Foo: =?'.$header->getCharset().'?Q?fo=8Fbar?=; lookslike=foobar', $header->toString());
}
public function testValueAndParamCanBeEncodedIfNonAscii()
{
$value = 'fo'.pack('C', 0x8F).'bar';
$header = new ParameterizedHeader('X-Foo', $value);
$header->setCharset('iso-8859-1');
$header->setParameters(['says' => $value]);
$this->assertEquals('X-Foo: =?'.$header->getCharset().'?Q?fo=8Fbar?=; says*='.$header->getCharset()."''fo%8Fbar", $header->toString());
}
public function testParamsAreEncodedIfNonAscii()
{
$value = 'fo'.pack('C', 0x8F).'bar';
$header = new ParameterizedHeader('X-Foo', 'bar');
$header->setCharset('iso-8859-1');
$header->setParameters(['says' => $value]);
$this->assertEquals('X-Foo: bar; says*='.$header->getCharset()."''fo%8Fbar", $header->toString());
}
public function testParamsAreEncodedWithLegacyEncodingEnabled()
{
$value = 'fo'.pack('C', 0x8F).'bar';
$header = new ParameterizedHeader('Content-Type', 'bar');
$header->setCharset('iso-8859-1');
$header->setParameters(['says' => $value]);
$this->assertEquals('Content-Type: bar; says="=?'.$header->getCharset().'?Q?fo=8Fbar?="', $header->toString());
}
public function testLanguageInformationAppearsInEncodedWords()
{
/* -- RFC 2231, 5.
5. Language specification in Encoded Words
RFC 2047 provides support for non-US-ASCII character sets in RFC 822
message header comments, phrases, and any unstructured text field.
This is done by defining an encoded word construct which can appear
in any of these places. Given that these are fields intended for
display, it is sometimes necessary to associate language information
with encoded words as well as just the character set. This
specification extends the definition of an encoded word to allow the
inclusion of such information. This is simply done by suffixing the
character set specification with an asterisk followed by the language
tag. For example:
From: =?US-ASCII*EN?Q?Keith_Moore?= <moore@cs.utk.edu>
-- RFC 2047, 5. Use of encoded-words in message headers
...
+ An 'encoded-word' MUST NOT be used in parameter of a MIME
Content-Type or Content-Disposition field, or in any structured
field body except within a 'comment' or 'phrase'.
-- RFC 2047, Appendix - changes since RFC 1522
...
+ clarify that encoded-words are allowed in '*text' fields in both
RFC822 headers and MIME body part headers, but NOT as parameter
values.
*/
$value = 'fo'.pack('C', 0x8F).'bar';
$header = new ParameterizedHeader('X-Foo', $value);
$header->setCharset('iso-8859-1');
$header->setLanguage('en');
$header->setParameters(['says' => $value]);
$this->assertEquals('X-Foo: =?'.$header->getCharset().'*en?Q?fo=8Fbar?=; says*='.$header->getCharset()."'en'fo%8Fbar", $header->toString());
}
public function testSetBody()
{
$header = new ParameterizedHeader('Content-Type', 'text/html');
$header->setBody('text/plain');
$this->assertEquals('text/plain', $header->getValue());
}
public function testGetBody()
{
$header = new ParameterizedHeader('Content-Type', 'text/plain');
$this->assertEquals('text/plain', $header->getBody());
}
public function testSetParameter()
{
$header = new ParameterizedHeader('Content-Type', 'text/html');
$header->setParameters(['charset' => 'utf-8', 'delsp' => 'yes']);
$header->setParameter('delsp', 'no');
$this->assertEquals(['charset' => 'utf-8', 'delsp' => 'no'], $header->getParameters());
}
public function testGetParameter()
{
$header = new ParameterizedHeader('Content-Type', 'text/html');
$header->setParameters(['charset' => 'utf-8', 'delsp' => 'yes']);
$this->assertEquals('utf-8', $header->getParameter('charset'));
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mime\Tests\Header;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Header\PathHeader;
class PathHeaderTest extends TestCase
{
public function testSingleAddressCanBeSetAndFetched()
{
$header = new PathHeader('Return-Path', $address = new Address('chris@swiftmailer.org'));
$this->assertEquals($address, $header->getAddress());
}
public function testAddressMustComplyWithRfc2822()
{
$this->expectException('Exception');
$header = new PathHeader('Return-Path', new Address('chr is@swiftmailer.org'));
}
public function testValueIsAngleAddrWithValidAddress()
{
/* -- RFC 2822, 3.6.7.
return = "Return-Path:" path CRLF
path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
obs-path
*/
$header = new PathHeader('Return-Path', new Address('chris@swiftmailer.org'));
$this->assertEquals('<chris@swiftmailer.org>', $header->getBodyAsString());
}
public function testAddressIsIdnEncoded()
{
$header = new PathHeader('Return-Path', new Address('chris@swïftmailer.org'));
$this->assertEquals('<chris@xn--swftmailer-78a.org>', $header->getBodyAsString());
}
public function testAddressMustBeEncodable()
{
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
$header = new PathHeader('Return-Path', new Address('chrïs@swiftmailer.org'));
$header->getBodyAsString();
}
public function testSetBody()
{
$header = new PathHeader('Return-Path', new Address('foo@example.com'));
$header->setBody($address = new Address('foo@bar.tld'));
$this->assertEquals($address, $header->getAddress());
}
public function testGetBody()
{
$header = new PathHeader('Return-Path', $address = new Address('foo@bar.tld'));
$this->assertEquals($address, $header->getBody());
}
public function testToString()
{
$header = new PathHeader('Return-Path', new Address('chris@swiftmailer.org'));
$this->assertEquals('Return-Path: <chris@swiftmailer.org>', $header->toString());
}
}

View File

@@ -0,0 +1,247 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mime\Tests\Header;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\Header\UnstructuredHeader;
class UnstructuredHeaderTest extends TestCase
{
private $charset = 'utf-8';
public function testGetNameReturnsNameVerbatim()
{
$header = new UnstructuredHeader('Subject', '');
$this->assertEquals('Subject', $header->getName());
}
public function testGetValueReturnsValueVerbatim()
{
$header = new UnstructuredHeader('Subject', 'Test');
$this->assertEquals('Test', $header->getValue());
}
public function testBasicStructureIsKeyValuePair()
{
/* -- RFC 2822, 2.2
Header fields are lines composed of a field name, followed by a colon
(":"), followed by a field body, and terminated by CRLF.
*/
$header = new UnstructuredHeader('Subject', 'Test');
$this->assertEquals('Subject: Test', $header->toString());
}
public function testLongHeadersAreFoldedAtWordBoundary()
{
/* -- RFC 2822, 2.2.3
Each header field is logically a single line of characters comprising
the field name, the colon, and the field body. For convenience
however, and to deal with the 998/78 character limitations per line,
the field body portion of a header field can be split into a multiple
line representation; this is called "folding". The general rule is
that wherever this standard allows for folding white space (not
simply WSP characters), a CRLF may be inserted before any WSP.
*/
$value = 'The quick brown fox jumped over the fence, he was a very very '.
'scary brown fox with a bushy tail';
$header = new UnstructuredHeader('X-Custom-Header', $value);
/*
X-Custom-Header: The quick brown fox jumped over the fence, he was a very very
scary brown fox with a bushy tail
*/
$this->assertEquals(
'X-Custom-Header: The quick brown fox jumped over the fence, he was a'.
' very'."\r\n".//Folding
' very scary brown fox with a bushy tail',
$header->toString(), '%s: The header should have been folded at 76th char'
);
}
public function testPrintableAsciiOnlyAppearsInHeaders()
{
/* -- RFC 2822, 2.2.
A field name MUST be composed of printable US-ASCII characters (i.e.,
characters that have values between 33 and 126, inclusive), except
colon. A field body may be composed of any US-ASCII characters,
except for CR and LF.
*/
$nonAsciiChar = pack('C', 0x8F);
$header = new UnstructuredHeader('X-Test', $nonAsciiChar);
$this->assertRegExp('~^[^:\x00-\x20\x80-\xFF]+: [^\x80-\xFF\r\n]+$~s', $header->toString());
}
public function testEncodedWordsFollowGeneralStructure()
{
/* -- RFC 2047, 1.
Generally, an "encoded-word" is a sequence of printable ASCII
characters that begins with "=?", ends with "?=", and has two "?"s in
between.
*/
$nonAsciiChar = pack('C', 0x8F);
$header = new UnstructuredHeader('X-Test', $nonAsciiChar);
$this->assertRegExp('~^X-Test: \=?.*?\?.*?\?.*?\?=$~s', $header->toString());
}
public function testEncodedWordIncludesCharsetAndEncodingMethodAndText()
{
/* -- RFC 2047, 2.
An 'encoded-word' is defined by the following ABNF grammar. The
notation of RFC 822 is used, with the exception that white space
characters MUST NOT appear between components of an 'encoded-word'.
encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
*/
$nonAsciiChar = pack('C', 0x8F);
$header = new UnstructuredHeader('X-Test', $nonAsciiChar);
$header->setCharset('iso-8859-1');
$this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8F?=', $header->toString());
}
public function testEncodedWordsAreUsedToEncodedNonPrintableAscii()
{
// SPACE and TAB permitted
$nonPrintableBytes = array_merge(range(0x00, 0x08), range(0x10, 0x19), [0x7F]);
foreach ($nonPrintableBytes as $byte) {
$char = pack('C', $byte);
$encodedChar = sprintf('=%02X', $byte);
$header = new UnstructuredHeader('X-A', $char);
$header->setCharset('iso-8859-1');
$this->assertEquals('X-A: =?'.$header->getCharset().'?Q?'.$encodedChar.'?=', $header->toString(), 'Non-printable ascii should be encoded');
}
}
public function testEncodedWordsAreUsedToEncode8BitOctets()
{
foreach (range(0x80, 0xFF) as $byte) {
$char = pack('C', $byte);
$encodedChar = sprintf('=%02X', $byte);
$header = new UnstructuredHeader('X-A', $char);
$header->setCharset('iso-8859-1');
$this->assertEquals('X-A: =?'.$header->getCharset().'?Q?'.$encodedChar.'?=', $header->toString(), '8-bit octets should be encoded');
}
}
public function testEncodedWordsAreNoMoreThan75CharsPerLine()
{
/* -- RFC 2047, 2.
An 'encoded-word' may not be more than 75 characters long, including
'charset', 'encoding', 'encoded-text', and delimiters.
... SNIP ...
While there is no limit to the length of a multiple-line header
field, each line of a header field that contains one or more
'encoded-word's is limited to 76 characters.
*/
$nonAsciiChar = pack('C', 0x8F);
//Note that multi-line headers begin with LWSP which makes 75 + 1 = 76
//Note also that =?utf-8?q??= is 12 chars which makes 75 - 12 = 63
//* X-Test: is 8 chars
$header = new UnstructuredHeader('X-Test', $nonAsciiChar);
$header->setCharset('iso-8859-1');
$this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8F?=', $header->toString());
}
public function testFWSPIsUsedWhenEncoderReturnsMultipleLines()
{
/* --RFC 2047, 2.
If it is desirable to encode more text than will fit in an 'encoded-word' of
75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may
be used.
*/
// Note that multi-line headers begin with LWSP which makes 75 + 1 = 76
// Note also that =?utf-8?q??= is 12 chars which makes 75 - 12 = 63
//* X-Test: is 8 chars
$header = new UnstructuredHeader('X-Test', pack('C', 0x8F).'line_one_here'."\r\n".'line_two_here');
$header->setCharset('iso-8859-1');
$this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8Fline=5Fone=5Fhere?='."\r\n".' =?'.$header->getCharset().'?Q?line=5Ftwo=5Fhere?=', $header->toString());
}
public function testAdjacentWordsAreEncodedTogether()
{
/* -- RFC 2047, 5 (1)
Ordinary ASCII text and 'encoded-word's may appear together in the
same header field. However, an 'encoded-word' that appears in a
header field defined as '*text' MUST be separated from any adjacent
'encoded-word' or 'text' by 'linear-white-space'.
-- RFC 2047, 2.
IMPORTANT: 'encoded-word's are designed to be recognized as 'atom's
by an RFC 822 parser. As a consequence, unencoded white space
characters (such as SPACE and HTAB) are FORBIDDEN within an
'encoded-word'.
*/
// It would be valid to encode all words needed, however it's probably
// easiest to encode the longest amount required at a time
$word = 'w'.pack('C', 0x8F).'rd';
$text = 'start '.$word.' '.$word.' then '.$word;
// 'start', ' word word', ' and end', ' word'
$header = new UnstructuredHeader('X-Test', $text);
$header->setCharset('iso-8859-1');
$this->assertEquals('X-Test: start =?'.$header->getCharset().'?Q?'.
'w=8Frd_w=8Frd?= then =?'.$header->getCharset().'?Q?'.
'w=8Frd?=', $header->toString(),
'Adjacent encoded words should appear grouped with WSP encoded'
);
}
public function testLanguageInformationAppearsInEncodedWords()
{
/* -- RFC 2231, 5.
5. Language specification in Encoded Words
RFC 2047 provides support for non-US-ASCII character sets in RFC 822
message header comments, phrases, and any unstructured text field.
This is done by defining an encoded word construct which can appear
in any of these places. Given that these are fields intended for
display, it is sometimes necessary to associate language information
with encoded words as well as just the character set. This
specification extends the definition of an encoded word to allow the
inclusion of such information. This is simply done by suffixing the
character set specification with an asterisk followed by the language
tag. For example:
From: =?US-ASCII*EN?Q?Keith_Moore?= <moore@cs.utk.edu>
*/
$value = 'fo'.pack('C', 0x8F).'bar';
$header = new UnstructuredHeader('Subject', $value);
$header->setLanguage('en');
$header->setCharset('iso-8859-1');
$this->assertEquals('Subject: =?iso-8859-1*en?Q?fo=8Fbar?=', $header->toString());
}
public function testSetBody()
{
$header = new UnstructuredHeader('X-Test', '');
$header->setBody('test');
$this->assertEquals('test', $header->getValue());
}
public function testGetBody()
{
$header = new UnstructuredHeader('Subject', 'test');
$this->assertEquals('test', $header->getBody());
}
}