Completed
Push — 1.x ( 66a912...7a84e1 )
by Théo
01:22
created

test_it_uses_the_userland_defined_cloned_method()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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