Completed
Push — 1.x ( 0fa590...3b8a3a )
by Théo
01:13
created

DeepCopyTest   C

Complexity

Total Complexity 27

Size/Duplication

Total Lines 400
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 19

Importance

Changes 15
Bugs 2 Features 2
Metric Value
c 15
b 2
f 2
dl 0
loc 400
rs 6.875
wmc 27
lcom 1
cbo 19

26 Methods

Rating   Name   Duplication   Size   Complexity  
A test_it_can_copy_scalar_values() 0 6 1
A provideScalarValues() 0 11 1
A test_it_can_copy_an_array_of_scalar_values() 0 6 1
A test_it_can_copy_an_object() 0 8 1
A test_it_can_copy_an_array_of_objects() 0 9 1
A test_it_can_copy_an_object_with_scalar_properties() 0 7 1
A provideObjectWithScalarValues() 0 17 1
A test_it_can_copy_an_object_with_an_object_property() 0 12 1
A test_it_copies_dynamic_properties() 0 12 1
A test_it_can_copy_an_object_with_a_date_object_property() 0 16 1
A test_it_skips_the_copy_for_userland_datetimezone() 0 16 1
A test_it_skips_the_copy_for_userland_dateinterval() 0 16 1
A test_it_copies_the_private_properties_of_the_parent_class() 0 13 1
A test_it_keeps_reference_of_the_copied_objects_when_copying_the_graph() 0 21 1
A test_it_can_copy_graphs_with_circular_references() 0 15 1
A test_it_can_copy_graphs_with_circular_references_with_userland_class() 0 16 1
A test_it_cannot_copy_unclonable_items() 0 20 2
A test_it_can_skip_uncloneable_objects() 0 11 1
A test_it_uses_the_userland_defined_cloned_method() 0 8 1
A test_it_only_uses_the_userland_defined_cloned_method_when_configured_to_do_so() 0 10 1
A test_it_uses_type_filter_to_copy_objects_if_matcher_matches() 0 20 1
A test_it_uses_filters_to_copy_object_properties_if_matcher_matches() 0 19 1
A test_it_uses_the_first_filter_matching_for_copying_object_properties() 0 23 1
A test_it_can_copy_a_SplDoublyLinkedList() 0 20 1
A test_matchers_can_access_to_parent_private_properties() 0 12 1
A assertEqualButNotSame() 0 5 1
1
<?php
2
3
namespace DeepCopyTest;
4
5
use DateInterval;
6
use DateTime;
7
use DateTimeImmutable;
8
use DateTimeZone;
9
use DeepCopy\DeepCopy;
10
use DeepCopy\Exception\CloneException;
11
use DeepCopy\f001;
12
use DeepCopy\f002;
13
use DeepCopy\f003;
14
use DeepCopy\f004;
15
use DeepCopy\f005;
16
use DeepCopy\f006;
17
use DeepCopy\f007;
18
use DeepCopy\f008;
19
use DeepCopy\Filter\KeepFilter;
20
use DeepCopy\Filter\SetNullFilter;
21
use DeepCopy\Matcher\PropertyNameMatcher;
22
use DeepCopy\Matcher\PropertyTypeMatcher;
23
use DeepCopy\TypeFilter\ShallowCopyFilter;
24
use DeepCopy\TypeMatcher\TypeMatcher;
25
use PHPUnit_Framework_TestCase;
26
use SplDoublyLinkedList;
27
use stdClass;
28
use function DeepCopy\deep_copy;
29
30
/**
31
 * @covers \DeepCopy\DeepCopy
32
 */
33
class DeepCopyTest extends PHPUnit_Framework_TestCase
34
{
35
    /**
36
     * @dataProvider provideScalarValues
37
     */
38
    public function test_it_can_copy_scalar_values($value)
39
    {
40
        $copy = deep_copy($value);
41
42
        $this->assertSame($value, $copy);
43
    }
44
45
    public function provideScalarValues()
46
    {
47
        return [
48
            [true],
49
            ['string'],
50
            [null],
51
            [10],
52
            [-1],
53
            [.5],
54
        ];
55
    }
56
57
    public function test_it_can_copy_an_array_of_scalar_values()
58
    {
59
        $copy = deep_copy([10, 20]);
60
61
        $this->assertSame([10, 20], $copy);
62
    }
63
64
    public function test_it_can_copy_an_object()
65
    {
66
        $object = new stdClass();
67
68
        $copy = deep_copy($object);
69
70
        $this->assertEqualButNotSame($object, $copy);
71
    }
72
73
    public function test_it_can_copy_an_array_of_objects()
74
    {
75
        $object = [new stdClass()];
76
77
        $copy = deep_copy($object);
78
79
        $this->assertEqualButNotSame($object, $copy);
80
        $this->assertEqualButNotSame($object[0], $copy[0]);
81
    }
82
83
    /**
84
     * @dataProvider provideObjectWithScalarValues
85
     */
86
    public function test_it_can_copy_an_object_with_scalar_properties($object, $expectedVal)
87
    {
88
        $copy = deep_copy($object);
89
90
        $this->assertEqualButNotSame($object, $copy);
91
        $this->assertSame($expectedVal, $copy->prop);
92
    }
93
94
    public function provideObjectWithScalarValues()
95
    {
96
        $createObject = function ($val) {
97
            $object = new stdClass();
98
99
            $object->prop = $val;
100
101
            return $object;
102
        };
103
104
        return array_map(
105
            function (array $vals) use ($createObject) {
106
                return [$createObject($vals[0]), $vals[0]];
107
            },
108
            $this->provideScalarValues()
109
        );
110
    }
111
112
    public function test_it_can_copy_an_object_with_an_object_property()
113
    {
114
        $foo = new stdClass();
115
        $bar = new stdClass();
116
117
        $foo->bar = $bar;
118
119
        $copy = deep_copy($foo);
120
121
        $this->assertEqualButNotSame($foo, $copy);
122
        $this->assertEqualButNotSame($foo->bar, $copy->bar);
123
    }
124
125
    public function test_it_copies_dynamic_properties()
126
    {
127
        $foo = new stdClass();
128
        $bar = new stdClass();
129
130
        $foo->bar = $bar;
131
132
        $copy = deep_copy($foo);
133
134
        $this->assertEqualButNotSame($foo, $copy);
135
        $this->assertEqualButNotSame($foo->bar, $copy->bar);
136
    }
137
138
    /**
139
     * @ticket https://github.com/myclabs/DeepCopy/issues/38
140
     * @ticket https://github.com/myclabs/DeepCopy/pull/70
141
     * @ticket https://github.com/myclabs/DeepCopy/pull/76
142
     */
143
    public function test_it_can_copy_an_object_with_a_date_object_property()
144
    {
145
        $object = new stdClass();
146
147
        $object->d1 = new DateTime();
148
        $object->d2 = new DateTimeImmutable();
149
        $object->dtz = new DateTimeZone('UTC');
150
        $object->di = new DateInterval('P2D');
151
152
        $copy = deep_copy($object);
153
154
        $this->assertEqualButNotSame($object->d1, $copy->d1);
155
        $this->assertEqualButNotSame($object->d2, $copy->d2);
156
        $this->assertEqualButNotSame($object->dtz, $copy->dtz);
157
        $this->assertEqualButNotSame($object->di, $copy->di);
158
    }
159
160
    /**
161
     * @ticket https://github.com/myclabs/DeepCopy/pull/70
162
     */
163
    public function test_it_skips_the_copy_for_userland_datetimezone()
164
    {
165
        $deepCopy = new DeepCopy();
166
        $deepCopy->addFilter(
167
            new SetNullFilter(),
168
            new PropertyNameMatcher('cloned')
169
        );
170
171
        $object = new stdClass();
172
173
        $object->dtz = new f007\FooDateTimeZone('UTC');
174
175
        $copy = $deepCopy->copy($object);
176
177
        $this->assertTrue($copy->dtz->cloned);
178
    }
179
180
    /**
181
     * @ticket https://github.com/myclabs/DeepCopy/pull/76
182
     */
183
    public function test_it_skips_the_copy_for_userland_dateinterval()
184
    {
185
        $deepCopy = new DeepCopy();
186
        $deepCopy->addFilter(
187
            new SetNullFilter(),
188
            new PropertyNameMatcher('cloned')
189
        );
190
191
        $object = new stdClass();
192
193
        $object->di = new f007\FooDateInterval('P2D');
194
195
        $copy = $deepCopy->copy($object);
196
197
        $this->assertFalse($copy->di->cloned);
198
    }
199
200
    public function test_it_copies_the_private_properties_of_the_parent_class()
201
    {
202
        $object = new f001\B();
203
204
        $object->setAProp($aStdClass = new stdClass());
205
        $object->setBProp($bStdClass = new stdClass());
206
207
        /** @var f001\B $copy */
208
        $copy = deep_copy($object);
209
210
        $this->assertEqualButNotSame($aStdClass, $copy->getAProp());
211
        $this->assertEqualButNotSame($bStdClass, $copy->getBProp());
212
    }
213
214
    public function test_it_keeps_reference_of_the_copied_objects_when_copying_the_graph()
215
    {
216
        $a = new f002\A();
217
218
        $b = new stdClass();
219
        $c = new stdClass();
220
221
        $a->setProp1($b);
222
        $a->setProp2($c);
223
224
        $b->c = $c;
225
226
        /** @var f002\A $copy */
227
        $copy = deep_copy($a);
228
229
        $this->assertEqualButNotSame($a, $copy);
230
        $this->assertEqualButNotSame($b, $copy->getProp1());
231
        $this->assertEqualButNotSame($c, $copy->getProp2());
232
233
        $this->assertSame($copy->getProp1()->c, $copy->getProp2());
234
    }
235
236
    public function test_it_can_copy_graphs_with_circular_references()
237
    {
238
        $a = new stdClass();
239
        $b = new stdClass();
240
241
        $a->prop = $b;
242
        $b->prop = $a;
243
244
        $copy = deep_copy($a);
245
246
        $this->assertEqualButNotSame($a, $copy);
247
        $this->assertEqualButNotSame($b, $copy->prop);
248
249
        $this->assertSame($copy, $copy->prop->prop);
250
    }
251
252
    public function test_it_can_copy_graphs_with_circular_references_with_userland_class()
253
    {
254
        $a = new f003\Foo('a');
255
        $b = new f003\Foo('b');
256
257
        $a->setProp($b);
258
        $b->setProp($a);
259
260
        /** @var f003\Foo $copy */
261
        $copy = deep_copy($a);
262
263
        $this->assertEqualButNotSame($a, $copy);
264
        $this->assertEqualButNotSame($b, $copy->getProp());
265
266
        $this->assertSame($copy, $copy->getProp()->getProp());
267
    }
268
269
    public function test_it_cannot_copy_unclonable_items()
270
    {
271
        $object = new f004\UnclonableItem();
272
273
        try {
274
            deep_copy($object);
275
276
            $this->fail('Expected exception to be thrown.');
277
        } catch (CloneException $exception) {
278
            $this->assertSame(
279
                sprintf(
280
                    'The class "%s" is not cloneable.',
281
                    f004\UnclonableItem::class
282
                ),
283
                $exception->getMessage()
284
            );
285
            $this->assertSame(0, $exception->getCode());
286
            $this->assertNull($exception->getPrevious());
287
        }
288
    }
289
290
    public function test_it_can_skip_uncloneable_objects()
291
    {
292
        $object = new f004\UnclonableItem();
293
294
        $deepCopy = new DeepCopy();
295
        $deepCopy->skipUncloneable(true);
296
297
        $copy = $deepCopy->copy($object);
298
299
        $this->assertSame($object, $copy);
300
    }
301
302
    public function test_it_uses_the_userland_defined_cloned_method()
303
    {
304
        $object = new f005\Foo();
305
306
        $copy = deep_copy($object);
307
308
        $this->assertTrue($copy->cloned);
309
    }
310
311
    public function test_it_only_uses_the_userland_defined_cloned_method_when_configured_to_do_so()
312
    {
313
        $object = new f005\Foo();
314
        $object->foo = new stdClass();
0 ignored issues
show
Bug introduced by Théo FIDRY
The property foo does not seem to exist in DeepCopy\f005\Foo.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
315
316
        $copy = deep_copy($object, true);
317
318
        $this->assertTrue($copy->cloned);
319
        $this->assertSame($object->foo, $copy->foo);
320
    }
321
322
    public function test_it_uses_type_filter_to_copy_objects_if_matcher_matches()
323
    {
324
        $deepCopy = new DeepCopy();
325
        $deepCopy->addTypeFilter(
326
            new ShallowCopyFilter(),
327
            new TypeMatcher(f006\A::class)
328
        );
329
330
        $a = new f006\A;
331
        $b = new f006\B;
332
333
        $a->setAProp($b);
334
335
        /** @var f006\A $copy */
336
        $copy = $deepCopy->copy($a);
337
338
        $this->assertTrue($copy->cloned);
339
        $this->assertFalse($copy->getAProp()->cloned);
340
        $this->assertSame($b, $copy->getAProp());
341
    }
342
343
    public function test_it_uses_filters_to_copy_object_properties_if_matcher_matches()
344
    {
345
        $deepCopy = new DeepCopy();
346
        $deepCopy->addFilter(
347
            new SetNullFilter(),
348
            new PropertyNameMatcher('cloned')
349
        );
350
351
        $a = new f006\A;
352
        $b = new f006\B;
353
354
        $a->setAProp($b);
355
356
        /** @var f006\A $copy */
357
        $copy = $deepCopy->copy($a);
358
359
        $this->assertNull($copy->cloned);
360
        $this->assertNull($copy->getAProp()->cloned);
361
    }
362
363
    public function test_it_uses_the_first_filter_matching_for_copying_object_properties()
364
    {
365
        $deepCopy = new DeepCopy();
366
        $deepCopy->addFilter(
367
            new SetNullFilter(),
368
            new PropertyNameMatcher('cloned')
369
        );
370
        $deepCopy->addFilter(
371
            new KeepFilter(),
372
            new PropertyNameMatcher('cloned')
373
        );
374
375
        $a = new f006\A;
376
        $b = new f006\B;
377
378
        $a->setAProp($b);
379
380
        /** @var f006\A $copy */
381
        $copy = $deepCopy->copy($a);
382
383
        $this->assertNull($copy->cloned);
384
        $this->assertNull($copy->getAProp()->cloned);
385
    }
386
387
    /**
388
     * @ticket https://github.com/myclabs/DeepCopy/pull/49
389
     */
390
    public function test_it_can_copy_a_SplDoublyLinkedList()
391
    {
392
        $object = new SplDoublyLinkedList();
393
394
        $a = new stdClass();
395
        $b = new stdClass();
396
397
        $a->b = $b;
398
399
        $object->push($a);
400
401
        /** @var SplDoublyLinkedList $copy */
402
        $copy = deep_copy($object);
403
404
        $this->assertEqualButNotSame($object, $copy);
405
406
        $aCopy = $copy->pop();
407
408
        $this->assertEqualButNotSame($b, $aCopy->b);
409
    }
410
411
    /**
412
     * @ticket https://github.com/myclabs/DeepCopy/issues/62
413
     */
414
    public function test_matchers_can_access_to_parent_private_properties()
415
    {
416
        $deepCopy = new DeepCopy();
417
        $deepCopy->addFilter(new SetNullFilter(), new PropertyTypeMatcher(stdClass::class));
418
419
        $object = new f008\B(new stdClass());
420
421
        /** @var f008\B $copy */
422
        $copy = $deepCopy->copy($object);
423
424
        $this->assertNull($copy->getFoo());
425
    }
426
427
    private function assertEqualButNotSame($expected, $val)
428
    {
429
        $this->assertEquals($expected, $val);
430
        $this->assertNotSame($expected, $val);
431
    }
432
}
433