3
* Gallery - a web based photo album viewer and editor
4
* Copyright (C) 2000-2007 Bharat Mediratta
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or (at
9
* your option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
22
* Test FileSystem functionality
23
* @package GalleryCore
25
* @author Bharat Mediratta <bharat@menalto.com>
26
* @version $Revision: 15513 $
28
class FileSystemTest extends GalleryTestCase {
30
function FileSystemTest($methodName) {
31
$this->GalleryTestCase($methodName);
40
$parentId = $this->_getRootId();
41
for ($i = 0; $i < $iterations; $i++) {
42
$gallery->guaranteeTimeLimit(5);
44
list ($ret, $this->_albums[$i]) = $this->_createRandomAlbum($parentId);
46
print $ret->getAsHtml();
47
return $this->failWithStatus($ret);
50
$parentId = $this->_albums[$i]->getId();
53
/* delete the top album */
54
$this->_markForCleanup($this->_albums[0]);
57
function testFetchItemIdByPath() {
59
for ($i = 0; $i < sizeof($this->_albums); $i++) {
60
$path .= $this->_albums[$i]->getPathComponent() . '/';
62
list ($ret, $id) = GalleryCoreApi::fetchItemIdByPath($path);
64
return $this->failWithStatus($ret);
67
$this->assertEquals($this->_albums[2]->getId(), $id);
70
function testFetchLogicalPath() {
71
list ($ret, $root) = GalleryCoreApi::loadEntitiesById($this->_getRootId());
73
return $this->failWithStatus($ret);
76
list ($ret, $logicalPath) = $root->fetchLogicalPath();
78
return $this->failWithStatus($ret);
81
$this->assertEquals('/', $logicalPath);
83
list ($ret, $logicalPath) = $this->_albums[1]->fetchLogicalPath();
85
return $this->failWithStatus($ret);
88
$this->assertEquals(sprintf('/%s/%s/',
89
$this->_albums[0]->getPathComponent(),
90
$this->_albums[1]->getPathComponent()),
93
list ($ret, $item) = $this->_createRandomDataItem($this->_albums[1]->getId());
95
return $this->failWithStatus($ret);
98
list ($ret, $logicalPath) = $item->fetchLogicalPath();
100
return $this->failWithStatus($ret);
103
$this->assertEquals(sprintf('/%s/%s/%s',
104
$this->_albums[0]->getPathComponent(),
105
$this->_albums[1]->getPathComponent(),
106
$item->getPathComponent()),
110
function testFetchPath() {
112
$originalPlatform =& $gallery->getPlatform();
113
$gallery->setPlatform(new FileSystemTestPlatform('/'));
114
$originalAlbumsDir = $gallery->getConfig('data.gallery.albums');
115
$gallery->setConfig('data.gallery.albums', '');
117
list ($ret, $path) = $this->_albums[1]->fetchPath();
119
return $this->failWithStatus($ret);
122
$this->assertEquals(sprintf('%s/%s/',
123
$this->_albums[0]->getPathComponent(),
124
$this->_albums[1]->getPathComponent()),
127
$gallery->setPlatform(new FileSystemTestPlatform('\\'));
129
list ($ret, $path) = $this->_albums[1]->fetchPath();
131
return $this->failWithStatus($ret);
134
$this->assertEquals(sprintf('%s\\%s\\',
135
$this->_albums[0]->getPathComponent(),
136
$this->_albums[1]->getPathComponent()),
139
$gallery->setPlatform($originalPlatform);
140
$gallery->setConfig('data.gallery.albums', $originalAlbumsDir);
143
function testFetchChildIdByPathComponent() {
144
list ($ret, $id) = GalleryCoreApi::fetchChildIdByPathComponent(
145
$this->_albums[1]->getId(), $this->_albums[2]->getPathComponent());
147
$this->assertEquals($this->_albums[2]->getId(), $id);
151
* Verify that creating a second filesystem entity with the same path as
152
* an existing one throws a collision error.
154
function testCreateCollision() {
157
list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($this->_albums[0]->getId());
159
return $this->failWithStatus($ret);
162
for ($i = 0; $i < 3; $i++) {
163
$entity[$i] = new GalleryFileSystemEntity();
164
$ret = $entity[$i]->create($this->_albums[0]->getId(), 'valid_path.jpg');
166
return $this->failWithStatus($ret);
169
$ret = $entity[$i]->save();
171
return $this->failWithStatus($ret);
175
$this->assertEquals(sprintf('valid_path_%03d.jpg', $i),
176
$entity[$i]->getPathComponent());
180
$ret = GalleryCoreApi::releaseLocks($lockId);
182
return $this->failWithStatus($ret);
186
function testMoveCollision() {
187
list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock(array($this->_albums[0]->getId(),
188
$this->_albums[1]->getId(),
189
$this->_albums[2]->getId()));
191
return $this->failWithStatus($ret);
194
$ret = $this->_albums[1]->rename('foo');
196
return $this->failWithStatus($ret);
198
$ret = $this->_albums[1]->save();
200
$ret = $this->_albums[1]->move($this->_albums[0]->getId());
202
return $this->failWithStatus($ret);
205
$ret = $this->_albums[2]->rename('foo');
207
return $this->failWithStatus($ret);
209
$ret = $this->_albums[2]->move($this->_albums[0]->getId());
211
return $this->failWithStatus($ret);
214
$this->assertEquals('foo_001', $this->_albums[2]->getPathComponent());
216
$ret = GalleryCoreApi::releaseLocks($lockId);
218
return $this->failWithStatus($ret);
223
* Test the platform->rename($old,$newpath) call of FileSystemEntity::move.
224
* The call should have legal platformspecific slashes.
226
* It tests not the functionality of FileSystemEntity::move, it only tests if
227
* FileSystemEntity::move uses valid paths (no incorrect slashes) in its call to the platform
228
* specific "rename($oldname, $newname)" function.
230
function testMoveRenameCall() {
232
/* Use a windows alike mock platfrom */
233
$originalPlatform =& $gallery->getPlatform();
234
/* Acquire the write locks */
235
list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock(array($this->_albums[0]->getId(),
236
$this->_albums[1]->getId(),
237
$this->_albums[2]->getId()));
239
return $this->failWithStatus($ret);
241
$gallery->setPlatform(new FileSystemTestPlatformForRename('\\'));
243
/* Execute the move command, success expected */
244
$ret = $this->_albums[2]->move($this->_albums[0]->getId());
246
$gallery->setPlatform($originalPlatform);
247
return $this->failWithStatus($ret);
250
/* Now change the mock platform to a unix like system */
251
$gallery->setPlatform(new FileSystemTestPlatformForRename('/'));
252
/* And move again album 1 (back, but all virtual move command), success expected */
253
$ret = $this->_albums[2]->move($this->_albums[1]->getId());
255
$gallery->setPlatform($originalPlatform);
256
return $this->failWithStatus($ret);
259
$gallery->setPlatform($originalPlatform);
260
$ret = GalleryCoreApi::releaseLocks($lockId);
262
return $this->failWithStatus($ret);
266
function testGetLegalPathComponent() {
267
/* Simple case, no collision */
269
GalleryCoreApi::getLegalPathComponent('testpath', $this->_albums[2]->getId());
271
return $this->failWithStatus($ret);
273
$this->assertEquals('testpath', $path, 'no collision');
275
/* Collision with existing album: _001 gets added */
276
list ($ret, $path) = GalleryCoreApi::getLegalPathComponent(
277
$this->_albums[1]->getPathComponent(), $this->_albums[0]->getId());
279
return $this->failWithStatus($ret);
281
$this->assertEquals($this->_albums[1]->getPathComponent() . '_001', $path,
284
/* Ignore self-collision */
285
list ($ret, $path) = GalleryCoreApi::getLegalPathComponent(
286
$this->_albums[1]->getPathComponent(), $this->_albums[0]->getId(),
287
$this->_albums[1]->getId());
289
return $this->failWithStatus($ret);
291
$this->assertEquals($this->_albums[1]->getPathComponent(), $path, 'ignore self-collision');
293
/* Filename with some invalid path characters and .php extension */
294
list ($ret, $path) = GalleryCoreApi::getLegalPathComponent(
295
'my/test&file!.php', $this->_albums[1]->getId());
297
return $this->failWithStatus($ret);
299
$this->assertEquals('my_test_file__php', $path, 'a few bad characters');
301
/* Filename of all extended characters, except extension: we rewrite with date-filename */
302
list ($ret, $path) = GalleryCoreApi::getLegalPathComponent(
303
"\xe6\xaa\x94\xe6\xa1\x88.jpg", $this->_albums[1]->getId());
305
return $this->failWithStatus($ret);
307
$this->assertEquals(strftime('%Y%m%d') . '.jpg', $path, 'extended characters');
310
function testPathComponentLength() {
312
$storage =& $gallery->getStorage();
314
$string = '1234567890123456789012345678901234567890123456789012345678901234567890';
315
$string .= '1234567890123456789012345678901234567890123456789012345678901234567890';
316
$this->assertEquals(140, strlen($string), 'precondition: length of test string');
319
list ($ret, $entityInfo) = GalleryCoreApi::describeEntity('GalleryFileSystemEntity');
321
return $this->failWithStatus($ret);
323
$size = $entityInfo['GalleryFileSystemEntity']['members']['pathComponent']['size'];
325
$this->assertEquals(128, strlen($storage->_truncateString($string, $size)),
326
'pathComponent string size changed, change the redundant value in ' .
327
'GalleryFileSystemEntityHelper_medium!');
330
/* Verify that too long path components get truncated and that the extension gets preserved. */
331
function testGetLegalPathComponentForTruncatedName() {
332
/* Prepare by setting the name of an existing album to a string with max length. */
333
$component = '1234567890123456789012345678901234567890123456789012345678901234567890' .
334
'1234567890123456789012345678901234567890123456789012345678';
335
list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($this->_albums[0]->getId());
337
return $this->failWithStatus($ret);
339
$this->_albums[0]->setPathComponent($component);
340
$ret = $this->_albums[0]->save();
342
return $this->failWithStatus($ret);
344
$ret = GalleryCoreApi::releaseLocks($lockId);
346
return $this->failWithStatus($ret);
349
/* Execute the test: Get the legal path component for a too long colliding name. */
350
$newComponent = $component . 'abcdefghi.jpg';
351
list ($ret, $path) = GalleryCoreApi::getLegalPathComponent(
352
$newComponent, $this->_getRootId());
354
return $this->failWithStatus($ret);
356
$expectedPathComponent = substr($component, 0, 124) . '.jpg';
357
$this->assertEquals($expectedPathComponent, $path);
360
function testGetLegalPathComponentForTruncatedNameWithCollision() {
361
/* Prepare the 2nd case, where we try to fix a collision. */
362
$component = '1234567890123456789012345678901234567890123456789012345678901234567890' .
363
'123456789012345678901234567890123456789012345678901234.jpg';
364
list ($ret, $item) = $this->_createRandomDataItem($this->_albums[0]->getId());
366
return $this->failWithStatus($ret);
368
list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($item->getId());
370
return $this->failWithStatus($ret);
372
$ret = $item->rename($component);
374
return $this->failWithStatus($ret);
376
$ret = $item->save();
378
return $this->failWithStatus($ret);
380
$ret = GalleryCoreApi::releaseLocks($lockId);
382
return $this->failWithStatus($ret);
385
$this->assertEquals($component, $item->getPathComponent(), 'precondition');
387
/* Execute the test: path component with truncation and collision. */
388
$newComponent = $component . 'abcdefghi.jpg';
389
list ($ret, $path) = GalleryCoreApi::getLegalPathComponent(
390
$newComponent, $this->_albums[0]->getId());
392
return $this->failWithStatus($ret);
394
$expectedPathComponent = substr($component, 0, 120) . '_001.jpg';
395
$this->assertEquals($expectedPathComponent, $path);
399
* Verify that a path component that would be truncated is detected as one that would
400
* collide with an existing path component of max length.
402
function testCheckPathCollisionTruncation() {
403
/* Prepare by setting the name of an existing album to a string with max length. */
404
$component = '1234567890123456789012345678901234567890123456789012345678901234567890' .
405
'1234567890123456789012345678901234567890123456789012345678';
406
list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($this->_albums[0]->getId());
408
return $this->failWithStatus($ret);
410
$this->_albums[0]->setPathComponent($component);
411
$ret = $this->_albums[0]->save();
413
return $this->failWithStatus($ret);
415
$ret = GalleryCoreApi::releaseLocks($lockId);
417
return $this->failWithStatus($ret);
420
/* Execute the test: Try to use a path component that collides once it's truncated. */
421
$newComponent = $component . 'abcdefghi';
422
list ($ret, $isCollision) =
423
GalleryCoreApi::checkPathCollision($newComponent, $this->_getRootId());
425
return $this->failWithStatus($ret);
427
$this->assertEquals(true, $isCollision);
430
function testCheckPathCollisionCaseSensitivity() {
431
$pathComponentA = 'test';
432
$pathComponentB = 'TEST';
433
list ($ret, $item) = $this->_createRandomAlbum($this->_albums[0]->getId());
435
return $this->failWithStatus($ret);
437
list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($item->getId());
439
return $this->failWithStatus($ret);
441
$ret = $item->rename($pathComponentA);
443
return $this->failWithStatus($ret);
445
$ret = $item->save();
447
return $this->failWithStatus($ret);
449
$ret = GalleryCoreApi::releaseLocks($lockId);
451
return $this->failWithStatus($ret);
454
/* Execute the test: Try a path that only varies in the letter case. */
455
list ($ret, $isCollision) =
456
GalleryCoreApi::checkPathCollision($pathComponentB, $this->_albums[0]->getId());
458
return $this->failWithStatus($ret);
460
$this->assertEquals(true, $isCollision);
467
* @package GalleryCore
468
* @subpackage PHPUnit
470
class FileSystemTestPlatform {
471
function FileSystemTestPlatform($separator) {
472
$this->_separator = $separator;
475
function getDirectorySeparator() {
476
return $this->_separator;
482
* Mock platform for the rename method
484
* Implements all methods used by FileSystemEntity::move()
486
* @package GalleryCore
487
* @subpackage PHPUnit
489
class FileSystemTestPlatformForRename extends GalleryPlatform {
490
function FileSystemTestPlatformForRename($separator) {
491
$this->_separator = $separator;
494
function getDirectorySeparator() {
495
return $this->_separator;
501
* Override rename method for the testMoveRenamePaths
502
* It won't rename the item actually, just check if the paths contain no invalid slashs
504
function rename($oldname, $newname) {
506
if ($gallery->getDebug()) {
507
$gallery->debug("rename($oldname, $newname)");
510
* Check if there are some platform specific slash problems in the paths
511
* The platform should be forced to have a '\' separator and thus, no '/'
512
* should be found in the paths.
515
* Strip off the g2data path part of the $oldname and $newname, because they are platform
516
* specific and correct anyway.
518
$oldname = substr($oldname,
519
strlen($gallery->getConfig('data.gallery.albums')));
520
$newname = substr($newname,
521
strlen($gallery->getConfig('data.gallery.albums')));
522
/* We had a case where FileSystemEntity::move produced a rename(a,b) path b, which had a
523
* separator too much and this additional seapartor wasn't even platform specific, but
524
* just '/'. The consequence: ->move() didn't work on windows xp.
525
* What we do here is: Force a windows xp separator '\' and check if no '/' separator is
526
* found in the paths. nested ifs are not necessary, but more readable.
527
* And we don't accept // or \\ in our paths. Most probably this won't be an issue, but
528
* it's good to create exactly the paths that we actually indend to create.
530
if ($this->_separator == '\\') {
531
if (strrchr($oldname, '/') || strrchr($newname, '/')
532
|| strpos($oldname, '\\\\') || strpos($newname, '\\\\')) {
535
} else if ($this->_separator == '/') {
536
if (strrchr($oldname, '\\') || strrchr($newname, '\\')
537
|| strpos($oldname, '//') || strpos($newname, '//')) {
542
/* Now pretend the rename command was successful */