Passed
Pull Request — master (#1)
by Kevin
12:50
created

FactoryTest::can_persist_many_objects()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 15
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 21
rs 9.7666
1
<?php
2
3
namespace Zenstruck\Foundry\Tests\Unit;
4
5
use Doctrine\Persistence\ManagerRegistry;
6
use Doctrine\Persistence\ObjectManager;
7
use Faker;
8
use Zenstruck\Foundry\Factory;
9
use Zenstruck\Foundry\Proxy;
10
use Zenstruck\Foundry\Tests\Fixtures\Entity\Category;
11
use Zenstruck\Foundry\Tests\Fixtures\Entity\Post;
12
use Zenstruck\Foundry\Tests\UnitTestCase;
13
14
/**
15
 * @author Kevin Bond <[email protected]>
16
 */
17
final class FactoryTest extends UnitTestCase
18
{
19
    /**
20
     * @test
21
     */
22
    public function can_instantiate_object(): void
23
    {
24
        $attributeArray = ['title' => 'title', 'body' => 'body'];
25
        $attributeCallback = static function(Faker\Generator $faker) {
0 ignored issues
show
Unused Code introduced by
The parameter $faker is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

25
        $attributeCallback = static function(/** @scrutinizer ignore-unused */ Faker\Generator $faker) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
26
            return ['title' => 'title', 'body' => 'body'];
27
        };
28
29
        $this->assertSame('title', (new Factory(Post::class, $attributeArray))->withoutPersisting()->create()->getTitle());
0 ignored issues
show
Bug introduced by
The method getTitle() does not exist on Zenstruck\Foundry\Proxy. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

29
        $this->assertSame('title', (new Factory(Post::class, $attributeArray))->withoutPersisting()->create()->/** @scrutinizer ignore-call */ getTitle());
Loading history...
30
        $this->assertSame('title', (new Factory(Post::class))->withoutPersisting()->create($attributeArray)->getTitle());
31
        $this->assertSame('title', (new Factory(Post::class))->withoutPersisting()->withAttributes($attributeArray)->create()->getTitle());
32
        $this->assertSame('title', (new Factory(Post::class, $attributeCallback))->withoutPersisting()->create()->getTitle());
33
        $this->assertSame('title', (new Factory(Post::class))->withoutPersisting()->create($attributeCallback)->getTitle());
34
        $this->assertSame('title', (new Factory(Post::class))->withAttributes($attributeCallback)->withoutPersisting()->create()->getTitle());
35
    }
36
37
    /**
38
     * @test
39
     */
40
    public function can_instantiate_many_objects(): void
41
    {
42
        $attributeArray = ['title' => 'title', 'body' => 'body'];
43
        $attributeCallback = static function(Faker\Generator $faker) {
0 ignored issues
show
Unused Code introduced by
The parameter $faker is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

43
        $attributeCallback = static function(/** @scrutinizer ignore-unused */ Faker\Generator $faker) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
44
            return ['title' => 'title', 'body' => 'body'];
45
        };
46
47
        $objects = (new Factory(Post::class, $attributeArray))->withoutPersisting()->createMany(3);
48
49
        $this->assertCount(3, $objects);
50
        $this->assertSame('title', $objects[0]->getTitle());
51
        $this->assertSame('title', $objects[1]->getTitle());
52
        $this->assertSame('title', $objects[2]->getTitle());
53
54
        $objects = (new Factory(Post::class))->withoutPersisting()->createMany(3, $attributeArray);
55
56
        $this->assertCount(3, $objects);
57
        $this->assertSame('title', $objects[0]->getTitle());
58
        $this->assertSame('title', $objects[1]->getTitle());
59
        $this->assertSame('title', $objects[2]->getTitle());
60
61
        $objects = (new Factory(Post::class))->withAttributes($attributeArray)->withoutPersisting()->createMany(3);
62
63
        $this->assertCount(3, $objects);
64
        $this->assertSame('title', $objects[0]->getTitle());
65
        $this->assertSame('title', $objects[1]->getTitle());
66
        $this->assertSame('title', $objects[2]->getTitle());
67
68
        $objects = (new Factory(Post::class, $attributeCallback))->withoutPersisting()->createMany(3);
69
70
        $this->assertCount(3, $objects);
71
        $this->assertSame('title', $objects[0]->getTitle());
72
        $this->assertSame('title', $objects[1]->getTitle());
73
        $this->assertSame('title', $objects[2]->getTitle());
74
75
        $objects = (new Factory(Post::class))->withoutPersisting()->createMany(3, $attributeCallback);
76
77
        $this->assertCount(3, $objects);
78
        $this->assertSame('title', $objects[0]->getTitle());
79
        $this->assertSame('title', $objects[1]->getTitle());
80
        $this->assertSame('title', $objects[2]->getTitle());
81
82
        $objects = (new Factory(Post::class))->withAttributes($attributeCallback)->withoutPersisting()->createMany(3);
83
84
        $this->assertCount(3, $objects);
85
        $this->assertSame('title', $objects[0]->getTitle());
86
        $this->assertSame('title', $objects[1]->getTitle());
87
        $this->assertSame('title', $objects[2]->getTitle());
88
    }
89
90
    /**
91
     * @test
92
     */
93
    public function can_set_instantiator(): void
94
    {
95
        $attributeArray = ['title' => 'original title', 'body' => 'original body'];
96
97
        $object = (new Factory(Post::class))
98
            ->instantiateWith(function(array $attributes, string $class) use ($attributeArray) {
99
                $this->assertSame(Post::class, $class);
100
                $this->assertSame($attributes, $attributeArray);
101
102
                return new Post('title', 'body');
103
            })
104
            ->withoutPersisting()
105
            ->create($attributeArray)
106
        ;
107
108
        $this->assertSame('title', $object->getTitle());
109
        $this->assertSame('body', $object->getBody());
0 ignored issues
show
Bug introduced by
The method getBody() does not exist on Zenstruck\Foundry\Proxy. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

109
        $this->assertSame('body', $object->/** @scrutinizer ignore-call */ getBody());
Loading history...
110
    }
111
112
    /**
113
     * @test
114
     */
115
    public function can_add_before_instantiate_events(): void
116
    {
117
        $attributeArray = ['title' => 'original title', 'body' => 'original body'];
118
119
        $object = (new Factory(Post::class))
120
            ->beforeInstantiate(function(array $attributes) {
121
                $attributes['title'] = 'title';
122
123
                return $attributes;
124
            })
125
            ->beforeInstantiate(function(array $attributes) {
126
                $attributes['body'] = 'body';
127
128
                return $attributes;
129
            })
130
            ->withoutPersisting()
131
            ->create($attributeArray)
132
        ;
133
134
        $this->assertSame('title', $object->getTitle());
135
        $this->assertSame('body', $object->getBody());
136
    }
137
138
    /**
139
     * @test
140
     */
141
    public function before_instantiate_event_must_return_an_array(): void
142
    {
143
        $this->expectException(\LogicException::class);
144
        $this->expectExceptionMessage('Before Instantiate event callback must return an array.');
145
146
        (new Factory(Post::class))->beforeInstantiate(function() {})->withoutPersisting()->create();
147
    }
148
149
    /**
150
     * @test
151
     */
152
    public function can_add_after_instantiate_events(): void
153
    {
154
        $attributesArray = ['title' => 'title', 'body' => 'body'];
155
156
        $object = (new Factory(Post::class))
157
            ->afterInstantiate(function(Post $post, array $attributes) use ($attributesArray) {
158
                $this->assertSame($attributesArray, $attributes);
159
160
                $post->increaseViewCount();
161
            })
162
            ->afterInstantiate(function(Post $post, array $attributes) use ($attributesArray) {
163
                $this->assertSame($attributesArray, $attributes);
164
165
                $post->increaseViewCount();
166
            })
167
            ->withoutPersisting()
168
            ->create($attributesArray)
169
        ;
170
171
        $this->assertSame(2, $object->getViewCount());
0 ignored issues
show
Bug introduced by
The method getViewCount() does not exist on Zenstruck\Foundry\Proxy. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

171
        $this->assertSame(2, $object->/** @scrutinizer ignore-call */ getViewCount());
Loading history...
172
    }
173
174
    /**
175
     * @test
176
     */
177
    public function can_register_custom_faker(): void
178
    {
179
        $defaultFaker = Factory::faker();
180
        Factory::configuration()->setFaker(new Faker\Generator());
181
182
        $this->assertNotSame(\spl_object_id(Factory::faker()), \spl_object_id($defaultFaker));
183
    }
184
185
    /**
186
     * @test
187
     */
188
    public function can_register_default_instantiator(): void
189
    {
190
        $this->configuration->setInstantiator(function() {
0 ignored issues
show
Bug introduced by
The method setInstantiator() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

190
        $this->configuration->/** @scrutinizer ignore-call */ 
191
                              setInstantiator(function() {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
191
            return new Post('different title', 'different body');
192
        });
193
194
        $object = (new Factory(Post::class, ['title' => 'title', 'body' => 'body']))->withoutPersisting()->create();
195
196
        $this->assertSame('different title', $object->getTitle());
197
        $this->assertSame('different body', $object->getBody());
198
    }
199
200
    /**
201
     * @test
202
     */
203
    public function instantiating_with_proxy_attribute_normalizes_to_underlying_object(): void
204
    {
205
        $object = (new Factory(Post::class))->withoutPersisting()->create([
206
            'title' => 'title',
207
            'body' => 'body',
208
            'category' => new Proxy(new Category()),
209
        ]);
210
211
        $this->assertInstanceOf(Category::class, $object->getCategory());
0 ignored issues
show
Bug introduced by
The method getCategory() does not exist on Zenstruck\Foundry\Proxy. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

211
        $this->assertInstanceOf(Category::class, $object->/** @scrutinizer ignore-call */ getCategory());
Loading history...
212
    }
213
214
    /**
215
     * @test
216
     */
217
    public function instantiating_with_factory_attribute_instantiates_the_factory(): void
218
    {
219
        $object = (new Factory(Post::class))->withoutPersisting()->create([
220
            'title' => 'title',
221
            'body' => 'body',
222
            'category' => new Factory(Category::class),
223
        ]);
224
225
        $this->assertInstanceOf(Category::class, $object->getCategory());
226
    }
227
228
    /**
229
     * @test
230
     */
231
    public function factory_is_immutable(): void
232
    {
233
        $factory = new Factory(Post::class);
234
        $objectId = \spl_object_id($factory);
235
236
        $this->assertNotSame(\spl_object_id($factory->withAttributes([])), $objectId);
237
        $this->assertNotSame(\spl_object_id($factory->withoutPersisting()), $objectId);
238
        $this->assertNotSame(\spl_object_id($factory->instantiateWith(function() {})), $objectId);
239
        $this->assertNotSame(\spl_object_id($factory->beforeInstantiate(function() {})), $objectId);
240
        $this->assertNotSame(\spl_object_id($factory->afterInstantiate(function() {})), $objectId);
241
        $this->assertNotSame(\spl_object_id($factory->afterPersist(function() {})), $objectId);
242
    }
243
244
    /**
245
     * @test
246
     */
247
    public function can_create_object(): void
248
    {
249
        $registry = $this->createMock(ManagerRegistry::class);
250
        $registry
251
            ->expects($this->exactly(2))
252
            ->method('getManagerForClass')
253
            ->with(Post::class)
254
            ->willReturn($this->createMock(ObjectManager::class))
255
        ;
256
257
        $this->configuration->setManagerRegistry($registry);
258
259
        $object = (new Factory(Post::class))->create(['title' => 'title', 'body' => 'body']);
260
261
        $this->assertInstanceOf(Proxy::class, $object);
262
        $this->assertSame('title', $object->disableAutoRefresh()->getTitle());
263
    }
264
265
    /**
266
     * @test
267
     */
268
    public function can_create_many_objects(): void
269
    {
270
        $registry = $this->createMock(ManagerRegistry::class);
271
        $registry
272
            ->expects($this->exactly(6))
273
            ->method('getManagerForClass')
274
            ->with(Post::class)
275
            ->willReturn($this->createMock(ObjectManager::class))
276
        ;
277
278
        $this->configuration->setManagerRegistry($registry);
279
280
        $objects = (new Factory(Post::class))->createMany(3, ['title' => 'title', 'body' => 'body']);
281
282
        $this->assertCount(3, $objects);
283
        $this->assertInstanceOf(Proxy::class, $objects[0]);
284
        $this->assertInstanceOf(Proxy::class, $objects[1]);
285
        $this->assertInstanceOf(Proxy::class, $objects[2]);
286
        $this->assertSame('title', $objects[0]->disableAutoRefresh()->getTitle());
287
        $this->assertSame('title', $objects[1]->disableAutoRefresh()->getTitle());
288
        $this->assertSame('title', $objects[2]->disableAutoRefresh()->getTitle());
289
    }
290
291
    /**
292
     * @test
293
     */
294
    public function can_add_after_persist_events(): void
295
    {
296
        $registry = $this->createMock(ManagerRegistry::class);
297
        $registry
298
            ->expects($this->exactly(2)) // once for persisting, once for each afterPersist event
299
            ->method('getManagerForClass')
300
            ->with(Post::class)
301
            ->willReturn($this->createMock(ObjectManager::class))
302
        ;
303
304
        $this->configuration->setManagerRegistry($registry);
305
306
        $attributesArray = ['title' => 'title', 'body' => 'body'];
307
        $calls = 0;
308
309
        $object = (new Factory(Post::class))
310
            ->afterPersist(function(Proxy $post, array $attributes) use ($attributesArray, &$calls) {
311
                /* @var Post $post */
312
                $this->assertSame($attributesArray, $attributes);
313
314
                $post->increaseViewCount();
315
                ++$calls;
316
            })
317
            ->afterPersist(function(Post $post, array $attributes) use ($attributesArray, &$calls) {
318
                $this->assertSame($attributesArray, $attributes);
319
320
                $post->increaseViewCount();
321
                ++$calls;
322
            })
323
            ->afterPersist(function(Post $post, array $attributes) use ($attributesArray, &$calls) {
324
                $this->assertSame($attributesArray, $attributes);
325
326
                $post->increaseViewCount();
327
                ++$calls;
328
            })
329
            ->afterPersist(function($post) use (&$calls) {
330
                $this->assertInstanceOf(Proxy::class, $post);
331
332
                ++$calls;
333
            })
334
            ->afterPersist(static function() use (&$calls) {
335
                ++$calls;
336
            })
337
            ->create($attributesArray)
338
        ;
339
340
        $this->assertSame(3, $object->disableAutoRefresh()->getViewCount());
341
        $this->assertSame(5, $calls);
342
    }
343
}
344