Passed
Push — master ( b92a69...6bab70 )
by Kevin
03:06
created

ModelFactoryTest::can_find_random_object()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 11
rs 10
c 1
b 0
f 1
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\Factories\CategoryFactory;
11
use Zenstruck\Foundry\Tests\Fixtures\Factories\CommentFactory;
12
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactory;
13
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactoryWithInvalidInitialize;
14
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactoryWithNullInitialize;
15
use Zenstruck\Foundry\Tests\Fixtures\Factories\PostFactoryWithValidInitialize;
16
use Zenstruck\Foundry\Tests\Fixtures\Factories\TagFactory;
17
use Zenstruck\Foundry\Tests\Fixtures\Factories\UserFactory;
18
19
/**
20
 * @author Kevin Bond <[email protected]>
21
 */
22
final class ModelFactoryTest extends KernelTestCase
23
{
24
    use Factories, ResetDatabase;
25
26
    /**
27
     * @test
28
     */
29
    public function can_find_or_create(): void
30
    {
31
        CategoryFactory::repository()->assertCount(0);
32
        CategoryFactory::findOrCreate(['name' => 'php']);
33
        CategoryFactory::repository()->assertCount(1);
34
        CategoryFactory::findOrCreate(['name' => 'php']);
35
        CategoryFactory::repository()->assertCount(1);
36
    }
37
38
    /**
39
     * @test
40
     */
41
    public function can_override_initialize(): void
42
    {
43
        $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

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

79
            $ids[] = CategoryFactory::random()->/** @scrutinizer ignore-call */ getId();
Loading history...
80
        }
81
82
        $this->assertCount(5, \array_unique($ids));
83
    }
84
85
    /**
86
     * @test
87
     */
88
    public function can_create_random_object_if_none_exists(): void
89
    {
90
        CategoryFactory::repository()->assertCount(0);
91
        $this->assertInstanceOf(Category::class, CategoryFactory::randomOrCreate()->object());
92
        CategoryFactory::repository()->assertCount(1);
93
        $this->assertInstanceOf(Category::class, CategoryFactory::randomOrCreate()->object());
94
        CategoryFactory::repository()->assertCount(1);
95
    }
96
97
    /**
98
     * @test
99
     */
100
    public function can_get_or_create_random_object_with_attributes(): void
101
    {
102
        CategoryFactory::createMany(5, ['name' => 'name1']);
103
104
        CategoryFactory::repository()->assertCount(5);
105
        $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

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

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

220
        $this->assertCount(3, $post->/** @scrutinizer ignore-call */ getTags());
Loading history...
221
        TagFactory::repository()->assertCount(5); // 3 created by this test and 2 in global state
222
        PostFactory::repository()->assertCount(1);
223
    }
224
225
    /**
226
     * @test
227
     */
228
    public function inverse_many_to_many_with_nested_collection_relationship(): void
229
    {
230
        $tag = TagFactory::createOne([
231
            'posts' => PostFactory::new()->many(3),
232
        ]);
233
234
        $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

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

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

314
        $this->assertSame('My Category', $post->/** @scrutinizer ignore-call */ getCategory()->getName());
Loading history...
315
    }
316
317
    /**
318
     * @test
319
     */
320
    public function many_to_one_unmanaged_raw_entity(): void
321
    {
322
        $category = CategoryFactory::createOne(['name' => 'My Category'])->object();
323
324
        self::$container->get(EntityManagerInterface::class)->clear();
325
326
        $post = PostFactory::createOne(['category' => $category]);
327
328
        $this->assertSame('My Category', $post->getCategory()->getName());
329
    }
330
}
331