packages/deriver/tests/Unit/Configuration/LoaderTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Configuration;
6
7use Deriver\Configuration\Loader;
8use Deriver\Exception\ConfigurationException;
9use org\bovigo\vfs\vfsStream;
10use Override;
11use phpmock\Mock;
12use phpmock\MockBuilder;
13use PHPUnit\Framework\Attributes\CoversNothing;
14use PHPUnit\Framework\Attributes\PreserveGlobalState;
15use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
16use PHPUnit\Framework\TestCase;
17
18#[CoversNothing]
19#[RunTestsInSeparateProcesses]
20#[PreserveGlobalState(false)]
21final class LoaderTest extends TestCase
22{
23 /**
24 * @throws \phpmock\MockEnabledException
25 */
26 #[Override]
27 protected function setUp(): void
28 {
29 parent::setUp();
30 vfsStream::setup('project', null, ['config' => ['deliver.yaml' => "paths: [src, /external]\nphpVersion: '8.4'\n"]]);
31 (new MockBuilder())->setNamespace('Deriver\Configuration')->setName('is_file')->setFunction(static fn (string $path): bool => is_file('vfs:/' . $path))->build()->enable();
32 (new MockBuilder())->setNamespace('Deriver\Configuration')->setName('is_readable')->setFunction(static fn (string $path): bool => is_readable('vfs:/' . $path))->build()->enable();
33 (new MockBuilder())->setNamespace('Deriver\Configuration')->setName('file_get_contents')->setFunction(static fn (string $path): string|false => file_get_contents('vfs:/' . $path))->build()->enable();
34 }
35
36 public function testLoadAnchorsRelativeRootsToTheConfigurationDirectory(): void
37 {
38 $configuration = (new Loader())->load('/project/config/deliver.yaml');
39 self::assertSame(['/project/config/src', '/external'], $configuration->paths);
40 self::assertSame('8.4', $configuration->phpVersion);
41 }
42
43 public function testLoadWithoutAPathUsesDefaults(): void
44 {
45 self::assertSame(['.'], (new Loader())->load()->paths);
46 }
47
48 public function testLoadAnchorsDefaultRootForAnEmptyFile(): void
49 {
50 file_put_contents('vfs://project/config/deliver.yaml', '');
51 self::assertSame(['/project/config/.'], (new Loader())->load('/project/config/deliver.yaml')->paths);
52 }
53
54 public function testLoadRejectsMissingFiles(): void
55 {
56 $this->expectException(ConfigurationException::class);
57 (new Loader())->load('/project/missing.yaml');
58 }
59
60 public function testLoadRejectsMalformedYamlWithItsCause(): void
61 {
62 file_put_contents('vfs://project/config/deliver.yaml', "paths: [\n");
63 $this->expectException(ConfigurationException::class);
64 $this->expectExceptionMessage('Cannot load configuration');
65 (new Loader())->load('/project/config/deliver.yaml');
66 }
67
68 public function testLoadRejectsScalarDocuments(): void
69 {
70 file_put_contents('vfs://project/config/deliver.yaml', 'not-a-mapping');
71 $this->expectException(ConfigurationException::class);
72 (new Loader())->load('/project/config/deliver.yaml');
73 }
74
75 public function testLoadRejectsObjectTags(): void
76 {
77 file_put_contents('vfs://project/config/deliver.yaml', "environment: {APP_ENV: !php/object 'O:8:\"stdClass\":0:{}'}");
78 $this->expectException(ConfigurationException::class);
79 (new Loader())->load('/project/config/deliver.yaml');
80 }
81
82 #[Override]
83 protected function tearDown(): void
84 {
85 Mock::disableAll();
86 parent::tearDown();
87 }
88}
89