Skip to content

Commit

Permalink
Write unhappy tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bigfoot90 committed Mar 25, 2024
1 parent 1a7fa0e commit ab3cd8b
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 24 deletions.
81 changes: 57 additions & 24 deletions src/Types/EnumType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Types\Exception\InvalidFormat;
use Doctrine\DBAL\Types\Exception\InvalidType;
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
use ReflectionClass;
use StringBackedEnum;

Check failure on line 16 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Type StringBackedEnum is not used in this file.
use Throwable;
use UnitEnum;
use ValueError;

use function array_map;
use function class_exists;
use function enum_exists;
use function implode;
use function is_object;
use function is_string;
use function sprintf;

Expand Down Expand Up @@ -69,14 +71,34 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str
return null;
}

if ($value instanceof UnitEnum) {
if ($value instanceof BackedEnum) {
if ($this->enumClassname === null) {
if (! is_string($value)) {
throw InvalidType::new($value, $this->name, ['null', 'string']);
}

if (! in_array($value, $this->members)) {

Check failure on line 79 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Call to function in_array() requires parameter #3 to be set.

Check failure on line 79 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Function in_array() should not be referenced via a fallback global name, but via a use statement.
throw InvalidType::new($value, $this->name, ['null', 'string']);
}

return $value;
}

if (enum_exists($this->enumClassname)) {
if (! $value instanceof UnitEnum) {
throw InvalidType::new($value, $this->name, ['null', $this->enumClassname]);
}

if ($value instanceof \BackedEnum) {

Check failure on line 91 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Class \BackedEnum should not be referenced via a fully qualified name, but via a use statement.
return $value->value;

Check failure on line 92 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

InvalidReturnStatement

src/Types/EnumType.php:92:24: InvalidReturnStatement: The inferred type 'int|string' does not match the declared return type 'null|string' for Doctrine\DBAL\Types\EnumType::convertToDatabaseValue (see https://psalm.dev/128)

Check failure on line 92 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Method Doctrine\DBAL\Types\EnumType::convertToDatabaseValue() should return string|null but returns int|string.
}

return $value->name;
}

if (! (is_object($value) && $value::class === $this->enumClassname)) {
throw InvalidType::new($value, $this->name, ['null', $this->enumClassname]);
}

return (string) $value;

Check failure on line 102 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Cannot cast object to string.
}

Expand All @@ -87,35 +109,46 @@ public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mix
}

if (! is_string($value)) {
throw InvalidType::new($value, $this->name, ['null', 'string']);
throw InvalidFormat::new($value, $this->name, ['null', 'string']);

Check failure on line 112 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

InvalidArgument

src/Types/EnumType.php:112:59: InvalidArgument: Argument 3 of Doctrine\DBAL\Types\Exception\InvalidFormat::new expects null|string, but list{'null', 'string'} provided (see https://psalm.dev/004)

Check failure on line 112 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Parameter #1 $value of static method Doctrine\DBAL\Types\Exception\InvalidFormat::new() expects string, mixed given.

Check failure on line 112 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Parameter #3 $expectedFormat of static method Doctrine\DBAL\Types\Exception\InvalidFormat::new() expects string|null, array<int, string> given.
}

if ($this->enumClassname) {
if (enum_exists($this->enumClassname)) {
try {
foreach ($this->enumClassname::cases() as $case) {
if (($case instanceof BackedEnum && $value === $case->value) || $value === $case->name) {
return $case;
}
}

throw new ValueError(sprintf("'%s' is not a valid backing value for enum %s", $value, $this->enumClassname));
} catch (Throwable $e) {
throw ValueNotConvertible::new($value, $this->name, $e->getMessage(), $e);
}
if ($this->enumClassname === null) {
if (! in_array($value, $this->members)) {

Check failure on line 116 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Call to function in_array() requires parameter #3 to be set.

Check failure on line 116 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Function in_array() should not be referenced via a fallback global name, but via a use statement.
throw ValueNotConvertible::new($value, $this->name);
}

if (class_exists($this->enumClassname)) {
$refl = new ReflectionClass($this->enumClassname);
return $value;
}

try {
return $refl->newInstance($value);
} catch (Throwable $e) {
throw ValueNotConvertible::new($value, $this->name, $e->getMessage(), $e);
if (enum_exists($this->enumClassname)) {
foreach ($this->enumClassname::cases() as $case) {
if (($case instanceof BackedEnum && $value === $case->value) || $value === $case->name) {
return $case;
}
}

throw ValueNotConvertible::new($value, $this->getInternalDocrineType());
}

if (class_exists($this->enumClassname)) {
$refl = new ReflectionClass($this->enumClassname);

try {
return $refl->newInstance($value);
} catch (Throwable $e) {
throw ValueNotConvertible::new($value, $this->getInternalDocrineType(), $e->getMessage(), $e);
}
}

throw new ConversionException(sprintf('Class %s does not exists', $this->enumClassname));
}

private function getInternalDocrineType(): string
{
if ($this->enumClassname) {

Check failure on line 148 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

RiskyTruthyFalsyComparison

src/Types/EnumType.php:148:13: RiskyTruthyFalsyComparison: Operand of type null|string contains type string, which can be falsy and truthy. This can cause possibly unexpected behavior. Use strict comparison instead. (see https://psalm.dev/356)

Check failure on line 148 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Only booleans are allowed in an if condition, string|null given.
return sprintf('%s(%s)', $this->name, $this->enumClassname);
}

return $value;
return sprintf('%s(%s)', $this->name, 'string');
}
}
114 changes: 114 additions & 0 deletions tests/Types/EnumTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Doctrine\DBAL\Tests\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\EnumType;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Stringable;
Expand Down Expand Up @@ -62,6 +64,8 @@ public function testConvertToPHPObject(): void

public function testConvertStringToDatabaseValue(): void
{
$this->type->members = ['a', 'b'];

self::assertSame('a', $this->type->convertToDatabaseValue('a', $this->platform));
self::assertNull($this->type->convertToDatabaseValue(null, $this->platform));
}
Expand Down Expand Up @@ -89,6 +93,107 @@ public function testConvertObjectToDatabaseValue(): void
self::assertSame('a', $this->type->convertToDatabaseValue(new EnumClass('a'), $this->platform));
self::assertNull($this->type->convertToDatabaseValue(null, $this->platform));
}

#[DataProvider('provideInvalidDataForEnumStringToDatabaseValueConversion')]

Check failure on line 97 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Method Doctrine\DBAL\Tests\Types\EnumTest::testEnumStringDoesNotSupportInvalidValuesToDatabaseValueConversion() has parameter $value with no type specified.
public function testEnumStringDoesNotSupportInvalidValuesToDatabaseValueConversion($value): void

Check failure on line 98 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

MissingParamType

tests/Types/EnumTest.php:98:88: MissingParamType: Parameter $value has no provided type (see https://psalm.dev/154)

Check failure on line 98 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Method \Doctrine\DBAL\Tests\Types\EnumTest::testEnumStringDoesNotSupportInvalidValuesToDatabaseValueConversion() does not have parameter type hint nor @param annotation for its parameter $value.
{
$this->expectException(ConversionException::class);

$this->type->convertToDatabaseValue($value, $this->platform);
}

public static function provideInvalidDataForEnumStringToDatabaseValueConversion()

Check failure on line 105 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

MissingReturnType

tests/Types/EnumTest.php:105:28: MissingReturnType: Method Doctrine\DBAL\Tests\Types\EnumTest::provideInvalidDataForEnumStringToDatabaseValueConversion does not have a return type, expecting array{'boolean false': list{false}, 'boolean true': list{true}, 'enum backed': list{enum(Doctrine\DBAL\Tests\Types\EnumPhpBacked::A)}, array: list{list{''}}, enum: list{enum(Doctrine\DBAL\Tests\Types\EnumPhp::A)}, integer: list{17}, object: list{stdClass}, string: list{'not_in_members'}, stringable: list{_home_runner_work_dbal_dbal_tests_Types_EnumTest_php_116_4388}} (see https://psalm.dev/050)

Check failure on line 105 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Method Doctrine\DBAL\Tests\Types\EnumTest::provideInvalidDataForEnumStringToDatabaseValueConversion() has no return type specified.

Check failure on line 105 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Method \Doctrine\DBAL\Tests\Types\EnumTest::provideInvalidDataForEnumStringToDatabaseValueConversion() does not have return type hint nor @return annotation for its return value.
{
return [
'boolean true' => [true],
'boolean false' => [false],
'integer' => [17],
'string' => ['not_in_members'],
'array' => [['']],
'enum' => [EnumPhp::A],
'enum backed' => [EnumPhpBacked::A],
'object' => [new \stdClass()],

Check failure on line 115 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Class \stdClass should not be referenced via a fully qualified name, but via a use statement.
'stringable' => [new class() { function __toString() { return 'a'; }}],

Check failure on line 116 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Expected 1 space after class keyword; 0 found

Check failure on line 116 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

There must be exactly 0 empty lines after class opening brace.
];
}

#[DataProvider('provideInvalidDataForEnumPhpToDatabaseValueConversion')]
public function testEnumPhpDoesNotSupportInvalidValuesToDatabaseValueConversion($value): void

Check failure on line 121 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

MissingParamType

tests/Types/EnumTest.php:121:85: MissingParamType: Parameter $value has no provided type (see https://psalm.dev/154)
{
$this->expectException(ConversionException::class);

$this->type->convertToDatabaseValue($value, $this->platform);
}

public static function provideInvalidDataForEnumPhpToDatabaseValueConversion()

Check failure on line 128 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

MissingReturnType

tests/Types/EnumTest.php:128:28: MissingReturnType: Method Doctrine\DBAL\Tests\Types\EnumTest::provideInvalidDataForEnumPhpToDatabaseValueConversion does not have a return type, expecting array{'boolean false': list{false}, 'boolean true': list{true}, 'enum backed': list{enum(Doctrine\DBAL\Tests\Types\EnumPhpBacked::A)}, array: list{list{''}}, enum: list{enum(Doctrine\DBAL\Tests\Types\WrongEnumPhp::WRONG)}, integer: list{17}, object: list{stdClass}, string: list{'a'}, stringable: list{_home_runner_work_dbal_dbal_tests_Types_EnumTest_php_139_5223}} (see https://psalm.dev/050)
{
return [
'boolean true' => [true],
'boolean false' => [false],
'integer' => [17],
'string' => ['a'],
'array' => [['']],
'enum' => [WrongEnumPhp::WRONG],
'enum backed' => [EnumPhpBacked::A],
'object' => [new \stdClass()],
'stringable' => [new class() { function __toString() { return 'a'; }}],
];
}

#[DataProvider('provideInvalidDataForEnumPhpBackedToDatabaseValueConversion')]
public function testEnumPhpBackedDoesNotSupportInvalidValuesToDatabaseValueConversion($value): void

Check failure on line 144 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

MissingParamType

tests/Types/EnumTest.php:144:91: MissingParamType: Parameter $value has no provided type (see https://psalm.dev/154)
{
$this->expectException(ConversionException::class);

$this->type->convertToDatabaseValue($value, $this->platform);
}

public static function provideInvalidDataForEnumPhpBackedToDatabaseValueConversion()

Check failure on line 151 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

MissingReturnType

tests/Types/EnumTest.php:151:28: MissingReturnType: Method Doctrine\DBAL\Tests\Types\EnumTest::provideInvalidDataForEnumPhpBackedToDatabaseValueConversion does not have a return type, expecting array{'boolean false': list{false}, 'boolean true': list{true}, 'enum backed': list{enum(Doctrine\DBAL\Tests\Types\WrongEnumPhpBacked::WRONG)}, array: list{list{''}}, enum: list{enum(Doctrine\DBAL\Tests\Types\EnumPhp::A)}, integer: list{17}, object: list{stdClass}, string: list{'a'}, stringable: list{_home_runner_work_dbal_dbal_tests_Types_EnumTest_php_162_6076}} (see https://psalm.dev/050)
{
return [
'boolean true' => [true],
'boolean false' => [false],
'integer' => [17],
'string' => ['a'],
'array' => [['']],
'enum' => [EnumPhp::A],
'enum backed' => [WrongEnumPhpBacked::WRONG],
'object' => [new \stdClass()],
'stringable' => [new class() { function __toString() { return 'a'; }}],
];
}

#[DataProvider('provideInvalidDataForEnumObjectToDatabaseValueConversion')]
public function testEnumObjectDoesNotSupportInvalidValuesToDatabaseValueConversion($value): void

Check failure on line 167 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

MissingParamType

tests/Types/EnumTest.php:167:88: MissingParamType: Parameter $value has no provided type (see https://psalm.dev/154)
{
$this->expectException(ConversionException::class);

$this->type->convertToDatabaseValue($value, $this->platform);
}

public static function provideInvalidDataForEnumObjectToDatabaseValueConversion()
{
return [
'boolean true' => [true],
'boolean false' => [false],
'integer' => [17],
'string' => ['a'],
'array' => [['']],
'enum' => [EnumPhp::A],
'enum backed' => [EnumPhpBacked::A],
'object' => [new \stdClass()],
'stringable' => [new class() { function __toString() { return 'a'; }}],
];
}

public function testInvalidValueForDatabaseValueToEnumStringConversion(): void
{
$this->type->members = ['a', 'b'];

$this->expectException(ConversionException::class);

$this->type->convertToPHPValue('not_in_members', $this->platform);
}
}

enum EnumPhp
Expand All @@ -97,13 +202,22 @@ enum EnumPhp
case B;
}

enum WrongEnumPhp
{
case WRONG;
}

enum EnumPhpBacked: string
{
case A = 'a';
case B = 'b';
}

enum WrongEnumPhpBacked: string
{
case WRONG = 'wrong';
}

final class EnumClass implements Stringable
{
public function __construct(
Expand Down

0 comments on commit ab3cd8b

Please sign in to comment.