Completed
Push — master ( 6bd7a6...d192a4 )
by Sam
08:56
created

FolderTest::testRootFolder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 9.4285
1
<?php
2
3
namespace SilverStripe\Assets\Tests;
4
5
use SilverStripe\ORM\Versioning\Versioned;
6
use SilverStripe\ORM\DataObject;
7
use SilverStripe\Assets\Folder;
8
use SilverStripe\Assets\Filesystem;
9
use SilverStripe\Assets\File;
10
use SilverStripe\Core\Config\Config;
11
use SilverStripe\Dev\SapphireTest;
12
use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore;
13
14
/**
15
 * @author Ingo Schommer (ingo at silverstripe dot com)
16
 */
17
class FolderTest extends SapphireTest
18
{
19
20
    protected static $fixture_file = 'FileTest.yml';
21
22
    public function setUp()
23
    {
24
        parent::setUp();
25
26
        $this->logInWithPermission('ADMIN');
27
        Versioned::set_stage(Versioned::DRAFT);
28
29
        // Set backend root to /FolderTest
30
        TestAssetStore::activate('FolderTest');
31
32
        // Set the File Name Filter replacements so files have the expected names
33
        Config::inst()->update(
34
            'SilverStripe\\Assets\\FileNameFilter',
35
            'default_replacements',
36
            array(
37
            '/\s/' => '-', // remove whitespace
38
            '/_/' => '-', // underscores to dashes
39
            '/[^A-Za-z0-9+.\-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot
40
            '/[\-]{2,}/' => '-', // remove duplicate dashes
41
            '/^[\.\-_]+/' => '', // Remove all leading dots, dashes or underscores
42
            )
43
        );
44
45
        // Create a test folders for each of the fixture references
46
        foreach (Folder::get() as $folder) {
47
            $path = TestAssetStore::getLocalPath($folder);
48
            Filesystem::makeFolder($path);
49
        }
50
51
        // Create a test files for each of the fixture references
52
        $files = File::get()->exclude('ClassName', Folder::class);
53
        foreach ($files as $file) {
54
            $path = TestAssetStore::getLocalPath($file);
55
            Filesystem::makeFolder(dirname($path));
56
            $fh = fopen($path, "w+");
57
            fwrite($fh, str_repeat('x', 1000000));
58
            fclose($fh);
59
        }
60
    }
61
62
    public function tearDown()
63
    {
64
        TestAssetStore::reset();
65
        parent::tearDown();
66
    }
67
68
    public function testCreateFromNameAndParentIDSetsFilename()
69
    {
70
        $folder1 = $this->objFromFixture(Folder::class, 'folder1');
71
        $newFolder = new Folder();
72
        $newFolder->Name = 'CreateFromNameAndParentID';
73
        $newFolder->ParentID = $folder1->ID;
74
        $newFolder->write();
75
76
        $this->assertEquals($folder1->Filename . 'CreateFromNameAndParentID/', $newFolder->Filename);
77
    }
78
79
    public function testRenamesDuplicateFolders()
80
    {
81
        $original = new Folder();
82
        $original->update([
83
            'Name' => 'folder1',
84
            'ParentID' => 0
85
        ]);
86
        $original->write();
87
88
        $duplicate = new Folder();
89
        $duplicate->update([
90
            'Name' => 'folder1',
91
            'ParentID' => 0
92
        ]);
93
        $duplicate->write();
94
95
        $original = Folder::get()->byID($original->ID);
96
97
        $this->assertEquals($original->Name, 'folder1');
98
        $this->assertEquals($original->Title, 'folder1');
99
        $this->assertEquals($duplicate->Name, 'folder1-v2');
100
        $this->assertEquals($duplicate->Title, 'folder1-v2');
101
    }
102
103
    public function testAllChildrenIncludesFolders()
104
    {
105
        $folder1 = $this->objFromFixture(Folder::class, 'folder1');
106
        $subfolder1 = $this->objFromFixture(Folder::class, 'folder1-subfolder1');
107
        $file1 = $this->objFromFixture(File::class, 'file1-folder1');
108
109
        $children = $folder1->allChildren();
110
        $this->assertEquals(2, $children->Count());
111
        $this->assertContains($subfolder1->ID, $children->column('ID'));
112
        $this->assertContains($file1->ID, $children->column('ID'));
113
    }
114
115
    public function testFindOrMake()
116
    {
117
        $path = 'parent/testFindOrMake/';
118
        $folder = Folder::find_or_make($path);
119
        $this->assertEquals(
120
            ASSETS_PATH . '/FolderTest/' . $path,
121
            TestAssetStore::getLocalPath($folder),
122
            'Nested path information is correctly saved to database (with trailing slash)'
123
        );
124
125
        // Folder does not exist until it contains files
126
        $this->assertFileNotExists(
127
            TestAssetStore::getLocalPath($folder),
128
            'Empty folder does not have a filesystem record automatically'
129
        );
130
131
        $parentFolder = DataObject::get_one(
132
            Folder::class,
133
            array(
134
            '"File"."Name"' => 'parent'
135
            )
136
        );
137
        $this->assertNotNull($parentFolder);
138
        $this->assertEquals($parentFolder->ID, $folder->ParentID);
139
140
        $path = 'parent/testFindOrMake'; // no trailing slash
141
        $folder = Folder::find_or_make($path);
142
        $this->assertEquals(
143
            ASSETS_PATH . '/FolderTest/' . $path . '/', // Slash is automatically added here
144
            TestAssetStore::getLocalPath($folder),
145
            'Path information is correctly saved to database (without trailing slash)'
146
        );
147
148
        $path = 'assets/'; // relative to "assets/" folder, should produce "assets/assets/"
149
        $folder = Folder::find_or_make($path);
150
        $this->assertEquals(
151
            ASSETS_PATH . '/FolderTest/' . $path,
152
            TestAssetStore::getLocalPath($folder),
153
            'A folder named "assets/" within "assets/" is allowed'
154
        );
155
    }
156
157
    /**
158
     * Tests for the bug #5994 - Moving folder after executing Folder::findOrMake will not set the Filenames properly
159
     */
160
    public function testFindOrMakeFolderThenMove()
161
    {
162
        $folder1 = $this->objFromFixture(Folder::class, 'folder1');
163
        Folder::find_or_make($folder1->Filename);
164
        $folder2 = $this->objFromFixture(Folder::class, 'folder2');
165
166
        // Publish file1
167
        /**
168
 * @var File $file1
169
*/
170
        $file1 = DataObject::get_by_id(File::class, $this->idFromFixture(File::class, 'file1-folder1'), false);
171
        $file1->publishRecursive();
172
173
        // set ParentID. This should cause updateFilesystem to be called on all children
174
        $folder1->ParentID = $folder2->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<SilverStripe\ORM\DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
175
        $folder1->write();
176
177
        // Check if the file in the folder moved along
178
        /**
179
 * @var File $file1Draft
180
*/
181
        $file1Draft = Versioned::get_by_stage(File::class, Versioned::DRAFT)->byID($file1->ID);
182
        $this->assertFileExists(TestAssetStore::getLocalPath($file1Draft));
183
184
        $this->assertEquals(
185
            'FileTest-folder2/FileTest-folder1/File1.txt',
186
            $file1Draft->Filename,
187
            'The file DataObject has updated path'
188
        );
189
190
        // File should be located in new folder
191
        $this->assertEquals(
192
            ASSETS_PATH . '/FolderTest/.protected/FileTest-folder2/FileTest-folder1/55b443b601/File1.txt',
193
            TestAssetStore::getLocalPath($file1Draft)
194
        );
195
196
        // Published (live) version remains in the old location
197
        /**
198
 * @var File $file1Live
199
*/
200
        $file1Live = Versioned::get_by_stage(File::class, Versioned::LIVE)->byID($file1->ID);
201
        $this->assertEquals(
202
            ASSETS_PATH . '/FolderTest/FileTest-folder1/55b443b601/File1.txt',
203
            TestAssetStore::getLocalPath($file1Live)
204
        );
205
206
        // Publishing the draft to live should move the new file to the public store
207
        $file1Draft->publishRecursive();
208
        $this->assertEquals(
209
            ASSETS_PATH . '/FolderTest/FileTest-folder2/FileTest-folder1/55b443b601/File1.txt',
210
            TestAssetStore::getLocalPath($file1Draft)
211
        );
212
    }
213
214
    /**
215
     * Tests for the bug #5994 - if you don't execute get_by_id prior to the rename or move, it will fail.
216
     */
217
    public function testRenameFolderAndCheckTheFile()
218
    {
219
        // ID is prefixed in case Folder is subclassed by project/other module.
220
        $folder1 = DataObject::get_one(
221
            Folder::class,
222
            array(
223
            '"File"."ID"' => $this->idFromFixture(Folder::class, 'folder1')
224
            )
225
        );
226
227
        $folder1->Name = 'FileTest-folder1-changed';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<SilverStripe\ORM\DataObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
228
        $folder1->write();
229
230
        // Check if the file in the folder moved along
231
        $file1 = DataObject::get_by_id(File::class, $this->idFromFixture(File::class, 'file1-folder1'), false);
232
        $this->assertFileExists(
233
            TestAssetStore::getLocalPath($file1)
234
        );
235
        $this->assertEquals(
236
            $file1->Filename,
237
            'FileTest-folder1-changed/File1.txt',
238
            'The file DataObject path uses renamed folder'
239
        );
240
241
        // File should be located in new folder
242
        $this->assertEquals(
243
            ASSETS_PATH . '/FolderTest/.protected/FileTest-folder1-changed/55b443b601/File1.txt',
244
            TestAssetStore::getLocalPath($file1)
245
        );
246
    }
247
248
    /**
249
     * URL and Link are undefined for folder dataobjects
250
     */
251
    public function testLinkAndRelativeLink()
252
    {
253
        $folder = $this->objFromFixture(Folder::class, 'folder1');
254
        $this->assertEmpty($folder->getURL());
255
        $this->assertEmpty($folder->Link());
256
    }
257
258
    public function testIllegalFilenames()
259
    {
260
261
        // Test that generating a filename with invalid characters generates a correctly named folder.
262
        $folder = Folder::find_or_make('/FolderTest/EN_US Lang');
263
        $this->assertEquals('FolderTest/EN-US-Lang/', $folder->getFilename());
264
265
        // Test repeatitions of folder
266
        $folder2 = Folder::find_or_make('/FolderTest/EN_US Lang');
267
        $this->assertEquals($folder->ID, $folder2->ID);
268
269
        $folder3 = Folder::find_or_make('/FolderTest/EN--US_L!ang');
270
        $this->assertEquals($folder->ID, $folder3->ID);
271
272
        $folder4 = Folder::find_or_make('/FolderTest/EN-US-Lang');
273
        $this->assertEquals($folder->ID, $folder4->ID);
274
    }
275
276
    public function testTitleTiedToName()
277
    {
278
        $newFolder = new Folder();
279
280
        $newFolder->Name = 'TestNameCopiedToTitle';
281
        $this->assertEquals($newFolder->Name, $newFolder->Title);
282
        $this->assertEquals($newFolder->Title, 'TestNameCopiedToTitle');
283
284
        $newFolder->Title = 'TestTitleCopiedToName';
285
        $this->assertEquals($newFolder->Name, $newFolder->Title);
286
        $this->assertEquals($newFolder->Title, 'TestTitleCopiedToName');
287
288
        $newFolder->Name = 'TestNameWithIllegalCharactersCopiedToTitle <!BANG!>';
289
        $this->assertEquals($newFolder->Name, $newFolder->Title);
290
        $this->assertEquals($newFolder->Title, 'TestNameWithIllegalCharactersCopiedToTitle <!BANG!>');
291
292
        $newFolder->Title = 'TestTitleWithIllegalCharactersCopiedToName <!BANG!>';
293
        $this->assertEquals($newFolder->Name, $newFolder->Title);
294
        $this->assertEquals($newFolder->Title, 'TestTitleWithIllegalCharactersCopiedToName <!BANG!>');
295
    }
296
297
    public function testRootFolder()
298
    {
299
        $root = Folder::singleton();
300
        $this->assertEquals('/', $root->getFilename());
301
    }
302
}
303