PhpEnumTypeTest::setUp()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 11
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace JDecool\Test\Doctrine\Type;
5
6
use Doctrine\DBAL\Platforms\AbstractPlatform;
7
use Doctrine\DBAL\Types\Type;
8
use JDecool\Doctrine\Exception\InvalidArgumentException;
9
use JDecool\Doctrine\Type\PhpEnumType;
10
use JDecool\Test\Doctrine\Enum\Action;
11
use JDecool\Test\Doctrine\Enum\Gender;
12
use JDecool\Test\Doctrine\Enum\WithCastingMethods;
13
use JDecool\Test\Doctrine\Enum\WithIntegerValues;
14
use MabeEnum\Enum;
15
use PHPUnit\Framework\TestCase;
16
use Prophecy\Argument;
17
use Prophecy\Prophecy\ObjectProphecy;
18
use ReflectionProperty;
19
use stdClass;
20
use function implode;
21
use function sprintf;
22
23
class PhpEnumTypeTest extends TestCase
24
{
25
    /** @var ObjectProphecy */
26
    protected $platform;
27
28
    public function setUp(): void
29
    {
30
        $this->platform = $this->prophesize(AbstractPlatform::class);
31
32
        // Before every test, clean registered types
33
        $refProp = new ReflectionProperty(Type::class, '_typeObjects');
34
        $refProp->setAccessible(true);
35
        $refProp->setValue(null, []);
36
        $refProp = new ReflectionProperty(Type::class, '_typesMap');
37
        $refProp->setAccessible(true);
38
        $refProp->setValue(null, []);
39
    }
40
41
    /**
42
     * @test
43
     */
44
    public function enumTypesAreProperlyRegistered(): void
45
    {
46
        $this->assertFalse(Type::hasType(Action::class));
47
        $this->assertFalse(Type::hasType('gender'));
48
49
        PhpEnumType::registerEnumType(Action::class);
50
        PhpEnumType::registerEnumTypes([
51
            'gender' => Gender::class,
52
        ]);
53
54
        $this->assertTrue(Type::hasType(Action::class));
55
        $this->assertTrue(Type::hasType('gender'));
56
    }
57
58
    /**
59
     * @test
60
     */
61
    public function enumTypesAreProperlyCustomizedWhenRegistered(): void
62
    {
63
        $this->assertFalse(Type::hasType(Action::class));
64
        $this->assertFalse(Type::hasType(Gender::class));
65
66
        PhpEnumType::registerEnumTypes([
67
            'gender' => Gender::class,
68
            Action::class,
69
        ]);
70
71
        /** @var Type $actionType */
72
        $actionType = Type::getType(Action::class);
73
        $this->assertInstanceOf(PhpEnumType::class, $actionType);
74
        $this->assertEquals(Action::class, $actionType->getName());
75
76
        /** @var Type $actionType */
77
        $genderType = Type::getType('gender');
78
        $this->assertInstanceOf(PhpEnumType::class, $genderType);
79
        $this->assertEquals('gender', $genderType->getName());
80
    }
81
82
    /**
83
     * @test
84
     */
85
    public function registerInvalidEnumThrowsException(): void
86
    {
87
        $this->expectException(InvalidArgumentException::class);
88
        $this->expectExceptionMessage(sprintf(
89
            'Provided enum class "%s" is not valid. Enums must extend "%s"',
90
            stdClass::class,
91
            Enum::class
92
        ));
93
        PhpEnumType::registerEnumType(stdClass::class);
94
    }
95
96
    /**
97
     * @test
98
     */
99
    public function getSQLDeclarationReturnsValueFromPlatform(): void
100
    {
101
        $this->platform->getVarcharTypeDeclarationSQL(Argument::cetera())->willReturn('declaration');
102
103
        $type = $this->getType(Gender::class);
104
105
        $this->assertEquals('declaration', $type->getSQLDeclaration([], $this->platform->reveal()));
106
    }
107
108
    /**
109
     * @test
110
     * @dataProvider provideValues
111
     * @param string $typeName
112
     * @param $phpValue
113
     * @param string $expectedValue
114
     */
115
    public function convertToDatabaseValueParsesEnum(string $typeName, $phpValue, string $expectedValue): void
116
    {
117
        $type = $this->getType($typeName);
118
119
        $actualValue = $type->convertToDatabaseValue($phpValue, $this->platform->reveal());
120
121
        $this->assertEquals($expectedValue, $actualValue);
122
    }
123
124
    public function provideValues(): iterable
125
    {
126
        yield [Action::class, Action::CREATE(), Action::CREATE];
127
        yield [Action::class, Action::READ(), Action::READ];
128
        yield [Action::class, Action::UPDATE(), Action::UPDATE];
129
        yield [Action::class, Action::DELETE(), Action::DELETE];
130
        yield [Gender::class, Gender::FEMALE(), Gender::FEMALE];
131
        yield [Gender::class, Gender::MALE(), Gender::MALE];
132
    }
133
134
    /**
135
     * @test
136
     */
137
    public function convertToDatabaseValueReturnsNullWhenNullIsProvided(): void
138
    {
139
        $type = $this->getType(Action::class);
140
141
        $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 JDecool\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...
142
    }
143
144
    /**
145
     * @test
146
     */
147
    public function convertToPHPValueWithValidValueReturnsParsedData(): void
148
    {
149
        $type = $this->getType(Action::class);
150
151
        /** @var Action $value */
152
        $value = $type->convertToPHPValue(Action::CREATE, $this->platform->reveal());
153
        $this->assertInstanceOf(Action::class, $value);
154
        $this->assertEquals(Action::CREATE, $value->getValue());
155
156
        $value = $type->convertToPHPValue(Action::DELETE, $this->platform->reveal());
157
        $this->assertInstanceOf(Action::class, $value);
158
        $this->assertEquals(Action::DELETE, $value->getValue());
159
    }
160
161
    /**
162
     * @test
163
     */
164
    public function convertToPHPValueWithNullReturnsNull(): void
165
    {
166
        $type = $this->getType(Action::class);
167
168
        $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 JDecool\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...
169
        $this->assertNull($value);
170
    }
171
172
    /**
173
     * @test
174
     */
175
    public function convertToPHPValueWithInvalidValueThrowsException(): void
176
    {
177
        $type = $this->getType(Action::class);
178
179
        $this->expectException(InvalidArgumentException::class);
180
        $this->expectExceptionMessage(sprintf(
181
            'The value "invalid" is not valid for the enum "%s". Expected one of ["%s"]',
182
            Action::class,
183
            implode('", "', Action::getConstants())
184
        ));
185
        $type->convertToPHPValue('invalid', $this->platform->reveal());
186
    }
187
188
    /**
189
     * @test
190
     */
191
    public function convertToPHPValueWithCastingMethodProperlyCastsIt(): void
192
    {
193
        $type = $this->getType(WithCastingMethods::class);
194
195
        $value = $type->convertToPHPValue('foo VALUE', $this->platform->reveal());
196
        $this->assertInstanceOf(WithCastingMethods::class, $value);
197
        $this->assertEquals(WithCastingMethods::FOO, $value->getValue());
198
199
        $intType = $this->getType(WithIntegerValues::class);
200
201
        $value = $intType->convertToPHPValue('1', $this->platform->reveal());
202
        $this->assertInstanceOf(WithIntegerValues::class, $value);
203
        $this->assertEquals(1, $value->getValue());
204
    }
205
206
    /**
207
     * @test
208
     */
209
    public function convertToDatabaseValueWithCastingMethodProperlyCastsIt(): void
210
    {
211
        $type = $this->getType(WithCastingMethods::class);
212
213
        $value = $type->convertToDatabaseValue(WithCastingMethods::FOO(), $this->platform->reveal());
214
        $this->assertEquals('FOO VALUE', $value);
215
    }
216
217
    /**
218
     * @test
219
     */
220
    public function usingChildCustomEnumTypeRegisteredValueIsCorrect(): void
221
    {
222
        MyCustomEnumType::registerEnumType(Action::class);
223
        $type = MyCustomEnumType::getType(Action::class);
224
225
        $this->assertInstanceOf(MyCustomEnumType::class, $type);
226
        $this->assertEquals(
227
            'ENUM("create", "read", "update", "delete") COMMENT "JDecool\Test\Doctrine\Enum\Action"',
228
            $type->getSQLDeclaration([], $this->platform->reveal())
229
        );
230
    }
231
232
    /**
233
     * @test
234
     */
235
    public function SQLCommentHintIsAlwaysRequired(): void
236
    {
237
        $type = $this->getType(Gender::class);
238
239
        $this->assertTrue($type->requiresSQLCommentHint($this->platform->reveal()));
240
    }
241
242
    private function getType(string $typeName): PhpEnumType
243
    {
244
        PhpEnumType::registerEnumType($typeName);
245
        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 JDecool\Doctrine\Type\PhpEnumType.
Loading history...
246
    }
247
}
248