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.

FieldGeneratorTest::buildAndCheck()   B
last analyzed

Complexity

Conditions 8
Paths 30

Size

Total Lines 65
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 44
nc 30
nop 4
dl 0
loc 65
rs 7.9715
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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