Completed
Push — master ( 2fdc96...4f1f24 )
by Damian
12:09
created

FileTest::testGetExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 8
rs 9.4285
cc 1
eloc 7
nc 1
nop 0
1
<?php
2
3
use Filesystem as SS_Filesystem;
4
use SilverStripe\Filesystem\Storage\AssetStore;
5
6
/**
7
 * Tests for the File class
8
 */
9
class FileTest extends SapphireTest {
10
11
	protected static $fixture_file = 'FileTest.yml';
12
13
	protected $extraDataObjects = array('FileTest_MyCustomFile');
14
15
	public function setUp() {
16
		parent::setUp();
17
		$this->logInWithPermission('ADMIN');
18
		Versioned::reading_stage('Stage');
19
20
		// Set backend root to /ImageTest
21
		AssetStoreTest_SpyStore::activate('FileTest');
22
		
23
		// Create a test folders for each of the fixture references
24
		$folderIDs = $this->allFixtureIDs('Folder');
25
		foreach($folderIDs as $folderID) {
0 ignored issues
show
Bug introduced by
The expression $folderIDs of type object<A> is not traversable.
Loading history...
26
			$folder = DataObject::get_by_id('Folder', $folderID);
27
			$filePath = ASSETS_PATH . '/FileTest/' . $folder->getFilename();
28
			SS_Filesystem::makeFolder($filePath);
29
		}
30
31
		// Create a test files for each of the fixture references
32
		$fileIDs = $this->allFixtureIDs('File');
33
		foreach($fileIDs as $fileID) {
0 ignored issues
show
Bug introduced by
The expression $fileIDs of type object<A> is not traversable.
Loading history...
34
			$file = DataObject::get_by_id('File', $fileID);
35
			$root = ASSETS_PATH . '/FileTest/';
36
			if($folder = $file->Parent()) {
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on DataObject. Did you maybe mean parentClass()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
37
				$root .= $folder->getFilename();
38
			}
39
			$path = $root . substr($file->getHash(), 0, 10) . '/' . basename($file->getFilename());
40
			SS_Filesystem::makeFolder(dirname($path));
41
			$fh = fopen($path, "w+");
42
			fwrite($fh, str_repeat('x', 1000000));
43
			fclose($fh);
44
		}
45
46
		// Conditional fixture creation in case the 'cms' module is installed
47
		if(class_exists('ErrorPage')) {
48
			$page = new ErrorPage(array(
49
				'Title' => 'Page not Found',
50
				'ErrorCode' => 404
51
			));
52
			$page->write();
53
			$page->publish('Stage', 'Live');
54
		}
55
	}
56
57
	public function tearDown() {
58
		AssetStoreTest_SpyStore::reset();
59
		parent::tearDown();
60
	}
61
62
	public function testLinkShortcodeHandler() {
63
		$testFile = $this->objFromFixture('File', 'asdf');
64
65
		$parser = new ShortcodeParser();
66
		$parser->register('file_link', array('File', 'handle_shortcode'));
67
68
		$fileShortcode = sprintf('[file_link,id=%d]', $testFile->ID);
69
		$fileEnclosed  = sprintf('[file_link,id=%d]Example Content[/file_link]', $testFile->ID);
70
71
		$fileShortcodeExpected = $testFile->Link();
72
		$fileEnclosedExpected  = sprintf(
73
			'<a href="%s" class="file" data-type="txt" data-size="977 KB">Example Content</a>', $testFile->Link());
74
75
		$this->assertEquals($fileShortcodeExpected, $parser->parse($fileShortcode), 'Test that simple linking works.');
76
		$this->assertEquals($fileEnclosedExpected, $parser->parse($fileEnclosed), 'Test enclosed content is linked.');
77
78
		$testFile->delete();
79
80
		$fileShortcode = '[file_link,id="-1"]';
81
		$fileEnclosed  = '[file_link,id="-1"]Example Content[/file_link]';
82
83
		$this->assertEquals('', $parser->parse('[file_link]'), 'Test that invalid ID attributes are not parsed.');
84
		$this->assertEquals('', $parser->parse('[file_link,id="text"]'));
85
		$this->assertEquals('', $parser->parse('[file_link]Example Content[/file_link]'));
86
87
		if(class_exists('ErrorPage')) {
88
			$errorPage = ErrorPage::get()->filter('ErrorCode', 404)->First();
89
			$this->assertEquals(
90
				$errorPage->Link(),
91
				$parser->parse($fileShortcode),
92
				'Test link to 404 page if no suitable matches.'
93
			);
94
			$this->assertEquals(
95
				sprintf('<a href="%s">Example Content</a>', $errorPage->Link()),
96
				$parser->parse($fileEnclosed)
97
			);
98
		} else {
99
			$this->assertEquals('', $parser->parse($fileShortcode),
100
				'Short code is removed if file record is not present.');
101
			$this->assertEquals('', $parser->parse($fileEnclosed));
102
		}
103
	}
104
105
	public function testCreateWithFilenameWithSubfolder() {
106
		// Note: We can't use fixtures/setUp() for this, as we want to create the db record manually.
107
		// Creating the folder is necessary to avoid having "Filename" overwritten by setName()/setRelativePath(),
108
		// because the parent folders don't exist in the database
109
		$folder = Folder::find_or_make('/FileTest/');
110
		$testfilePath = BASE_PATH . '/assets/FileTest/CreateWithFilenameHasCorrectPath.txt'; // Important: No leading slash
111
		$fh = fopen($testfilePath, "w");
112
		fwrite($fh, str_repeat('x',1000000));
113
		fclose($fh);
114
115
		$file = new File();
116
		$file->setFromLocalFile($testfilePath);
117
		$file->ParentID = $folder->ID;
118
		$file->write();
119
120
		$this->assertEquals(
121
			'CreateWithFilenameHasCorrectPath.txt',
122
			$file->Name,
123
			'"Name" property is automatically set from "Filename"'
124
		);
125
		$this->assertEquals(
126
			'FileTest/CreateWithFilenameHasCorrectPath.txt',
127
			$file->Filename,
128
			'"Filename" property remains unchanged'
129
		);
130
131
		// TODO This should be auto-detected, see File->updateFilesystem()
132
		// $this->assertInstanceOf('Folder', $file->Parent(), 'Parent folder is created in database');
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
133
		// $this->assertFileExists($file->Parent()->getURL(), 'Parent folder is created on filesystem');
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
134
		// $this->assertEquals('FileTest', $file->Parent()->Name);
0 ignored issues
show
Unused Code Comprehensibility introduced by
71% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
135
		// $this->assertInstanceOf('Folder', $file->Parent()->Parent(), 'Grandparent folder is created in database');
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
136
		// $this->assertFileExists($file->Parent()->Parent()->getURL(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
137
		// 'Grandparent folder is created on filesystem');
138
		// $this->assertEquals('assets', $file->Parent()->Parent()->Name);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
139
	}
140
141
	public function testGetExtension() {
142
		$this->assertEquals('', File::get_file_extension('myfile'),
143
			'No extension');
144
		$this->assertEquals('txt', File::get_file_extension('myfile.txt'),
145
			'Simple extension');
146
		$this->assertEquals('gz', File::get_file_extension('myfile.tar.gz'),
147
			'Double-barrelled extension only returns last bit');
148
	}
149
150
	public function testValidateExtension() {
151
		Session::set('loggedInAs', null);
152
153
		$orig = Config::inst()->get('File', 'allowed_extensions');
154
		Config::inst()->remove('File', 'allowed_extensions');
155
		Config::inst()->update('File', 'allowed_extensions', array('txt'));
156
157
		$file = $this->objFromFixture('File', 'asdf');
158
159
		// Invalid ext
160
		$file->Name = 'asdf.php';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<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...
161
		$v = $file->validate();
162
		$this->assertFalse($v->valid());
163
		$this->assertContains('Extension is not allowed', $v->message());
164
165
		// Valid ext
166
		$file->Name = 'asdf.txt';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<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...
167
		$v = $file->validate();
168
		$this->assertTrue($v->valid());
169
170
		// Capital extension is valid as well
171
		$file->Name = 'asdf.TXT';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<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...
172
		$v = $file->validate();
173
		$this->assertTrue($v->valid());
174
175
		Config::inst()->remove('File', 'allowed_extensions');
176
		Config::inst()->update('File', 'allowed_extensions', $orig);
177
	}
178
179
	public function testAppCategory() {
180
		// Test various categories
181
		$this->assertEquals('image', File::get_app_category('jpg'));
182
		$this->assertEquals('image', File::get_app_category('JPG'));
183
		$this->assertEquals('image', File::get_app_category('JPEG'));
184
		$this->assertEquals('image', File::get_app_category('png'));
185
		$this->assertEquals('image', File::get_app_category('tif'));
186
		$this->assertEquals('document', File::get_app_category('pdf'));
187
		$this->assertEquals('video', File::get_app_category('mov'));
188
		$this->assertEquals('audio', File::get_app_category('OGG'));
189
	}
190
191
	public function testGetCategoryExtensions() {
192
		// Test specific categories
193
		$images = array(
194
			'alpha', 'als', 'bmp', 'cel', 'gif', 'ico', 'icon', 'jpeg', 'jpg', 'pcx', 'png', 'ps', 'tif', 'tiff'
195
		);
196
		$this->assertEquals($images, File::get_category_extensions('image'));
197
		$this->assertEquals(array('gif', 'jpeg', 'jpg', 'png'), File::get_category_extensions('image/supported'));
198
		$this->assertEquals($images, File::get_category_extensions(array('image', 'image/supported')));
199
		$this->assertEquals(
200
			array('fla', 'gif', 'jpeg', 'jpg', 'png', 'swf'),
201
			File::get_category_extensions(array('flash', 'image/supported'))
202
		);
203
204
		// Test other categories have at least one item
205
		$this->assertNotEmpty(File::get_category_extensions('archive'));
206
		$this->assertNotEmpty(File::get_category_extensions('audio'));
207
		$this->assertNotEmpty(File::get_category_extensions('document'));
208
		$this->assertNotEmpty(File::get_category_extensions('flash'));
209
		$this->assertNotEmpty(File::get_category_extensions('video'));
210
	}
211
212
	/**
213
	 * @dataProvider allowedExtensions
214
	 * @param string $extension
215
	 */
216
	public function testAllFilesHaveCategory($extension) {
217
		$this->assertNotEmpty(
218
			File::get_app_category($extension),
219
			"Assert that extension {$extension} has a valid category"
220
		);
221
	}
222
223
	/**
224
	 * Gets the list of all extensions for testing
225
	 *
226
	 * @return array
227
	 */
228
	public function allowedExtensions() {
229
		$args = array();
230
		foreach(array_filter(File::config()->allowed_extensions) as $ext) {
231
			$args[] = array($ext);
232
		}
233
		return $args;
234
	}
235
236
	public function testSetNameChangesFilesystemOnWrite() {
237
		$file = $this->objFromFixture('File', 'asdf');
238
		$this->logInWithPermission('ADMIN');
239
		$file->doPublish();
240
		$oldTuple = $file->File->getValue();
241
242
		// Rename
243
		$file->Name = 'renamed.txt';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<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...
244
		$newTuple = $oldTuple;
245
		$newTuple['Filename'] = $file->getFilename();
246
247
		// Before write()
248
		$this->assertTrue(
249
			$this->getAssetStore()->exists($oldTuple['Filename'], $oldTuple['Hash']),
250
			'Old path is still present'
251
		);
252
		$this->assertFalse(
253
			$this->getAssetStore()->exists($newTuple['Filename'], $newTuple['Hash']),
254
			'New path is updated in memory, not written before write() is called'
255
		);
256
257
		// After write()
258
		$file->write();
259
		$this->assertTrue(
260
			$this->getAssetStore()->exists($oldTuple['Filename'], $oldTuple['Hash']),
261
			'Old path exists after draft change'
262
		);
263
		$this->assertTrue(
264
			$this->getAssetStore()->exists($newTuple['Filename'], $newTuple['Hash']),
265
			'New path is created after write()'
266
		);
267
268
		// After publish
269
		$file->doPublish();
270
		$this->assertFalse(
271
			$this->getAssetStore()->exists($oldTuple['Filename'], $oldTuple['Hash']),
272
			'Old file is finally removed after publishing new file'
273
		);
274
		$this->assertTrue(
275
			$this->getAssetStore()->exists($newTuple['Filename'], $newTuple['Hash']),
276
			'New path is created after write()'
277
		);
278
	}
279
280
	public function testSetParentIDChangesFilesystemOnWrite() {
281
		$file = $this->objFromFixture('File', 'asdf');
282
		$this->logInWithPermission('ADMIN');
283
		$file->doPublish();
284
		$subfolder = $this->objFromFixture('Folder', 'subfolder');
285
		$oldTuple = $file->File->getValue();
286
287
		// set ParentID
288
		$file->ParentID = $subfolder->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<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...
289
		$newTuple = $oldTuple;
290
		$newTuple['Filename'] = $file->getFilename();
291
292
		// Before write()
293
		$this->assertTrue(
294
			$this->getAssetStore()->exists($oldTuple['Filename'], $oldTuple['Hash']),
295
			'Old path is still present'
296
		);
297
		$this->assertFalse(
298
			$this->getAssetStore()->exists($newTuple['Filename'], $newTuple['Hash']),
299
			'New path is updated in memory, not written before write() is called'
300
		);
301
		$file->write();
302
303
		// After write()
304
		$file->write();
305
		$this->assertTrue(
306
			$this->getAssetStore()->exists($oldTuple['Filename'], $oldTuple['Hash']),
307
			'Old path exists after draft change'
308
		);
309
		$this->assertTrue(
310
			$this->getAssetStore()->exists($newTuple['Filename'], $newTuple['Hash']),
311
			'New path is created after write()'
312
		);
313
314
		// After publish
315
		$file->doPublish();
316
		$this->assertFalse(
317
			$this->getAssetStore()->exists($oldTuple['Filename'], $oldTuple['Hash']),
318
			'Old file is finally removed after publishing new file'
319
		);
320
		$this->assertTrue(
321
			$this->getAssetStore()->exists($newTuple['Filename'], $newTuple['Hash']),
322
			'New path is created after write()'
323
		);
324
	}
325
326
	/**
327
	 * @see http://open.silverstripe.org/ticket/5693
328
	 *
329
	 * @expectedException ValidationException
330
	 */
331
	public function testSetNameWithInvalidExtensionDoesntChangeFilesystem() {
332
		$orig = Config::inst()->get('File', 'allowed_extensions');
333
		Config::inst()->remove('File', 'allowed_extensions');
334
		Config::inst()->update('File', 'allowed_extensions', array('txt'));
335
336
		$file = $this->objFromFixture('File', 'asdf');
337
		$oldPath = $file->getURL();
338
339
		$file->Name = 'renamed.php'; // evil extension
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<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...
340
		try {
341
			$file->write();
342
		} catch(ValidationException $e) {
343
			Config::inst()->remove('File', 'allowed_extensions');
344
			Config::inst()->update('File', 'allowed_extensions', $orig);
345
			throw $e;
346
		}
347
	}
348
349
	public function testGetURL() {
350
		$rootfile = $this->objFromFixture('File', 'asdf');
351
		$this->assertEquals('/assets/FileTest/55b443b601/FileTest.txt', $rootfile->getURL());
352
	}
353
354
	public function testGetAbsoluteURL() {
355
		$rootfile = $this->objFromFixture('File', 'asdf');
356
		$this->assertEquals(
357
			Director::absoluteBaseURL() . 'assets/FileTest/55b443b601/FileTest.txt',
358
			$rootfile->getAbsoluteURL()
359
		);
360
	}
361
362
	public function testNameAndTitleGeneration() {
363
		// When name is assigned, title is automatically assigned
364
		$file = $this->objFromFixture('Image', 'setfromname');
365
		$this->assertEquals('FileTest', $file->Title);
366
	}
367
368
	public function testSizeAndAbsoluteSizeParameters() {
369
		$file = $this->objFromFixture('File', 'asdf');
370
371
		/* AbsoluteSize will give the integer number */
372
		$this->assertEquals(1000000, $file->AbsoluteSize);
373
		/* Size will give a humanised number */
374
		$this->assertEquals('977 KB', $file->Size);
375
	}
376
377
	public function testFileType() {
378
		$file = $this->objFromFixture('Image', 'gif');
379
		$this->assertEquals("GIF image - good for diagrams", $file->FileType);
380
381
		$file = $this->objFromFixture('File', 'pdf');
382
		$this->assertEquals("Adobe Acrobat PDF file", $file->FileType);
383
384
		$file = $this->objFromFixture('Image', 'gifupper');
385
		$this->assertEquals("GIF image - good for diagrams", $file->FileType);
386
387
		/* Only a few file types are given special descriptions; the rest are unknown */
388
		$file = $this->objFromFixture('File', 'asdf');
389
		$this->assertEquals("unknown", $file->FileType);
390
	}
391
392
	/**
393
	 * Test the File::format_size() method
394
	 */
395
	public function testFormatSize() {
396
		$this->assertEquals("1000 bytes", File::format_size(1000));
397
		$this->assertEquals("1023 bytes", File::format_size(1023));
398
		$this->assertEquals("1 KB", File::format_size(1025));
399
		$this->assertEquals("9.8 KB", File::format_size(10000));
400
		$this->assertEquals("49 KB", File::format_size(50000));
401
		$this->assertEquals("977 KB", File::format_size(1000000));
402
		$this->assertEquals("1 MB", File::format_size(1024*1024));
403
		$this->assertEquals("954 MB", File::format_size(1000000000));
404
		$this->assertEquals("1 GB", File::format_size(1024*1024*1024));
405
		$this->assertEquals("9.3 GB", File::format_size(10000000000));
406
		// It use any denomination higher than GB.  It also doesn't overflow with >32 bit integers
407
		$this->assertEquals("93132.3 GB", File::format_size(100000000000000));
408
	}
409
410
	public function testDeleteFile() {
411
		$file = $this->objFromFixture('File', 'asdf');
412
		$this->logInWithPermission('ADMIN');
413
		$file->doPublish();
414
		$tuple = $file->File->getValue();
415
416
		// Before delete
417
		$this->assertTrue(
418
			$this->getAssetStore()->exists($tuple['Filename'], $tuple['Hash']),
419
			'File is still present'
420
		);
421
422
		// after unpublish
423
		$file->doUnpublish();
424
		$this->assertTrue(
425
			$this->getAssetStore()->exists($tuple['Filename'], $tuple['Hash']),
426
			'File is still present after unpublish'
427
		);
428
429
		// after delete
430
		$file->delete();
431
		$this->assertFalse(
432
			$this->getAssetStore()->exists($tuple['Filename'], $tuple['Hash']),
433
			'File is deleted after unpublish and delete'
434
		);
435
	}
436
437
	public function testRenameFolder() {
438
		$newTitle = "FileTest-folder-renamed";
439
440
		//rename a folder's title
441
		$folderID = $this->objFromFixture("Folder","folder2")->ID;
442
		$folder = DataObject::get_by_id('Folder',$folderID);
443
		$folder->Title = $newTitle;
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<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...
444
		$folder->write();
445
446
		//get folder again and see if the filename has changed
447
		$folder = DataObject::get_by_id('Folder',$folderID);
448
		$this->assertEquals(
449
			$newTitle . "/",
450
			$folder->Filename,
451
			"Folder Filename updated after rename of Title"
452
		);
453
454
		//rename a folder's name
455
		$newTitle2 = "FileTest-folder-renamed2";
456
		$folder->Name = $newTitle2;
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<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...
457
		$folder->write();
458
459
		//get folder again and see if the Title has changed
460
		$folder = DataObject::get_by_id('Folder',$folderID);
461
		$this->assertEquals($folder->Title, $newTitle2,
462
			"Folder Title updated after rename of Name");
463
464
465
		//rename a folder's Filename
466
		$newTitle3 = "FileTest-folder-renamed3";
467
		$folder->Filename = $newTitle3;
0 ignored issues
show
Documentation introduced by
The property Filename does not exist on object<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...
468
		$folder->write();
469
470
		//get folder again and see if the Title has changed
471
		$folder = DataObject::get_by_id('Folder',$folderID);
472
		$this->assertEquals($folder->Title, $newTitle3,
473
			"Folder Title updated after rename of Filename");
474
	}
475
476
	public function testSetsOwnerOnFirstWrite() {
477
		Session::set('loggedInAs', null);
478
		$member1 = new Member();
479
		$member1->write();
480
		$member2 = new Member();
481
		$member2->write();
482
483
		$file1 = new File();
484
		$file1->write();
485
		$this->assertEquals(0, $file1->OwnerID, 'Owner not written when no user is logged in');
486
487
		$member1->logIn();
488
		$file2 = new File();
489
		$file2->write();
490
		$this->assertEquals($member1->ID, $file2->OwnerID, 'Owner written when user is logged in');
491
492
		$member2->logIn();
493
		$file2->forceChange();
494
		$file2->write();
495
		$this->assertEquals($member1->ID, $file2->OwnerID, 'Owner not overwritten on existing files');
496
	}
497
498
	public function testCanEdit() {
499
		$file = $this->objFromFixture('Image', 'gif');
500
501
		// Test anonymous permissions
502
		Session::set('loggedInAs', null);
503
		$this->assertFalse($file->canEdit(), "Anonymous users can't edit files");
504
505
		// Test permissionless user
506
		$this->objFromFixture('Member', 'frontend')->logIn();
507
		$this->assertFalse($file->canEdit(), "Permissionless users can't edit files");
508
509
		// Test global CMS section users
510
		$this->objFromFixture('Member', 'cms')->logIn();
511
		$this->assertTrue($file->canEdit(), "Users with all CMS section access can edit files");
512
513
		// Test cms access users without file access
514
		$this->objFromFixture('Member', 'security')->logIn();
515
		$this->assertFalse($file->canEdit(), "Security CMS users can't edit files");
516
517
		// Test asset-admin user
518
		$this->objFromFixture('Member', 'assetadmin')->logIn();
519
		$this->assertTrue($file->canEdit(), "Asset admin users can edit files");
520
521
		// Test admin
522
		$this->objFromFixture('Member', 'admin')->logIn();
523
		$this->assertTrue($file->canEdit(), "Admins can edit files");
524
	}
525
		
526
527
	public function testJoinPaths() {
528
		$this->assertEquals('name/file.jpg', File::join_paths('/name', 'file.jpg'));
529
		$this->assertEquals('name/file.jpg', File::join_paths('name', 'file.jpg'));
530
		$this->assertEquals('name/file.jpg', File::join_paths('/name', '/file.jpg'));
531
		$this->assertEquals('name/file.jpg', File::join_paths('name/', '/', 'file.jpg'));
532
		$this->assertEquals('file.jpg', File::join_paths('/', '/', 'file.jpg'));
533
		$this->assertEquals('', File::join_paths('/', '/'));
534
	}
535
536
	/**
537
	 * @return AssetStore
538
	 */
539
	protected function getAssetStore() {
540
		return Injector::inst()->get('AssetStore');
541
	}
542
543
}
544
545
class FileTest_MyCustomFile extends File implements TestOnly {
546
547
}
548