GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#101)
by joseph
18:59
created

buildUniqueFieldsAndSetToEntity()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\Tests\Large\CodeGeneration\Generator\Field;
4
5
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\AbstractGenerator;
6
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\EntityFieldSetter;
7
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\FieldGenerator;
8
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
9
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\Boolean\DefaultsEnabledFieldTrait;
10
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\BusinessIdentifierCodeFieldTrait;
11
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\NullableStringFieldTrait;
12
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\UniqueStringFieldTrait;
13
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
14
use EdmondsCommerce\DoctrineStaticMeta\Tests\Assets\AbstractTest;
15
16
/**
17
 * Class FieldGeneratorIntegrationTest
18
 *
19
 * @package EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator
20
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
21
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
22
 * @coversDefaultClass \EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\FieldGenerator
23
 */
24
class FieldGeneratorTest extends AbstractTest
25
{
26
    public const WORK_DIR = AbstractTest::VAR_PATH .
27
                            '/' .
28
                            self::TEST_TYPE_LARGE .
29
                            '/FieldGeneratorIntegrationTest/';
30
31
    private const TEST_ENTITY_CAR = self::TEST_PROJECT_ROOT_NAMESPACE . '\\'
32
                                    . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\Car';
33
34
    private const TEST_FIELD_NAMESPACE = self::TEST_PROJECT_ROOT_NAMESPACE
35
                                         . AbstractGenerator::ENTITY_FIELD_TRAIT_NAMESPACE;
36
37
    private const CAR_FIELDS_TO_TYPES = [
38
        [self::TEST_FIELD_NAMESPACE . '\\Brand', MappingHelper::TYPE_STRING],
39
        [self::TEST_FIELD_NAMESPACE . '\\EngineCC', MappingHelper::TYPE_INTEGER],
40
        [self::TEST_FIELD_NAMESPACE . '\\Manufactured', MappingHelper::TYPE_DATETIME],
41
        [self::TEST_FIELD_NAMESPACE . '\\Mpg', MappingHelper::TYPE_FLOAT],
42
        [self::TEST_FIELD_NAMESPACE . '\\Description', MappingHelper::TYPE_TEXT],
43
        [self::TEST_FIELD_NAMESPACE . '\\IsCar', MappingHelper::TYPE_BOOLEAN],
44
    ];
45
46
    private const UNIQUE_FIELDS_TO_TYPES = [
47
        [self::TEST_FIELD_NAMESPACE . '\\UniqueString', MappingHelper::TYPE_STRING],
48
        [self::TEST_FIELD_NAMESPACE . '\\UniqueInt', MappingHelper::TYPE_INTEGER],
49
    ];
50
51
    /**
52
     * @var FieldGenerator
53
     */
54
    private $fieldGenerator;
55
    /**
56
     * @var EntityFieldSetter
57
     */
58
    private $entityFieldSetter;
59
    /**
60
     * @var NamespaceHelper
61
     */
62
    private $namespaceHelper;
63
64
    public function setup()
65
    {
66
        parent::setup();
67
        $this->getEntityGenerator()->generateEntity(self::TEST_ENTITY_CAR);
68
        $this->fieldGenerator    = $this->getFieldGenerator();
69
        $this->entityFieldSetter = $this->getFieldSetter();
70
        $this->namespaceHelper   = $this->container->get(NamespaceHelper::class);
71
    }
72
73
    /**
74
     * @test
75
     * @large
76
     * @covers ::generateField
77
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
78
     * @throws \ReflectionException
79
     */
80
    public function archetypeFieldCanBeStandardLibraryField(): void
81
    {
82
        foreach (FieldGenerator::STANDARD_FIELDS as $standardField) {
83
            $fieldFqn = \str_replace(
84
                [
85
                    'EdmondsCommerce\\DoctrineStaticMeta',
86
                    $this->namespaceHelper->getClassShortName($standardField),
87
                ],
88
                [
89
                    self::TEST_PROJECT_ROOT_NAMESPACE,
90
                    'Copied' . $this->namespaceHelper->getClassShortName($standardField),
91
                ],
92
                $standardField
93
            );
94
            $this->buildAndCheck(
95
                $fieldFqn,
96
                $standardField
97
            );
98
        }
99
    }
100
101
    /**
102
     * Build and then test a field
103
     *
104
     * @param string $name
105
     * @param string $type
106
     *
107
     * @param mixed  $default
108
     * @param bool   $isUnique
109
     *
110
     * @return string
111
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
112
     * @throws \ReflectionException
113
     * @SuppressWarnings(PHPMD.StaticAccess)
114
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
115
     */
116
    protected function buildAndCheck(
117
        string $name,
118
        string $type,
119
        $default = null,
120
        bool $isUnique = false
121
    ): string {
122
        $fieldTraitFqn = $this->fieldGenerator->generateField(
123
            $name,
124
            $type,
125
            null,
126
            $default,
127
            $isUnique
128
        );
129
        $isArchetype   = !\in_array($type, MappingHelper::ALL_DBAL_TYPES, true);
130
        $this->qaGeneratedCode();
131
        $interfacePath = $this->getPathFromFqn(
132
            \str_replace(
133
                '\\Fields\\Traits\\',
134
                '\\Fields\\Interfaces\\',
135
                $this->namespaceHelper->cropSuffix($fieldTraitFqn, 'Trait') . 'Interface'
136
            )
137
        );
138
        $checkFor      = [];
139
        if (true === $isArchetype) {
140
            $archetypeBasename = $this->namespaceHelper->basename($type);
141
            $newBaseName       = $this->namespaceHelper->basename($name);
142
            if (false === strpos($newBaseName, 'FieldTrait')) {
143
                $newBaseName .= 'FieldTrait';
144
            }
145
            if ($archetypeBasename !== $newBaseName) {
146
                $checkFor = [
147
                    $this->getCodeHelper()->consty($archetypeBasename),
148
                    $this->getCodeHelper()->classy($archetypeBasename),
149
                    $this->getCodeHelper()->propertyIsh($archetypeBasename),
150
                ];
151
            }
152
        }
153
        $this->assertNoMissedReplacements($interfacePath, $checkFor);
154
155
        $traitPath = $this->getPathFromFqn($fieldTraitFqn);
156
        $this->assertNoMissedReplacements($traitPath, $checkFor);
157
158
        $interfaceContents = file_get_contents($interfacePath);
159
        $traitContents     = file_get_contents($traitPath);
160
161
        if (!$isArchetype && !\in_array($type, [MappingHelper::TYPE_TEXT, MappingHelper::TYPE_STRING], true)) {
162
            self::assertNotContains(': string', $interfaceContents);
163
            self::assertNotContains('(string', $interfaceContents);
164
            self::assertNotContains(': string', $traitContents);
165
            self::assertNotContains('(string', $traitContents);
166
            $phpType = MappingHelper::COMMON_TYPES_TO_PHP_TYPES[$type];
167
            if (null === $default) {
168
                $phpType = "?$phpType";
169
            }
170
            self::assertContains(': ' . $phpType, $interfaceContents);
171
            self::assertContains('(' . $phpType, $interfaceContents);
172
            self::assertContains(': ' . $phpType, $traitContents);
173
            self::assertContains('(' . $phpType, $traitContents);
174
        }
175
176
        self::assertNotContains('public function isIs', $interfaceContents, '', true);
177
        self::assertNotContains('public function isIs', $traitContents, '', true);
178
        if ($type === MappingHelper::TYPE_BOOLEAN) {
179
            self::assertNotContains('public function get', $interfaceContents);
180
            self::assertNotContains('public function get', $traitContents);
181
        }
182
183
        return $fieldTraitFqn;
184
    }
185
186
    protected function getPathFromFqn(string $fqn): string
187
    {
188
        $path = self::WORK_DIR . 'src/Entity/Fields';
189
        $exp  = explode(
190
            '\\',
191
            \substr(
192
                $fqn,
193
                strpos(
194
                    $fqn,
195
                    '\\Entity\\Fields\\'
196
                ) + \strlen('\\Entity\\Fields\\')
197
            )
198
        );
199
        foreach ($exp as $item) {
200
            $path .= '/' . $item;
201
        }
202
        $path .= '.php';
203
204
        return $path;
205
    }
206
207
    /**
208
     * @test
209
     * @large
210
     * @covers ::generateField
211
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
212
     * @throws \ReflectionException
213
     */
214
    public function archetypeFieldCanBeNonStandardLibraryField(): void
215
    {
216
        $args         = current(self::CAR_FIELDS_TO_TYPES);
217
        $archetypeFqn = $this->fieldGenerator->generateField($args[0], $args[1]);
218
        $this->buildAndCheck(self::TEST_FIELD_NAMESPACE . '\\BrandCopied', $archetypeFqn);
219
    }
220
221
    /**
222
     * @test
223
     * @large
224
     * @covers ::generateField
225
     */
226
    public function fieldCanBeDeeplyNamespaced(): void
227
    {
228
        $deeplyNamespaced = self::TEST_FIELD_NAMESPACE . '\\Deeply\\Nested\\String';
229
        $this->buildAndCheck($deeplyNamespaced, MappingHelper::TYPE_STRING);
230
    }
231
232
    /**
233
     * @test
234
     * @large
235
     * @covers ::generateField
236
     */
237
    public function archetypeFieldCanBeDeeplyNested(): void
238
    {
239
        $deeplyNamespaced = self::TEST_FIELD_NAMESPACE . '\\Deeply\\Nested\\StringFieldTrait';
240
        $this->buildAndCheck($deeplyNamespaced, NullableStringFieldTrait::class);
241
    }
242
243
    /**
244
     * @test
245
     * @large
246
     * @covers ::generateField
247
     */
248
    public function theGeneratedFieldCanHaveTheSameNameAsTheArchetype(): void
249
    {
250
        $deeplyNamespaced = self::TEST_FIELD_NAMESPACE . '\\Deeply\\Nested\\NullableString';
251
        $this->buildAndCheck($deeplyNamespaced, NullableStringFieldTrait::class);
252
    }
253
254
    /**
255
     * @test
256
     * @large
257
     * @covers ::generateField
258
     */
259
    public function archetypeBooleansBeginningWithIsAreHandledProperly(): void
260
    {
261
        $deeplyNamespaced = self::TEST_FIELD_NAMESPACE . '\\Deeply\\Nested\\IsBoolean';
262
        $this->buildAndCheck($deeplyNamespaced, DefaultsEnabledFieldTrait::class);
263
    }
264
265
    /**
266
     * @test
267
     * @large
268
     * @covers ::generateField
269
     */
270
    public function fieldMustContainEntityNamespace(): void
271
    {
272
        $this->expectException(\InvalidArgumentException::class);
273
        $this->fieldGenerator->generateField(
274
            '\\Blah\\Foop',
275
            MappingHelper::TYPE_STRING,
276
            null,
277
            null,
278
            true
279
        );
280
    }
281
282
    /**
283
     * @test
284
     * @large
285
     * @covers ::generateField
286
     */
287
    public function fieldTypeMustBeValid(): void
288
    {
289
        $this->expectException(\InvalidArgumentException::class);
290
        $this->fieldGenerator->generateField(
291
            self::CAR_FIELDS_TO_TYPES[0][0],
292
            'invalid',
293
            null,
294
            null,
295
            true
296
        );
297
    }
298
299
    /**
300
     * @test
301
     * @large
302
     * @covers ::generateField
303
     */
304
    public function phpTypeMustBeValid(): void
305
    {
306
        $this->expectException(\InvalidArgumentException::class);
307
        $this->fieldGenerator->generateField(
308
            self::CAR_FIELDS_TO_TYPES[0][0],
309
            MappingHelper::PHP_TYPE_FLOAT,
310
            'invalid',
311
            null,
312
            true
313
        );
314
    }
315
316
    /**
317
     * @test
318
     * @large
319
     * @covers ::generateField
320
     */
321
    public function defaultTypeMustBeValid(): void
322
    {
323
        $this->expectException(\InvalidArgumentException::class);
324
        $this->fieldGenerator->generateField(
325
            self::CAR_FIELDS_TO_TYPES[0][0],
326
            MappingHelper::PHP_TYPE_FLOAT,
327
            'invalid',
328
            'clearly not a float',
329
            true
330
        );
331
    }
332
333
    /**
334
     * @test
335
     * @large
336
     * @covers ::generateField
337
     */
338
    public function defaultValueIsNormalised(): void
339
    {
340
        $defaultValuesToTypes = [
341
            MappingHelper::TYPE_INTEGER => [
342
                1,
343
                '1',
344
                ' 1',
345
                ' 1 ',
346
            ],
347
            MappingHelper::TYPE_FLOAT   => [
348
                1,
349
                1.0,
350
                '1',
351
                '1.1',
352
                ' 1.1 ',
353
                ' 1.1 ',
354
            ],
355
            MappingHelper::TYPE_BOOLEAN => [
356
                'true',
357
                'false',
358
                'TRUE',
359
                'FALSE',
360
                ' TRue ',
361
                ' FaLse ',
362
            ],
363
        ];
364
        $errors               = [];
365
        foreach ($defaultValuesToTypes as $type => $defaultValues) {
366
            foreach ($defaultValues as $key => $defaultValue) {
367
                try {
368
                    $this->buildAndCheck(
369
                        self::TEST_FIELD_NAMESPACE . '\\normalisedDefault' . $type . $key,
370
                        $type,
371
                        $defaultValue
372
                    );
373
                } catch (\Throwable $e) {
374
                    $errors[] = [
375
                        'type'    => $type,
376
                        'default' => $defaultValue,
377
                        'error'   => $e->getMessage(),
378
                    ];
379
                }
380
            }
381
        }
382
        self::assertSame([], $errors, print_r($errors, true));
383
    }
384
385
    /**
386
     * @test
387
     * @large
388
     * @covers ::generateField
389
     */
390
    public function buildFieldsAndSetToEntity(): void
391
    {
392
        foreach (self::CAR_FIELDS_TO_TYPES as $args) {
393
            $fieldFqn = $this->buildAndCheck($args[0], $args[1], null);
394
            $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $fieldFqn);
395
        }
396
        $this->qaGeneratedCode();
397
    }
398
399
    /**
400
     * @test
401
     * @large
402
     * @covers ::generateField
403
     */
404
    public function buildFieldsWithSuffixAndSetToEntity(): void
405
    {
406
        foreach (self::CAR_FIELDS_TO_TYPES as $args) {
407
            $fieldFqn = $this->buildAndCheck($args[0] . FieldGenerator::FIELD_TRAIT_SUFFIX, $args[1], null);
408
            $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $fieldFqn);
409
        }
410
        $this->qaGeneratedCode();
411
    }
412
413
    /**
414
     * @test
415
     * @large
416
     * @covers ::generateField
417
     */
418
    public function buildNullableFieldsAndSetToEntity(): void
419
    {
420
        foreach (self::CAR_FIELDS_TO_TYPES as $args) {
421
            $fieldFqn = $this->buildAndCheck($args[0], $args[1], null);
422
            $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $fieldFqn);
423
        }
424
        $this->qaGeneratedCode();
425
    }
426
427
    /**
428
     * @test
429
     * @large
430
     * @covers ::generateField
431
     */
432
    public function buildUniqueFieldsAndSetToEntity(): void
433
    {
434
        foreach (self::UNIQUE_FIELDS_TO_TYPES as $args) {
435
            $fieldFqn = $this->buildAndCheck($args[0], $args[1], null, true);
436
            $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $fieldFqn);
437
        }
438
        $this->qaGeneratedCode();
439
    }
440
441
    /**
442
     * @test
443
     * @large
444
     * @covers ::generateField
445
     */
446
    public function buildingAnArchetypeThenNormalField(): void
447
    {
448
        $this->buildAndCheck(self::TEST_FIELD_NAMESPACE . '\\UniqueName', UniqueStringFieldTrait::class);
449
        $this->buildAndCheck(self::TEST_FIELD_NAMESPACE . '\\SimpleString', MappingHelper::TYPE_STRING);
450
        $this->buildAndCheck(self::TEST_FIELD_NAMESPACE . '\\UniqueThing', UniqueStringFieldTrait::class);
451
    }
452
453
    /**
454
     * @test
455
     * @large
456
     * @covers ::generateField
457
     */
458
    public function notPossibleToAddDuplicateNamedFieldsToSingleEntity(): void
459
    {
460
        $someThing  = self::TEST_FIELD_NAMESPACE . '\\Something\\FooFieldTrait';
461
        $otherThing = self::TEST_FIELD_NAMESPACE . '\\Otherthing\\FooFieldTrait';
462
        $this->buildAndCheck($someThing, UniqueStringFieldTrait::class);
463
        $this->buildAndCheck($otherThing, BusinessIdentifierCodeFieldTrait::class);
464
        $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $someThing);
465
        $this->expectException(\InvalidArgumentException::class);
466
        $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $otherThing);
467
    }
468
}
469