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 (#93)
by joseph
14:47
created

FieldGeneratorIntegrationTest   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 357
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 36
eloc 194
dl 0
loc 357
rs 9.52
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A testPHPTypeMustBeValid() 0 9 1
A testBuildUniqueFieldsAndSetToEntity() 0 7 2
A testDefaultValueIsNormalised() 0 45 4
A testNotPossibleToAddDuplicateNamedFieldsToSingleEntity() 0 9 1
B buildAndCheck() 0 68 8
A testDefaultTypeMustBeValid() 0 9 1
A testBuildFieldsAndSetToEntity() 0 7 2
A testFieldTypeMustBeValid() 0 9 1
A testTheGeneratedFieldCanHaveTheSameNameAsTheArchetype() 0 4 1
A testArchetypeFieldCanBeDeeplyNested() 0 4 1
A testBuildingAnArchetypeThenNormalField() 0 5 1
A testArchetypeFieldCanBeStandardLibraryField() 0 17 2
A testArchetypeFieldCanBeNonStandardLibraryField() 0 5 1
A testBuildFieldsWithSuffixAndSetToEntity() 0 7 2
A testFieldCanBeDeeplyNamespaced() 0 4 1
A testFieldMustContainEntityNamespace() 0 9 1
A testBuildNullableFieldsAndSetToEntity() 0 7 2
A testArchetypeBooleansBeginningWithIsAreHandledProperly() 0 4 1
A getPathFromFqn() 0 19 2
A setup() 0 7 1
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field;
4
5
use EdmondsCommerce\DoctrineStaticMeta\AbstractIntegrationTest;
6
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\AbstractGenerator;
7
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
8
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\Boolean\DefaultsEnabledFieldTrait;
9
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\BusinessIdentifierCodeFieldTrait;
10
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\NullableStringFieldTrait;
11
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\UniqueStringFieldTrait;
12
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
13
14
/**
15
 * Class FieldGeneratorIntegrationTest
16
 *
17
 * @package EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator
18
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
19
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
20
 */
21
class FieldGeneratorIntegrationTest extends AbstractIntegrationTest
22
{
23
    public const WORK_DIR = AbstractIntegrationTest::VAR_PATH .
24
                            '/' .
25
                            self::TEST_TYPE .
26
                            '/FieldGeneratorIntegrationTest/';
27
28
    private const TEST_ENTITY_CAR = self::TEST_PROJECT_ROOT_NAMESPACE . '\\'
29
                                    . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\Car';
30
31
    private const TEST_FIELD_NAMESPACE = self::TEST_PROJECT_ROOT_NAMESPACE
32
                                         . AbstractGenerator::ENTITY_FIELD_TRAIT_NAMESPACE;
33
34
    private const CAR_FIELDS_TO_TYPES = [
35
        [self::TEST_FIELD_NAMESPACE . '\\Brand', MappingHelper::TYPE_STRING],
36
        [self::TEST_FIELD_NAMESPACE . '\\EngineCC', MappingHelper::TYPE_INTEGER],
37
        [self::TEST_FIELD_NAMESPACE . '\\Manufactured', MappingHelper::TYPE_DATETIME],
38
        [self::TEST_FIELD_NAMESPACE . '\\Mpg', MappingHelper::TYPE_FLOAT],
39
        [self::TEST_FIELD_NAMESPACE . '\\Description', MappingHelper::TYPE_TEXT],
40
        [self::TEST_FIELD_NAMESPACE . '\\IsCar', MappingHelper::TYPE_BOOLEAN],
41
    ];
42
43
    private const UNIQUE_FIELDS_TO_TYPES = [
44
        [self::TEST_FIELD_NAMESPACE . '\\UniqueString', MappingHelper::TYPE_STRING],
45
        [self::TEST_FIELD_NAMESPACE . '\\UniqueInt', MappingHelper::TYPE_INTEGER],
46
    ];
47
48
    /**
49
     * @var FieldGenerator
50
     */
51
    private $fieldGenerator;
52
    /**
53
     * @var EntityFieldSetter
54
     */
55
    private $entityFieldSetter;
56
    /**
57
     * @var NamespaceHelper
58
     */
59
    private $namespaceHelper;
60
61
    public function setup()
62
    {
63
        parent::setup();
64
        $this->getEntityGenerator()->generateEntity(self::TEST_ENTITY_CAR);
65
        $this->fieldGenerator    = $this->getFieldGenerator();
66
        $this->entityFieldSetter = $this->getFieldSetter();
67
        $this->namespaceHelper   = $this->container->get(NamespaceHelper::class);
68
    }
69
70
    public function testArchetypeFieldCanBeStandardLibraryField(): void
71
    {
72
        foreach (FieldGenerator::STANDARD_FIELDS as $standardField) {
73
            $fieldFqn = \str_replace(
74
                [
75
                    'EdmondsCommerce\\DoctrineStaticMeta',
76
                    $this->namespaceHelper->getClassShortName($standardField),
77
                ],
78
                [
79
                    self::TEST_PROJECT_ROOT_NAMESPACE,
80
                    'Copied' . $this->namespaceHelper->getClassShortName($standardField),
81
                ],
82
                $standardField
83
            );
84
            $this->buildAndCheck(
85
                $fieldFqn,
86
                $standardField
87
            );
88
        }
89
    }
90
91
    /**
92
     * Build and then test a field
93
     *
94
     * @param string $name
95
     * @param string $type
96
     *
97
     * @param mixed  $default
98
     * @param bool   $isUnique
99
     *
100
     * @return string
101
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
102
     * @throws \ReflectionException
103
     * @SuppressWarnings(PHPMD.StaticAccess)
104
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
105
     */
106
    protected function buildAndCheck(
107
        string $name,
108
        string $type,
109
        $default = null,
110
        bool $isUnique = false
111
    ): string {
112
        $fieldTraitFqn = $this->fieldGenerator->generateField(
113
            $name,
114
            $type,
115
            null,
116
            $default,
117
            $isUnique
118
        );
119
        $isArchetype   = !\in_array($type, MappingHelper::ALL_DBAL_TYPES, true);
120
        $this->qaGeneratedCode();
121
        $interfacePath = $this->getPathFromFqn(
122
            \str_replace(
123
                '\\Fields\\Traits\\',
124
                '\\Fields\\Interfaces\\',
125
                $this->namespaceHelper->cropSuffix($fieldTraitFqn, 'Trait') . 'Interface'
126
            )
127
        );
128
        $checkFor      = [];
129
        if (true === $isArchetype) {
130
            $archetypeBasename = $this->namespaceHelper->basename($type);
131
            $newBaseName       = $this->namespaceHelper->basename($name);
132
            if (false === strpos($newBaseName, 'FieldTrait')) {
133
                $newBaseName .= 'FieldTrait';
134
            }
135
            if ($archetypeBasename !== $newBaseName) {
136
                $checkFor = [
137
                    $this->getCodeHelper()->consty($archetypeBasename),
138
                    $this->getCodeHelper()->classy($archetypeBasename),
139
                    $this->getCodeHelper()->propertyIsh($archetypeBasename),
140
                ];
141
            }
142
        }
143
        $this->assertNoMissedReplacements($interfacePath, $checkFor);
144
145
        $traitPath = $this->getPathFromFqn($fieldTraitFqn);
146
        $this->assertNoMissedReplacements($traitPath, $checkFor);
147
148
        $interfaceContents = file_get_contents($interfacePath);
149
        $traitContents     = file_get_contents($traitPath);
150
151
        if (!$isArchetype && !\in_array($type, [MappingHelper::TYPE_TEXT, MappingHelper::TYPE_STRING], true)) {
152
            self::assertNotContains(': string', $interfaceContents);
153
            self::assertNotContains('(string', $interfaceContents);
154
            self::assertNotContains(': string', $traitContents);
155
            self::assertNotContains('(string', $traitContents);
156
            $phpType = MappingHelper::COMMON_TYPES_TO_PHP_TYPES[$type];
157
            if (null === $default) {
158
                $phpType = "?$phpType";
159
            }
160
            self::assertContains(': ' . $phpType, $interfaceContents);
161
            self::assertContains('(' . $phpType, $interfaceContents);
162
            self::assertContains(': ' . $phpType, $traitContents);
163
            self::assertContains('(' . $phpType, $traitContents);
164
        }
165
166
        self::assertNotContains('public function isIs', $interfaceContents, '', true);
167
        self::assertNotContains('public function isIs', $traitContents, '', true);
168
        if ($type === MappingHelper::TYPE_BOOLEAN) {
169
            self::assertNotContains('public function get', $interfaceContents);
170
            self::assertNotContains('public function get', $traitContents);
171
        }
172
173
        return $fieldTraitFqn;
174
    }
175
176
    protected function getPathFromFqn(string $fqn): string
177
    {
178
        $path = self::WORK_DIR . 'src/Entity/Fields';
179
        $exp  = explode(
180
            '\\',
181
            \substr(
182
                $fqn,
183
                strpos(
184
                    $fqn,
185
                    '\\Entity\\Fields\\'
186
                ) + \strlen('\\Entity\\Fields\\')
187
            )
188
        );
189
        foreach ($exp as $item) {
190
            $path .= '/' . $item;
191
        }
192
        $path .= '.php';
193
194
        return $path;
195
    }
196
197
    public function testArchetypeFieldCanBeNonStandardLibraryField(): void
198
    {
199
        $args         = current(self::CAR_FIELDS_TO_TYPES);
200
        $archetypeFqn = $this->fieldGenerator->generateField($args[0], $args[1]);
201
        $this->buildAndCheck(self::TEST_FIELD_NAMESPACE . '\\BrandCopied', $archetypeFqn);
202
    }
203
204
    public function testFieldCanBeDeeplyNamespaced(): void
205
    {
206
        $deeplyNamespaced = self::TEST_FIELD_NAMESPACE . '\\Deeply\\Nested\\String';
207
        $this->buildAndCheck($deeplyNamespaced, MappingHelper::TYPE_STRING);
208
    }
209
210
    public function testArchetypeFieldCanBeDeeplyNested(): void
211
    {
212
        $deeplyNamespaced = self::TEST_FIELD_NAMESPACE . '\\Deeply\\Nested\\StringFieldTrait';
213
        $this->buildAndCheck($deeplyNamespaced, NullableStringFieldTrait::class);
214
    }
215
216
    public function testTheGeneratedFieldCanHaveTheSameNameAsTheArchetype(): void
217
    {
218
        $deeplyNamespaced = self::TEST_FIELD_NAMESPACE . '\\Deeply\\Nested\\NullableString';
219
        $this->buildAndCheck($deeplyNamespaced, NullableStringFieldTrait::class);
220
    }
221
222
    public function testArchetypeBooleansBeginningWithIsAreHandledProperly(): void
223
    {
224
        $deeplyNamespaced = self::TEST_FIELD_NAMESPACE . '\\Deeply\\Nested\\IsBoolean';
225
        $this->buildAndCheck($deeplyNamespaced, DefaultsEnabledFieldTrait::class);
226
    }
227
228
    public function testFieldMustContainEntityNamespace(): void
229
    {
230
        $this->expectException(\InvalidArgumentException::class);
231
        $this->fieldGenerator->generateField(
232
            '\\Blah\\Foop',
233
            MappingHelper::TYPE_STRING,
234
            null,
235
            null,
236
            true
237
        );
238
    }
239
240
    public function testFieldTypeMustBeValid(): void
241
    {
242
        $this->expectException(\InvalidArgumentException::class);
243
        $this->fieldGenerator->generateField(
244
            self::CAR_FIELDS_TO_TYPES[0][0],
245
            'invalid',
246
            null,
247
            null,
248
            true
249
        );
250
    }
251
252
    public function testPHPTypeMustBeValid(): void
253
    {
254
        $this->expectException(\InvalidArgumentException::class);
255
        $this->fieldGenerator->generateField(
256
            self::CAR_FIELDS_TO_TYPES[0][0],
257
            MappingHelper::PHP_TYPE_FLOAT,
258
            'invalid',
259
            null,
260
            true
261
        );
262
    }
263
264
    public function testDefaultTypeMustBeValid(): void
265
    {
266
        $this->expectException(\InvalidArgumentException::class);
267
        $this->fieldGenerator->generateField(
268
            self::CAR_FIELDS_TO_TYPES[0][0],
269
            MappingHelper::PHP_TYPE_FLOAT,
270
            'invalid',
271
            'clearly not a float',
272
            true
273
        );
274
    }
275
276
    /**
277
     * Default values passed in by CLI could come through quite dirty and need to be normalised     *
278
     */
279
    public function testDefaultValueIsNormalised(): void
280
    {
281
        $defaultValuesToTypes = [
282
            MappingHelper::TYPE_INTEGER => [
283
                1,
284
                '1',
285
                ' 1',
286
                ' 1 ',
287
            ],
288
            MappingHelper::TYPE_FLOAT   => [
289
                1,
290
                1.0,
291
                '1',
292
                '1.1',
293
                ' 1.1 ',
294
                ' 1.1 ',
295
            ],
296
            MappingHelper::TYPE_BOOLEAN => [
297
                'true',
298
                'false',
299
                'TRUE',
300
                'FALSE',
301
                ' TRue ',
302
                ' FaLse ',
303
            ],
304
        ];
305
        $errors               = [];
306
        foreach ($defaultValuesToTypes as $type => $defaultValues) {
307
            foreach ($defaultValues as $key => $defaultValue) {
308
                try {
309
                    $this->buildAndCheck(
310
                        self::TEST_FIELD_NAMESPACE . '\\normalisedDefault' . $type . $key,
311
                        $type,
312
                        $defaultValue
313
                    );
314
                } catch (\Throwable $e) {
315
                    $errors[] = [
316
                        'type'    => $type,
317
                        'default' => $defaultValue,
318
                        'error'   => $e->getMessage(),
319
                    ];
320
                }
321
            }
322
        }
323
        self::assertSame([], $errors, print_r($errors, true));
324
    }
325
326
    public function testBuildFieldsAndSetToEntity(): void
327
    {
328
        foreach (self::CAR_FIELDS_TO_TYPES as $args) {
329
            $fieldFqn = $this->buildAndCheck($args[0], $args[1], null);
330
            $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $fieldFqn);
331
        }
332
        $this->qaGeneratedCode();
333
    }
334
335
    public function testBuildFieldsWithSuffixAndSetToEntity(): void
336
    {
337
        foreach (self::CAR_FIELDS_TO_TYPES as $args) {
338
            $fieldFqn = $this->buildAndCheck($args[0] . FieldGenerator::FIELD_TRAIT_SUFFIX, $args[1], null);
339
            $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $fieldFqn);
340
        }
341
        $this->qaGeneratedCode();
342
    }
343
344
    public function testBuildNullableFieldsAndSetToEntity(): void
345
    {
346
        foreach (self::CAR_FIELDS_TO_TYPES as $args) {
347
            $fieldFqn = $this->buildAndCheck($args[0], $args[1], null);
348
            $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $fieldFqn);
349
        }
350
        $this->qaGeneratedCode();
351
    }
352
353
    public function testBuildUniqueFieldsAndSetToEntity(): void
354
    {
355
        foreach (self::UNIQUE_FIELDS_TO_TYPES as $args) {
356
            $fieldFqn = $this->buildAndCheck($args[0], $args[1], null, true);
357
            $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $fieldFqn);
358
        }
359
        $this->qaGeneratedCode();
360
    }
361
362
    public function testBuildingAnArchetypeThenNormalField(): void
363
    {
364
        $this->buildAndCheck(self::TEST_FIELD_NAMESPACE . '\\UniqueName', UniqueStringFieldTrait::class);
365
        $this->buildAndCheck(self::TEST_FIELD_NAMESPACE . '\\SimpleString', MappingHelper::TYPE_STRING);
366
        $this->buildAndCheck(self::TEST_FIELD_NAMESPACE . '\\UniqueThing', UniqueStringFieldTrait::class);
367
    }
368
369
    public function testNotPossibleToAddDuplicateNamedFieldsToSingleEntity(): void
370
    {
371
        $someThing  = self::TEST_FIELD_NAMESPACE . '\\Something\\FooFieldTrait';
372
        $otherThing = self::TEST_FIELD_NAMESPACE . '\\Otherthing\\FooFieldTrait';
373
        $this->buildAndCheck($someThing, UniqueStringFieldTrait::class);
374
        $this->buildAndCheck($otherThing, BusinessIdentifierCodeFieldTrait::class);
375
        $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $someThing);
376
        $this->expectException(\InvalidArgumentException::class);
377
        $this->entityFieldSetter->setEntityHasField(self::TEST_ENTITY_CAR, $otherThing);
378
379
    }
380
}
381