Passed
Pull Request — master (#153)
by Kevin
03:37
created

ModelFactoryTest::can_override_initialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Zenstruck\Foundry\Tests\Functional;
4
5
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
6
use Zenstruck\Foundry\Test\Factories;
7
use Zenstruck\Foundry\Test\ResetDatabase;
8
use Zenstruck\Foundry\Tests\Fixtures\Factories\AddressFactory;
9
use Zenstruck\Foundry\Tests\Fixtures\Factories\CategoryFactory;
10
use Zenstruck\Foundry\Tests\Fixtures\Factories\CommentFactory;
11
use Zenstruck\Foundry\Tests\Fixtures\Factories\ContactFactory;
12
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactory;
13
use Zenstruck\Foundry\Tests\Fixtures\Factories\TagFactory;
14
use Zenstruck\Foundry\Tests\Fixtures\Factories\UserFactory;
15
16
/**
17
 * @author Kevin Bond <[email protected]>
18
 */
19
abstract class ModelFactoryTest extends KernelTestCase
20
{
21
    use ContainerBC, Factories, ResetDatabase;
22
23
    /**
24
     * @test
25
     */
26
    public function can_find_or_create(): void
27
    {
28
        $categoryFactoryClass = $this->categoryFactoryClass();
29
30
        $categoryFactoryClass::assert()->count(0);
31
        $categoryFactoryClass::findOrCreate(['name' => 'php']);
32
        $categoryFactoryClass::assert()->count(1);
33
        $categoryFactoryClass::findOrCreate(['name' => 'php']);
34
        $categoryFactoryClass::assert()->count(1);
35
    }
36
37
    /**
38
     * @test
39
     */
40
    public function can_find_random_object(): void
41
    {
42
        $categoryFactoryClass = $this->categoryFactoryClass();
43
44
        $categoryFactoryClass::createMany(5);
45
46
        $ids = [];
47
48
        while (5 !== \count(\array_unique($ids))) {
49
            $ids[] = $categoryFactoryClass::random()->getId();
50
        }
51
52
        $this->assertCount(5, \array_unique($ids));
53
    }
54
55
    /**
56
     * @test
57
     */
58
    public function can_create_random_object_if_none_exists(): void
59
    {
60
        $categoryFactoryClass = $this->categoryFactoryClass();
61
62
        $categoryFactoryClass::assert()->count(0);
63
        $this->assertInstanceOf($this->categoryClass(), $categoryFactoryClass::randomOrCreate()->object());
64
        $categoryFactoryClass::assert()->count(1);
65
        $this->assertInstanceOf($this->categoryClass(), $categoryFactoryClass::randomOrCreate()->object());
66
        $categoryFactoryClass::assert()->count(1);
67
    }
68
69
    /**
70
     * @test
71
     */
72
    public function can_get_or_create_random_object_with_attributes(): void
73
    {
74
        $categoryFactoryClass = $this->categoryFactoryClass();
75
76
        $categoryFactoryClass::createMany(5, ['name' => 'name1']);
77
78
        $categoryFactoryClass::assert()->count(5);
79
        $this->assertSame('name2', $categoryFactoryClass::randomOrCreate(['name' => 'name2'])->getName());
80
        $categoryFactoryClass::assert()->count(6);
81
        $this->assertSame('name2', $categoryFactoryClass::randomOrCreate(['name' => 'name2'])->getName());
82
        $categoryFactoryClass::assert()->count(6);
83
    }
84
85
    /**
86
     * @test
87
     */
88
    public function can_find_random_set_of_objects(): void
89
    {
90
        $categoryFactoryClass = $this->categoryFactoryClass();
91
92
        $categoryFactoryClass::createMany(5);
93
94
        $objects = $categoryFactoryClass::randomSet(3);
95
96
        $this->assertCount(3, $objects);
97
        $this->assertCount(3, \array_unique(\array_map(static function($category) { return $category->getId(); }, $objects)));
98
    }
99
100
    /**
101
     * @test
102
     */
103
    public function can_find_random_set_of_objects_with_attributes(): void
104
    {
105
        $categoryFactoryClass = $this->categoryFactoryClass();
106
107
        $categoryFactoryClass::createMany(20, ['name' => 'name1']);
108
        $categoryFactoryClass::createMany(5, ['name' => 'name2']);
109
110
        $objects = $categoryFactoryClass::randomSet(2, ['name' => 'name2']);
111
112
        $this->assertCount(2, $objects);
113
        $this->assertSame('name2', $objects[0]->getName());
114
        $this->assertSame('name2', $objects[1]->getName());
115
    }
116
117
    /**
118
     * @test
119
     */
120
    public function can_find_random_range_of_objects(): void
121
    {
122
        $categoryFactoryClass = $this->categoryFactoryClass();
123
124
        $categoryFactoryClass::createMany(5);
125
126
        $counts = [];
127
128
        while (4 !== \count(\array_unique($counts))) {
129
            $counts[] = \count($categoryFactoryClass::randomRange(0, 3));
130
        }
131
132
        $this->assertCount(4, \array_unique($counts));
133
        $this->assertContains(0, $counts);
134
        $this->assertContains(1, $counts);
135
        $this->assertContains(2, $counts);
136
        $this->assertContains(3, $counts);
137
        $this->assertNotContains(4, $counts);
138
        $this->assertNotContains(5, $counts);
139
    }
140
141
    /**
142
     * @test
143
     */
144
    public function can_find_random_range_of_objects_with_attributes(): void
145
    {
146
        $categoryFactoryClass = $this->categoryFactoryClass();
147
148
        $categoryFactoryClass::createMany(20, ['name' => 'name1']);
149
        $categoryFactoryClass::createMany(5, ['name' => 'name2']);
150
151
        $objects = $categoryFactoryClass::randomRange(2, 4, ['name' => 'name2']);
152
153
        $this->assertGreaterThanOrEqual(2, \count($objects));
154
        $this->assertLessThanOrEqual(4, \count($objects));
155
156
        foreach ($objects as $object) {
157
            $this->assertSame('name2', $object->getName());
158
        }
159
    }
160
161
    /**
162
     * @test
163
     */
164
    public function one_to_many_with_nested_collection_relationship(): void
165
    {
166
        $post = PostFactory::createOne([
167
            'comments' => CommentFactory::new()->many(4),
168
        ]);
169
170
        $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

170
        $this->assertCount(4, $post->/** @scrutinizer ignore-call */ getComments());
Loading history...
171
        UserFactory::assert()->count(4);
172
        CommentFactory::assert()->count(4);
173
        PostFactory::assert()->count(1);
174
    }
175
176
    /**
177
     * @test
178
     */
179
    public function create_multiple_one_to_many_with_nested_collection_relationship(): void
180
    {
181
        $user = UserFactory::createOne();
182
        $posts = PostFactory::createMany(2, [
183
            'comments' => CommentFactory::new(['user' => $user])->many(4),
184
        ]);
185
186
        $this->assertCount(4, $posts[0]->getComments());
187
        $this->assertCount(4, $posts[1]->getComments());
188
        UserFactory::assert()->count(1);
189
        CommentFactory::assert()->count(8);
190
        PostFactory::assert()->count(2);
191
    }
192
193
    /**
194
     * @test
195
     */
196
    public function many_to_many_with_nested_collection_relationship(): void
197
    {
198
        $post = PostFactory::createOne([
199
            'tags' => TagFactory::new()->many(3),
200
        ]);
201
202
        $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

202
        $this->assertCount(3, $post->/** @scrutinizer ignore-call */ getTags());
Loading history...
203
        TagFactory::assert()->count(5); // 3 created by this test and 2 in global state
204
        PostFactory::assert()->count(1);
205
    }
206
207
    /**
208
     * @test
209
     */
210
    public function inverse_many_to_many_with_nested_collection_relationship(): void
211
    {
212
        $tag = TagFactory::createOne([
213
            'posts' => PostFactory::new()->many(3),
214
        ]);
215
216
        $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

216
        $this->assertCount(3, $tag->/** @scrutinizer ignore-call */ getPosts());
Loading history...
217
        TagFactory::assert()->count(3); // 1 created by this test and 2 in global state
218
        PostFactory::assert()->count(3);
219
    }
220
221
    /**
222
     * @test
223
     */
224
    public function create_multiple_many_to_many_with_nested_collection_relationship(): void
225
    {
226
        $posts = PostFactory::createMany(2, [
227
            'tags' => TagFactory::new()->many(3),
228
        ]);
229
230
        $this->assertCount(3, $posts[0]->getTags());
231
        $this->assertCount(3, $posts[1]->getTags());
232
        TagFactory::assert()->count(8); // 6 created by this test and 2 in global state
233
        PostFactory::assert()->count(2);
234
    }
235
236
    /**
237
     * @test
238
     */
239
    public function unpersisted_one_to_many_with_nested_collection_relationship(): void
240
    {
241
        $post = PostFactory::new()->withoutPersisting()->create([
242
            'comments' => CommentFactory::new()->many(4),
243
        ]);
244
245
        $this->assertCount(4, $post->getComments());
246
        UserFactory::assert()->empty();
247
        CommentFactory::assert()->empty();
248
        PostFactory::assert()->empty();
249
    }
250
251
    /**
252
     * @test
253
     */
254
    public function unpersisted_many_to_many_with_nested_collection_relationship(): void
255
    {
256
        $post = PostFactory::new()->withoutPersisting()->create([
257
            'tags' => TagFactory::new()->many(3),
258
        ]);
259
260
        $this->assertCount(3, $post->getTags());
261
        TagFactory::assert()->count(2); // 2 created in global state
262
        PostFactory::assert()->empty();
263
    }
264
265
    /**
266
     * @test
267
     * @dataProvider dataProvider
268
     */
269
    public function can_use_model_factories_in_a_data_provider(PostFactory $factory, bool $published): void
270
    {
271
        $post = $factory->create();
272
273
        $post->assertPersisted();
274
        $this->assertSame($published, $post->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

274
        $this->assertSame($published, $post->/** @scrutinizer ignore-call */ isPublished());
Loading history...
275
    }
276
277
    public static function dataProvider(): array
278
    {
279
        return [
280
            [PostFactory::new(), false],
281
            [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

281
            [PostFactory::new()->/** @scrutinizer ignore-call */ published(), true],
Loading history...
282
        ];
283
    }
284
285
    /**
286
     * @test
287
     */
288
    public function many_to_one_unmanaged_entity(): void
289
    {
290
        $category = CategoryFactory::createOne(['name' => 'My Category']);
291
292
        self::container()->get(EntityManagerInterface::class)->clear();
0 ignored issues
show
Bug introduced by
The type Zenstruck\Foundry\Tests\...\EntityManagerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
293
294
        $post = PostFactory::createOne(['category' => $category]);
295
296
        $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

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

447
        $this->assertSame('Some address', $object1->/** @scrutinizer ignore-call */ getValue());
Loading history...
448
        $this->assertSame('another address', $object2->getValue());
449
    }
450
451
    /**
452
     * @test
453
     */
454
    public function factory_with_embeddable(): void
455
    {
456
        ContactFactory::repository()->assert()->empty();
457
458
        $object = ContactFactory::createOne();
459
460
        ContactFactory::repository()->assert()->count(1);
461
        $this->assertSame('Sally', $object->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

461
        $this->assertSame('Sally', $object->/** @scrutinizer ignore-call */ getName());
Loading history...
462
        $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

462
        $this->assertSame('Some address', $object->/** @scrutinizer ignore-call */ getAddress()->getValue());
Loading history...
463
    }
464
465
    abstract protected function categoryClass(): string;
466
467
    abstract protected function categoryFactoryClass(): string;
468
}
469