1<?php
2
3namespace Drupal\Tests\Component\Discovery;
4
5use Drupal\Component\Discovery\DiscoveryException;
6use Drupal\Component\Discovery\YamlDirectoryDiscovery;
7use Drupal\Component\FileCache\FileCacheFactory;
8use org\bovigo\vfs\vfsStream;
9use PHPUnit\Framework\TestCase;
10
11/**
12 * YamlDirectoryDiscoveryTest component unit tests.
13 *
14 * @coversDefaultClass \Drupal\Component\Discovery\YamlDirectoryDiscovery
15 *
16 * @group Discovery
17 */
18class YamlDirectoryDiscoveryTest extends TestCase {
19
20  /**
21   * {@inheritdoc}
22   */
23  protected function setUp(): void {
24    // Ensure that FileCacheFactory has a prefix.
25    FileCacheFactory::setPrefix('prefix');
26  }
27
28  /**
29   * Tests YAML directory discovery.
30   *
31   * @covers ::findAll
32   */
33  public function testDiscovery() {
34    vfsStream::setup('modules', NULL, [
35      'test_1' => [
36        'subdir1' => [
37          'item_1.test.yml' => "id: item1\nname: 'test1 item 1'",
38        ],
39        'subdir2' => [
40          'item_2.test.yml' => "id: item2\nname: 'test1 item 2'",
41        ],
42      ],
43      'test_2' => [
44        'subdir1' => [
45          'item_3.test.yml' => "id: item3\nname: 'test2 item 3'",
46        ],
47        'subdir2' => [],
48      ],
49      'test_3' => [],
50      'test_4' => [
51        'subdir1' => [
52          'item_4.test.yml' => "id: item4\nname: 'test4 item 4'",
53          'item_5.test.yml' => "id: item5\nname: 'test4 item 5'",
54          'item_6.test.yml' => "id: item6\nname: 'test4 item 6'",
55        ],
56      ],
57    ]);
58
59    // Set up the directories to search.
60    $directories = [
61      // Multiple directories both with valid items.
62      'test_1' => [
63        vfsStream::url('modules/test_1/subdir1'),
64        vfsStream::url('modules/test_1/subdir2'),
65      ],
66      // The subdir2 directory is empty.
67      'test_2' => [
68        vfsStream::url('modules/test_2/subdir1'),
69        vfsStream::url('modules/test_2/subdir2'),
70      ],
71      // Directories that do not exist.
72      'test_3' => [
73        vfsStream::url('modules/test_3/subdir1'),
74        vfsStream::url('modules/test_3/subdir2'),
75      ],
76      // A single directory.
77      'test_4' => vfsStream::url('modules/test_4/subdir1'),
78    ];
79
80    $discovery = new YamlDirectoryDiscovery($directories, 'test');
81    $data = $discovery->findAll();
82
83    $this->assertSame(['id' => 'item1', 'name' => 'test1 item 1', YamlDirectoryDiscovery::FILE_KEY => 'vfs://modules/test_1/subdir1/item_1.test.yml'], $data['test_1']['item1']);
84    $this->assertSame(['id' => 'item2', 'name' => 'test1 item 2', YamlDirectoryDiscovery::FILE_KEY => 'vfs://modules/test_1/subdir2/item_2.test.yml'], $data['test_1']['item2']);
85    $this->assertCount(2, $data['test_1']);
86
87    $this->assertSame(['id' => 'item3', 'name' => 'test2 item 3', YamlDirectoryDiscovery::FILE_KEY => 'vfs://modules/test_2/subdir1/item_3.test.yml'], $data['test_2']['item3']);
88    $this->assertCount(1, $data['test_2']);
89
90    $this->assertTrue(empty($data['test_3']), 'test_3 provides 0 items');
91
92    $this->assertSame(['id' => 'item4', 'name' => 'test4 item 4', YamlDirectoryDiscovery::FILE_KEY => 'vfs://modules/test_4/subdir1/item_4.test.yml'], $data['test_4']['item4']);
93    $this->assertSame(['id' => 'item5', 'name' => 'test4 item 5', YamlDirectoryDiscovery::FILE_KEY => 'vfs://modules/test_4/subdir1/item_5.test.yml'], $data['test_4']['item5']);
94    $this->assertSame(['id' => 'item6', 'name' => 'test4 item 6', YamlDirectoryDiscovery::FILE_KEY => 'vfs://modules/test_4/subdir1/item_6.test.yml'], $data['test_4']['item6']);
95    $this->assertCount(3, $data['test_4']);
96  }
97
98  /**
99   * Tests YAML directory discovery with an alternate ID key.
100   *
101   * @covers ::findAll
102   */
103  public function testDiscoveryAlternateId() {
104    vfsStream::setup('modules', NULL, [
105      'test_1' => [
106        'item_1.test.yml' => "alt_id: item1\nid: ignored",
107      ],
108    ]);
109
110    // Set up the directories to search.
111    $directories = ['test_1' => vfsStream::url('modules/test_1')];
112
113    $discovery = new YamlDirectoryDiscovery($directories, 'test', 'alt_id');
114    $data = $discovery->findAll();
115
116    $this->assertSame(['alt_id' => 'item1', 'id' => 'ignored', YamlDirectoryDiscovery::FILE_KEY => 'vfs://modules/test_1/item_1.test.yml'], $data['test_1']['item1']);
117    $this->assertCount(1, $data['test_1']);
118  }
119
120  /**
121   * Tests YAML directory discovery with a missing ID key.
122   *
123   * @covers ::findAll
124   * @covers ::getIdentifier
125   */
126  public function testDiscoveryNoIdException() {
127    $this->expectException(DiscoveryException::class);
128    $this->expectExceptionMessage('The vfs://modules/test_1/item_1.test.yml contains no data in the identifier key \'id\'');
129    vfsStream::setup('modules', NULL, [
130      'test_1' => [
131        'item_1.test.yml' => "",
132      ],
133    ]);
134
135    // Set up the directories to search.
136    $directories = ['test_1' => vfsStream::url('modules/test_1')];
137
138    $discovery = new YamlDirectoryDiscovery($directories, 'test');
139    $discovery->findAll();
140  }
141
142  /**
143   * Tests YAML directory discovery with invalid YAML.
144   *
145   * @covers ::findAll
146   */
147  public function testDiscoveryInvalidYamlException() {
148    $this->expectException(DiscoveryException::class);
149    $this->expectExceptionMessage('The vfs://modules/test_1/item_1.test.yml contains invalid YAML');
150    vfsStream::setup('modules', NULL, [
151      'test_1' => [
152        'item_1.test.yml' => "id: invalid\nfoo : [bar}",
153      ],
154    ]);
155
156    // Set up the directories to search.
157    $directories = ['test_1' => vfsStream::url('modules/test_1')];
158
159    $discovery = new YamlDirectoryDiscovery($directories, 'test');
160    $discovery->findAll();
161  }
162
163}
164