[BUGFIX] Add initialization of DataMapper on QueryResult object wakeup
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Reflection / ClassSchemaTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Reflection;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Extbase\Reflection\ClassSchema;
19 use TYPO3\CMS\Extbase\Validation\Exception\InvalidTypeHintException;
20 use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationConfigurationException;
21 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
22
23 /**
24 * Test case
25 */
26 class ClassSchemaTest extends UnitTestCase
27 {
28 /**
29 * @test
30 */
31 public function classSchemaForModelIsSetAggregateRootIfRepositoryClassIsFoundForNamespacedClasses()
32 {
33 $this->resetSingletonInstances = true;
34 $service = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Reflection\ReflectionService::class);
35 $classSchema = $service->getClassSchema(Fixture\DummyModel::class);
36 $this->assertTrue($classSchema->isAggregateRoot());
37 }
38
39 /**
40 * @test
41 */
42 public function classSchemaHasConstructor()
43 {
44 $classSchema = new ClassSchema(Fixture\DummyClassWithConstructorAndConstructorArguments::class);
45 static::assertTrue($classSchema->hasConstructor());
46 }
47
48 /**
49 * @test
50 */
51 public function classSchemaGetProperties()
52 {
53 static::assertSame(
54 [
55 'publicProperty',
56 'protectedProperty',
57 'privateProperty',
58 'publicStaticProperty',
59 'protectedStaticProperty',
60 'privateStaticProperty',
61 'publicPropertyWithDefaultValue',
62 'propertyWithIgnoredTags',
63 'propertyWithInjectAnnotation',
64 'propertyWithTransientAnnotation',
65 'propertyWithCascadeAnnotation',
66 'propertyWithCascadeAnnotationWithoutVarAnnotation',
67 'propertyWithObjectStorageAnnotation',
68 'propertyWithObjectStorageAnnotationWithoutFQCN',
69 'uid',
70 '_localizedUid',
71 '_languageUid',
72 '_versionedUid',
73 'pid',
74 ],
75 array_keys((new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class))->getProperties())
76 );
77 }
78
79 /**
80 * @test
81 */
82 public function classSchemaHasMethod()
83 {
84 $classSchema = new ClassSchema(Fixture\DummyClassWithAllTypesOfMethods::class);
85 static::assertTrue($classSchema->hasMethod('publicMethod'));
86 static::assertFalse($classSchema->hasMethod('nonExistentMethod'));
87 }
88
89 /**
90 * @test
91 */
92 public function classSchemaGetMethods()
93 {
94 static::assertSame(
95 [
96 'publicMethod',
97 'protectedMethod',
98 'privateMethod',
99 'methodWithIgnoredTags',
100 'injectSettings',
101 'injectMethodWithoutParam',
102 'injectMethodThatIsProtected',
103 'injectFoo',
104 'staticMethod',
105 'methodWithMandatoryParam',
106 'methodWithNullableParam',
107 'methodWithDefaultValueParam',
108 'methodWithTypeHintedParam',
109 'methodWithDocBlockTypeHintOnly',
110 ],
111 array_keys((new ClassSchema(Fixture\DummyClassWithAllTypesOfMethods::class))->getMethods())
112 );
113 }
114
115 /**
116 * @test
117 */
118 public function classSchemaDetectsInjectProperties()
119 {
120 $classSchema = new ClassSchema(Fixture\DummyClassWithInjectDoctrineAnnotation::class);
121 static::assertTrue($classSchema->hasInjectProperties());
122
123 $injectProperties = $classSchema->getInjectProperties();
124 static::assertArrayHasKey('propertyWithFullQualifiedClassName', $injectProperties);
125 static::assertSame(Fixture\DummyClassWithInjectDoctrineAnnotation::class, $injectProperties['propertyWithFullQualifiedClassName']->getType());
126
127 static::assertArrayHasKey('propertyWithRelativeClassName', $injectProperties);
128 static::assertSame(Fixture\DummyClassWithInjectDoctrineAnnotation::class, $injectProperties['propertyWithRelativeClassName']->getType());
129
130 static::assertArrayHasKey('propertyWithImportedClassName', $injectProperties);
131 static::assertSame(self::class, $injectProperties['propertyWithImportedClassName']->getType());
132
133 static::assertArrayHasKey('propertyWithImportedAndAliasedClassName', $injectProperties);
134 static::assertSame(self::class, $injectProperties['propertyWithImportedAndAliasedClassName']->getType());
135 }
136
137 /**
138 * @test
139 */
140 public function classSchemaDetectsPropertyDefaultValue()
141 {
142 $classSchema = new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class);
143
144 $propertyDefinition = $classSchema->getProperty('publicPropertyWithDefaultValue');
145 static::assertSame('foo', $propertyDefinition->getDefaultValue());
146 }
147
148 /**
149 * @test
150 */
151 public function classSchemaDetectsSingletons()
152 {
153 static::assertTrue((new ClassSchema(Fixture\DummySingleton::class))->isSingleton());
154 }
155
156 /**
157 * @test
158 */
159 public function classSchemaDetectsModels()
160 {
161 static::assertTrue((new ClassSchema(Fixture\DummyEntity::class))->isModel());
162 static::assertTrue((new ClassSchema(Fixture\DummyValueObject::class))->isModel());
163 }
164
165 /**
166 * @test
167 */
168 public function classSchemaDetectsEntities()
169 {
170 static::assertTrue((new ClassSchema(Fixture\DummyEntity::class))->isEntity());
171 }
172
173 /**
174 * @test
175 */
176 public function classSchemaDetectsValueObjects()
177 {
178 static::assertTrue((new ClassSchema(Fixture\DummyValueObject::class))->isValueObject());
179 }
180
181 /**
182 * @test
183 */
184 public function classSchemaDetectsClassName()
185 {
186 $this->resetSingletonInstances = true;
187 static::assertSame(Fixture\DummyModel::class, (new ClassSchema(Fixture\DummyModel::class))->getClassName());
188 }
189
190 /**
191 * @test
192 */
193 public function classSchemaDetectsNonStaticProperties()
194 {
195 static::assertTrue((new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class))->hasProperty('publicProperty'));
196 static::assertTrue((new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class))->hasProperty('protectedProperty'));
197 static::assertTrue((new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class))->hasProperty('privateProperty'));
198 }
199
200 /**
201 * @test
202 */
203 public function classSchemaDetectsStaticProperties()
204 {
205 static::assertTrue((new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class))->hasProperty('publicStaticProperty'));
206 static::assertTrue((new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class))->hasProperty('protectedStaticProperty'));
207 static::assertTrue((new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class))->hasProperty('privateStaticProperty'));
208 }
209
210 /**
211 * @test
212 */
213 public function classSchemaGenerationThrowsExceptionWithValidateDoctrineAnnotationsForParamWithoutTypeHint()
214 {
215 $this->resetSingletonInstances = true;
216 $this->expectException(InvalidTypeHintException::class);
217 $this->expectExceptionMessage('Missing type information for parameter "$fooParam" in TYPO3\CMS\Extbase\Tests\Unit\Reflection\Fixture\DummyControllerWithValidateAnnotationWithoutParamTypeHint->methodWithValidateAnnotationsAction(): Either use an @param annotation or use a type hint.');
218 $this->expectExceptionCode(1515075192);
219
220 new ClassSchema(Fixture\DummyControllerWithValidateAnnotationWithoutParamTypeHint::class);
221 }
222
223 /**
224 * @test
225 */
226 public function classSchemaGenerationThrowsExceptionWithValidateDoctrineAnnotationsForMissingParam()
227 {
228 $this->resetSingletonInstances = true;
229 $this->expectException(InvalidValidationConfigurationException::class);
230 $this->expectExceptionMessage('Invalid validate annotation in TYPO3\CMS\Extbase\Tests\Unit\Reflection\Fixture\DummyControllerWithValidateAnnotationWithoutParam->methodWithValidateAnnotationsAction(): The following validators have been defined for missing param "$fooParam": NotEmpty, StringLength');
231 $this->expectExceptionCode(1515073585);
232
233 new ClassSchema(Fixture\DummyControllerWithValidateAnnotationWithoutParam::class);
234 }
235
236 /**
237 * @test
238 */
239 public function classSchemaDetectsMethodParameterTypeViaReflection(): void
240 {
241 $class = new class {
242 public function foo(string $foo)
243 {
244 }
245
246 public function bar(ClassSchema $foo)
247 {
248 }
249 };
250
251 $classSchema = new ClassSchema(get_class($class));
252 static::assertSame('string', $classSchema->getMethod('foo')->getParameter('foo')->getType());
253 static::assertSame(ClassSchema::class, $classSchema->getMethod('bar')->getParameter('foo')->getType());
254 }
255
256 /**
257 * @test
258 */
259 public function classSchemaPrefersMethodParameterTypeDetectionViaReflection(): void
260 {
261 $class = new class {
262 /**
263 * @param ClassSchema $foo
264 */
265 public function foo(string $foo)
266 {
267 }
268 };
269
270 $classSchema = new ClassSchema(get_class($class));
271 static::assertSame('string', $classSchema->getMethod('foo')->getParameter('foo')->getType());
272 }
273
274 /**
275 * @test
276 */
277 public function classSchemaDetectsMethodParameterTypeDetectionViaDocBlocksIfNoTypeHintIsGiven(): void
278 {
279 $classSchema = new ClassSchema(Fixture\DummyClassWithAllTypesOfMethods::class);
280 static::assertSame(Fixture\DummyClassWithAllTypesOfMethods::class, $classSchema->getMethod('methodWithDocBlockTypeHintOnly')->getParameter('param')->getType());
281 }
282 }