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
Push — master ( 6a4e57...36c412 )
by joseph
26:54
created

itDoesNotClobberValidatorClassNames()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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