Completed
Push — 1.x ( 7a84e1...770e50 )
by Théo
01:33
created

test_it_does_not_skip_the_copy_for_userland_datetimezone()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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