1<?php
2/*
3 * vim:set softtabstop=4 shiftwidth=4 expandtab:
4 *
5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later)
6 * Copyright 2001 - 2020 Ampache.org
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 */
21
22declare(strict_types=1);
23
24namespace Ampache\Module\Album\Export;
25
26use Ahc\Cli\IO\Interactor;
27use Ampache\Config\ConfigContainerInterface;
28use Ampache\Config\ConfigurationKeyEnum;
29use Ampache\MockeryTestCase;
30use Ampache\Repository\Model\Album;
31use Ampache\Repository\Model\Art;
32use Ampache\Repository\Model\Catalog;
33use Ampache\Repository\Model\ModelFactoryInterface;
34use Ampache\Repository\Model\Song;
35use Ampache\Module\Album\Export\Writer\MetadataWriterInterface;
36use Ampache\Repository\SongRepositoryInterface;
37use Mockery\MockInterface;
38use org\bovigo\vfs\vfsStream;
39use Psr\Log\LoggerInterface;
40
41class AlbumArtExporterTest extends MockeryTestCase
42{
43    /** @var ConfigContainerInterface|MockInterface|null */
44    private MockInterface $configContainer;
45
46    /** @var LoggerInterface|MockInterface|null */
47    private MockInterface $logger;
48
49    /** @var ModelFactoryInterface|MockInterface|null */
50    private MockInterface $modelFactory;
51
52    /** @var MockInterface|SongRepositoryInterface|null */
53    private MockInterface $songRepository;
54
55    private ?AlbumArtExporter $subject;
56
57    public function setUp(): void
58    {
59        $this->configContainer = $this->mock(ConfigContainerInterface::class);
60        $this->logger          = $this->mock(LoggerInterface::class);
61        $this->modelFactory    = $this->mock(ModelFactoryInterface::class);
62        $this->songRepository  = $this->mock(SongRepositoryInterface::class);
63
64        $this->subject = new AlbumArtExporter(
65            $this->configContainer,
66            $this->logger,
67            $this->modelFactory,
68            $this->songRepository
69        );
70    }
71
72    public function testExportDoesNothingIfNoInfoExists(): void
73    {
74        $interacor      = $this->mock(Interactor::class);
75        $catalog        = $this->mock(Catalog::class);
76        $metadataWriter = $this->mock(MetadataWriterInterface::class);
77        $art            = $this->mock(Art::class);
78
79        $albumId = 666;
80
81        $catalog->shouldReceive('get_album_ids')
82            ->withNoArgs()
83            ->once()
84            ->andReturn([(string) $albumId]);
85
86        $this->modelFactory->shouldReceive('createArt')
87            ->with($albumId)
88            ->once()
89            ->andReturn($art);
90
91        $art->shouldReceive('has_db_info')
92            ->withNoArgs()
93            ->once()
94            ->andReturnFalse();
95
96        $this->subject->export(
97            $interacor,
98            $catalog,
99            $metadataWriter
100        );
101    }
102
103    public function testExportThrowsExceptionIfFileCouldNotBeOpened(): void
104    {
105        $interactor     = $this->mock(Interactor::class);
106        $catalog        = $this->mock(Catalog::class);
107        $metadataWriter = $this->mock(MetadataWriterInterface::class);
108        $art            = $this->mock(Art::class);
109        $album          = $this->mock(Album::class);
110        $song           = $this->mock(Song::class);
111        $fs_root        = vfsStream::setup('', 0000);
112
113        $albumId  = 666;
114        $songId   = 42;
115        $file     = $fs_root->url() . '/some-file';
116        $raw_mime = '/some-raw-mime.png';
117
118        $album->id = $albumId;
119
120        $this->expectException(Exception\AlbumArtExportException::class);
121        $this->expectExceptionMessage(
122            'Unable to open `vfs:/folder.some-raw-mime.png` for writing',
123        );
124
125        $catalog->shouldReceive('get_album_ids')
126            ->withNoArgs()
127            ->once()
128            ->andReturn([(string) $albumId]);
129
130        $this->modelFactory->shouldReceive('createArt')
131            ->with($albumId)
132            ->once()
133            ->andReturn($art);
134        $this->modelFactory->shouldReceive('createAlbum')
135            ->with($albumId)
136            ->once()
137            ->andReturn($album);
138        $this->modelFactory->shouldReceive('createSong')
139            ->with($songId)
140            ->once()
141            ->andReturn($song);
142
143        $this->songRepository->shouldReceive('getByAlbum')
144            ->with($albumId, 1)
145            ->once()
146            ->andReturn([$songId]);
147
148        $art->shouldReceive('has_db_info')
149            ->withNoArgs()
150            ->once()
151            ->andReturnTrue();
152
153        $this->configContainer->shouldReceive('get')
154            ->with(ConfigurationKeyEnum::ALBUM_ART_PREFERRED_FILENAME)
155            ->once()
156            ->andReturn('');
157
158        $art->raw_mime = $raw_mime;
159        $song->file    = $file;
160
161        $this->subject->export(
162            $interactor,
163            $catalog,
164            $metadataWriter
165        );
166    }
167
168    public function testExportThrowsExceptionIfFileCouldNotBeWritten(): void
169    {
170        $interactor     = $this->mock(Interactor::class);
171        $catalog        = $this->mock(Catalog::class);
172        $metadataWriter = $this->mock(MetadataWriterInterface::class);
173        $art            = $this->mock(Art::class);
174        $album          = $this->mock(Album::class);
175        $song           = $this->mock(Song::class);
176        $fs_root        = vfsStream::setup('');
177        $file           = vfsStream::newFile('folder.png');
178
179        $fs_root->addChild($file);
180
181        $albumId   = 666;
182        $songId    = 42;
183        $file_name = $fs_root->url() . '/some-file';
184        $raw_mime  = 'image/png';
185        $raw_art   = 'some-raw-bytes';
186
187        $album->id = $albumId;
188
189        $catalog->shouldReceive('get_album_ids')
190            ->withNoArgs()
191            ->once()
192            ->andReturn([(string) $albumId]);
193
194        $this->modelFactory->shouldReceive('createArt')
195            ->with($albumId)
196            ->once()
197            ->andReturn($art);
198        $this->modelFactory->shouldReceive('createAlbum')
199            ->with($albumId)
200            ->once()
201            ->andReturn($album);
202        $this->modelFactory->shouldReceive('createSong')
203            ->with($songId)
204            ->once()
205            ->andReturn($song);
206
207        $this->songRepository->shouldReceive('getByAlbum')
208            ->with($albumId, 1)
209            ->once()
210            ->andReturn([$songId]);
211
212        $art->shouldReceive('has_db_info')
213            ->withNoArgs()
214            ->once()
215            ->andReturnTrue();
216
217        $this->configContainer->shouldReceive('get')
218            ->with(ConfigurationKeyEnum::ALBUM_ART_PREFERRED_FILENAME)
219            ->once()
220            ->andReturn('//folder.png');
221
222        $art->raw_mime = $raw_mime;
223        $art->raw      = $raw_art;
224        $song->file    = $file_name;
225
226        $metadataWriter->shouldReceive('write')
227            ->with(
228                $album,
229                'vfs:',
230                'vfs:///folder.png'
231            )
232            ->once();
233
234        $this->subject->export(
235            $interactor,
236            $catalog,
237            $metadataWriter
238        );
239
240        $this->assertSame(
241            $raw_art,
242            $file->getContent()
243        );
244    }
245}
246