[TASK] Mock SignalSlot\Dispatcher Singletons in unit tests
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Resource / MetaDataAspectTest.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Core\Tests\Unit\Resource;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use Prophecy\Argument;
20 use TYPO3\CMS\Core\Database\Connection;
21 use TYPO3\CMS\Core\Database\ConnectionPool;
22 use TYPO3\CMS\Core\Resource\Exception\InvalidUidException;
23 use TYPO3\CMS\Core\Resource\File;
24 use TYPO3\CMS\Core\Resource\Index\MetaDataRepository;
25 use TYPO3\CMS\Core\Resource\MetaDataAspect;
26 use TYPO3\CMS\Core\Resource\ResourceStorage;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher;
29 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
30
31 /**
32 * Test case
33 */
34 class MetaDataAspectTest extends UnitTestCase
35 {
36 /**
37 * @var ResourceStorage|\PHPUnit\Framework\MockObject\MockObject
38 */
39 protected $storageMock;
40
41 /**
42 * Set up
43 */
44 protected function setUp(): void
45 {
46 $this->storageMock = $this->createMock(ResourceStorage::class);
47 $this->storageMock->expects($this->any())->method('getUid')->will($this->returnValue(12));
48 }
49
50 /**
51 * Tear down
52 */
53 protected function tearDown(): void
54 {
55 $this->resetSingletonInstances = true;
56
57 GeneralUtility::purgeInstances();
58 parent::tearDown();
59 }
60
61 /**
62 * @test
63 */
64 public function knownMetaDataIsAdded(): void
65 {
66 $metaData = [
67 'width' => 4711,
68 'title' => 'Lorem ipsum meta sit amet',
69 ];
70 $file = new File([], $this->storageMock, $metaData);
71
72 $this->assertSame($metaData, $file->getMetaData()->get());
73 }
74
75 /**
76 * @test
77 */
78 public function manuallyAddedMetaDataIsMerged(): void
79 {
80 $metaData = [
81 'width' => 4711,
82 'title' => 'Lorem ipsum meta sit amet',
83 ];
84 $file = new File([], $this->storageMock, $metaData);
85 $file->getMetaData()->add([
86 'height' => 900,
87 'description' => 'This file is presented by TYPO3',
88 ]);
89
90 $expected = [
91 'width' => 4711,
92 'title' => 'Lorem ipsum meta sit amet',
93 'height' => 900,
94 'description' => 'This file is presented by TYPO3',
95 ];
96
97 $this->assertSame($expected, $file->getMetaData()->get());
98 }
99
100 /**
101 * @test
102 */
103 public function metaDataGetsRemoved(): void
104 {
105 $metaData = ['foo' => 'bar'];
106
107 $file = new File(['uid' => 12], $this->storageMock);
108
109 /** @var MetaDataAspect|\PHPUnit\Framework\MockObject\MockObject $metaDataAspectMock */
110 $metaDataAspectMock = $this->getMockBuilder(MetaDataAspect::class)
111 ->setConstructorArgs([$file])
112 ->setMethods(['getMetaDataRepository'])
113 ->getMock();
114
115 $metaDataAspectMock->add($metaData);
116 $metaDataAspectMock->remove();
117
118 $this->assertEmpty($metaDataAspectMock->get());
119 }
120
121 /**
122 * @test
123 */
124 public function positiveUidOfFileIsExpectedToLoadMetaData(): void
125 {
126 $this->expectException(InvalidUidException::class);
127 $this->expectExceptionCode(1381590731);
128
129 $file = new File(['uid' => -3], $this->storageMock);
130 $file->getMetaData()->get();
131 }
132
133 /**
134 * @test
135 */
136 public function newMetaDataIsCreated(): void
137 {
138 $GLOBALS['EXEC_TIME'] = 1534530781;
139 $metaData = [
140 'title' => 'Hooray',
141 // This value is ignored on purpose, we simulate the non-existence of the field "description"
142 'description' => 'Yipp yipp yipp',
143 ];
144
145 $file = new File(['uid' => 12], $this->storageMock);
146
147 $connectionProphecy = $this->prophesize(Connection::class);
148 $connectionProphecy->insert(Argument::cetera())->willReturn(1);
149 $connectionProphecy->lastInsertId(Argument::cetera())->willReturn(5);
150 $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
151 $connectionPoolProphecy->getConnectionForTable(Argument::cetera())->willReturn($connectionProphecy->reveal());
152 GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
153 $dispatcherProphecy = $this->prophesize(SignalSlotDispatcher::class);
154
155 $metaDataRepositoryMock = $this->getMockBuilder(MetaDataRepository::class)
156 ->setMethods(['findByFileUid', 'getTableFields', 'update', 'getSignalSlotDispatcher'])
157 ->getMock();
158 $metaDataRepositoryMock->expects($this->any())->method('findByFileUid')->willReturn([]);
159 $metaDataRepositoryMock->expects($this->any())->method('getTableFields')->willReturn(['title' => 'sometype']);
160 $metaDataRepositoryMock->expects($this->never())->method('update');
161 $metaDataRepositoryMock->expects($this->any())->method('getSignalSlotDispatcher')->willReturn($dispatcherProphecy->reveal());
162 GeneralUtility::setSingletonInstance(MetaDataRepository::class, $metaDataRepositoryMock);
163
164 $file->getMetaData()->add($metaData)->save();
165
166 $expected = [
167 'file' => $file->getUid(),
168 'pid' => 0,
169 'crdate' => 1534530781,
170 'tstamp' => 1534530781,
171 'cruser_id' => 0,
172 'l10n_diffsource' => '',
173 'title' => 'Hooray',
174 'uid' => '5',
175 'newlyCreated' => true,
176 ];
177
178 $this->assertSame($expected, $file->getMetaData()->get());
179 }
180
181 /**
182 * @test
183 */
184 public function existingMetaDataGetsUpdated(): void
185 {
186 $metaData = ['foo' => 'bar'];
187
188 $file = new File(['uid' => 12], $this->storageMock);
189
190 $metaDataRepositoryMock = $this->getMockBuilder(MetaDataRepository::class)
191 ->setMethods(['loadFromRepository', 'createMetaDataRecord', 'update'])
192 ->getMock();
193
194 $metaDataRepositoryMock->expects($this->any())->method('createMetaDataRecord')->willReturn($metaData);
195 GeneralUtility::setSingletonInstance(MetaDataRepository::class, $metaDataRepositoryMock);
196
197 $metaDataAspectMock = $this->getMockBuilder(MetaDataAspect::class)
198 ->setConstructorArgs([$file])
199 ->setMethods(['loadFromRepository'])
200 ->getMock();
201
202 $metaDataAspectMock->expects($this->any())->method('loadFromRepository')->will($this->onConsecutiveCalls([], $metaData));
203 $metaDataAspectMock->add($metaData)->save();
204 $metaDataAspectMock->add(['testproperty' => 'testvalue'])->save();
205
206 $this->assertSame(['foo' => 'bar', 'testproperty' => 'testvalue'], $metaDataAspectMock->get());
207 }
208
209 /**
210 * @return array
211 */
212 public function propertyDataProvider(): array
213 {
214 return [
215 [
216 [
217 'width' => 4711,
218 'title' => 'Lorem ipsum meta sit amet',
219 ],
220 [
221 'property' => 'width',
222 'expected' => true,
223 ],
224 [
225 'property' => 'width',
226 'expected' => 4711,
227 ],
228 ],
229 [
230 [
231 'foo' => 'bar',
232 ],
233 [
234 'property' => 'husel',
235 'expected' => false,
236 ],
237 [
238 'property' => 'husel',
239 'expected' => null,
240 ],
241 ],
242 ];
243 }
244
245 /**
246 * @param $metaData
247 * @param $has
248 * @param $get
249 * @test
250 * @dataProvider propertyDataProvider
251 */
252 public function propertyIsFetchedProperly($metaData, $has, $get): void
253 {
254 $file = new File([], $this->storageMock, $metaData);
255
256 $this->assertSame($has['expected'], isset($file->getMetaData()[$has['property']]));
257 $this->assertSame($get['expected'], $file->getMetaData()[$get['property']] ?? null);
258 }
259 }