Issues (40)

Tests/ApplicationTest.php (12 issues)

1
<?php
2
/**
3
* @author SignpostMarv
4
*/
5
declare(strict_types=1);
6
7
namespace SignpostMarv\DaftFramework\Tests;
8
9
use BadMethodCallException;
10
use Generator;
11
use PHPUnit\Framework\TestCase as Base;
12
use ReflectionClass;
13
use ReflectionMethod;
14
use RuntimeException;
15
use SignpostMarv\DaftFramework\Framework;
16
use SignpostMarv\DaftFramework\Symfony\Console\Application;
17
use SignpostMarv\DaftFramework\Symfony\Console\Command\Command;
18
use SignpostMarv\DaftFramework\Symfony\Console\Command\FastRouteCacheCommand;
19
use SignpostMarv\DaftFramework\Symfony\Console\DaftConsoleSource;
20
use SignpostMarv\DaftFramework\Tests\fixtures\Console\Command\ExecuteCoverageCommand;
21
use SignpostMarv\DaftFramework\Tests\fixtures\Console\Command\TestCommand;
22
use SignpostMarv\DaftRouter\DaftSource;
23
use SignpostMarv\DaftRouter\Tests\Fixtures\Config;
24
use Symfony\Component\Console\Command\Command as BaseCommand;
25
use Symfony\Component\Console\Input\InputArgument;
26
use Symfony\Component\Console\Tester\CommandTester;
27
28
class ApplicationTest extends Base
29
{
30
	const NUM_EXPECTED_ARGS = 6;
31
32
	/**
33
	* @psalm-return Generator<int, array{0:string, 1:string, 2:array<int, class-string>, 3:class-string<Framework>, 4:array}, mixed, void>
34
	*/
35
	final public function DataProviderConsoleApplicationConfigFiltered() : Generator
36
	{
37
		foreach ($this->DataProviderConsoleApplicationConfig() as $args) {
38
			if (
39
				self::NUM_EXPECTED_ARGS === count($args) &&
40
				is_file($args[0])
0 ignored issues
show
$args[0] of type array<integer,array<integer,string>|string> is incompatible with the type string expected by parameter $filename of is_file(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

40
				is_file(/** @scrutinizer ignore-type */ $args[0])
Loading history...
41
			) {
42
				$configFile = array_shift($args);
43
44
				end($args);
45
				$key = (int) key($args);
46
				$appendTo = (array) $args[$key];
47
				$appendTo[] = (array) include($configFile);
48
				$args[$key] = $appendTo;
49
50
				/**
51
				* @psalm-var array{0:string, 1:string, 2:array<int, class-string>, 3:class-string<Framework>, 4:array}
52
				*/
53
				$args = $args;
54
55
				yield $args;
56
			}
57
		}
58
	}
59
60
	/**
61
	* @psalm-return Generator<int, array{0:Framework, 1:Command}, mixed, void>
62
	*/
63
	final public function DataProviderDaftConsoleCommands() : Generator
64
	{
65
		foreach ($this->DataProviderConsoleApplicationConfigFiltered() as $args) {
66
			$frameworkImplementation = (string) $args[3];
67
68
			if ( ! is_a($frameworkImplementation, Framework::class, true)) {
69
				static::assertTrue(is_a($frameworkImplementation, Framework::class, true));
70
			}
71
72
			$framework = Utilities::ObtainFrameworkInstanceMixedArgs(
73
				$this,
74
				$frameworkImplementation,
75
				...array_values((array) $args[4])
76
			);
77
78
			/**
79
			* @var scalar[]
80
			*/
81
			$maybeCommandSources = ($args[2] ?? []);
82
83
			foreach ($maybeCommandSources as $maybeCommand) {
84
				if (
85
					is_string($maybeCommand) &&
86
					is_a($maybeCommand, Command::class, true) &&
87
					Command::class !== $maybeCommand
88
				) {
89
					$refClass = new ReflectionClass($maybeCommand);
90
91
					if ($refClass->isAbstract()) {
92
						static::assertFalse($refClass->isAbstract());
93
94
						return;
95
					}
96
97
					/**
98
					* @var Command
99
					*/
100
					$command = new $maybeCommand($maybeCommand::getDefaultName());
101
102
					yield [$framework, $command];
103
				}
104
			}
105
		}
106
	}
107
108
	/**
109
	* @param array<int, string> $expectedCommandInstances
110
	*
111
	* @psalm-param array<int, class-string> $expectedCommandInstances
112
	*
113
	* @dataProvider DataProviderConsoleApplicationConfigFiltered
114
	*/
115
	public function testApplicationSetup(
116
		string $name,
117
		string $version,
118
		array $expectedCommandInstances,
119
		string $frameworkImplementation,
120
		array $frameworkArgs
121
	) : void {
122
		if ( ! is_a($frameworkImplementation, Framework::class, true)) {
123
			static::assertTrue(is_a($frameworkImplementation, Framework::class, true));
124
125
			return;
126
		}
127
128
		$framework = Utilities::ObtainFrameworkInstanceMixedArgs(
129
			$this,
130
			$frameworkImplementation,
131
			...$frameworkArgs
132
		);
133
134
		static::assertSame($frameworkArgs[0], $framework->ObtainBaseUrl());
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\Assert::assertSame() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
		static::/** @scrutinizer ignore-call */ 
135
          assertSame($frameworkArgs[0], $framework->ObtainBaseUrl());
Loading history...
135
		static::assertSame($frameworkArgs[1], $framework->ObtainBasePath());
136
		static::assertSame($frameworkArgs[2], $framework->ObtainConfig());
137
138
		$application = Application::CollectApplicationWithCommands($name, $version, $framework);
139
140
		static::assertSame($name, $application->getName());
0 ignored issues
show
$name of type string is incompatible with the type PHPUnit\Framework\T expected by parameter $expected of PHPUnit\Framework\Assert::assertSame(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
		static::assertSame(/** @scrutinizer ignore-type */ $name, $application->getName());
Loading history...
141
		static::assertSame($version, $application->getVersion());
142
143
		$commands = array_map('get_class', $application->all());
144
145
		foreach ($expectedCommandInstances as $expectedComamnd) {
146
			static::assertTrue(class_exists($expectedComamnd));
147
			static::assertContains($expectedComamnd, $commands);
0 ignored issues
show
The method assertContains() does not exist on SignpostMarv\DaftFramework\Tests\ApplicationTest. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

147
			static::/** @scrutinizer ignore-call */ 
148
           assertContains($expectedComamnd, $commands);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
148
		}
149
150
		$constructedApplication = new Application($name, $version);
151
152
		$constructedApplication->AttachDaftFramework($framework);
153
154
		$constructedApplication->CollectCommands(...$expectedCommandInstances);
155
156
		$commands = array_map('get_class', $application->all());
157
158
		foreach ($expectedCommandInstances as $expectedComamnd) {
159
			static::assertTrue(class_exists($expectedComamnd));
160
			static::assertContains($expectedComamnd, $commands);
161
		}
162
163
		$failingApplication = new Application($name, $version);
164
165
		static::assertSame($name, $application->getName());
166
		static::assertSame($version, $application->getVersion());
167
168
		foreach ($expectedCommandInstances as $i => $expectedComamnd) {
169
			if ( ! is_a($expectedComamnd, BaseCommand::class, true)) {
170
				throw new RuntimeException(sprintf(
171
					'Index %s of Argument 3 passed to %s must be an implementation of %s, %s given!',
172
					$i,
173
					__METHOD__,
174
					BaseCommand::class,
175
					$expectedComamnd
176
				));
177
			}
178
179
			/**
180
			* @var BaseCommand
181
			*/
182
			$command = new $expectedComamnd($expectedComamnd::getDefaultName());
183
184
			$this->expectException(BadMethodCallException::class);
185
			$this->expectExceptionMessage(
0 ignored issues
show
The method expectExceptionMessage() does not exist on SignpostMarv\DaftFramework\Tests\ApplicationTest. Did you maybe mean expectException()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

185
			$this->/** @scrutinizer ignore-call */ 
186
          expectExceptionMessage(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
186
				'Cannot add a daft framework command without a framework being attached!'
187
			);
188
189
			$failingApplication->add($command);
190
		}
191
	}
192
193
	/**
194
	* @param array<int, string> $expectedCommandInstances
195
	*
196
	* @psalm-param array<int, class-string> $expectedCommandInstances
197
	*
198
	* @dataProvider DataProviderConsoleApplicationConfigFiltered
199
	*
200
	* @depends testApplicationSetup
201
	*/
202
	public function testCommandCollectionWithoutFramework(
203
		string $name,
204
		string $version,
205
		array $expectedCommandInstances
206
	) : void {
207
		$constructedApplication = new Application($name, $version);
208
209
		$this->expectException(BadMethodCallException::class);
210
		$this->expectExceptionMessage(
211
			'Cannot collect commands without an attached framework instance!'
212
		);
213
214
		$constructedApplication->CollectCommands(...$expectedCommandInstances);
215
	}
216
217
	/**
218
	* @dataProvider DataProviderDaftConsoleCommands
219
	*
220
	* @depends testApplicationSetup
221
	*/
222
	public function testCommandFrameworkAttachment(Framework $framework, Command $command) : void
223
	{
224
		static::assertFalse($command->CheckIfUsingFrameworkInstance($framework));
225
226
		$command->AttachDaftFramework($framework);
227
228
		static::assertTrue($command->CheckIfUsingFrameworkInstance($framework));
229
230
		static::assertSame($framework, $command->DetachDaftFramework());
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\Assert::assertSame() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

230
		static::/** @scrutinizer ignore-call */ 
231
          assertSame($framework, $command->DetachDaftFramework());
Loading history...
231
232
		static::assertFalse($command->CheckIfUsingFrameworkInstance($framework));
233
234
		$command->AttachDaftFramework($framework);
235
236
		static::assertTrue($command->CheckIfUsingFrameworkInstance($framework));
237
238
		$this->expectException(BadMethodCallException::class);
239
		$this->expectExceptionMessage(
240
			'Framework must not be attached if a framework is already attached!'
241
		);
242
243
		$command->AttachDaftFramework($framework);
244
	}
245
246
	/**
247
	* @psalm-return Generator<int, array{0:Application, 1:string}, mixed, void>
248
	*/
249
	public function DataProviderFastRouteCacheComamnd() : Generator
250
	{
251
		$expectedOutput = file_get_contents(
252
			__DIR__ .
253
			'/fixtures/here-is-one-i-made-earlier.fast-route.cache'
254
		);
255
256
		foreach ($this->DataProviderConsoleApplicationConfigFiltered() as $i => $args) {
257
			/**
258
			* @var string
259
			*/
260
			$frameworkImplementation = $args[3];
261
262
			if ( ! is_a($frameworkImplementation, Framework::class, true)) {
263
				throw new RuntimeException(sprintf(
264
					'Index %s[3] retrieved from %s::%s must be an implementation of %s, %s given!',
265
					$i,
266
					get_class($this),
267
					'DataProviderConsoleApplicationConfigFiltered',
268
					Framework::class,
269
					$frameworkImplementation
270
				));
271
			}
272
273
			/**
274
			* @var array<string, array>
275
			*/
276
			$args42 = (array) ((array) $args[4])[2] ?? [];
277
			$args42[DaftConsoleSource::class][] = FastRouteCacheCommand::class;
278
			$args42[DaftSource::class]['sources'] = [Config::class];
279
			$args4 = (array) $args[4];
280
			$args4[2] = $args42;
281
282
			$args[4] = $args4;
283
284
			$framework = Utilities::ObtainFrameworkInstanceMixedArgs(
285
				$this,
286
				$frameworkImplementation,
287
				...$args[4]
288
			);
289
290
			$application = Application::CollectApplicationWithCommands(
291
				(string) $args[0],
292
				(string) $args[1],
293
				$framework
294
			);
295
296
			yield [$application, $expectedOutput];
297
		}
298
	}
299
300
	/**
301
	* @dataProvider DataProviderFastRouteCacheComamnd
302
	*/
303
	public function testFastRouteCacheCommand(
304
		Application $application,
305
		string $expectedOutput
306
	) : void {
307
		$command = new FastRouteCacheCommand();
308
309
		$ref = new ReflectionMethod($command, 'configure');
310
		$ref->setAccessible(true);
311
312
		$command->getDefinition()->setDefinition([]);
313
314
		$ref->invoke($command);
315
316
		static::assertSame(
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\Assert::assertSame() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

316
		static::/** @scrutinizer ignore-call */ 
317
          assertSame(
Loading history...
317
			'Update the cache used by the daft framework router',
0 ignored issues
show
'Update the cache used b... daft framework router' of type string is incompatible with the type PHPUnit\Framework\T expected by parameter $expected of PHPUnit\Framework\Assert::assertSame(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

317
			/** @scrutinizer ignore-type */ 'Update the cache used by the daft framework router',
Loading history...
318
			$command->getDescription()
319
		);
320
321
		static::assertSame(
322
			[
0 ignored issues
show
array('sources' => array...ss names for sources')) of type array<string,array<string,array|string|true>> is incompatible with the type PHPUnit\Framework\T expected by parameter $expected of PHPUnit\Framework\Assert::assertSame(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

322
			/** @scrutinizer ignore-type */ [
Loading history...
323
				'sources' => [
324
					'name' => 'sources',
325
					'required' => true,
326
					'array' => true,
327
					'default' => [],
328
					'description' => 'class names for sources',
329
				],
330
			],
331
			array_map(
332
				function (InputArgument $arg) : array {
333
					return [
334
						'name' => $arg->getName(),
335
						'required' => $arg->isRequired(),
336
						'array' => $arg->isArray(),
337
						'default' => $arg->getDefault(),
338
						'description' => $arg->getDescription(),
339
					];
340
				},
341
				$command->getDefinition()->getArguments()
342
			)
343
		);
344
345
		// ref: https://stackoverflow.com/questions/47183273/test-command-symfony-with-phpunit
346
347
		$command = $application->find('daft-framework:router:update-cache');
348
349
		static::assertInstanceOf(FastRouteCacheCommand::class, $command);
350
351
		$commandTester = new CommandTester($command);
352
353
		$commandTester->execute(
354
			[
355
				'sources' => [
356
					Config::class,
357
				],
358
			],
359
			[
360
				'command' => $command->getName(),
361
			]
362
		);
363
364
		static::assertSame($expectedOutput, $commandTester->getDisplay());
365
	}
366
367
	/**
368
	* @dataProvider DataProviderFastRouteCacheComamnd
369
	*/
370
	public function testExecuteCoverageCommand(Application $application) : void
371
	{
372
		$command = $application->find('test:execute-coverage');
373
374
		static::assertInstanceOf(ExecuteCoverageCommand::class, $command);
375
376
		$commandTester = new CommandTester($command);
377
378
		$result = $commandTester->execute(
379
			[
380
				'sources' => [
381
					Config::class,
382
				],
383
			],
384
			[
385
				'command' => $command->getName(),
386
			]
387
		);
388
389
		static::assertSame(1, $result);
0 ignored issues
show
1 of type integer is incompatible with the type PHPUnit\Framework\T expected by parameter $expected of PHPUnit\Framework\Assert::assertSame(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

389
		static::assertSame(/** @scrutinizer ignore-type */ 1, $result);
Loading history...
Bug Best Practice introduced by
The method PHPUnit\Framework\Assert::assertSame() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

389
		static::/** @scrutinizer ignore-call */ 
390
          assertSame(1, $result);
Loading history...
390
		static::assertSame(
391
			('could not get temporary filename!' . PHP_EOL),
0 ignored issues
show
'could not get temporary...Framework\Tests\PHP_EOL of type string is incompatible with the type PHPUnit\Framework\T expected by parameter $expected of PHPUnit\Framework\Assert::assertSame(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

391
			/** @scrutinizer ignore-type */ ('could not get temporary filename!' . PHP_EOL),
Loading history...
392
			$commandTester->getDisplay()
393
		);
394
	}
395
396
	/**
397
	* @psalm-return Generator<int, array{0:string, 1:string, 2:string, 3:array<int, class-string>, 4:class-string<Framework>, 5:array}, mixed, void>
398
	*/
399
	protected function DataProviderConsoleApplicationConfig() : Generator
400
	{
401
		yield from [
402
			[
403
				__DIR__ . '/fixtures/config.php',
404
				'Test',
405
				'0.0.0',
406
				[
407
					TestCommand::class,
408
				],
409
				Framework::class,
410
				[
411
					'https://example.com/',
412
					realpath(__DIR__ . '/fixtures'),
413
				],
414
			],
415
		];
416
	}
417
}
418