Completed
Pull Request — master (#78)
by
unknown
21:08
created

testHydratingNull()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
rs 9.9332
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GeneratedHydratorTest\Functional;
6
7
use GeneratedHydrator\ClosureGenerator\Runtime\GenerateRuntimeExtractor;
8
use GeneratedHydrator\ClosureGenerator\Runtime\GenerateRuntimeHydrator;
9
use GeneratedHydratorTestAsset\BaseClass;
10
use GeneratedHydratorTestAsset\ClassWithMixedProperties;
11
use GeneratedHydratorTestAsset\ClassWithPrivateProperties;
12
use GeneratedHydratorTestAsset\ClassWithPrivatePropertiesAndParent;
13
use GeneratedHydratorTestAsset\ClassWithPrivatePropertiesAndParents;
14
use GeneratedHydratorTestAsset\ClassWithProtectedProperties;
15
use GeneratedHydratorTestAsset\ClassWithPublicProperties;
16
use GeneratedHydratorTestAsset\ClassWithStaticProperties;
17
use GeneratedHydratorTestAsset\EmptyClass;
18
use GeneratedHydratorTestAsset\HydratedObject;
19
use PHPUnit\Framework\TestCase;
20
use ReflectionClass;
21
use ReflectionException;
22
use stdClass;
23
use function get_class;
24
use function ksort;
25
26
/**
27
 * Tests for {@see \GeneratedHydrator\ClassGenerator\HydratorGenerator} produced objects
28
 *
29
 * @group Functional
30
 */
31
class GenerateClosureRuntimeFunctionalTest extends TestCase
32
{
33
    /**
34
     * @throws ReflectionException
35
     *
36
     * @dataProvider getHydratorClasses
37
     */
38
    public function testHydrator(object $instance) : void
39
    {
40
        $reflection  = new ReflectionClass($instance);
41
        $initialData = [];
42
        $newData     = [];
43
44
        $this->recursiveFindInitialData($reflection, $instance, $initialData, $newData);
45
46
        $extract = $this->generateExtractor($instance);
47
        $hydrate = $this->generateHydrator($instance);
48
49
        // Hydration and extraction don't guarantee ordering.
50
        ksort($initialData);
51
        ksort($newData);
52
        $extracted = $extract($instance);
53
        ksort($extracted);
54
55
        self::assertSame($initialData, $extracted);
56
        self::assertSame($instance, $hydrate($newData, $instance));
57
58
        // Same as upper applies
59
        $inspectionData = [];
60
        $this->recursiveFindInspectionData($reflection, $instance, $inspectionData);
61
        ksort($inspectionData);
62
        $extracted = $extract($instance);
63
        ksort($extracted);
64
65
        self::assertSame($inspectionData, $newData);
66
        self::assertSame($inspectionData, $extracted);
67
    }
68
69
    /**
70
     * @throws ReflectionException
71
     */
72
    public function testHydratingNull() : void
73
    {
74
        $instance = new ClassWithPrivateProperties();
75
76
        self::assertSame('property0', $instance->getProperty0());
77
78
        ($this->generateHydrator($instance))(['property0' => null], $instance);
0 ignored issues
show
Documentation introduced by
$instance is of type object<GeneratedHydrator...sWithPrivateProperties>, but the function expects a object<GeneratedHydratorTest\Functional\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
79
80
        self::assertNull($instance->getProperty0());
81
    }
82
83
    /**
84
     * @return mixed[]
85
     */
86
    public function getHydratorClasses() : array
87
    {
88
        return [
89
            [new stdClass()],
90
            [new EmptyClass()],
91
            [new HydratedObject()],
92
            [new BaseClass()],
93
            [new ClassWithPublicProperties()],
94
            [new ClassWithProtectedProperties()],
95
            [new ClassWithPrivateProperties()],
96
            [new ClassWithPrivatePropertiesAndParent()],
97
            [new ClassWithPrivatePropertiesAndParents()],
98
            [new ClassWithMixedProperties()],
99
            [new ClassWithStaticProperties()],
100
        ];
101
    }
102
103
    /**
104
     * Recursively populate the $initialData and $newData array browsing the
105
     * full class hierarchy tree
106
     *
107
     * Private properties from parent class that are hidden by children will be
108
     * dropped from the populated arrays
109
     *
110
     * @param mixed[] $initialData
111
     * @param mixed[] $newData
112
     */
113
    private function recursiveFindInitialData(
114
        ReflectionClass $class,
115
        object $instance,
116
        array &$initialData,
117
        array &$newData
118
    ) : void {
119
        $parentClass = $class->getParentClass();
120
        if ($parentClass) {
121
            $this->recursiveFindInitialData($parentClass, $instance, $initialData, $newData);
122
        }
123
124
        foreach ($class->getProperties() as $property) {
125
            if ($property->isStatic()) {
126
                continue;
127
            }
128
129
            $propertyName = $property->getName();
130
131
            $property->setAccessible(true);
132
            $initialData[$propertyName] = $property->getValue($instance);
133
            $newData[$propertyName]     = $property->getName() . '__new__value';
134
        }
135
    }
136
137
    /**
138
     * Recursively populate the $inspectedData array browsing the full class
139
     * hierarchy tree
140
     *
141
     * Private properties from parent class that are hidden by children will be
142
     * dropped from the populated arrays
143
     *
144
     * @param mixed[] $inspectionData
145
     */
146
    private function recursiveFindInspectionData(
147
        ReflectionClass $class,
148
        object $instance,
149
        array &$inspectionData
150
    ) : void {
151
        $parentClass = $class->getParentClass();
152
        if ($parentClass) {
153
            $this->recursiveFindInspectionData($parentClass, $instance, $inspectionData);
154
        }
155
156
        foreach ($class->getProperties() as $property) {
157
            if ($property->isStatic()) {
158
                continue;
159
            }
160
161
            $propertyName = $property->getName();
162
163
            $property->setAccessible(true);
164
            $inspectionData[$propertyName] = $property->getValue($instance);
165
        }
166
    }
167
168
    /**
169
     * @throws ReflectionException
170
     */
171
    private function generateExtractor(object $instance) : callable
172
    {
173
        $className         = get_class($instance);
174
        $generateExtractor = new GenerateRuntimeExtractor();
175
176
        return $generateExtractor($className);
177
    }
178
179
    /**
180
     * @throws ReflectionException
181
     */
182
    private function generateHydrator(object $instance) : callable
183
    {
184
        $className         = get_class($instance);
185
        $generateExtractor = new GenerateRuntimeHydrator();
186
187
        return $generateExtractor($className);
188
    }
189
}
190