Completed
Push — 1.x ( 770e50...c04239 )
by Théo
02:28 queued 01:12
created

DeepCopyTest   B

Complexity

Total Complexity 26

Size/Duplication

Total Lines 371
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 15
Bugs 2 Features 2
Metric Value
dl 0
loc 371
rs 7.8571
c 15
b 2
f 2
wmc 26
lcom 1
cbo 17

25 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 14 1
A test_it_does_not_skip_the_copy_for_userland_datetimezone() 0 10 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 DateTime;
6
use DateTimeImmutable;
7
use DateTimeZone;
8
use DeepCopy\DeepCopy;
9
use DeepCopy\Exception\CloneException;
10
use DeepCopy\f001;
11
use DeepCopy\f002;
12
use DeepCopy\f003;
13
use DeepCopy\f004;
14
use DeepCopy\f005;
15
use DeepCopy\f006;
16
use DeepCopy\f008;
17
use DeepCopy\Filter\KeepFilter;
18
use DeepCopy\Filter\SetNullFilter;
19
use DeepCopy\Matcher\PropertyNameMatcher;
20
use DeepCopy\Matcher\PropertyTypeMatcher;
21
use DeepCopy\TypeFilter\ShallowCopyFilter;
22
use DeepCopy\TypeMatcher\TypeMatcher;
23
use PHPUnit_Framework_TestCase;
24
use SplDoublyLinkedList;
25
use stdClass;
26
use function DeepCopy\deep_copy;
27
28
/**
29
 * @covers \DeepCopy\DeepCopy
30
 */
31
class DeepCopyTest extends PHPUnit_Framework_TestCase
32
{
33
    /**
34
     * @dataProvider provideScalarValues
35
     */
36
    public function test_it_can_copy_scalar_values($value)
37
    {
38
        $copy = deep_copy($value);
39
40
        $this->assertSame($value, $copy);
41
    }
42
43
    public function provideScalarValues()
44
    {
45
        return [
46
            [true],
47
            ['string'],
48
            [null],
49
            [10],
50
            [-1],
51
            [.5],
52
        ];
53
    }
54
55
    public function test_it_can_copy_an_array_of_scalar_values()
56
    {
57
        $copy = deep_copy([10, 20]);
58
59
        $this->assertSame([10, 20], $copy);
60
    }
61
62
    public function test_it_can_copy_an_object()
63
    {
64
        $object = new stdClass();
65
66
        $copy = deep_copy($object);
67
68
        $this->assertEqualButNotSame($object, $copy);
69
    }
70
71
    public function test_it_can_copy_an_array_of_objects()
72
    {
73
        $object = [new stdClass()];
74
75
        $copy = deep_copy($object);
76
77
        $this->assertEqualButNotSame($object, $copy);
78
        $this->assertEqualButNotSame($object[0], $copy[0]);
79
    }
80
81
    /**
82
     * @dataProvider provideObjectWithScalarValues
83
     */
84
    public function test_it_can_copy_an_object_with_scalar_properties($object, $expectedVal)
85
    {
86
        $copy = deep_copy($object);
87
88
        $this->assertEqualButNotSame($object, $copy);
89
        $this->assertSame($expectedVal, $copy->prop);
90
    }
91
92
    public function provideObjectWithScalarValues()
93
    {
94
        $createObject = function ($val) {
95
            $object = new stdClass();
96
97
            $object->prop = $val;
98
99
            return $object;
100
        };
101
102
        return array_map(
103
            function (array $vals) use ($createObject) {
104
                return [$createObject($vals[0]), $vals[0]];
105
            },
106
            $this->provideScalarValues()
107
        );
108
    }
109
110
    public function test_it_can_copy_an_object_with_an_object_property()
111
    {
112
        $foo = new stdClass();
113
        $bar = new stdClass();
114
115
        $foo->bar = $bar;
116
117
        $copy = deep_copy($foo);
118
119
        $this->assertEqualButNotSame($foo, $copy);
120
        $this->assertEqualButNotSame($foo->bar, $copy->bar);
121
    }
122
123
    public function test_it_copies_dynamic_properties()
124
    {
125
        $foo = new stdClass();
126
        $bar = new stdClass();
127
128
        $foo->bar = $bar;
129
130
        $copy = deep_copy($foo);
131
132
        $this->assertEqualButNotSame($foo, $copy);
133
        $this->assertEqualButNotSame($foo->bar, $copy->bar);
134
    }
135
136
    /**
137
     * @ticket https://github.com/myclabs/DeepCopy/issues/38
138
     * @ticket https://github.com/myclabs/DeepCopy/pull/70
139
     */
140
    public function test_it_can_copy_an_object_with_a_date_object_property()
141
    {
142
        $object = new stdClass();
143
144
        $object->d1 = new DateTime();
145
        $object->d2 = new DateTimeImmutable();
146
        $object->dtz = new DateTimeZone('UTC');
147
148
        $copy = deep_copy($object);
149
150
        $this->assertEqualButNotSame($object->d1, $copy->d1);
151
        $this->assertEqualButNotSame($object->d2, $copy->d2);
152
        $this->assertEqualButNotSame($object->dtz, $copy->dtz);
153
    }
154
155
    /**
156
     * @ticket https://github.com/myclabs/DeepCopy/pull/70g
157
     */
158
    public function test_it_does_not_skip_the_copy_for_userland_datetimezone()
159
    {
160
        $object = new stdClass();
161
162
        $object->dtz = new DateTimeZone('UTC');
163
164
        $copy = deep_copy($object);
165
166
        $this->assertEqualButNotSame($object->dtz, $copy->dtz);
167
    }
168
169
    public function test_it_copies_the_private_properties_of_the_parent_class()
170
    {
171
        $object = new f001\B();
172
173
        $object->setAProp($aStdClass = new stdClass());
174
        $object->setBProp($bStdClass = new stdClass());
175
176
        /** @var f001\B $copy */
177
        $copy = deep_copy($object);
178
179
        $this->assertEqualButNotSame($aStdClass, $copy->getAProp());
180
        $this->assertEqualButNotSame($bStdClass, $copy->getBProp());
181
    }
182
183
    public function test_it_keeps_reference_of_the_copied_objects_when_copying_the_graph()
184
    {
185
        $a = new f002\A();
186
187
        $b = new stdClass();
188
        $c = new stdClass();
189
190
        $a->setProp1($b);
191
        $a->setProp2($c);
192
193
        $b->c = $c;
194
195
        /** @var f002\A $copy */
196
        $copy = deep_copy($a);
197
198
        $this->assertEqualButNotSame($a, $copy);
199
        $this->assertEqualButNotSame($b, $copy->getProp1());
200
        $this->assertEqualButNotSame($c, $copy->getProp2());
201
202
        $this->assertSame($copy->getProp1()->c, $copy->getProp2());
203
    }
204
205
    public function test_it_can_copy_graphs_with_circular_references()
206
    {
207
        $a = new stdClass();
208
        $b = new stdClass();
209
210
        $a->prop = $b;
211
        $b->prop = $a;
212
213
        $copy = deep_copy($a);
214
215
        $this->assertEqualButNotSame($a, $copy);
216
        $this->assertEqualButNotSame($b, $copy->prop);
217
218
        $this->assertSame($copy, $copy->prop->prop);
219
    }
220
221
    public function test_it_can_copy_graphs_with_circular_references_with_userland_class()
222
    {
223
        $a = new f003\Foo('a');
224
        $b = new f003\Foo('b');
225
226
        $a->setProp($b);
227
        $b->setProp($a);
228
229
        /** @var f003\Foo $copy */
230
        $copy = deep_copy($a);
231
232
        $this->assertEqualButNotSame($a, $copy);
233
        $this->assertEqualButNotSame($b, $copy->getProp());
234
235
        $this->assertSame($copy, $copy->getProp()->getProp());
236
    }
237
238
    public function test_it_cannot_copy_unclonable_items()
239
    {
240
        $object = new f004\UnclonableItem();
241
242
        try {
243
            deep_copy($object);
244
245
            $this->fail('Expected exception to be thrown.');
246
        } catch (CloneException $exception) {
247
            $this->assertSame(
248
                sprintf(
249
                    'The class "%s" is not cloneable.',
250
                    f004\UnclonableItem::class
251
                ),
252
                $exception->getMessage()
253
            );
254
            $this->assertSame(0, $exception->getCode());
255
            $this->assertNull($exception->getPrevious());
256
        }
257
    }
258
259
    public function test_it_can_skip_uncloneable_objects()
260
    {
261
        $object = new f004\UnclonableItem();
262
263
        $deepCopy = new DeepCopy();
264
        $deepCopy->skipUncloneable(true);
265
266
        $copy = $deepCopy->copy($object);
267
268
        $this->assertSame($object, $copy);
269
    }
270
271
    public function test_it_uses_the_userland_defined_cloned_method()
272
    {
273
        $object = new f005\Foo();
274
275
        $copy = deep_copy($object);
276
277
        $this->assertTrue($copy->cloned);
278
    }
279
280
    public function test_it_only_uses_the_userland_defined_cloned_method_when_configured_to_do_so()
281
    {
282
        $object = new f005\Foo();
283
        $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...
284
285
        $copy = deep_copy($object, true);
286
287
        $this->assertTrue($copy->cloned);
288
        $this->assertSame($object->foo, $copy->foo);
289
    }
290
291
    public function test_it_uses_type_filter_to_copy_objects_if_matcher_matches()
292
    {
293
        $deepCopy = new DeepCopy();
294
        $deepCopy->addTypeFilter(
295
            new ShallowCopyFilter(),
296
            new TypeMatcher(f006\A::class)
297
        );
298
299
        $a = new f006\A;
300
        $b = new f006\B;
301
302
        $a->setAProp($b);
303
304
        /** @var f006\A $copy */
305
        $copy = $deepCopy->copy($a);
306
307
        $this->assertTrue($copy->cloned);
308
        $this->assertFalse($copy->getAProp()->cloned);
309
        $this->assertSame($b, $copy->getAProp());
310
    }
311
312
    public function test_it_uses_filters_to_copy_object_properties_if_matcher_matches()
313
    {
314
        $deepCopy = new DeepCopy();
315
        $deepCopy->addFilter(
316
            new SetNullFilter(),
317
            new PropertyNameMatcher('cloned')
318
        );
319
320
        $a = new f006\A;
321
        $b = new f006\B;
322
323
        $a->setAProp($b);
324
325
        /** @var f006\A $copy */
326
        $copy = $deepCopy->copy($a);
327
328
        $this->assertNull($copy->cloned);
329
        $this->assertNull($copy->getAProp()->cloned);
330
    }
331
332
    public function test_it_uses_the_first_filter_matching_for_copying_object_properties()
333
    {
334
        $deepCopy = new DeepCopy();
335
        $deepCopy->addFilter(
336
            new SetNullFilter(),
337
            new PropertyNameMatcher('cloned')
338
        );
339
        $deepCopy->addFilter(
340
            new KeepFilter(),
341
            new PropertyNameMatcher('cloned')
342
        );
343
344
        $a = new f006\A;
345
        $b = new f006\B;
346
347
        $a->setAProp($b);
348
349
        /** @var f006\A $copy */
350
        $copy = $deepCopy->copy($a);
351
352
        $this->assertNull($copy->cloned);
353
        $this->assertNull($copy->getAProp()->cloned);
354
    }
355
356
    /**
357
     * @ticket https://github.com/myclabs/DeepCopy/pull/49
358
     */
359
    public function test_it_can_copy_a_SplDoublyLinkedList()
360
    {
361
        $object = new SplDoublyLinkedList();
362
363
        $a = new stdClass();
364
        $b = new stdClass();
365
366
        $a->b = $b;
367
368
        $object->push($a);
369
370
        /** @var SplDoublyLinkedList $copy */
371
        $copy = deep_copy($object);
372
373
        $this->assertEqualButNotSame($object, $copy);
374
375
        $aCopy = $copy->pop();
376
377
        $this->assertEqualButNotSame($b, $aCopy->b);
378
    }
379
380
    /**
381
     * @ticket https://github.com/myclabs/DeepCopy/issues/62
382
     */
383
    public function test_matchers_can_access_to_parent_private_properties()
384
    {
385
        $deepCopy = new DeepCopy();
386
        $deepCopy->addFilter(new SetNullFilter(), new PropertyTypeMatcher(stdClass::class));
387
388
        $object = new f008\B(new stdClass());
389
390
        /** @var f008\B $copy */
391
        $copy = $deepCopy->copy($object);
392
393
        $this->assertNull($copy->getFoo());
394
    }
395
396
    private function assertEqualButNotSame($expected, $val)
397
    {
398
        $this->assertEquals($expected, $val);
399
        $this->assertNotSame($expected, $val);
400
    }
401
}
402