convertToDatabaseValueWithCastingMethodProperlyCastsIt()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Acelaya\Test\Doctrine\Type;
6
7
use Acelaya\Doctrine\Exception\InvalidArgumentException;
8
use Acelaya\Doctrine\Type\PhpEnumType;
9
use Acelaya\Test\Doctrine\Enum\Action;
10
use Acelaya\Test\Doctrine\Enum\Gender;
11
use Acelaya\Test\Doctrine\Enum\WithCastingMethods;
12
use Acelaya\Test\Doctrine\Enum\WithIntegerValues;
13
use Doctrine\DBAL\Platforms\AbstractPlatform;
14
use Doctrine\DBAL\Types\Type;
15
use MyCLabs\Enum\Enum;
16
use PHPUnit\Framework\TestCase;
17
use Prophecy\Argument;
18
use Prophecy\Prophecy\ObjectProphecy;
19
use ReflectionObject;
20
use stdClass;
21
22
use function implode;
23
use function sprintf;
24
25
class PhpEnumTypeTest extends TestCase
26
{
27
    /** @var ObjectProphecy */
28
    protected $platform;
29
30
    public function setUp(): void
31
    {
32
        $this->platform = $this->prophesize(AbstractPlatform::class);
33
34
        // Before every test, clean registered types
35
        $typeRegistry = Type::getTypeRegistry();
36
        $ref = new ReflectionObject($typeRegistry);
37
        $instancesProp = $ref->getProperty('instances');
38
        $instancesProp->setAccessible(true);
39
        $instancesProp->setValue($typeRegistry, []);
40
    }
41
42
    /**
43
     * @test
44
     */
45
    public function enumTypesAreProperlyRegistered(): void
46
    {
47
        $this->assertFalse(Type::hasType(Action::class));
48
        $this->assertFalse(Type::hasType('gender'));
49
50
        PhpEnumType::registerEnumType(Action::class);
51
        PhpEnumType::registerEnumTypes([
52
            'gender' => Gender::class,
53
        ]);
54
55
        $this->assertTrue(Type::hasType(Action::class));
56
        $this->assertTrue(Type::hasType('gender'));
57
    }
58
59
    /**
60
     * @test
61
     */
62
    public function enumTypesAreProperlyCustomizedWhenRegistered(): void
63
    {
64
        $this->assertFalse(Type::hasType(Action::class));
65
        $this->assertFalse(Type::hasType(Gender::class));
66
67
        PhpEnumType::registerEnumTypes([
68
            'gender' => Gender::class,
69
            Action::class,
70
        ]);
71
72
        /** @var Type $actionType */
73
        $actionType = Type::getType(Action::class);
74
        $this->assertInstanceOf(PhpEnumType::class, $actionType);
75
        $this->assertEquals(Action::class, $actionType->getName());
76
77
        /** @var Type $actionType */
78
        $genderType = Type::getType('gender');
79
        $this->assertInstanceOf(PhpEnumType::class, $genderType);
80
        $this->assertEquals('gender', $genderType->getName());
81
    }
82
83
    /**
84
     * @test
85
     */
86
    public function registerInvalidEnumThrowsException(): void
87
    {
88
        $this->expectException(InvalidArgumentException::class);
89
        $this->expectExceptionMessage(sprintf(
90
            'Provided enum class "%s" is not valid. Enums must extend "%s"',
91
            stdClass::class,
92
            Enum::class
93
        ));
94
        PhpEnumType::registerEnumType(stdClass::class);
95
    }
96
97
    /**
98
     * @test
99
     */
100
    public function getSQLDeclarationReturnsValueFromPlatform(): void
101
    {
102
        $this->platform->getVarcharTypeDeclarationSQL(Argument::cetera())->willReturn('declaration');
103
104
        $type = $this->getType(Gender::class);
105
106
        $this->assertEquals('declaration', $type->getSQLDeclaration([], $this->platform->reveal()));
107
    }
108
109
    /**
110
     * @test
111
     * @dataProvider provideValues
112
     * @param string $typeName
113
     * @param $phpValue
114
     * @param string $expectedValue
115
     */
116
    public function convertToDatabaseValueParsesEnum(string $typeName, $phpValue, string $expectedValue): void
117
    {
118
        $type = $this->getType($typeName);
119
120
        $actualValue = $type->convertToDatabaseValue($phpValue, $this->platform->reveal());
121
122
        $this->assertEquals($expectedValue, $actualValue);
123
    }
124
125
    public function provideValues(): iterable
126
    {
127
        yield [Action::class, Action::CREATE(), Action::CREATE];
128
        yield [Action::class, Action::READ(), Action::READ];
129
        yield [Action::class, Action::UPDATE(), Action::UPDATE];
130
        yield [Action::class, Action::DELETE(), Action::DELETE];
131
        yield [Gender::class, Gender::FEMALE(), Gender::FEMALE];
132
        yield [Gender::class, Gender::MALE(), Gender::MALE];
133
    }
134
135
    /**
136
     * @test
137
     */
138
    public function convertToDatabaseValueReturnsNullWhenNullIsProvided(): void
139
    {
140
        $type = $this->getType(Action::class);
141
142
        $this->assertNull($type->convertToDatabaseValue(null, $this->platform->reveal()));
0 ignored issues
show
Bug introduced by
Are you sure the usage of $type->convertToDatabase...is->platform->reveal()) targeting Acelaya\Doctrine\Type\Ph...onvertToDatabaseValue() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
143
    }
144
145
    /**
146
     * @test
147
     */
148
    public function convertToPHPValueWithValidValueReturnsParsedData(): void
149
    {
150
        $type = $this->getType(Action::class);
151
152
        /** @var Action $value */
153
        $value = $type->convertToPHPValue(Action::CREATE, $this->platform->reveal());
154
        $this->assertInstanceOf(Action::class, $value);
155
        $this->assertEquals(Action::CREATE, $value->getValue());
156
157
        $value = $type->convertToPHPValue(Action::DELETE, $this->platform->reveal());
158
        $this->assertInstanceOf(Action::class, $value);
159
        $this->assertEquals(Action::DELETE, $value->getValue());
160
    }
161
162
    /**
163
     * @test
164
     */
165
    public function convertToPHPValueWithNullReturnsNull(): void
166
    {
167
        $type = $this->getType(Action::class);
168
169
        $value = $type->convertToPHPValue(null, $this->platform->reveal());
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $value is correct as $type->convertToPHPValue...is->platform->reveal()) targeting Acelaya\Doctrine\Type\Ph...pe::convertToPHPValue() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
170
        $this->assertNull($value);
171
    }
172
173
    /**
174
     * @test
175
     */
176
    public function convertToPHPValueWithInvalidValueThrowsException(): void
177
    {
178
        $type = $this->getType(Action::class);
179
180
        $this->expectException(InvalidArgumentException::class);
181
        $this->expectExceptionMessage(sprintf(
182
            'The value "invalid" is not valid for the enum "%s". Expected one of ["%s"]',
183
            Action::class,
184
            implode('", "', Action::toArray())
185
        ));
186
        $type->convertToPHPValue('invalid', $this->platform->reveal());
187
    }
188
189
    /**
190
     * @test
191
     */
192
    public function convertToPHPValueWithCastingMethodProperlyCastsIt(): void
193
    {
194
        $type = $this->getType(WithCastingMethods::class);
195
196
        $value = $type->convertToPHPValue('foo VALUE', $this->platform->reveal());
197
        $this->assertInstanceOf(WithCastingMethods::class, $value);
198
        $this->assertEquals(WithCastingMethods::FOO, $value->getValue());
199
200
        $intType = $this->getType(WithIntegerValues::class);
201
202
        $value = $intType->convertToPHPValue('1', $this->platform->reveal());
203
        $this->assertInstanceOf(WithIntegerValues::class, $value);
204
        $this->assertEquals(1, $value->getValue());
205
    }
206
207
    /**
208
     * @test
209
     */
210
    public function convertToDatabaseValueWithCastingMethodProperlyCastsIt(): void
211
    {
212
        $type = $this->getType(WithCastingMethods::class);
213
214
        $value = $type->convertToDatabaseValue(WithCastingMethods::FOO(), $this->platform->reveal());
215
        $this->assertEquals('FOO VALUE', $value);
216
    }
217
218
    /**
219
     * @test
220
     */
221
    public function usingChildCustomEnumTypeRegisteredValueIsCorrect(): void
222
    {
223
        MyCustomEnumType::registerEnumType(Action::class);
224
        $type = MyCustomEnumType::getType(Action::class);
225
226
        $this->assertInstanceOf(MyCustomEnumType::class, $type);
227
        $this->assertEquals(
228
            'ENUM("create", "read", "update", "delete") COMMENT "Acelaya\Test\Doctrine\Enum\Action"',
229
            $type->getSQLDeclaration([], $this->platform->reveal())
230
        );
231
    }
232
233
    /**
234
     * @test
235
     */
236
    public function SQLCommentHintIsAlwaysRequired(): void
237
    {
238
        $type = $this->getType(Gender::class);
239
240
        $this->assertTrue($type->requiresSQLCommentHint($this->platform->reveal()));
241
    }
242
243
    private function getType(string $typeName): PhpEnumType
244
    {
245
        PhpEnumType::registerEnumType($typeName);
246
        return Type::getType($typeName);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Doctrine\DBAL\Typ...ype::getType($typeName) returns the type Doctrine\DBAL\Types\Type which includes types incompatible with the type-hinted return Acelaya\Doctrine\Type\PhpEnumType.
Loading history...
247
    }
248
}
249