--- /dev/null
+++ tests/t3lib/file/storage/t3lib_file_storage_filesystemstorageTest.php
@@ -0,0 +1,123 @@
+<?php
+
+include_once 'vfsStream/vfsStreamWrapper.php';
+include_once 'vfsStream/vfsStream.php';
+
+class t3lib_file_storage_FileSystemStorageTest extends tx_phpunit_testcase {
+	/**
+	 * @test
+	 */
+	public function basePathAlwaysEndsWithSlash() {
+		$storageConfiguration = array('relative' => TRUE, 'path' => 'relative/path');
+
+		$storageBackend = new t3lib_file_storage_FileSystemStorage($storageConfiguration);
+		$this->assertEquals(PATH_site . $storageConfiguration['path'] . '/', $storageBackend->getBasePath());
+
+		$storageConfiguration = array('relative' => FALSE, 'path' => '/absolute/path');
+
+		$storageBackend = new t3lib_file_storage_FileSystemStorage($storageConfiguration);
+		$this->assertEquals($storageConfiguration['path'] . '/', $storageBackend->getBasePath());
+	}
+
+	/**
+	 * @test
+	 */
+	public function relativePathIsResolvedCorrectly() {
+		$storageConfiguration = array('relative' => 1, 'path' => 'relative/path/');
+
+		$storageBackend = new t3lib_file_storage_FileSystemStorage($storageConfiguration);
+		$this->assertEquals(PATH_site . $storageConfiguration['path'], $storageBackend->getBasePath());
+	}
+
+	/**
+	 * @test
+	 */
+	public function relativePathWithDotsIsResolvedCorrectly() {
+		$storageConfiguration = array('relative' => 1, 'path' => '../a/relative/path/outside/the/typo3/site/directory/');
+
+		$storageBackend = new t3lib_file_storage_FileSystemStorage($storageConfiguration);
+		$expectedPath = substr(PATH_site, 0, strrpos(PATH_site, '/', -2)) . substr($storageConfiguration['path'], strpos($storageConfiguration['path'], '/'));
+		$this->assertEquals($expectedPath, $storageBackend->getBasePath());
+	}
+
+	/**
+	 * @test
+	 */
+	public function copyCopiesFileToCorrectLocation() {
+		$root = vfsStream::setup('root');
+		$subdir = vfsStream::newDirectory('somedir')->at($root);
+		$file = vfsStream::newFile('source.txt')->at($subdir);
+		$storageBackend = new t3lib_file_storage_FileSystemStorage(array('path' => vfsStream::url('root'), 'relative' => FALSE));
+		$storageBackend->copyFile('somedir/source.txt', 'somedir/target.txt');
+
+		$this->assertTrue($subdir->hasChild('target.txt'));
+	}
+
+	/**
+	 * @test
+	 */
+	public function copyThrowsExceptionIfSourceFileIsNotFound() {
+		$this->setExpectedException('InvalidArgumentException');
+
+		$root = vfsStream::setup('root');
+		$subdir = vfsStream::newDirectory('somedir')->at($root);
+		$storageBackend = new t3lib_file_storage_FileSystemStorage(array('path' => vfsStream::url('root'), 'relative' => FALSE));
+		$storageBackend->copyFile('somedir/source.txt', 'somedir/target.txt');
+	}
+
+	/**
+	 * @test
+	 */
+	public function moveFileMovesToCorrectLocation() {
+		$root = vfsStream::setup('root');
+		$subdir = vfsStream::newDirectory('somedir')->at($root);
+		$file = vfsStream::newFile('source.txt')->at($subdir);
+		$storageBackend = new t3lib_file_storage_FileSystemStorage(array('path' => vfsStream::url('root'), 'relative' => FALSE));
+		$storageBackend->moveFile('somedir/source.txt', 'somedir/target.txt');
+
+		$this->assertFalse($subdir->hasChild('source.txt'));
+		$this->assertTrue($subdir->hasChild('target.txt'));
+	}
+
+	/**
+	 * @test
+	 */
+	public function moveFileThrowsExceptionIfSourceFileDoesNotExist() {
+		$this->setExpectedException('InvalidArgumentException');
+
+		$root = vfsStream::setup('root');
+		$subdir = vfsStream::newDirectory('somedir')->at($root);
+		$storageBackend = new t3lib_file_storage_FileSystemStorage(array('path' => vfsStream::url('root'), 'relative' => FALSE));
+		$storageBackend->moveFile('somedir/source.txt', 'somedir/target.txt');
+	}
+
+	/**
+	 * @test
+	 */
+	public function moveFileThrowsExceptionIfDestinationFileExists() {
+		$this->setExpectedException('InvalidArgumentException');
+
+		$root = vfsStream::setup('root');
+		$subdir = vfsStream::newDirectory('somedir')->at($root);
+		vfsStream::newFile('source.txt')->at($subdir);
+		vfsStream::newFile('target.txt')->at($subdir);
+		$storageBackend = new t3lib_file_storage_FileSystemStorage(array('path' => vfsStream::url('root'), 'relative' => FALSE));
+		$storageBackend->moveFile('somedir/source.txt', 'somedir/target.txt');
+	}
+
+	/**
+	 * @test
+	 */
+	public function createDirectoryCreatesDirectory() {
+		$root = vfsStream::setup('root');
+		$storageBackend = new t3lib_file_storage_FileSystemStorage(array('path' => vfsStream::url('root'), 'relative' => FALSE));
+
+		$storageBackend->createDirectory('', 'aDirOnTheFirstLevel');
+		$this->assertTrue($root->hasChild('aDirOnTheFirstLevel'));
+
+		$subdir = vfsStream::newDirectory('someDir')->at($root);
+		$storageBackend->createDirectory('someDir', 'anotherDir');
+
+		$this->assertTrue($subdir->hasChild('anotherDir'));
+	}
+}
\ No newline at end of file
--- /dev/null
+++ tests/t3lib/file/t3lib_file_fileTest.php
@@ -0,0 +1,58 @@
+<?php
+/***************************************************************
+* Copyright notice
+*
+* (c) 2010 Andreas Wolf <andreas.wolf@ikt-werk.de>
+* All rights reserved
+*
+* This script is part of the TYPO3 project. The TYPO3 project is
+* free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* The GNU General Public License can be found at
+* http://www.gnu.org/copyleft/gpl.html.
+*
+* This script is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Testcase for the t3lib_file_File class in the TYPO3 Core.
+ *
+ * @package TYPO3
+ * @subpackage t3lib
+ *
+ * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
+ */
+class t3lib_file_fileTest extends tx_phpunit_testcase {
+
+	/**
+	 * @test
+	 */
+	public function constructorStoresFileData() {
+		// pseudo file data from the database
+		$fileData = array(
+			'uid' => 1,
+			'file_name' => 'test.jpg',
+			'file_path' => 'just/a/random/testfolder/',
+			'file_size' => 1234,
+			'file_hash' => sha1(uniqid())
+		);
+		$mockMount = $this->getMock('t3lib_file_Mount');
+
+		$fileObject = new t3lib_file_File($mockMount, $fileData);
+
+		$this->assertEquals($fileData['uid'], $fileObject->getUid(), 'File uid was not stored correctly.');
+		$this->assertEquals($fileData['file_name'], $fileObject->getName(), 'File name was not stored correctly.');
+		$this->assertEquals($fileData['file_size'], $fileObject->getSize(), 'File size was not stored correctly.');
+		$this->assertEquals($fileData['file_path'], $fileObject->getPath(), 'Node path was not stored correctly.');
+		$this->assertEquals($fileData['file_hash'], $fileObject->getHash(), 'Node path was not stored correctly.');
+	}
+}
+?>
\ No newline at end of file
--- /dev/null
+++ tests/t3lib/file/t3lib_file_indexerTest.php
@@ -0,0 +1,92 @@
+<?php
+
+class t3lib_file_IndexerTest extends tx_phpunit_testcase {
+
+	private $_dbConnectionBackup;
+
+	/**
+	 * @var t3lib_file_Mount
+	 */
+	private $mockedMount;
+
+	/**
+	 * @var t3lib_file_storage_Interface
+	 */
+	private $mockedStorage;
+
+	/**
+	 * @var t3lib_DB
+	 */
+	private $mockedDatabase;
+
+	public function setUp() {
+		$this->mockedStorage = $this->getMock('t3lib_file_storage_Interface');
+		$this->mockedStorage->expects($this->any())->method('exists')->will($this->returnValue(TRUE));
+		$this->mockedMount = $this->getMock('t3lib_file_Mount');
+		$this->mockedMount->expects($this->any())->method('getUid')->will($this->returnValue(1));
+		$this->mockedMount->expects($this->any())->method('getStorageBackend')->will($this->returnValue($this->mockedStorage));
+
+		$this->mockedDatabase = $this->getMock('t3lib_DB');
+
+		$this->_dbConnectionBackup = $GLOBALS['TYPO3_DB'];
+		$GLOBALS['TYPO3_DB'] = $this->mockedDatabase;
+	}
+
+	public function tearDown() {
+		$GLOBALS['TYPO3_DB'] = $this->_dbConnectionBackup;
+		$this->mockedMount = NULL;
+		$this->mockedStorage = NULL;
+	}
+
+	/**
+	 * @test
+	 */
+	public function indexerCorrectlyResolvesFilePath() {
+		$fakedPath = 'someFolder/' . uniqid() . 'with/someFileInIt_' . uniqid() . '.ext';
+
+		$this->mockedMount->expects($this->any())->method('getStorageBackend')->will($this->returnValue($this->mockedStorage));
+		$this->mockedDatabase->expects($this->any())->method('exec_INSERTquery')->with(
+			$this->anything(),
+			$this->logicalAnd($this->contains(basename($fakedPath)), $this->contains(dirname($fakedPath) . '/'))
+		);
+
+		t3lib_file_Indexer::addFileToIndex($this->mockedMount, $fakedPath);
+	}
+
+	/**
+	 * @test
+	 */
+	public function indexerStoresTimesWithNewFileRecords() {
+		$fakedPath = 'someFolder/' . uniqid() . 'with/someFileInIt_' . uniqid() . '.ext';
+
+		$this->mockedMount->expects($this->any())->method('getStorageBackend')->will($this->returnValue($this->mockedStorage));
+		$this->mockedDatabase->expects($this->any())->method('exec_INSERTquery')->with(
+			$this->anything(),
+			$this->logicalAnd($this->contains($GLOBALS['EXEC_TIME']))
+		);
+
+		t3lib_file_Indexer::addFileToIndex($this->mockedMount, $fakedPath);
+	}
+
+	/**
+	 * @test
+	 */
+	public function indexerQueriesBackendForFileData() {
+		$fakedPath = 'someFolder/' . uniqid() . 'with/someFileInIt_' . uniqid() . '.ext';
+
+		$modificationTime = time();
+		$hash = uniqid();
+		$size = rand(1, 1048576);
+		$this->mockedStorage->expects($this->any())->method('getSize')->will($this->returnValue($size));
+		$this->mockedStorage->expects($this->any())->method('getFileHash')->will($this->returnValue($hash));
+		$this->mockedStorage->expects($this->any())->method('getModificationTime')->will($this->returnValue($modificationTime));
+		$this->mockedMount->expects($this->any())->method('getStorageBackend')->will($this->returnValue($this->mockedStorage));
+
+		$this->mockedDatabase->expects($this->atLeastOnce())->method('exec_INSERTquery')->with(
+			'sys_files',
+			$this->logicalAnd($this->contains($hash), $this->contains($size), $this->contains($modificationTime))
+		);
+
+		t3lib_file_Indexer::addFileToIndex($this->mockedMount, $fakedPath);
+	}
+}
\ No newline at end of file
--- /dev/null
+++ tests/t3lib/file/t3lib_file_mountTest.php
@@ -0,0 +1,49 @@
+<?php
+
+class t3lib_file_mountTest extends tx_phpunit_testcase {
+
+	/**
+	 * @test
+	 */
+	public function getInstanceReturnsInstanceForUidZero() {
+		$mountObject = t3lib_file_Mount::getInstanceForUid(0);
+
+		$this->assertType('t3lib_file_Mount', $mountObject);
+	}
+
+	/**
+	 * @test
+	 */
+	public function backendInInstanceForUidZeroPointsToCorrectLocation() {
+		$mountObject = t3lib_file_Mount::getInstanceForUid(0);
+		$backend = $mountObject->getStorageBackend();
+
+		$this->assertEquals(PATH_site . 'fileadmin/', $backend->getBasePath());
+	}
+
+	/**
+	 * @test
+	 */
+	public function getUrlForPathUsesBaseUrlFromBackend() {
+		$baseUrl = 'protocol://some-host/some/path/to/a/mount/';
+		$filePath = 'a/file/inside/the/mount.ext';
+
+		$mountObject = new t3lib_file_Mount();
+		$backendObject = $this->getMock('t3lib_file_storage_filesystemstorage', array('getBaseUrl'));
+		$backendObject->expects($this->any())->method('getBaseUrl')->will($this->returnValue($baseUrl));
+		$mountObject->setStorageBackend($backendObject);
+
+		$this->assertEquals($baseUrl . $filePath, $mountObject->getUrlForPath($filePath));
+	}
+
+	/**
+	 * @test
+	 */
+	public function getInstanceForAliasReturnsCorrectMount() {
+		$mount = t3lib_file_Mount::getInstanceForAlias('fileadmin');
+
+		$this->assertEquals(0, $mount->getUid());
+		$this->assertEquals('fileadmin', $mount->getAlias());
+	}
+}
+?>
\ No newline at end of file
--- /dev/null
+++ tests/t3lib/file/t3lib_file_repositoryTest.php
@@ -0,0 +1,195 @@
+<?php
+
+class t3lib_file_repositoryTest extends tx_phpunit_testcase {
+
+	protected function _getFakedMount($uid, $alias) {
+		return new t3lib_file_Mount(array('uid' => $uid, 'alias' => $alias));
+	}
+
+	/**
+	 * @test
+	 */
+	public function getByIdFetchesCorrectRecordFromDatabase() {
+		$fakeRecord = array(
+			'uid' => 1,
+			'file_name' => 'test.jpg',
+			'file_path' => 'just/a/testfolder/somewhere/',
+			'file_size' => 1234,
+			'mount' => 0
+		);
+		$databaseMock = $this->getMock('t3lib_DB', array('exec_SELECTgetRows'));
+		$databaseMock->expects($this->at(0))->method('exec_SELECTgetRows')->with(
+			$this->anything(),
+			$this->equalTo('sys_files'),
+			$this->stringEndsWith($fakeRecord['uid'])
+		)->will($this->returnValue(array($fakeRecord)));
+
+		$fakedMount = $this->_getFakedMount(0, 'fileadmin');
+
+		$GLOBALS['TYPO3_DB'] = $databaseMock;
+		$repository = $this->getMock('t3lib_file_Repository', array('getMountForFile'));
+		$repository->expects($this->any())->method('getMountForFile')->will($this->returnValue($fakedMount));
+
+		$fileObject = $repository->getFileById($fakeRecord['uid']);
+		$this->assertType('t3lib_file_File', $fileObject);
+		$this->assertEquals($fakeRecord['uid'], $fileObject->getUid());
+	}
+
+	/**
+	 * @test
+	 */
+	public function getByIdThrowsExceptionIfRecordDoesNotExist() {
+		$databaseMock = $this->getMock('t3lib_DB', array('exec_SELECTgetRows'));
+		$databaseMock->expects($this->once())->method('exec_SELECTgetRows')->with(
+				$this->anything(),
+				$this->equalTo('sys_files'),
+				$this->anything()
+			)->will($this->returnValue(array()));
+
+		$fakedMount = $this->_getFakedMount(0, 'fileadmin');
+
+		$GLOBALS['TYPO3_DB'] = $databaseMock;
+		$repository = $this->getMock('t3lib_file_Repository', array('getMountForFile'));
+		$repository->expects($this->any())->method('getMountForFile')->will($this->returnValue($fakedMount));
+
+		$this->setExpectedException('t3lib_file_exception_FileNotFound');
+		$repository->getFileById(1);
+	}
+
+	/**
+	 * @test
+	 */
+	public function getFileByPathFetchesCorrectRecordFromDatabase() {
+		$fakeRecord = array(
+			'uid' => 1,
+			'file_name' => 'test.jpg',
+			'file_path' => 'fileadmin/just/a/testfolder/somewhere/',
+			'file_size' => 1234,
+			'mount' => 0
+		);
+		$databaseMock = $this->getMock('t3lib_DB', array('exec_SELECTgetRows'));
+		$databaseMock->expects($this->once())->method('exec_SELECTgetRows')->with(
+			$this->anything(),
+			$this->equalTo('sys_files'),
+			$this->logicalAnd($this->stringContains('"' . $fakeRecord['file_name'] . '"'), $this->stringContains('"' . $fakeRecord['file_path'] . '"'))
+		)->will($this->returnValue(array($fakeRecord)));
+
+		$fakedMount = $this->_getFakedMount(0, 'fileadmin');
+
+		$GLOBALS['TYPO3_DB'] = $databaseMock;
+		$repository = $this->getMock('t3lib_file_Repository', array('getMountForFile'));
+		$repository->expects($this->any())->method('getMountForFile')->will($this->returnValue($fakedMount));
+
+		$fileObject = $repository->getFileByPath($fakeRecord['file_path'] . $fakeRecord['file_name']);
+		$this->assertType('t3lib_file_File', $fileObject);
+	}
+
+	/**
+	 * @test
+	 */
+	public function getAllInPathFetchesAllRecordsFromPath() {
+		$fakePath = 'just/a/testfolder/somewhere/';
+		$fakeRecords = array(
+			array(
+				'uid' => 1,
+				'file_name' => 'test.jpg',
+				'file_path' => $fakePath,
+				'file_size' => 1234,
+				'mount' => 0
+			),
+			array(
+				'uid' => 2,
+				'file_name' => 'test.odt',
+				'file_path' => $fakePath,
+				'file_size' => 321,
+				'mount' => 0
+			)
+		);
+		$databaseMock = $this->getMock('t3lib_DB', array('exec_SELECTgetRows'));
+		$databaseMock->expects($this->once())->method('exec_SELECTgetRows')->with(
+			$this->anything(),
+			$this->equalTo('sys_files'),
+			$this->stringContains('"' . $fakePath . '"')
+		)->will($this->returnValue($fakeRecords));
+
+		$GLOBALS['TYPO3_DB'] = $databaseMock;
+		// TODO: use the real mount here
+		$mount = t3lib_file_Mount::getInstanceForUid(0);
+
+		$repository = new t3lib_file_Repository();
+
+		$fileObjects = $repository->getAllInPath($fakePath);
+		$this->assertType('array', $fileObjects);
+		$this->assertEquals(2, count($fileObjects));
+		$this->assertType('t3lib_file_File', $fileObjects[0]);
+		$this->assertType('t3lib_file_File', $fileObjects[1]);
+		$this->assertEquals($fileObjects[0], new t3lib_file_File($mount, $fakeRecords[0]));
+		$this->assertEquals($fileObjects[1], new t3lib_file_File($mount, $fakeRecords[1]));
+	}
+
+	/**
+	 * @test
+	 */
+	public function getFilesFromRelation() {
+		t3lib_div::loadTCA('tx_test');
+		$fakePath = 'just/a/testfolder/somewhere/';
+		$fakeRecords = array(
+			array(
+				'uid' => 1,
+				'file_name' => 'test.jpg',
+				'file_path' => $fakePath,
+				'file_size' => 1234,
+				'mount' => 0
+			),
+			array(
+				'uid' => 2,
+				'file_name' => 'test.odt',
+				'file_path' => $fakePath,
+				'file_size' => 321,
+				'mount' => 0
+			)
+		);
+		$fakeRelations = array(
+			array(
+				'tablenames' => 'sys_files_usage_mm',
+				'uid_foreign' => '8',
+				'uid_local' => '1',
+				'table' => 'tx_test',
+				'ident' => 'testField'
+			)
+		);
+
+		$GLOBALS['TCA']['tx_test']['columns']['testField']['config'] = array(
+			'type' => 'group',
+			'internal_type' => 'db',
+			'allowed' => 'sys_files',
+			'internal_subtype' => 'file_record',
+			'internal_subtype_allowed' => 'gif,jpg,jpeg,tif,tiff,bmp,pcx,tga,png,pdf,ai',
+			'prepend_tname' => 1,
+			'size' => 5,
+			'minitems' => 0,
+			'MM_opposite_field' => 'file_usage',
+			'MM' => 'sys_files_usage_mm',
+			'MM_match_fields' => array(
+				'ident' => 'testField'
+			)
+		);
+
+		$databaseMock = $this->getMock('t3lib_DB', array('exec_SELECTgetRows'));
+		$databaseMock->expects($this->once())->method('exec_SELECTgetRows')->will($this->returnValue(array($fakeRecords[0])));
+		$databaseMock->expects($this->once())->method('exec_SELECTgetRows')->with(
+			$this->anything(),
+			$this->equalTo('sys_files_usage_mm')
+		)->will($this->returnValue($fakeRelations));
+
+		$GLOBALS['TYPO3_DB'] = $databaseMock;
+
+		$repository = new t3lib_file_Repository();
+
+		$fileObjects = $repository->getFilesFromRelation('testField', 'tx_test', 1);
+		$this->assertType('array', $fileObjects);
+		$this->assertEquals(1, count($fileObjects));
+	}
+}
+
+?>
\ No newline at end of file
