Passed
Pull Request — master (#1)
by Kevin
02:02
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 PHPUnit\Framework\TestCase;
9
use Zenstruck\Foundry\Factory;
10
use Zenstruck\Foundry\PersistenceManager;
11
use Zenstruck\Foundry\Proxy;
12
use Zenstruck\Foundry\Tests\Fixtures\Entity\Category;
13
use Zenstruck\Foundry\Tests\Fixtures\Entity\Post;
14
use Zenstruck\Foundry\Tests\ResetGlobals;
15
16
/**
17
 * @author Kevin Bond <[email protected]>
18
 */
19
final class FactoryTest extends TestCase
20
{
21
    use ResetGlobals;
22
23
    /**
24
     * @test
25
     */
26
    public function can_instantiate_object(): void
27
    {
28
        $attributeArray = ['title' => 'title', 'body' => 'body'];
29
        $attributeCallback = fn(Faker\Generator $faker) => ['title' => 'title', 'body' => 'body'];
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

29
        $attributeCallback = fn(/** @scrutinizer ignore-unused */ Faker\Generator $faker) => ['title' => 'title', 'body' => 'body'];

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...
30
31
        $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

31
        $this->assertSame('title', (new Factory(Post::class, $attributeArray))->withoutPersisting()->create()->/** @scrutinizer ignore-call */ getTitle());
Loading history...
32
        $this->assertSame('title', (new Factory(Post::class))->withoutPersisting()->create($attributeArray)->getTitle());
33
        $this->assertSame('title', (new Factory(Post::class))->withoutPersisting()->withAttributes($attributeArray)->create()->getTitle());
34
        $this->assertSame('title', (new Factory(Post::class, $attributeCallback))->withoutPersisting()->create()->getTitle());
35
        $this->assertSame('title', (new Factory(Post::class))->withoutPersisting()->create($attributeCallback)->getTitle());
36
        $this->assertSame('title', (new Factory(Post::class))->withAttributes($attributeCallback)->withoutPersisting()->create()->getTitle());
37
    }
38
39
    /**
40
     * @test
41
     */
42
    public function can_instantiate_many_objects(): void
43
    {
44
        $attributeArray = ['title' => 'title', 'body' => 'body'];
45
        $attributeCallback = fn(Faker\Generator $faker) => ['title' => 'title', 'body' => 'body'];
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

45
        $attributeCallback = fn(/** @scrutinizer ignore-unused */ Faker\Generator $faker) => ['title' => 'title', 'body' => 'body'];

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...
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
            ->instantiator(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
        $faker = Factory::faker();
180
181
        Factory::registerFaker(new Faker\Generator());
182
183
        $this->assertNotSame(\spl_object_id(Factory::faker()), \spl_object_id($faker));
184
    }
185
186
    /**
187
     * @test
188
     */
189
    public function can_register_default_instantiator(): void
190
    {
191
        Factory::registerDefaultInstantiator(function() {
192
            return new Post('different title', 'different body');
193
        });
194
195
        $object = (new Factory(Post::class, ['title' => 'title', 'body' => 'body']))->withoutPersisting()->create();
196
197
        $this->assertSame('different title', $object->getTitle());
198
        $this->assertSame('different body', $object->getBody());
199
    }
200
201
    /**
202
     * @test
203
     */
204
    public function instantiating_with_proxy_attribute_normalizes_to_underlying_object(): void
205
    {
206
        $object = (new Factory(Post::class))->withoutPersisting()->create([
207
            'title' => 'title',
208
            'body' => 'body',
209
            'category' => new Proxy(new Category()),
210
        ]);
211
212
        $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

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