Add test for RedirectCondition request matching

This commit is contained in:
Alejandro Celaya 2024-02-25 19:21:39 +01:00
parent 202d0b86b3
commit 3f1b253c31
2 changed files with 80 additions and 9 deletions

View file

@ -9,17 +9,34 @@ use Shlinkio\Shlink\Core\RedirectRule\Model\RedirectConditionType;
use function explode; use function explode;
use function Shlinkio\Shlink\Core\ArrayUtils\some; use function Shlinkio\Shlink\Core\ArrayUtils\some;
use function Shlinkio\Shlink\Core\normalizeLocale; use function Shlinkio\Shlink\Core\normalizeLocale;
use function sprintf;
class RedirectCondition extends AbstractEntity class RedirectCondition extends AbstractEntity
{ {
public function __construct( private function __construct(
public readonly string $name, public readonly string $name,
public readonly RedirectConditionType $type, private readonly RedirectConditionType $type,
public readonly string $matchValue, public readonly string $matchValue,
public readonly ?string $matchKey = null, public readonly ?string $matchKey = null,
) { ) {
} }
public static function forQueryParam(string $param, string $value): self
{
$type = RedirectConditionType::QUERY_PARAM;
$name = sprintf('%s-%s-%s', $type->value, $param, $value);
return new self($name, $type, $value, $param);
}
public static function forLanguage(string $language): self
{
$type = RedirectConditionType::LANGUAGE;
$name = sprintf('%s-%s', $type->value, $language);
return new self($name, $type, $language);
}
/** /**
* Tells if this condition matches provided request * Tells if this condition matches provided request
*/ */
@ -28,23 +45,18 @@ class RedirectCondition extends AbstractEntity
return match ($this->type) { return match ($this->type) {
RedirectConditionType::QUERY_PARAM => $this->matchesQueryParam($request), RedirectConditionType::QUERY_PARAM => $this->matchesQueryParam($request),
RedirectConditionType::LANGUAGE => $this->matchesLanguage($request), RedirectConditionType::LANGUAGE => $this->matchesLanguage($request),
default => false,
}; };
} }
public function matchesQueryParam(ServerRequestInterface $request): bool private function matchesQueryParam(ServerRequestInterface $request): bool
{ {
if ($this->matchKey !== null) {
return false;
}
$query = $request->getQueryParams(); $query = $request->getQueryParams();
$queryValue = $query[$this->matchKey] ?? null; $queryValue = $query[$this->matchKey] ?? null;
return $queryValue === $this->matchValue; return $queryValue === $this->matchValue;
} }
public function matchesLanguage(ServerRequestInterface $request): bool private function matchesLanguage(ServerRequestInterface $request): bool
{ {
$acceptLanguage = $request->getHeaderLine('Accept-Language'); $acceptLanguage = $request->getHeaderLine('Accept-Language');
if ($acceptLanguage === '' || $acceptLanguage === '*') { if ($acceptLanguage === '' || $acceptLanguage === '*') {

View file

@ -0,0 +1,59 @@
<?php
namespace RedirectRule\Entity;
use Laminas\Diactoros\ServerRequestFactory;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\RedirectRule\Entity\RedirectCondition;
class RedirectConditionTest extends TestCase
{
#[Test]
#[TestWith(['nop', '', false])] // param not present
#[TestWith(['foo', 'not-bar', false])] // param present with wrong value
#[TestWith(['foo', 'bar', true])] // param present with correct value
public function matchesQueryParams(string $param, string $value, bool $expectedResult): void
{
$request = ServerRequestFactory::fromGlobals()->withQueryParams(['foo' => 'bar']);
$result = RedirectCondition::forQueryParam($param, $value)->matchesRequest($request);
self::assertEquals($expectedResult, $result);
}
#[Test]
#[TestWith([null, '', false])] // no accept language
#[TestWith(['', '', false])] // empty accept language
#[TestWith(['*', '', false])] // wildcard accept language
#[TestWith(['en', 'en', true])] // single language match
#[TestWith(['es, en,fr', 'en', true])] // multiple languages match
#[TestWith(['es_ES', 'es-ES', true])] // single locale match
#[TestWith(['en-UK', 'en-uk', true])] // different casing match
public function matchesLanguage(?string $acceptLanguage, string $value, bool $expected): void
{
$request = ServerRequestFactory::fromGlobals();
if ($acceptLanguage !== null) {
$request = $request->withHeader('Accept-Language', $acceptLanguage);
}
$result = RedirectCondition::forLanguage($value)->matchesRequest($request);
self::assertEquals($expected, $result);
}
#[Test, DataProvider('provideNames')]
public function generatesExpectedName(RedirectCondition $condition, string $expectedName): void
{
self::assertEquals($expectedName, $condition->name);
}
public static function provideNames(): iterable
{
yield [RedirectCondition::forLanguage('es-ES'), 'language-es-ES'];
yield [RedirectCondition::forLanguage('en_UK'), 'language-en_UK'];
yield [RedirectCondition::forQueryParam('foo', 'bar'), 'query-foo-bar'];
yield [RedirectCondition::forQueryParam('baz', 'foo'), 'query-baz-foo'];
}
}