Completed
Pull Request — master (#19)
by Alejandro
01:41
created

PhpEnumTypeTest::setUp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Acelaya\Test\Doctrine\Type;
5
6
use Acelaya\Doctrine\Exception\InvalidArgumentException;
7
use Acelaya\Doctrine\Type\PhpEnumType;
8
use Acelaya\Test\Doctrine\Enum\Action;
9
use Acelaya\Test\Doctrine\Enum\Gender;
10
use Acelaya\Test\Doctrine\Enum\WithCastingMethods;
11
use Acelaya\Test\Doctrine\Enum\WithIntegerValues;
12
use Doctrine\DBAL\Platforms\AbstractPlatform;
13
use Doctrine\DBAL\Types\Type;
14
use MyCLabs\Enum\Enum;
15
use PHPUnit\Framework\TestCase;
16
use Prophecy\Argument;
17
use Prophecy\Prophecy\ObjectProphecy;
18
19
class PhpEnumTypeTest extends TestCase
20
{
21
    /**
22
     * @var ObjectProphecy
23
     */
24
    protected $platform;
25
26
    public function setUp()
27
    {
28
        $this->platform = $this->prophesize(AbstractPlatform::class);
29
30
        // Before every test, clean registered types
31
        $refProp = new \ReflectionProperty(Type::class, '_typeObjects');
32
        $refProp->setAccessible(true);
33
        $refProp->setValue(null, []);
34
        $refProp = new \ReflectionProperty(Type::class, '_typesMap');
35
        $refProp->setAccessible(true);
36
        $refProp->setValue(null, []);
37
    }
38
39
    /**
40
     * @test
41
     */
42
    public function enumTypesAreProperlyRegistered()
43
    {
44
        $this->assertFalse(Type::hasType(Action::class));
45
        $this->assertFalse(Type::hasType('gender'));
46
47
        PhpEnumType::registerEnumType(Action::class);
48
        PhpEnumType::registerEnumTypes([
49
            'gender' => Gender::class,
50
        ]);
51
52
        $this->assertTrue(Type::hasType(Action::class));
53
        $this->assertTrue(Type::hasType('gender'));
54
    }
55
56
    /**
57
     * @test
58
     */
59
    public function enumTypesAreProperlyCustomizedWhenRegistered()
60
    {
61
        $this->assertFalse(Type::hasType(Action::class));
62
        $this->assertFalse(Type::hasType(Gender::class));
63
64
        PhpEnumType::registerEnumTypes([
65
            'gender' => Gender::class,
66
            Action::class,
67
        ]);
68
69
        /** @var Type $actionType */
70
        $actionType = Type::getType(Action::class);
71
        $this->assertInstanceOf(PhpEnumType::class, $actionType);
72
        $this->assertEquals(Action::class, $actionType->getName());
73
74
        /** @var Type $actionType */
75
        $genderType = Type::getType('gender');
76
        $this->assertInstanceOf(PhpEnumType::class, $genderType);
77
        $this->assertEquals('gender', $genderType->getName());
78
    }
79
80
    /**
81
     * @test
82
     */
83
    public function registerInvalidEnumThrowsException()
84
    {
85
        $this->expectException(InvalidArgumentException::class);
86
        $this->expectExceptionMessage(sprintf(
87
            'Provided enum class "%s" is not valid. Enums must extend "%s"',
88
            \stdClass::class,
89
            Enum::class
90
        ));
91
        PhpEnumType::registerEnumType(\stdClass::class);
92
    }
93
94
    /**
95
     * @test
96
     */
97
    public function getSQLDeclarationReturnsValueFromPlatform()
98
    {
99
        $this->platform->getVarcharTypeDeclarationSQL(Argument::cetera())->willReturn('declaration');
100
101
        $type = $this->getType(Gender::class);
102
103
        $this->assertEquals('declaration', $type->getSQLDeclaration([], $this->platform->reveal()));
104
    }
105
106
    /**
107
     * @test
108
     * @dataProvider provideValues
109
     * @param string $typeName
110
     * @param $phpValue
111
     * @param string $expectedValue
112
     */
113
    public function convertToDatabaseValueParsesEnum(string $typeName, $phpValue, string $expectedValue)
114
    {
115
        $type = $this->getType($typeName);
116
117
        $actualValue = $type->convertToDatabaseValue($phpValue, $this->platform->reveal());
118
119
        $this->assertEquals($expectedValue, $actualValue);
120
    }
121
122
    public function provideValues(): array
123
    {
124
        return [
125
            [Action::class, Action::CREATE(), Action::CREATE],
126
            [Action::class, Action::READ(), Action::READ],
127
            [Action::class, Action::UPDATE(), Action::UPDATE],
128
            [Action::class, Action::DELETE(), Action::DELETE],
129
            [Gender::class, Gender::FEMALE(), Gender::FEMALE],
130
            [Gender::class, Gender::MALE(), Gender::MALE],
131
        ];
132
    }
133
134
    /**
135
     * @test
136
     */
137
    public function convertToDatabaseValueReturnsNullWhenNullIsProvided()
138
    {
139
        $type = $this->getType(Action::class);
140
141
        $this->assertNull($type->convertToDatabaseValue(null, $this->platform->reveal()));
142
    }
143
144
    /**
145
     * @test
146
     */
147
    public function convertToPHPValueWithValidValueReturnsParsedData()
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()
165
    {
166
        $type = $this->getType(Action::class);
167
168
        $value = $type->convertToPHPValue(null, $this->platform->reveal());
169
        $this->assertNull($value);
170
    }
171
172
    /**
173
     * @test
174
     */
175
    public function convertToPHPValueWithInvalidValueThrowsException()
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::toArray())
184
        ));
185
        $type->convertToPHPValue('invalid', $this->platform->reveal());
186
    }
187
188
    /**
189
     * @test
190
     */
191
    public function convertToPHPValueWithCastingMethodProperlyCastsIt()
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()
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()
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 "Acelaya\Test\Doctrine\Enum\Action"',
228
            $type->getSQLDeclaration([], $this->platform->reveal())
229
        );
230
    }
231
232
    /**
233
     * @test
234
     */
235
    public function SQLCommentHintIsAlwaysRequired()
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);
246
    }
247
}
248