Skip to content

Commit 82c53d0

Browse files
fix: Enhance error handling in ServiceMap for invalid configuration structures and add corresponding test cases. (#27)
1 parent 20c3dea commit 82c53d0

11 files changed

+312
-221
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# Change Log
22

3-
## 0.2.3 June 05, 2025
3+
## 0.2.3 June 06, 2025
44

55
- Enh #25: Add support for PHPStan Extension Installer (@samuelrajan747)
6-
- Enh #26: Add PHPStan extension installer instructions and improve `ServiceMap` configuration handling.
6+
- Enh #26: Add PHPStan extension installer instructions and improve `ServiceMap` configuration handling (@terabytesoftw)
7+
- Bug #27: Enhance error handling in `ServiceMap` for invalid configuration structures and add corresponding test cases (@terabytesoftw)
78

89
## 0.2.2 June 04, 2025
910

src/ServiceMap.php

Lines changed: 211 additions & 175 deletions
Large diffs are not rendered by default.

tests/ServiceMapTest.php

Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function testItAllowsContainerWithoutDefinitionsAndSingletons(): void
4949

5050
$ds = DIRECTORY_SEPARATOR;
5151

52-
new ServiceMap(__DIR__ . "{$ds}fixture{$ds}container-not-definitions.php");
52+
new ServiceMap(__DIR__ . "{$ds}fixture{$ds}config-container-empty.php");
5353
}
5454

5555
/**
@@ -76,7 +76,6 @@ public function testItLoadsServicesAndComponents(): void
7676
$serviceMap->getServiceClassFromNode(new String_(MyActiveRecord::class)),
7777
'ServiceMap should resolve \'MyActiveRecord::class\' as a singleton string service.',
7878
);
79-
// Assert: Singleton closure service resolves to SplStack::class.
8079
$this->assertSame(
8180
SplStack::class,
8281
$serviceMap->getServiceClassFromNode(new String_('singleton-closure')),
@@ -123,26 +122,34 @@ public function testItLoadsServicesAndComponents(): void
123122
);
124123
}
125124

126-
/**
127-
* @throws ReflectionException if the service definition is invalid or can't be resolved.
128-
*/
129125
public function testItAllowsWithoutEmptyConfigPath(): void
130126
{
131127
$this->expectNotToPerformAssertions();
132128

133129
new ServiceMap();
134130
}
135131

136-
/**
137-
* @throws ReflectionException if the service definition is invalid or can't be resolved.
138-
*/
139132
public function testItAllowsWithoutEmptyConfigPathStringValue(): void
140133
{
141134
$this->expectNotToPerformAssertions();
142135

143136
new ServiceMap('');
144137
}
145138

139+
/**
140+
* @throws ReflectionException if the service definition is invalid or can't be resolved.
141+
*/
142+
public function testThrowRuntimeExceptionWhenComponentsHasUnsupportedIsNotArrayValue(): void
143+
{
144+
$ds = DIRECTORY_SEPARATOR;
145+
$fixturePath = __DIR__ . "{$ds}fixture{$ds}components-unsupported-is-not-array.php";
146+
147+
$this->expectException(RuntimeException::class);
148+
$this->expectExceptionMessage("Configuration file '{$fixturePath}' must contain a valid 'components' 'array'.");
149+
150+
new ServiceMap($fixturePath);
151+
}
152+
146153
/**
147154
* @throws ReflectionException if the service definition is invalid or can't be resolved.
148155
*/
@@ -152,44 +159,93 @@ public function testThrowRuntimeExceptionWhenComponentsHasUnsupportedIdNotString
152159
$fixturePath = __DIR__ . "{$ds}fixture{$ds}components-unsupported-id-not-string.php";
153160

154161
$this->expectException(RuntimeException::class);
155-
$this->expectExceptionMessage('Component ID must be a string, got \'integer\'.');
162+
$this->expectExceptionMessage('\'Component\': ID must be a string, got \'integer\'.');
156163

157164
new ServiceMap($fixturePath);
158165
}
159166

160167
/**
161168
* @throws ReflectionException if the service definition is invalid or can't be resolved.
162169
*/
163-
public function testThrowRuntimeExceptionWhenComponentsHasUnsupportedTypeIntegerValue(): void
170+
public function testThrowRuntimeExceptionWhenComponentsHasUnsupportedTypeArrayInvalidValue(): void
164171
{
165172
$ds = DIRECTORY_SEPARATOR;
166-
$fixturePath = __DIR__ . "{$ds}fixture{$ds}components-unsupported-type-integer.php";
173+
$fixturePath = __DIR__ . "{$ds}fixture{$ds}components-unsupported-type-array-invalid.php";
167174

168175
$this->expectException(RuntimeException::class);
169-
$this->expectExceptionMessage('Unsupported component definition for \'integer\'.');
176+
$this->expectExceptionMessage('Unsupported definition for \'unsupported-array-invalid\'.');
170177

171178
new ServiceMap($fixturePath);
172179
}
173180

174181
public function testThrowRuntimeExceptionWhenConfigPathFileDoesNotExist(): void
175182
{
176183
$this->expectException(InvalidArgumentException::class);
177-
$this->expectExceptionMessage('Provided config path invalid-path must exist');
184+
$this->expectExceptionMessage('Provided config path \'invalid-path\' must be a readable file.');
178185

179186
new ServiceMap('invalid-path');
180187
}
181188

189+
/**
190+
* @throws ReflectionException if the service definition is invalid or can't be resolved.
191+
*/
182192
public function testThrowRuntimeExceptionWhenConfigHasUnsupportedIsNotArrayValue(): void
183193
{
184194
$ds = DIRECTORY_SEPARATOR;
185-
$fixturePath = __DIR__ . "{$ds}fixture{$ds}config-unsupported-integer.php";
195+
$fixturePath = __DIR__ . "{$ds}fixture{$ds}config-unsupported-is-not-array.php";
186196

187197
$this->expectException(RuntimeException::class);
188198
$this->expectExceptionMessage("Configuration file '{$fixturePath}' must return an array.");
189199

190200
new ServiceMap($fixturePath);
191201
}
192202

203+
/**
204+
* @throws ReflectionException if the service definition is invalid or can't be resolved.
205+
*/
206+
public function testThrowRuntimeExceptionWhenConfigContainerDefinitionsHasUnsupportedIsNotArrayValue(): void
207+
{
208+
$ds = DIRECTORY_SEPARATOR;
209+
$fixturePath = __DIR__ . "{$ds}fixture{$ds}definitions-unsupported-is-not-array.php";
210+
211+
$this->expectException(RuntimeException::class);
212+
$this->expectExceptionMessage(
213+
"Configuration file '{$fixturePath}' must contain a valid 'container.definitions' 'array'.",
214+
);
215+
216+
new ServiceMap($fixturePath);
217+
}
218+
219+
/**
220+
* @throws ReflectionException if the service definition is invalid or can't be resolved.
221+
*/
222+
public function testThrowRuntimeExceptionWhenConfigContainerHasUnsupportedIsNotArrayValue(): void
223+
{
224+
$ds = DIRECTORY_SEPARATOR;
225+
$fixturePath = __DIR__ . "{$ds}fixture{$ds}config-container-unsupported-type-array-invalid.php";
226+
227+
$this->expectException(RuntimeException::class);
228+
$this->expectExceptionMessage("Configuration file '{$fixturePath}' must contain a valid 'container' 'array'.");
229+
230+
new ServiceMap($fixturePath);
231+
}
232+
233+
/**
234+
* @throws ReflectionException if the service definition is invalid or can't be resolved.
235+
*/
236+
public function testThrowRuntimeExceptionWhenConfigContainerSingletonsHasUnsupportedIsNotArrayValue(): void
237+
{
238+
$ds = DIRECTORY_SEPARATOR;
239+
$fixturePath = __DIR__ . "{$ds}fixture{$ds}singletons-unsupported-is-not-array.php";
240+
241+
$this->expectException(RuntimeException::class);
242+
$this->expectExceptionMessage(
243+
"Configuration file '{$fixturePath}' must contain a valid 'container.singletons' 'array'.",
244+
);
245+
246+
new ServiceMap($fixturePath);
247+
}
248+
193249
/**
194250
* @throws ReflectionException if the service definition is invalid or can't be resolved.
195251
*/
@@ -213,7 +269,7 @@ public function testThrowRuntimeExceptionWhenContainerDefinitionsHasUnsupportedI
213269
$fixturePath = __DIR__ . "{$ds}fixture{$ds}definitions-unsupported-id-not-string.php";
214270

215271
$this->expectException(RuntimeException::class);
216-
$this->expectExceptionMessage('Service ID must be a string, got \'integer\'.');
272+
$this->expectExceptionMessage('\'Definition\': ID must be a string, got \'integer\'.');
217273

218274
new ServiceMap($fixturePath);
219275
}
@@ -224,10 +280,10 @@ public function testThrowRuntimeExceptionWhenContainerDefinitionsHasUnsupportedI
224280
public function testThrowRuntimeExceptionWhenContainerDefinitionsHasUnsupportedIsNotArrayValue(): void
225281
{
226282
$ds = DIRECTORY_SEPARATOR;
227-
$fixturePath = __DIR__ . "{$ds}fixture{$ds}definitions-unsupported-integer.php";
283+
$fixturePath = __DIR__ . "{$ds}fixture{$ds}definitions-unsupported-type-integer.php";
228284

229285
$this->expectException(RuntimeException::class);
230-
$this->expectExceptionMessage('Unsupported service definition for \'integer\'.');
286+
$this->expectExceptionMessage('Unsupported definition for \'unsupported-type-integer\'.');
231287

232288
new ServiceMap($fixturePath);
233289
}
@@ -241,9 +297,7 @@ public function testThrowRuntimeExceptionWhenContainerDefinitionsHasUnsupportedT
241297
$fixturePath = __DIR__ . "{$ds}fixture{$ds}definitions-unsupported-type-array-invalid.php";
242298

243299
$this->expectException(RuntimeException::class);
244-
$this->expectExceptionMessage(
245-
'Service definition must be an \'array\', \'integer\', \'object\', or \'string\', got \'resource\'.',
246-
);
300+
$this->expectExceptionMessage('Unsupported definition for \'unsupported-array-invalid\'.');
247301

248302
new ServiceMap($fixturePath);
249303
}
@@ -257,7 +311,7 @@ public function testThrowRuntimeExceptionWhenContainerDefinitionsHasUnsupportedT
257311
$fixturePath = __DIR__ . "{$ds}fixture{$ds}definitions-unsupported-empty-array.php";
258312

259313
$this->expectException(RuntimeException::class);
260-
$this->expectExceptionMessage('Cannot guess service definition for \'unsupported-empty-array\'.');
314+
$this->expectExceptionMessage('Unsupported definition for \'unsupported-empty-array\'.');
261315

262316
new ServiceMap($fixturePath);
263317
}
@@ -271,7 +325,7 @@ public function testThrowRuntimeExceptionWhenContainerDefinitionsHasUnsupportedT
271325
$fixturePath = __DIR__ . "{$ds}fixture{$ds}definitions-unsupported-type-integer.php";
272326

273327
$this->expectException(RuntimeException::class);
274-
$this->expectExceptionMessage('Unsupported service definition for \'unsupported-type-integer\'.');
328+
$this->expectExceptionMessage('Unsupported definition for \'unsupported-type-integer\'.');
275329

276330
new ServiceMap($fixturePath);
277331
}
@@ -299,21 +353,21 @@ public function testThrowRuntimeExceptionWhenContainerSingletonsHasUnsupportedId
299353
$fixturePath = __DIR__ . "{$ds}fixture{$ds}singletons-unsupported-id-not-string.php";
300354

301355
$this->expectException(RuntimeException::class);
302-
$this->expectExceptionMessage('Singleton ID must be a string, got \'integer\'.');
356+
$this->expectExceptionMessage('\'Singleton\': ID must be a string, got \'integer\'.');
303357

304358
new ServiceMap($fixturePath);
305359
}
306360

307361
/**
308362
* @throws ReflectionException if the service definition is invalid or can't be resolved.
309363
*/
310-
public function testThrowRuntimeExceptionWhenContainerSingletonsHasUnsupportedIsNotArrayValue(): void
364+
public function testThrowRuntimeExceptionWhenContainerSingletonsHasUnsupportedTypeArrayInvalidValue(): void
311365
{
312366
$ds = DIRECTORY_SEPARATOR;
313-
$fixturePath = __DIR__ . "{$ds}fixture{$ds}singletons-unsupported-is-not-array.php";
367+
$fixturePath = __DIR__ . "{$ds}fixture{$ds}singletons-unsupported-type-array-invalid.php";
314368

315369
$this->expectException(RuntimeException::class);
316-
$this->expectExceptionMessage('Unsupported singletons definition for \'integer\'.');
370+
$this->expectExceptionMessage('Unsupported definition for \'unsupported-array-invalid\'.');
317371

318372
new ServiceMap($fixturePath);
319373
}
@@ -327,21 +381,7 @@ public function testThrowRuntimeExceptionWhenContainerSingletonsHasUnsupportedTy
327381
$fixturePath = __DIR__ . "{$ds}fixture{$ds}singletons-unsupported-empty-array.php";
328382

329383
$this->expectException(RuntimeException::class);
330-
$this->expectExceptionMessage('Cannot guess service definition for \'unsupported-empty-array\'.');
331-
332-
new ServiceMap($fixturePath);
333-
}
334-
335-
/**
336-
* @throws ReflectionException if the service definition is invalid or can't be resolved.
337-
*/
338-
public function testThrowRuntimeExceptionWhenContainerSingletonsHasUnsupportedTypeIntegerValue(): void
339-
{
340-
$ds = DIRECTORY_SEPARATOR;
341-
$fixturePath = __DIR__ . "{$ds}fixture{$ds}singletons-unsupported-type-integer.php";
342-
343-
$this->expectException(RuntimeException::class);
344-
$this->expectExceptionMessage('Singleton service definition must be an array, got \'integer\'.');
384+
$this->expectExceptionMessage('Unsupported definition for \'unsupported-empty-array\'.');
345385

346386
new ServiceMap($fixturePath);
347387
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return [
6+
'components' => 1,
7+
];

tests/fixture/components-unsupported-type-integer.php renamed to tests/fixture/components-unsupported-type-array-invalid.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
return [
66
'components' => [
7-
'unsupported-type-integer' => 5,
7+
'unsupported-array-invalid' => 1,
88
],
99
];
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return [
6+
'container' => 1,
7+
];

tests/fixture/definitions-unsupported-type-array-invalid.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
return [
66
'container' => [
77
'definitions' => [
8-
'unsupported-type-resource' => \fopen('php://memory', 'rb'),
8+
'unsupported-array-invalid' => 1,
99
],
1010
],
1111
];

0 commit comments

Comments
 (0)