MessageIDParser passing tests.

This commit is contained in:
Eduardo Gulias Davis
2021-02-21 22:41:37 +01:00
parent b80f568f75
commit 07464f87c8
7 changed files with 186 additions and 33 deletions
+109
View File
@@ -0,0 +1,109 @@
<?php
namespace Egulias\EmailValidator;
use Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Parser\LocalPart;
use Egulias\EmailValidator\Parser\IDLeftPart;
use Egulias\EmailValidator\Result\ValidEmail;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Warning\EmailTooLong;
use Egulias\EmailValidator\Result\Reason\NoLocalPart;
class MessageIDParser extends Parser
{
const EMAILID_MAX_LENGTH = 254;
/**
* @var string
*/
protected $idLeft = '';
/**
* @var string
*/
protected $idRight = '';
public function __construct(EmailLexer $lexer)
{
$this->lexer = $lexer;
}
public function parse(string $str) : Result
{
$result = parent::parse($str);
$this->addLongEmailWarning($this->localPart, $this->domainPart);
return $result;
}
protected function preRightParsing(): Result
{
if (!$this->hasAtToken()) {
return new InvalidEmail(new NoLocalPart(), $this->lexer->token["value"]);
}
return new ValidEmail();
}
protected function parseRightFromAt(): Result
{
return $this->processIDRight();
}
protected function parseLeftFromAt(): Result
{
return $this->processIDLeft();
}
private function processIDRight() : Result
{
$localPartParser = new LocalPart($this->lexer);
$localPartResult = $localPartParser->parse();
$this->localPart = $localPartParser->localPart();
$this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings);
return $localPartResult;
}
private function processIDLeft() : Result
{
$domainPartParser = new IDLeftPart($this->lexer);
$domainPartResult = $domainPartParser->parse();
$this->domainPart = $domainPartParser->domainPart();
$this->warnings = array_merge($domainPartParser->getWarnings(), $this->warnings);
return $domainPartResult;
}
public function getLeftPart() : string
{
return $this->idLeft;
}
public function getRightPart() : string
{
return $this->idRight;
}
private function hasAtToken() : bool
{
$this->lexer->moveNext();
$this->lexer->moveNext();
if ($this->lexer->token['type'] === EmailLexer::S_AT) {
return false;
}
return true;
}
private function addLongEmailWarning(string $localPart, string $parsedDomainPart) : void
{
if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAILID_MAX_LENGTH) {
$this->warnings[EmailTooLong::CODE] = new EmailTooLong();
}
}
}
+1 -3
View File
@@ -234,7 +234,6 @@ class DomainPart extends Parser
*/
protected function parseDomainLiteral() : Result
{
try {
$this->lexer->find(EmailLexer::S_CLOSEBRACKET);
} catch (\RuntimeException $e) {
@@ -268,7 +267,7 @@ class DomainPart extends Parser
return $this->validateTokens($hasComments);
}
private function validateTokens(bool $hasComments) : Result
protected function validateTokens(bool $hasComments) : Result
{
$validDomainTokens = array(
EmailLexer::GENERIC => true,
@@ -288,7 +287,6 @@ class DomainPart extends Parser
return new ValidEmail();
}
private function checkLabelLength(bool $isEndOfDomain = false) : Result
{
if ($this->lexer->token['type'] === EmailLexer::S_DOT || $isEndOfDomain) {
+8 -9
View File
@@ -23,7 +23,10 @@ class FoldingWhiteSpace extends Parser
$previous = $this->lexer->getPrevious();
$this->checkCRLFInFWS();
$resultCRLF = $this->checkCRLFInFWS();
if ($resultCRLF->isInvalid()) {
return $resultCRLF;
}
if ($this->lexer->token['type'] === EmailLexer::S_CR) {
return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']);
@@ -46,10 +49,7 @@ class FoldingWhiteSpace extends Parser
return new ValidEmail();
}
/**
* @return InvalidEmail|ValidEmail|null
*/
protected function checkCRLFInFWS()
protected function checkCRLFInFWS() : Result
{
if ($this->lexer->token['type'] !== EmailLexer::CRLF) {
return new ValidEmail();
@@ -63,12 +63,11 @@ class FoldingWhiteSpace extends Parser
if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
return new InvalidEmail(new CRLFAtTheEnd(), $this->lexer->token['value']);
}
return new ValidEmail();
}
/**
* @return bool
*/
protected function isFWS()
protected function isFWS() : bool
{
if ($this->escaped()) {
return false;
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Result\ValidEmail;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\ExpectingATEXT;
class IDLeftPart extends DomainPart
{
protected function validateTokens(bool $hasComments) : Result
{
$invalidDomainTokens = array(
EmailLexer::S_DQUOTE => true,
EmailLexer::S_SQUOTE => true,
EmailLexer::S_BACKTICK => true,
EmailLexer::S_SEMICOLON => true,
EmailLexer::S_GREATERTHAN => true,
EmailLexer::S_LOWERTHAN => true,
);
if (isset($invalidDomainTokens[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']);
}
return new ValidEmail();
}
}
+21 -16
View File
@@ -20,20 +20,6 @@ class LocalPart extends Parser
*/
private $localPart = '';
/**
* Invalid lexer tokens for local part
* @var array
*/
private $invalidTokens = array(
EmailLexer::S_COMMA => EmailLexer::S_COMMA,
EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET,
EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET,
EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN,
EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN,
EmailLexer::S_COLON => EmailLexer::S_COLON,
EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON,
EmailLexer::INVALID => EmailLexer::INVALID
);
public function parse() : Result
{
@@ -78,8 +64,9 @@ class LocalPart extends Parser
return $resultEscaping;
}
if (isset($this->invalidTokens[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']);
$resultToken = $this->validateTokens(false);
if ($resultToken->isInvalid()) {
return $resultToken;
}
$resultFWS = $this->parseLocalFWS();
@@ -99,6 +86,24 @@ class LocalPart extends Parser
return new ValidEmail();
}
protected function validateTokens(bool $hasComments) : Result
{
$invalidTokens = array(
EmailLexer::S_COMMA => EmailLexer::S_COMMA,
EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET,
EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET,
EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN,
EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN,
EmailLexer::S_COLON => EmailLexer::S_COLON,
EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON,
EmailLexer::INVALID => EmailLexer::INVALID
);
if (isset($invalidTokens[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']);
}
return new ValidEmail();
}
public function localPart() : string
{
return $this->localPart;
+2 -5
View File
@@ -25,6 +25,8 @@ abstract class Parser
$this->lexer = $lexer;
}
abstract public function parse() : Result;
/**
* @return \Egulias\EmailValidator\Warning\Warning[]
*/
@@ -33,8 +35,6 @@ abstract class Parser
return $this->warnings;
}
abstract public function parse() : Result;
protected function parseFWS() : Result
{
$foldingWS = new FoldingWhiteSpace($this->lexer);
@@ -52,9 +52,6 @@ abstract class Parser
return new ValidEmail();
}
/**
* @return bool
*/
protected function escaped() : bool
{
$previous = $this->lexer->getPrevious();
+16
View File
@@ -3,12 +3,28 @@
namespace Egulias\EmailValidator\Validation;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\MessageIDParser;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\ExceptionFound;
class MessageIDValidation implements EmailValidation
{
public function isValid(string $email, EmailLexer $emailLexer): bool
{
$this->parser = new MessageIDParser($emailLexer);
try {
$result = $this->parser->parse($email);
$this->warnings = $this->parser->getWarnings();
if ($result->isInvalid()) {
/** @psalm-suppress PropertyTypeCoercion */
$this->error = $result;
return false;
}
} catch (\Exception $invalid) {
$this->error = new InvalidEmail(new ExceptionFound($invalid), '');
return false;
}
return true;
}