ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
ZipTest.php
Go to the documentation of this file.
1<?php
2
19namespace ILIAS\Filesystem\Util;
20
21use PHPUnit\Framework\Attributes\BackupGlobals;
22use PHPUnit\Framework\Attributes\BackupStaticProperties;
23use PHPUnit\Framework\Attributes\PreserveGlobalState;
24use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
25use PHPUnit\Framework\Attributes\DataProvider;
30use PHPUnit\Framework\TestCase;
33
37#[BackupGlobals(false)]
38#[BackupStaticProperties(false)]
39#[PreserveGlobalState(false)]
40#[RunTestsInSeparateProcesses]
41class ZipTest extends TestCase
42{
43 public const ZIPPED_ZIP = 'zipped.zip';
44 protected string $zips_dir = __DIR__ . '/zips/';
45 protected string $unzips_dir = __DIR__ . '/unzips/';
46
47 protected function setUp(): void
48 {
49 if (file_exists($this->unzips_dir . self::ZIPPED_ZIP)) {
50 unlink($this->unzips_dir . self::ZIPPED_ZIP);
51 }
52 if (!file_exists($this->unzips_dir)) {
53 mkdir($this->unzips_dir);
54 }
55 }
56
57 protected function tearDown(): void
58 {
59 if (file_exists($this->unzips_dir)) {
60 $this->recurseRmdir($this->unzips_dir);
61 }
62 }
63
64 public function testZip(): void
65 {
66 $zip_options = new ZipOptions();
67 $streams = [
68 Streams::ofResource(fopen($this->zips_dir . '1_folder_1_file_mac.zip', 'r')),
69 Streams::ofResource(fopen($this->zips_dir . '1_folder_win.zip', 'r')),
70 ];
71 $zip = new Zip($zip_options, ...$streams);
72 $zip_stream = $zip->get();
73 $this->assertGreaterThan(0, $zip_stream->getSize());
74
75 $unzip_again = new Unzip(new UnzipOptions(), $zip_stream);
76 $this->assertSame(2, $unzip_again->getAmountOfFiles());
77 }
78
79 public function testLegacyZip(): void
80 {
81 $legacy = new LegacyArchives();
82
83 define('CLIENT_WEB_DIR', __DIR__);
84 define('ILIAS_WEB_DIR', 'public/data');
85 define('CLIENT_ID', 'test');
86 define('CLIENT_DATA_DIR', __DIR__);
87 define('ILIAS_ABSOLUTE_PATH', __DIR__);
88
89 $legacy->zip($this->zips_dir, $this->unzips_dir . self::ZIPPED_ZIP, false);
90 $this->assertFileExists($this->unzips_dir . self::ZIPPED_ZIP);
91
92 $unzip_again = new Unzip(new UnzipOptions(), Streams::ofResource(fopen($this->unzips_dir . self::ZIPPED_ZIP, 'r')));
93 $this->assertSame(5, $unzip_again->getAmountOfFiles());
94
95 $depth = 0;
96 foreach ($unzip_again->getPaths() as $path) {
97 $parts = explode('/', $path);
98 $depth = max($depth, count($parts));
99 }
100 $this->assertEquals(2, $depth);
101 $this->recurseRmdir($this->unzips_dir);
102 }
103
104 public function LegacyZipWithTop(): void
105 {
106 $legacy = new LegacyArchives();
107
108 define('CLIENT_WEB_DIR', __DIR__);
109 define('ILIAS_WEB_DIR', 'public/data');
110 define('CLIENT_ID', 'test');
111 define('CLIENT_DATA_DIR', __DIR__);
112 define('ILIAS_ABSOLUTE_PATH', __DIR__);
113
114 mkdir($this->unzips_dir);
115 $legacy->zip($this->zips_dir, $this->unzips_dir . self::ZIPPED_ZIP, true);
116 $this->assertFileExists($this->unzips_dir . self::ZIPPED_ZIP);
117
118 $unzip_again = new Unzip(new UnzipOptions(), Streams::ofResource(fopen($this->unzips_dir . self::ZIPPED_ZIP, 'r')));
119 $this->assertSame(5, $unzip_again->getAmountOfFiles());
120
121 $depth = 0;
122 foreach ($unzip_again->getPaths() as $path) {
123 $parts = explode('/', $path);
124 $depth = max($depth, count($parts));
125 }
126 $this->assertEquals(2, $depth);
127 $this->recurseRmdir($this->unzips_dir);
128 }
129
134 #[DataProvider('getZips')]
135 public function testUnzip(
136 string $zip,
137 bool $has_multiple_root_entries,
138 int $expected_amount_directories,
139 array $expected_directories,
140 int $expected_amount_files,
141 array $expected_files
142 ): void {
143 $this->assertStringContainsString('.zip', $zip);
144 $zip_path = $this->zips_dir . $zip;
145 $this->assertFileExists($zip_path);
146
147 $stream = Streams::ofResource(fopen($zip_path, 'rb'));
148 $options = new UnzipOptions();
149 $unzip = new Unzip($options, $stream);
150
151 $this->assertFalse($unzip->hasZipReadingError());
152 $this->assertSame($has_multiple_root_entries, $unzip->hasMultipleRootEntriesInZip());
153 $this->assertSame($expected_amount_directories, $unzip->getAmountOfDirectories());
154 $this->assertEquals($expected_directories, iterator_to_array($unzip->getDirectories()));
155 $this->assertSame($expected_amount_files, $unzip->getAmountOfFiles());
156 $this->assertEquals($expected_files, iterator_to_array($unzip->getFiles()));
157 }
158
159 public function testWrongZip(): void
160 {
161 $stream = Streams::ofResource(fopen(__FILE__, 'rb'));
162 $options = new UnzipOptions();
163 $unzip = new Unzip($options, $stream);
164 $this->assertTrue($unzip->hasZipReadingError());
165 $this->assertFalse($unzip->hasMultipleRootEntriesInZip());
166 $this->assertCount(0, iterator_to_array($unzip->getFiles()));
167 $this->assertCount(0, iterator_to_array($unzip->getDirectories()));
168 $this->assertCount(0, iterator_to_array($unzip->getPaths()));
169 $this->assertSame([], iterator_to_array($unzip->getDirectories()));
170 $this->assertSame([], iterator_to_array($unzip->getFiles()));
171 }
172
173
174 public function testLargeZIPs(): void
175 {
176 // get ulimit
177 $ulimit = (int) shell_exec('ulimit -n');
178 $limit = 2500;
179 if ($ulimit >= $limit) {
180 $this->markTestSkipped('ulimit is too high and would take too much resources');
181 }
182 $this->assertLessThan($limit, $ulimit);
183
184 $zip = new Zip(new ZipOptions());
185
186 $file_names = [];
187
188 for ($i = 0; $i < $ulimit * 2; $i++) {
189 $path_inside_zip = $file_names[] = 'test' . $i;
190 $zip->addStream(Streams::ofString('-'), $path_inside_zip);
191 }
192 $this->assertTrue(true); // no warning or error
193
194 // check if the zip now contains all files
195 $unzip = new Unzip(new UnzipOptions(), $zip->get());
196 $file_names_in_zip = iterator_to_array($unzip->getFiles());
197 sort($file_names);
198 sort($file_names_in_zip);
199 $this->assertEquals($file_names, $file_names_in_zip);
200 }
201
206 #[DataProvider('getZips')]
207 public function testLegacyUnzip(
208 string $zip,
209 bool $has_multiple_root_entries,
210 int $expected_amount_directories,
211 array $expected_directories,
212 int $expected_amount_files,
213 array $expected_files
214 ): void {
215 $legacy = new LegacyArchives();
216
217 $this->assertStringContainsString('.zip', $zip);
218 $zip_path = $this->zips_dir . $zip;
219 $this->assertFileExists($zip_path);
220
221 $temp_unzip_path = $this->unzips_dir . uniqid('unzip', true);
222
223 $return = $legacy->unzip(
224 $zip_path,
225 $temp_unzip_path
226 );
227
228 $this->assertTrue($return);
229
230 $unzipped_files = $this->directoryToArray($temp_unzip_path);
231 $expected_paths = array_merge($expected_directories, $expected_files);
232 sort($expected_paths);
233 $this->assertEquals($expected_paths, $unzipped_files);
234 $this->assertTrue($this->recurseRmdir($temp_unzip_path));
235 }
236
237 private function recurseRmdir(string $path_to_directory): bool
238 {
239 $files = array_diff(scandir($path_to_directory), ['.', '..']);
240 foreach ($files as $file) {
241 (is_dir("$path_to_directory/$file") && !is_link("$path_to_directory/$file")) ? $this->recurseRmdir(
242 "$path_to_directory/$file"
243 ) : unlink("$path_to_directory/$file");
244 }
245 return rmdir($path_to_directory);
246 }
247
251 private function directoryToArray(string $path_to_directory): array
252 {
253 $iterator = new \RecursiveIteratorIterator(
254 new \RecursiveDirectoryIterator($path_to_directory, \RecursiveDirectoryIterator::SKIP_DOTS),
255 \RecursiveIteratorIterator::SELF_FIRST,
256 \RecursiveIteratorIterator::CATCH_GET_CHILD
257 );
258 $paths = [];
259 foreach ($iterator as $item) {
260 $relative_path = str_replace($path_to_directory . '/', '', $item->getPathname());
261 $paths[] = $item->isDir() ? $relative_path . '/' : $relative_path;
262 }
263
264 sort($paths);
265
266 return $paths;
267 }
268
269 // PROVIDERS
270
271 public static function getZips(): \Iterator
272 {
273 yield ['1_folder_mac.zip', false, 10, self::$directories_one, 15, self::$files_one];
274 yield ['1_folder_win.zip', false, 10, self::$directories_one, 15, self::$files_one];
275 yield ['3_folders_mac.zip', true, 9, self::$directories_three, 12, self::$files_three];
276 yield ['3_folders_win.zip', true, 9, self::$directories_three, 12, self::$files_three];
277 yield ['1_folder_1_file_mac.zip', true, 3, self::$directories_mixed, 5, self::$files_mixed];
278 }
279
280 protected static array $files_mixed = [
281 0 => '03_Test.pdf',
282 1 => 'Ordner A/01_Test.pdf',
283 2 => 'Ordner A/02_Test.pdf',
284 3 => 'Ordner A/Ordner A_2/07_Test.pdf',
285 4 => 'Ordner A/Ordner A_2/08_Test.pdf'
286 ];
287
288 protected static array $directories_mixed = [
289 0 => 'Ordner A/',
290 1 => 'Ordner A/Ordner A_1/',
291 2 => 'Ordner A/Ordner A_2/'
292 ];
293
294 protected static array $directories_one = [
295 0 => 'Ordner 0/',
296 1 => 'Ordner 0/Ordner A/',
297 2 => 'Ordner 0/Ordner A/Ordner A_1/',
298 3 => 'Ordner 0/Ordner A/Ordner A_2/',
299 4 => 'Ordner 0/Ordner B/',
300 5 => 'Ordner 0/Ordner B/Ordner B_1/',
301 6 => 'Ordner 0/Ordner B/Ordner B_2/',
302 7 => 'Ordner 0/Ordner C/',
303 8 => 'Ordner 0/Ordner C/Ordner C_1/',
304 9 => 'Ordner 0/Ordner C/Ordner C_2/'
305 ];
306 protected static array $directories_three = [
307 0 => 'Ordner A/',
308 1 => 'Ordner A/Ordner A_1/',
309 2 => 'Ordner A/Ordner A_2/',
310 3 => 'Ordner B/',
311 4 => 'Ordner B/Ordner B_1/',
312 5 => 'Ordner B/Ordner B_2/',
313 6 => 'Ordner C/',
314 7 => 'Ordner C/Ordner C_1/',
315 8 => 'Ordner C/Ordner C_2/'
316 ];
317
318 protected static array $files_one = [
319 0 => 'Ordner 0/13_Test.pdf',
320 1 => 'Ordner 0/14_Test.pdf',
321 2 => 'Ordner 0/15_Test.pdf',
322 3 => 'Ordner 0/Ordner A/01_Test.pdf',
323 4 => 'Ordner 0/Ordner A/02_Test.pdf',
324 5 => 'Ordner 0/Ordner A/Ordner A_2/07_Test.pdf',
325 6 => 'Ordner 0/Ordner A/Ordner A_2/08_Test.pdf',
326 7 => 'Ordner 0/Ordner B/03_Test.pdf',
327 8 => 'Ordner 0/Ordner B/04_Test.pdf',
328 9 => 'Ordner 0/Ordner B/Ordner B_2/09_Test.pdf',
329 10 => 'Ordner 0/Ordner B/Ordner B_2/10_Test.pdf',
330 11 => 'Ordner 0/Ordner C/05_Test.pdf',
331 12 => 'Ordner 0/Ordner C/06_Test.pdf',
332 13 => 'Ordner 0/Ordner C/Ordner C_2/11_Test.pdf',
333 14 => 'Ordner 0/Ordner C/Ordner C_2/12_Test.pdf'
334 ];
335
336 protected static array $files_three = [
337 0 => 'Ordner A/01_Test.pdf',
338 1 => 'Ordner A/02_Test.pdf',
339 2 => 'Ordner A/Ordner A_2/07_Test.pdf',
340 3 => 'Ordner A/Ordner A_2/08_Test.pdf',
341 4 => 'Ordner B/03_Test.pdf',
342 5 => 'Ordner B/04_Test.pdf',
343 6 => 'Ordner B/Ordner B_2/09_Test.pdf',
344 7 => 'Ordner B/Ordner B_2/10_Test.pdf',
345 8 => 'Ordner C/05_Test.pdf',
346 9 => 'Ordner C/06_Test.pdf',
347 10 => 'Ordner C/Ordner C_2/11_Test.pdf',
348 11 => 'Ordner C/Ordner C_2/12_Test.pdf',
349 ];
350}
Stream factory which enables the user to create streams without the knowledge of the concrete class.
Definition: Streams.php:32
static ofString(string $string)
Creates a new stream with an initial value.
Definition: Streams.php:41
static ofResource($resource)
Wraps an already created resource with the stream abstraction.
Definition: Streams.php:64
recurseRmdir(string $path_to_directory)
Definition: ZipTest.php:237
directoryToArray(string $path_to_directory)
Definition: ZipTest.php:251
testLegacyUnzip(string $zip, bool $has_multiple_root_entries, int $expected_amount_directories, array $expected_directories, int $expected_amount_files, array $expected_files)
Definition: ZipTest.php:207
testUnzip(string $zip, bool $has_multiple_root_entries, int $expected_amount_directories, array $expected_directories, int $expected_amount_files, array $expected_files)
Definition: ZipTest.php:135
$path
Definition: ltiservices.php:30
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:61
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...