Completed
Push — master ( cd2604...399c1f )
by Matthieu
03:36
created

tests/DeepCopyTest/DeepCopyTest.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace DeepCopyTest;
4
5
use DeepCopy\DeepCopy;
6
use DeepCopy\Filter\Filter;
7
use DeepCopy\Matcher\PropertyMatcher;
8
use DeepCopy\Matcher\PropertyTypeMatcher;
9
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedList;
10
use DeepCopy\TypeFilter\Spl\SplStackFilter;
11
use DeepCopy\TypeFilter\TypeFilter;
12
use DeepCopy\TypeMatcher\TypeMatcher;
13
14
/**
15
 * DeepCopyTest
16
 */
17
class DeepCopyTest extends AbstractTestClass
18
{
19
    public function testSimpleObjectCopy()
20
    {
21
        $o = new A();
22
23
        $deepCopy = new DeepCopy();
24
25
        $this->assertDeepCopyOf($o, $deepCopy->copy($o));
26
    }
27
28
    public function testPropertyScalarCopy()
29
    {
30
        $o = new A();
31
        $o->property1 = 'foo';
32
33
        $deepCopy = new DeepCopy();
34
35
        $this->assertDeepCopyOf($o, $deepCopy->copy($o));
36
    }
37
38
    public function testPropertyObjectCopy()
39
    {
40
        $o = new A();
41
        $o->property1 = new B();
42
43
        $deepCopy = new DeepCopy();
44
45
        $this->assertDeepCopyOf($o, $deepCopy->copy($o));
46
    }
47
48
    public function testPropertyObjectCopyWithDateTimes()
49
    {
50
        $o = new A();
51
        $o->date1 = new \DateTime();
52
        if (class_exists('DateTimeImmutable')) {
53
            $o->date2 = new \DateTimeImmutable();
54
        }
55
56
        $deepCopy = new DeepCopy();
57
        $c = $deepCopy->copy($o);
58
59
        $this->assertDeepCopyOf($o, $c);
60
61
        $c->date1->setDate(2015, 01, 04);
62
        $this->assertNotEquals($c->date1, $o->date1);
63
    }
64
65
    public function testPrivatePropertyOfParentObjectCopy()
66
    {
67
        $o = new E();
68
        $o->setProperty1(new B);
69
        $o->setProperty2(new B);
70
71
        $deepCopy = new DeepCopy();
72
73
        $this->assertDeepCopyOf($o, $deepCopy->copy($o));
74
    }
75
76
    public function testPropertyArrayCopy()
77
    {
78
        $o = new A();
79
        $o->property1 = [new B()];
80
81
        $deepCopy = new DeepCopy();
82
83
        $this->assertDeepCopyOf($o, $deepCopy->copy($o));
84
    }
85
86
    public function testCycleCopy1()
87
    {
88
        $a = new A();
89
        $b = new B();
90
        $c = new B();
91
        $a->property1 = $b;
92
        $a->property2 = $c;
93
        $b->property = $c;
94
95
        $deepCopy = new DeepCopy();
96
        /** @var A $a2 */
97
        $a2 = $deepCopy->copy($a);
98
99
        $this->assertDeepCopyOf($a, $a2);
100
101
        $this->assertSame($a2->property1->property, $a2->property2);
102
    }
103
104
    public function testCycleCopy2()
105
    {
106
        $a = new B();
107
        $b = new B();
108
        $a->property = $b;
109
        $b->property = $a;
110
111
        $deepCopy = new DeepCopy();
112
        /** @var B $a2 */
113
        $a2 = $deepCopy->copy($a);
114
115
        $this->assertSame($a2, $a2->property->property);
116
    }
117
118
    /**
119
     * Dynamic properties should be cloned
120
     */
121
    public function testDynamicProperties()
122
    {
123
        $a = new \stdClass();
124
        $a->b = new \stdClass();
125
126
        $deepCopy = new DeepCopy();
127
        $a2 = $deepCopy->copy($a);
128
        $this->assertNotSame($a->b, $a2->b);
129
        $this->assertDeepCopyOf($a, $a2);
130
    }
131
132
    public function testCloneChild()
133
    {
134
        $h = new H();
135
136
        $deepCopy = new DeepCopy();
137
        $newH = $deepCopy->copy($h);
138
139
        $propRefl = (new \ReflectionObject($newH))->getProperty('prop');
140
        $propRefl->setAccessible(true);
141
142
        $this->assertNotSame($newH, $h);
143
        $this->assertEquals($newH, $h);
144
        $this->assertEquals('bar', $propRefl->getValue($newH));
145
    }
146
147
    public function testNonClonableItems()
148
    {
149
        $a = new \ReflectionClass('DeepCopyTest\A');
150
        $deepCopy = new DeepCopy();
151
        $a2 = $deepCopy->skipUncloneable()->copy($a);
152
        $this->assertSame($a, $a2);
153
    }
154
155
    /**
156
     * @expectedException \DeepCopy\Exception\CloneException
157
     * @expectedExceptionMessage Class "DeepCopyTest\C" is not cloneable.
158
     */
159
    public function testCloneException()
160
    {
161
        $o = new C;
162
        $deepCopy = new DeepCopy();
163
        $deepCopy->copy($o);
164
    }
165
166
    public function testCloneObjectsWithUserlandCloneMethod()
167
    {
168
        $f = new F();
169
        $f->prop = new \DateTime('2016-09-16');
170
171
        $deepCopy = new DeepCopy();
172
        $newF = $deepCopy->copy($f);
173
174
        $this->assertNotSame($newF->prop, $f->prop);
175
    }
176
177
    public function testCloneObjectsWithUserlandCloneMethodAndUseCloneableMethodEnabled()
178
    {
179
        $f = new F();
180
        $f->prop = new \DateTime('2016-09-16');
181
182
        $deepCopy = new DeepCopy(true);
183
        $newF = $deepCopy->copy($f);
184
185
        $this->assertSame($newF->prop, $f->prop);
186
    }
187
188
    /**
189
     * @test
190
     */
191
    public function filtersShouldBeApplied()
192
    {
193
        $o = new A();
194
        $o->property1 = 'foo';
195
196
        $filter = $this->getMockForAbstractClass('DeepCopy\Filter\Filter');
197
        $filter->expects($this->once())
198
            ->method('apply')
199
            ->will($this->returnCallback(function($object, $property) {
200
                        $object->$property = null;
201
                    }));
202
203
        $deepCopy = new DeepCopy();
204
        $deepCopy->addFilter($filter, new PropertyMatcher(get_class($o), 'property1'));
205
        /** @var A $new */
206
        $new = $deepCopy->copy($o);
207
208
        $this->assertNull($new->property1);
209
    }
210
211
    /**
212
     * If a filter applies to a property, the property shouldn't be copied
213
     * @test
214
     */
215
    public function filtersShouldBeAppliedAndBreakPropertyCopying()
216
    {
217
        $o = new A();
218
        $o->property1 = new B();
219
220
        /* @var Filter|\PHPUnit_Framework_MockObject_MockObject $filter */
221
        $filter = $this->getMockForAbstractClass('DeepCopy\Filter\Filter');
222
        $filter->expects($this->once())
223
            ->method('apply')
224
            ->will($this->returnCallback(function($object, $property, $objectCopier) {
225
                    }));
226
227
        $deepCopy = new DeepCopy();
228
        $deepCopy->addFilter($filter, new PropertyMatcher(get_class($o), 'property1'));
229
        /** @var A $new */
230
        $new = $deepCopy->copy($o);
231
232
        $this->assertSame($o->property1, $new->property1);
233
    }
234
235
    /**
236
     * If a filter applies to an object, it should not be copied
237
     */
238
    public function testTypeFilterShouldBeAppliedOnObject()
239
    {
240
        $o = new A();
241
        $o->property1 = new B();
242
243
        /* @var TypeFilter|\PHPUnit_Framework_MockObject_MockObject $filter */
244
        $filter = $this->getMockForAbstractClass('DeepCopy\TypeFilter\TypeFilter');
245
        $filter->expects($this->once())
246
            ->method('apply')
247
            ->will($this->returnValue(null));
248
249
        $deepCopy = new DeepCopy();
250
        $deepCopy->addTypeFilter($filter, new TypeMatcher('DeepCopyTest\B'));
251
        /** @var A $new */
252
        $new = $deepCopy->copy($o);
253
254
        $this->assertNull($new->property1);
255
    }
256
257
    /**
258
     * If a filter applies to an array member, it should not be copied
259
     */
260
    public function testTypeFilterShouldBeAppliedOnArrayMember()
261
    {
262
        $arr = [new A, new A, new B, new B, new A];
263
264
        /* @var TypeFilter|\PHPUnit_Framework_MockObject_MockObject $filter */
265
        $filter = $this->getMockForAbstractClass('DeepCopy\TypeFilter\TypeFilter');
266
        $filter->expects($this->exactly(2))
267
            ->method('apply')
268
            ->will($this->returnValue(null));
269
270
        $deepCopy = new DeepCopy();
271
        $deepCopy->addTypeFilter($filter, new TypeMatcher('DeepCopyTest\B'));
272
        /** @var A $new */
273
        $new = $deepCopy->copy($arr);
274
275
        $this->assertNull($new[2]);
276
        $this->assertNull($new[3]);
277
    }
278
279
    public function testSplDoublyLinkedListDeepCopy()
280
    {
281
        $a = new A();
282
        $a->property1 = 'foo';
283
        $a->property2 = new \SplDoublyLinkedList();
284
285
        $b = new B();
286
        $b->property = 'baz';
287
        $a->property2->push($b);
288
289
        $stack = new \SplDoublyLinkedList();
290
        $stack->push($a);
291
        $stack->push($b);
292
293
        $deepCopy = new DeepCopy();
294
        $this->assertDeepCopyOf($stack, $deepCopy->copy($stack));
295
    }
296
}
297
298
class A
299
{
300
    public $property1;
301
    public $property2;
302
}
303
304
class B
305
{
306
    public $property;
307
}
308
309
class C
310
{
311
    private function __clone(){}
312
}
313
314
class D
315
{
316
    private $property1;
317
318
    public function getProperty1()
319
    {
320
        return $this->property1;
321
    }
322
323
    public function setProperty1($property1)
324
    {
325
        $this->property1 = $property1;
326
        return $this;
327
    }
328
}
329
330
class E extends D
331
{
332
    private $property2;
333
334
    public function getProperty2()
335
    {
336
        return $this->property2;
337
    }
338
339
    public function setProperty2($property2)
340
    {
341
        $this->property2 = $property2;
342
        return $this;
343
    }
344
}
345
346
class F
347
{
348
    public $prop;
349
350
    public function __clone()
351
    {
352
        $this->foo = 'bar';
353
    }
354
}
355
356
class G
357
{
358
    private $prop = 'foo';
359
}
360
361
class H extends G
362
{
363
    private $prop = 'bar';
0 ignored issues
show
Comprehensibility introduced by Théo FIDRY
Consider using a different property name as you override a private property of the parent class.
Loading history...
364
}
365