add tests
All checks were successful
/ ls (push) Successful in 20s

This commit is contained in:
lubiana 2024-06-02 11:20:20 +02:00
parent 13bfbbe528
commit eb40f1df49
Signed by: lubiana
SSH key fingerprint: SHA256:gkqM8DUX4Blf6P52fycW8ISTd+4eAHH+Uzu9iyc8hAM
10 changed files with 388 additions and 44 deletions

View file

@ -24,7 +24,8 @@
"phpstan/phpstan": "^1.11", "phpstan/phpstan": "^1.11",
"phpstan/phpstan-strict-rules": "^1.6", "phpstan/phpstan-strict-rules": "^1.6",
"phpstan/extension-installer": "^1.3", "phpstan/extension-installer": "^1.3",
"pestphp/pest": "^2.34" "pestphp/pest": "^2.34",
"mockery/mockery": "^1.6"
}, },
"config": { "config": {
"allow-plugins": { "allow-plugins": {

136
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "e57b9ac60bbc4cb4066c8cefa8d6d1c4", "content-hash": "04633c6e5d6a281e4f5cf33a8246d0d3",
"packages": [ "packages": [
{ {
"name": "doctrine/collections", "name": "doctrine/collections",
@ -2097,6 +2097,57 @@
], ],
"time": "2023-11-03T12:00:00+00:00" "time": "2023-11-03T12:00:00+00:00"
}, },
{
"name": "hamcrest/hamcrest-php",
"version": "v2.0.1",
"source": {
"type": "git",
"url": "https://github.com/hamcrest/hamcrest-php.git",
"reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3",
"reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3",
"shasum": ""
},
"require": {
"php": "^5.3|^7.0|^8.0"
},
"replace": {
"cordoval/hamcrest-php": "*",
"davedevelopment/hamcrest-php": "*",
"kodova/hamcrest-php": "*"
},
"require-dev": {
"phpunit/php-file-iterator": "^1.4 || ^2.0",
"phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
}
},
"autoload": {
"classmap": [
"hamcrest"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "This is the PHP port of Hamcrest Matchers",
"keywords": [
"test"
],
"support": {
"issues": "https://github.com/hamcrest/hamcrest-php/issues",
"source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1"
},
"time": "2020-07-09T08:09:16+00:00"
},
{ {
"name": "jean85/pretty-package-versions", "name": "jean85/pretty-package-versions",
"version": "2.0.6", "version": "2.0.6",
@ -2185,6 +2236,89 @@
], ],
"time": "2024-05-04T18:26:43+00:00" "time": "2024-05-04T18:26:43+00:00"
}, },
{
"name": "mockery/mockery",
"version": "1.6.12",
"source": {
"type": "git",
"url": "https://github.com/mockery/mockery.git",
"reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699",
"reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699",
"shasum": ""
},
"require": {
"hamcrest/hamcrest-php": "^2.0.1",
"lib-pcre": ">=7.0",
"php": ">=7.3"
},
"conflict": {
"phpunit/phpunit": "<8.0"
},
"require-dev": {
"phpunit/phpunit": "^8.5 || ^9.6.17",
"symplify/easy-coding-standard": "^12.1.14"
},
"type": "library",
"autoload": {
"files": [
"library/helpers.php",
"library/Mockery.php"
],
"psr-4": {
"Mockery\\": "library/Mockery"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Pádraic Brady",
"email": "padraic.brady@gmail.com",
"homepage": "https://github.com/padraic",
"role": "Author"
},
{
"name": "Dave Marshall",
"email": "dave.marshall@atstsolutions.co.uk",
"homepage": "https://davedevelopment.co.uk",
"role": "Developer"
},
{
"name": "Nathanael Esayeas",
"email": "nathanael.esayeas@protonmail.com",
"homepage": "https://github.com/ghostwriter",
"role": "Lead Developer"
}
],
"description": "Mockery is a simple yet flexible PHP mock object framework",
"homepage": "https://github.com/mockery/mockery",
"keywords": [
"BDD",
"TDD",
"library",
"mock",
"mock objects",
"mockery",
"stub",
"test",
"test double",
"testing"
],
"support": {
"docs": "https://docs.mockery.io/",
"issues": "https://github.com/mockery/mockery/issues",
"rss": "https://github.com/mockery/mockery/releases.atom",
"security": "https://github.com/mockery/mockery/security/advisories",
"source": "https://github.com/mockery/mockery"
},
"time": "2024-05-16T03:13:13+00:00"
},
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
"version": "1.11.1", "version": "1.11.1",

View file

@ -4,18 +4,23 @@ namespace Lubiana\DoctrineUlid\IdGenerator;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Id\AbstractIdGenerator; use Doctrine\ORM\Id\AbstractIdGenerator;
use Override;
use Symfony\Component\Uid\Factory\UlidFactory; use Symfony\Component\Uid\Factory\UlidFactory;
use Symfony\Component\Uid\Ulid; use Symfony\Component\Uid\Ulid;
final class UlidGenerator extends AbstractIdGenerator final class UlidGenerator extends AbstractIdGenerator
{ {
public function __construct( private readonly ?UlidFactory $factory = null ){} public function __construct(
public function generateId(EntityManagerInterface $em, ?object $entity): mixed private readonly UlidFactory|null $factory = null
) {}
#[Override]
public function generateId(EntityManagerInterface $em, object|null $entity): mixed
{ {
if ($this->factory !== null) { if ($this->factory instanceof UlidFactory) {
return $this->factory->create(); return $this->factory->create();
} }
return new Ulid(); return new Ulid;
} }
} }

View file

@ -6,17 +6,21 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Exception\InvalidType; use Doctrine\DBAL\Types\Exception\InvalidType;
use Doctrine\DBAL\Types\Exception\ValueNotConvertible; use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use InvalidArgumentException;
use Override;
use Symfony\Component\Uid\Ulid; use Symfony\Component\Uid\Ulid;
use function is_string;
final class UlidType extends Type final class UlidType extends Type
{ {
public const NAME = 'ulid'; public const NAME = 'ulid';
/** #[Override]
* @inheritDoc public function getSQLDeclaration(
*/ array $column,
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string AbstractPlatform $platform,
{ ): string {
if ($this->hasNativeGuidType($platform)) { if ($this->hasNativeGuidType($platform)) {
return $platform->getGuidTypeDeclarationSQL($column); return $platform->getGuidTypeDeclarationSQL($column);
} }
@ -27,26 +31,35 @@ final class UlidType extends Type
]); ]);
} }
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?Ulid #[Override]
{ public function convertToPHPValue(
mixed $value,
AbstractPlatform $platform,
): Ulid|null {
if ($value instanceof Ulid || $value === null) { if ($value instanceof Ulid || $value === null) {
return $value; return $value;
} }
if (!is_string($value)) {
if (! is_string($value)) {
throw InvalidType::new($value, self::NAME, ['null', 'string', self::class]); throw InvalidType::new($value, self::NAME, ['null', 'string', self::class]);
} }
try { try {
return Ulid::fromString($value); return Ulid::fromString($value);
} catch (\InvalidArgumentException $e) { } catch (InvalidArgumentException $e) {
throw ValueNotConvertible::new($value, self::NAME, null, $e); throw ValueNotConvertible::new($value, self::NAME, null, $e);
} }
} }
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string #[Override]
{ public function convertToDatabaseValue(
$toStringFunc = fn (Ulid $v) => $v->toRfc4122(); mixed $value,
if (!$this->hasNativeGuidType($platform)) { AbstractPlatform $platform,
$toStringFunc = fn (Ulid $v) => $v->toBinary(); ): string|null {
$toStringFunc = static fn(Ulid $v): string => $v->toRfc4122();
if (! $this->hasNativeGuidType($platform)) {
$toStringFunc = static fn(Ulid $v): string => $v->toBinary();
} }
if ($value instanceof Ulid) { if ($value instanceof Ulid) {
@ -57,18 +70,32 @@ final class UlidType extends Type
return null; return null;
} }
if (!\is_string($value)) { if (! is_string($value)) {
throw InvalidType::new($value, self::NAME, ['null', 'string', self::class]); throw InvalidType::new($value, self::NAME, ['null', 'string', self::class]);
} }
try { try {
return $toStringFunc(Ulid::fromString($value)); return $toStringFunc(Ulid::fromString($value));
} catch (\InvalidArgumentException $e) { } catch (InvalidArgumentException $e) {
throw ValueNotConvertible::new($value, self::NAME, null, $e); throw ValueNotConvertible::new($value, self::NAME, null, $e);
} }
} }
private function hasNativeGuidType(AbstractPlatform $platform): bool private function hasNativeGuidType(AbstractPlatform $platform): bool
{ {
return $platform->getGuidTypeDeclarationSQL([]) !== $platform->getStringTypeDeclarationSQL(['fixed' => true, 'length' => 36]); return $platform->getGuidTypeDeclarationSQL([]) !== $platform->getStringTypeDeclarationSQL([
'fixed' => true,
'length' => 36,
]);
}
public static function register(): void
{
if (Type::hasType(self::NAME)) {
Type::overrideType(self::NAME, self::class);
return;
}
Type::addType(self::NAME, self::class);
} }
} }

View file

@ -1,8 +0,0 @@
<?php declare(strict_types=1);
test(
'example',
function (): void {
expect(true)->toBeTrue();
},
);

View file

@ -1,5 +1,6 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
use Mockery\MockInterface;
use Tests\TestCase; use Tests\TestCase;
/* /*
@ -24,7 +25,12 @@ uses(TestCase::class)->in('Feature', 'Unit');
| global functions to help you to reduce the number of lines of code in your test files. | global functions to help you to reduce the number of lines of code in your test files.
| |
*/ */
function something(): void /**
* @template T of object
* @param class-string<T> $className
* @return MockInterface&T
*/
function createMock(string $className): MockInterface
{ {
// .. return Mockery::mock($className);
} }

View file

@ -2,9 +2,15 @@
namespace Tests; namespace Tests;
use Lubiana\DoctrineUlid\Types\UlidType;
use Override;
use PHPUnit\Framework\TestCase as BaseTestCase; use PHPUnit\Framework\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase abstract class TestCase extends BaseTestCase
{ {
// #[Override]
protected function setUp(): void
{
UlidType::register();
}
} }

View file

@ -1,8 +0,0 @@
<?php declare(strict_types=1);
test(
'example',
function (): void {
expect(true)->toBeTrue();
},
);

View file

@ -0,0 +1,33 @@
<?php declare(strict_types=1);
use Doctrine\ORM\EntityManager;
use Lubiana\DoctrineUlid\IdGenerator\UlidGenerator;
use Symfony\Component\Uid\Factory\UlidFactory;
use Symfony\Component\Uid\Ulid;
test(
'UlidGenerator constructs without factory and generate Id',
function (): void {
$ulidGenerator = new UlidGenerator;
$em = createMock(EntityManager::class);
$id = $ulidGenerator->generateId($em, null);
expect($id)
->toBeInstanceOf(Ulid::class);
},
);
test(
'UlidGenerator constructs with factory and generate Id',
function (): void {
$factory = Mockery::mock(UlidFactory::class);
$ulid = new Ulid;
$factory->shouldReceive('create')
->andReturn($ulid)
->once();
$ulidGenerator = new UlidGenerator($factory);
$em = Mockery::mock(EntityManager::class);
$id = $ulidGenerator->generateId($em, null);
expect($id)
->toBe($ulid);
},
);

148
tests/Unit/UlidTypeTest.php Normal file
View file

@ -0,0 +1,148 @@
<?php declare(strict_types=1);
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Types\Exception\InvalidType;
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
use Doctrine\DBAL\Types\Type;
use Lubiana\DoctrineUlid\Types\UlidType;
use Symfony\Component\Uid\Ulid;
it(
'returns correct sql declaration on postgresql',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new PostgreSQLPlatform;
// If platform supports guid type, declaration is guid type.
$declaration = $ulidType->getSQLDeclaration([], $platform);
expect($declaration)
->toBe('UUID');
},
);
it(
'returns correct sql declaration on sqlite',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SqlitePlatform;
// If platform supports guid type, declaration is guid type.
$declaration = $ulidType->getSQLDeclaration([], $platform);
expect($declaration)
->toBe('BLOB');
},
);
it(
'can convert string to a Ulid object',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SQLitePlatform;
$stringUlid = '01FGRM9X8ACP5D6HZG9K31D6CZ';
$phpValue = $ulidType->convertToPHPValue($stringUlid, $platform);
expect(
$phpValue,
)->toBeInstanceOf(Ulid::class)->and((string) $phpValue)->toBe($stringUlid);
},
);
it(
'throws if value is not string during conversion to PHP Value',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SQLitePlatform;
$nonStringValue = 123;
expect(
static fn(): mixed
=> $ulidType->convertToPHPValue($nonStringValue, $platform),
)->toThrow(
InvalidType::class,
);
},
);
it(
'throws if value is not a valid Ulid string during conversion to PHP Value',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SQLitePlatform;
$invalidUlidString = 'invalid-ulid-string';
expect(
static fn(): mixed
=> $ulidType->convertToPHPValue($invalidUlidString, $platform),
)->toThrow(
ValueNotConvertible::class,
);
},
);
it(
'can convert Ulid object to database value',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SQLitePlatform;
$ulidObject = new Ulid;
$databaseValue = $ulidType->convertToDatabaseValue($ulidObject, $platform);
expect($databaseValue)
->toBe($ulidObject->toBinary());
},
);
it(
'can convert Ulid string to a database value',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SQLitePlatform;
$ulidObject = new Ulid;
$ulidBinary = $ulidObject->toBinary();
$databaseValue = $ulidType->convertToDatabaseValue(
(string) $ulidObject,
$platform,
);
expect($databaseValue)
->toBe($ulidBinary);
},
);
it(
'will return null when value is null',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SQLitePlatform;
$nullValue = null;
$databaseValue = $ulidType->convertToDatabaseValue($nullValue, $platform);
expect($databaseValue)
->toBe(null);
},
);
it(
'throws if value is not string during conversion to Database Value',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SQLitePlatform;
$nonStringValue = 123;
expect(
static fn(): mixed
=> $ulidType->convertToDatabaseValue($nonStringValue, $platform),
)->toThrow(
InvalidType::class,
);
},
);
it(
'throws if value is not a valid Ulid string during conversion to Database Value',
function (): void {
$ulidType = Type::getType(UlidType::NAME);
$platform = new SQLitePlatform;
$invalidUlidString = 'invalid-ulid-string';
expect(
static fn(): mixed
=> $ulidType->convertToDatabaseValue($invalidUlidString, $platform),
)->toThrow(
ValueNotConvertible::class,
);
},
);