Passed
Pull Request — master (#1)
by Kevin
02:39
created

FactoryTest::can_create_many_objects()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 15
nc 1
nop 0
dl 0
loc 21
rs 9.7666
c 0
b 0
f 0
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 = 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

25
        $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...
26
27
        $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

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

41
        $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...
42
43
        $objects = (new Factory(Post::class, $attributeArray))->withoutPersisting()->createMany(3);
44
45
        $this->assertCount(3, $objects);
46
        $this->assertSame('title', $objects[0]->getTitle());
47
        $this->assertSame('title', $objects[1]->getTitle());
48
        $this->assertSame('title', $objects[2]->getTitle());
49
50
        $objects = (new Factory(Post::class))->withoutPersisting()->createMany(3, $attributeArray);
51
52
        $this->assertCount(3, $objects);
53
        $this->assertSame('title', $objects[0]->getTitle());
54
        $this->assertSame('title', $objects[1]->getTitle());
55
        $this->assertSame('title', $objects[2]->getTitle());
56
57
        $objects = (new Factory(Post::class))->withAttributes($attributeArray)->withoutPersisting()->createMany(3);
58
59
        $this->assertCount(3, $objects);
60
        $this->assertSame('title', $objects[0]->getTitle());
61
        $this->assertSame('title', $objects[1]->getTitle());
62
        $this->assertSame('title', $objects[2]->getTitle());
63
64
        $objects = (new Factory(Post::class, $attributeCallback))->withoutPersisting()->createMany(3);
65
66
        $this->assertCount(3, $objects);
67
        $this->assertSame('title', $objects[0]->getTitle());
68
        $this->assertSame('title', $objects[1]->getTitle());
69
        $this->assertSame('title', $objects[2]->getTitle());
70
71
        $objects = (new Factory(Post::class))->withoutPersisting()->createMany(3, $attributeCallback);
72
73
        $this->assertCount(3, $objects);
74
        $this->assertSame('title', $objects[0]->getTitle());
75
        $this->assertSame('title', $objects[1]->getTitle());
76
        $this->assertSame('title', $objects[2]->getTitle());
77
78
        $objects = (new Factory(Post::class))->withAttributes($attributeCallback)->withoutPersisting()->createMany(3);
79
80
        $this->assertCount(3, $objects);
81
        $this->assertSame('title', $objects[0]->getTitle());
82
        $this->assertSame('title', $objects[1]->getTitle());
83
        $this->assertSame('title', $objects[2]->getTitle());
84
    }
85
86
    /**
87
     * @test
88
     */
89
    public function can_set_instantiator(): void
90
    {
91
        $attributeArray = ['title' => 'original title', 'body' => 'original body'];
92
93
        $object = (new Factory(Post::class))
94
            ->instantiator(function(array $attributes, string $class) use ($attributeArray) {
95
                $this->assertSame(Post::class, $class);
96
                $this->assertSame($attributes, $attributeArray);
97
98
                return new Post('title', 'body');
99
            })
100
            ->withoutPersisting()
101
            ->create($attributeArray)
102
        ;
103
104
        $this->assertSame('title', $object->getTitle());
105
        $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

105
        $this->assertSame('body', $object->/** @scrutinizer ignore-call */ getBody());
Loading history...
106
    }
107
108
    /**
109
     * @test
110
     */
111
    public function can_add_before_instantiate_events(): void
112
    {
113
        $attributeArray = ['title' => 'original title', 'body' => 'original body'];
114
115
        $object = (new Factory(Post::class))
116
            ->beforeInstantiate(function(array $attributes) {
117
                $attributes['title'] = 'title';
118
119
                return $attributes;
120
            })
121
            ->beforeInstantiate(function(array $attributes) {
122
                $attributes['body'] = 'body';
123
124
                return $attributes;
125
            })
126
            ->withoutPersisting()
127
            ->create($attributeArray)
128
        ;
129
130
        $this->assertSame('title', $object->getTitle());
131
        $this->assertSame('body', $object->getBody());
132
    }
133
134
    /**
135
     * @test
136
     */
137
    public function before_instantiate_event_must_return_an_array(): void
138
    {
139
        $this->expectException(\LogicException::class);
140
        $this->expectExceptionMessage('Before Instantiate event callback must return an array.');
141
142
        (new Factory(Post::class))->beforeInstantiate(function() {})->withoutPersisting()->create();
143
    }
144
145
    /**
146
     * @test
147
     */
148
    public function can_add_after_instantiate_events(): void
149
    {
150
        $attributesArray = ['title' => 'title', 'body' => 'body'];
151
152
        $object = (new Factory(Post::class))
153
            ->afterInstantiate(function(Post $post, array $attributes) use ($attributesArray) {
154
                $this->assertSame($attributesArray, $attributes);
155
156
                $post->increaseViewCount();
157
            })
158
            ->afterInstantiate(function(Post $post, array $attributes) use ($attributesArray) {
159
                $this->assertSame($attributesArray, $attributes);
160
161
                $post->increaseViewCount();
162
            })
163
            ->withoutPersisting()
164
            ->create($attributesArray)
165
        ;
166
167
        $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

167
        $this->assertSame(2, $object->/** @scrutinizer ignore-call */ getViewCount());
Loading history...
168
    }
169
170
    /**
171
     * @test
172
     */
173
    public function can_register_custom_faker(): void
174
    {
175
        $defaultFaker = Factory::faker();
176
        Factory::configuration()->setFaker(new Faker\Generator());
177
178
        $this->assertNotSame(\spl_object_id(Factory::faker()), \spl_object_id($defaultFaker));
179
    }
180
181
    /**
182
     * @test
183
     */
184
    public function can_register_default_instantiator(): void
185
    {
186
        $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

186
        $this->configuration->/** @scrutinizer ignore-call */ 
187
                              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...
187
            return new Post('different title', 'different body');
188
        });
189
190
        $object = (new Factory(Post::class, ['title' => 'title', 'body' => 'body']))->withoutPersisting()->create();
191
192
        $this->assertSame('different title', $object->getTitle());
193
        $this->assertSame('different body', $object->getBody());
194
    }
195
196
    /**
197
     * @test
198
     */
199
    public function instantiating_with_proxy_attribute_normalizes_to_underlying_object(): void
200
    {
201
        $object = (new Factory(Post::class))->withoutPersisting()->create([
202
            'title' => 'title',
203
            'body' => 'body',
204
            'category' => new Proxy(new Category()),
205
        ]);
206
207
        $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

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