Passed
Pull Request — master (#216)
by Charly
05:12 queued 01:12
created

disable_doctrine_events_lifecycle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 13
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Zenstruck\Foundry\Tests\Functional;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
7
use Zenstruck\Foundry\Test\Factories;
8
use Zenstruck\Foundry\Test\ResetDatabase;
9
use Zenstruck\Foundry\Tests\Fixtures\Entity\Category;
10
use Zenstruck\Foundry\Tests\Fixtures\Event\CommentEventSubscriber;
11
use Zenstruck\Foundry\Tests\Fixtures\Factories\AddressFactory;
12
use Zenstruck\Foundry\Tests\Fixtures\Factories\CategoryFactory;
13
use Zenstruck\Foundry\Tests\Fixtures\Factories\CommentFactory;
14
use Zenstruck\Foundry\Tests\Fixtures\Factories\ContactFactory;
15
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactory;
16
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactoryWithInvalidInitialize;
17
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactoryWithNullInitialize;
18
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactoryWithValidInitialize;
19
use Zenstruck\Foundry\Tests\Fixtures\Factories\TagFactory;
20
use Zenstruck\Foundry\Tests\Fixtures\Factories\UserFactory;
21
22
/**
23
 * @author Kevin Bond <[email protected]>
24
 */
25
final class ModelFactoryTest extends KernelTestCase
26
{
27
    use ContainerBC, Factories, ResetDatabase;
28
29
    /**
30
     * @test
31
     */
32
    public function can_find_or_create(): void
33
    {
34
        CategoryFactory::assert()->count(0);
35
        CategoryFactory::findOrCreate(['name' => 'php']);
36
        CategoryFactory::assert()->count(1);
37
        CategoryFactory::findOrCreate(['name' => 'php']);
38
        CategoryFactory::assert()->count(1);
39
    }
40
41
    /**
42
     * @test
43
     */
44
    public function can_override_initialize(): void
45
    {
46
        $this->assertFalse(PostFactory::createOne()->isPublished());
0 ignored issues
show
Bug introduced by
The method isPublished() 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

46
        $this->assertFalse(PostFactory::createOne()->/** @scrutinizer ignore-call */ isPublished());
Loading history...
47
        $this->assertTrue(PostFactoryWithValidInitialize::createOne()->isPublished());
48
    }
49
50
    /**
51
     * @test
52
     */
53
    public function initialize_must_return_an_instance_of_the_current_factory(): void
54
    {
55
        $this->expectException(\TypeError::class);
56
        $this->expectExceptionMessage(\sprintf('"%1$s::initialize()" must return an instance of "%1$s".', PostFactoryWithInvalidInitialize::class));
57
58
        PostFactoryWithInvalidInitialize::new();
59
    }
60
61
    /**
62
     * @test
63
     */
64
    public function initialize_must_return_a_value(): void
65
    {
66
        $this->expectException(\TypeError::class);
67
        $this->expectExceptionMessage(\sprintf('"%1$s::initialize()" must return an instance of "%1$s".', PostFactoryWithNullInitialize::class));
68
69
        PostFactoryWithNullInitialize::new();
70
    }
71
72
    /**
73
     * @test
74
     */
75
    public function can_find_random_object(): void
76
    {
77
        CategoryFactory::createMany(5);
78
79
        $ids = [];
80
81
        while (5 !== \count(\array_unique($ids))) {
82
            $ids[] = CategoryFactory::random()->getId();
0 ignored issues
show
Bug introduced by
The method getId() 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

82
            $ids[] = CategoryFactory::random()->/** @scrutinizer ignore-call */ getId();
Loading history...
83
        }
84
85
        $this->assertCount(5, \array_unique($ids));
86
    }
87
88
    /**
89
     * @test
90
     */
91
    public function can_create_random_object_if_none_exists(): void
92
    {
93
        CategoryFactory::assert()->count(0);
94
        $this->assertInstanceOf(Category::class, CategoryFactory::randomOrCreate()->object());
95
        CategoryFactory::assert()->count(1);
96
        $this->assertInstanceOf(Category::class, CategoryFactory::randomOrCreate()->object());
97
        CategoryFactory::assert()->count(1);
98
    }
99
100
    /**
101
     * @test
102
     */
103
    public function can_get_or_create_random_object_with_attributes(): void
104
    {
105
        CategoryFactory::createMany(5, ['name' => 'name1']);
106
107
        CategoryFactory::assert()->count(5);
108
        $this->assertSame('name2', CategoryFactory::randomOrCreate(['name' => 'name2'])->getName());
0 ignored issues
show
Bug introduced by
The method getName() 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

108
        $this->assertSame('name2', CategoryFactory::randomOrCreate(['name' => 'name2'])->/** @scrutinizer ignore-call */ getName());
Loading history...
109
        CategoryFactory::assert()->count(6);
110
        $this->assertSame('name2', CategoryFactory::randomOrCreate(['name' => 'name2'])->getName());
111
        CategoryFactory::assert()->count(6);
112
    }
113
114
    /**
115
     * @test
116
     */
117
    public function can_find_random_set_of_objects(): void
118
    {
119
        CategoryFactory::createMany(5);
120
121
        $objects = CategoryFactory::randomSet(3);
122
123
        $this->assertCount(3, $objects);
124
        $this->assertCount(3, \array_unique(\array_map(static function($category) { return $category->getId(); }, $objects)));
125
    }
126
127
    /**
128
     * @test
129
     */
130
    public function can_find_random_set_of_objects_with_attributes(): void
131
    {
132
        CategoryFactory::createMany(20, ['name' => 'name1']);
133
        CategoryFactory::createMany(5, ['name' => 'name2']);
134
135
        $objects = CategoryFactory::randomSet(2, ['name' => 'name2']);
136
137
        $this->assertCount(2, $objects);
138
        $this->assertSame('name2', $objects[0]->getName());
139
        $this->assertSame('name2', $objects[1]->getName());
140
    }
141
142
    /**
143
     * @test
144
     */
145
    public function can_find_random_range_of_objects(): void
146
    {
147
        CategoryFactory::createMany(5);
148
149
        $counts = [];
150
151
        while (4 !== \count(\array_unique($counts))) {
152
            $counts[] = \count(CategoryFactory::randomRange(0, 3));
153
        }
154
155
        $this->assertCount(4, \array_unique($counts));
156
        $this->assertContains(0, $counts);
157
        $this->assertContains(1, $counts);
158
        $this->assertContains(2, $counts);
159
        $this->assertContains(3, $counts);
160
        $this->assertNotContains(4, $counts);
161
        $this->assertNotContains(5, $counts);
162
    }
163
164
    /**
165
     * @test
166
     */
167
    public function can_find_random_range_of_objects_with_attributes(): void
168
    {
169
        CategoryFactory::createMany(20, ['name' => 'name1']);
170
        CategoryFactory::createMany(5, ['name' => 'name2']);
171
172
        $objects = CategoryFactory::randomRange(2, 4, ['name' => 'name2']);
173
174
        $this->assertGreaterThanOrEqual(2, \count($objects));
175
        $this->assertLessThanOrEqual(4, \count($objects));
176
177
        foreach ($objects as $object) {
178
            $this->assertSame('name2', $object->getName());
179
        }
180
    }
181
182
    /**
183
     * @test
184
     */
185
    public function one_to_many_with_nested_collection_relationship(): void
186
    {
187
        $post = PostFactory::createOne([
188
            'comments' => CommentFactory::new()->many(4),
189
        ]);
190
191
        $this->assertCount(4, $post->getComments());
0 ignored issues
show
Bug introduced by
The method getComments() 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

191
        $this->assertCount(4, $post->/** @scrutinizer ignore-call */ getComments());
Loading history...
192
        UserFactory::assert()->count(4);
193
        CommentFactory::assert()->count(4);
194
        PostFactory::assert()->count(1);
195
    }
196
197
    /**
198
     * @test
199
     */
200
    public function create_multiple_one_to_many_with_nested_collection_relationship(): void
201
    {
202
        $user = UserFactory::createOne();
203
        $posts = PostFactory::createMany(2, [
204
            'comments' => CommentFactory::new(['user' => $user])->many(4),
205
        ]);
206
207
        $this->assertCount(4, $posts[0]->getComments());
208
        $this->assertCount(4, $posts[1]->getComments());
209
        UserFactory::assert()->count(1);
210
        CommentFactory::assert()->count(8);
211
        PostFactory::assert()->count(2);
212
    }
213
214
    /**
215
     * @test
216
     */
217
    public function many_to_many_with_nested_collection_relationship(): void
218
    {
219
        $post = PostFactory::createOne([
220
            'tags' => TagFactory::new()->many(3),
221
        ]);
222
223
        $this->assertCount(3, $post->getTags());
0 ignored issues
show
Bug introduced by
The method getTags() 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

223
        $this->assertCount(3, $post->/** @scrutinizer ignore-call */ getTags());
Loading history...
224
        TagFactory::assert()->count(5); // 3 created by this test and 2 in global state
225
        PostFactory::assert()->count(1);
226
    }
227
228
    /**
229
     * @test
230
     */
231
    public function inverse_many_to_many_with_nested_collection_relationship(): void
232
    {
233
        $tag = TagFactory::createOne([
234
            'posts' => PostFactory::new()->many(3),
235
        ]);
236
237
        $this->assertCount(3, $tag->getPosts());
0 ignored issues
show
Bug introduced by
The method getPosts() 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

237
        $this->assertCount(3, $tag->/** @scrutinizer ignore-call */ getPosts());
Loading history...
238
        TagFactory::assert()->count(3); // 1 created by this test and 2 in global state
239
        PostFactory::assert()->count(3);
240
    }
241
242
    /**
243
     * @test
244
     */
245
    public function create_multiple_many_to_many_with_nested_collection_relationship(): void
246
    {
247
        $posts = PostFactory::createMany(2, [
248
            'tags' => TagFactory::new()->many(3),
249
        ]);
250
251
        $this->assertCount(3, $posts[0]->getTags());
252
        $this->assertCount(3, $posts[1]->getTags());
253
        TagFactory::assert()->count(8); // 6 created by this test and 2 in global state
254
        PostFactory::assert()->count(2);
255
    }
256
257
    /**
258
     * @test
259
     */
260
    public function unpersisted_one_to_many_with_nested_collection_relationship(): void
261
    {
262
        $post = PostFactory::new()->withoutPersisting()->create([
263
            'comments' => CommentFactory::new()->many(4),
264
        ]);
265
266
        $this->assertCount(4, $post->getComments());
267
        UserFactory::assert()->empty();
268
        CommentFactory::assert()->empty();
269
        PostFactory::assert()->empty();
270
    }
271
272
    /**
273
     * @test
274
     */
275
    public function unpersisted_many_to_many_with_nested_collection_relationship(): void
276
    {
277
        $post = PostFactory::new()->withoutPersisting()->create([
278
            'tags' => TagFactory::new()->many(3),
279
        ]);
280
281
        $this->assertCount(3, $post->getTags());
282
        TagFactory::assert()->count(2); // 2 created in global state
283
        PostFactory::assert()->empty();
284
    }
285
286
    /**
287
     * @test
288
     * @dataProvider dataProvider
289
     */
290
    public function can_use_model_factories_in_a_data_provider(PostFactory $factory, bool $published): void
291
    {
292
        $post = $factory->create();
293
294
        $post->assertPersisted();
295
        $this->assertSame($published, $post->isPublished());
296
    }
297
298
    public static function dataProvider(): array
299
    {
300
        return [
301
            [PostFactory::new(), false],
302
            [PostFactory::new()->published(), true],
0 ignored issues
show
Bug introduced by
The method published() does not exist on Zenstruck\Foundry\ModelFactory. 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

302
            [PostFactory::new()->/** @scrutinizer ignore-call */ published(), true],
Loading history...
303
        ];
304
    }
305
306
    /**
307
     * @test
308
     */
309
    public function many_to_one_unmanaged_entity(): void
310
    {
311
        $category = CategoryFactory::createOne(['name' => 'My Category']);
312
313
        self::container()->get(EntityManagerInterface::class)->clear();
314
315
        $post = PostFactory::createOne(['category' => $category]);
316
317
        $this->assertSame('My Category', $post->getCategory()->getName());
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

317
        $this->assertSame('My Category', $post->/** @scrutinizer ignore-call */ getCategory()->getName());
Loading history...
318
    }
319
320
    /**
321
     * @test
322
     */
323
    public function many_to_one_unmanaged_raw_entity(): void
324
    {
325
        $category = CategoryFactory::createOne(['name' => 'My Category'])->object();
326
327
        self::container()->get(EntityManagerInterface::class)->clear();
328
329
        $post = PostFactory::createOne(['category' => $category]);
330
331
        $this->assertSame('My Category', $post->getCategory()->getName());
332
    }
333
334
    /**
335
     * @test
336
     */
337
    public function first_and_last_return_the_correct_object(): void
338
    {
339
        $categoryA = CategoryFactory::createOne(['name' => '3']);
340
        $categoryB = CategoryFactory::createOne(['name' => '2']);
0 ignored issues
show
Unused Code introduced by
The assignment to $categoryB is dead and can be removed.
Loading history...
341
        $categoryC = CategoryFactory::createOne(['name' => '1']);
342
343
        $this->assertSame($categoryA->getId(), CategoryFactory::first()->getId());
344
        $this->assertSame($categoryC->getId(), CategoryFactory::first('name')->getId());
345
        $this->assertSame($categoryC->getId(), CategoryFactory::last()->getId());
346
        $this->assertSame($categoryA->getId(), CategoryFactory::last('name')->getId());
347
    }
348
349
    /**
350
     * @test
351
     */
352
    public function first_throws_exception_if_no_entities_exist(): void
353
    {
354
        $this->expectException(\RuntimeException::class);
355
356
        CategoryFactory::first();
357
    }
358
359
    /**
360
     * @test
361
     */
362
    public function last_throws_exception_if_no_entities_exist(): void
363
    {
364
        $this->expectException(\RuntimeException::class);
365
366
        CategoryFactory::last();
367
    }
368
369
    /**
370
     * @test
371
     */
372
    public function can_count_and_truncate_model_factory(): void
373
    {
374
        $this->assertSame(0, CategoryFactory::count());
375
376
        CategoryFactory::createMany(4);
377
378
        $this->assertSame(4, CategoryFactory::count());
379
380
        CategoryFactory::truncate();
381
382
        $this->assertSame(0, CategoryFactory::count());
383
    }
384
385
    /**
386
     * @test
387
     */
388
    public function can_get_all_entities(): void
389
    {
390
        $this->assertSame([], CategoryFactory::all());
391
392
        CategoryFactory::createMany(4);
393
394
        $categories = CategoryFactory::all();
395
396
        $this->assertCount(4, $categories);
397
        $this->assertInstanceOf(Category::class, $categories[0]->object());
398
        $this->assertInstanceOf(Category::class, $categories[1]->object());
399
        $this->assertInstanceOf(Category::class, $categories[2]->object());
400
        $this->assertInstanceOf(Category::class, $categories[3]->object());
401
    }
402
403
    /**
404
     * @test
405
     */
406
    public function can_find_entity(): void
407
    {
408
        CategoryFactory::createOne(['name' => 'first']);
409
        CategoryFactory::createOne(['name' => 'second']);
410
        $category = CategoryFactory::createOne(['name' => 'third']);
411
412
        $this->assertSame('second', CategoryFactory::find(['name' => 'second'])->getName());
413
        $this->assertSame('third', CategoryFactory::find(['id' => $category->getId()])->getName());
414
        $this->assertSame('third', CategoryFactory::find($category->getId())->getName());
415
        $this->assertSame('third', CategoryFactory::find($category->object())->getName());
416
        $this->assertSame('third', CategoryFactory::find($category)->getName());
417
    }
418
419
    /**
420
     * @test
421
     */
422
    public function find_throws_exception_if_no_entities_exist(): void
423
    {
424
        $this->expectException(\RuntimeException::class);
425
426
        CategoryFactory::find(99);
427
    }
428
429
    /**
430
     * @test
431
     */
432
    public function can_find_by(): void
433
    {
434
        $this->assertSame([], CategoryFactory::findBy(['name' => 'name2']));
435
436
        CategoryFactory::createOne(['name' => 'name1']);
437
        CategoryFactory::createOne(['name' => 'name2']);
438
        CategoryFactory::createOne(['name' => 'name2']);
439
440
        $categories = CategoryFactory::findBy(['name' => 'name2']);
441
442
        $this->assertCount(2, $categories);
443
        $this->assertSame('name2', $categories[0]->getName());
444
        $this->assertSame('name2', $categories[1]->getName());
445
    }
446
447
    /**
448
     * @test
449
     */
450
    public function embeddables_are_never_persisted(): void
451
    {
452
        $object1 = AddressFactory::createOne();
453
        $object2 = AddressFactory::createOne(['value' => 'another address']);
454
455
        $this->assertSame('Some address', $object1->getValue());
0 ignored issues
show
Bug introduced by
The method getValue() 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

455
        $this->assertSame('Some address', $object1->/** @scrutinizer ignore-call */ getValue());
Loading history...
456
        $this->assertSame('another address', $object2->getValue());
457
    }
458
459
    /**
460
     * @test
461
     */
462
    public function factory_with_embeddable(): void
463
    {
464
        ContactFactory::repository()->assert()->empty();
465
466
        $object = ContactFactory::createOne();
467
468
        ContactFactory::repository()->assert()->count(1);
469
        $this->assertSame('Sally', $object->getName());
470
        $this->assertSame('Some address', $object->getAddress()->getValue());
0 ignored issues
show
Bug introduced by
The method getAddress() 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

470
        $this->assertSame('Some address', $object->/** @scrutinizer ignore-call */ getAddress()->getValue());
Loading history...
471
    }
472
473
    /**
474
     * @test
475
     */
476
    public function doctrine_events_still_fired(): void
477
    {
478
        $comment = CommentFactory::new()->create([
479
            'body' => CommentEventSubscriber::COMMENT_BODY,
480
        ]);
481
482
        $this->assertSame(CommentEventSubscriber::NEW_COMMENT_BODY, $comment->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

482
        $this->assertSame(CommentEventSubscriber::NEW_COMMENT_BODY, $comment->/** @scrutinizer ignore-call */ getBody());
Loading history...
483
    }
484
485
    /**
486
     * @test
487
     */
488
    public function disable_doctrine_events_lifecycle(): void
489
    {
490
        $comment = CommentFactory::new()->withoutDoctrineEvents()->create([
491
            'body' => CommentEventSubscriber::COMMENT_BODY,
492
        ]);
493
494
        $this->assertSame(CommentEventSubscriber::COMMENT_BODY, $comment->getBody());
495
496
        $comment2 = CommentFactory::new()->create([
497
            'body' => CommentEventSubscriber::COMMENT_BODY,
498
        ]);
499
500
        $this->assertSame(CommentEventSubscriber::NEW_COMMENT_BODY, $comment2->getBody());
501
    }
502
}
503