Jelajahi Sumber

Added FolderChildrenTests and FolderTests

* implemented some testcases
* fixed some issues
Markus Kreusch 9 tahun lalu
induk
melakukan
20e7f4a548
16 mengubah file dengan 386 tambahan dan 64 penghapusan
  1. 15 0
      main/filesystem-api/src/main/java/org/cryptomator/filesystem/Deleter.java
  2. 6 0
      main/filesystem-api/src/main/java/org/cryptomator/filesystem/File.java
  3. 1 1
      main/filesystem-api/src/main/java/org/cryptomator/filesystem/Folder.java
  4. 1 0
      main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFileSystem.java
  5. 7 2
      main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java
  6. 2 6
      main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoFileSystemTest.java
  7. 11 4
      main/filesystem-inmemory/src/main/java/org/cryptomator/filesystem/inmem/InMemoryFolder.java
  8. 1 1
      main/filesystem-inmemory/src/main/java/org/cryptomator/filesystem/inmem/InMemoryNode.java
  9. 15 10
      main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FileSystemFactories.java
  10. 21 22
      main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FileSystemTests.java
  11. 133 0
      main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FolderChildrenTests.java
  12. 52 0
      main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FolderTests.java
  13. 112 0
      main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/SubfolderFactories.java
  14. 2 0
      main/filesystem-nameshortening/src/test/java/org/cryptomator/filesystem/shortening/ShorteningFileSystemTest.java
  15. 2 10
      main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/NioFolder.java
  16. 5 8
      main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/NioFolderTest.java

+ 15 - 0
main/filesystem-api/src/main/java/org/cryptomator/filesystem/Deleter.java

@@ -0,0 +1,15 @@
+package org.cryptomator.filesystem;
+
+public class Deleter {
+
+	/**
+	 * Deletes all and only the content of a given {@link Folder} but <b>not</b> the folder itself.
+	 */
+	public static void deleteContent(Folder folder) {
+		if (folder.exists()) {
+			folder.folders().forEach(Folder::delete);
+			folder.files().forEach(File::delete);
+		}
+	}
+
+}

+ 6 - 0
main/filesystem-api/src/main/java/org/cryptomator/filesystem/File.java

@@ -75,4 +75,10 @@ public interface File extends Node, Comparable<File> {
 		Mover.move(this, destination);
 	}
 
+	default void delete() {
+		try (WritableFile writableFile = openWritable()) {
+			writableFile.delete();
+		}
+	}
+
 }

+ 1 - 1
main/filesystem-api/src/main/java/org/cryptomator/filesystem/Folder.java

@@ -31,7 +31,7 @@ public interface Folder extends Node {
 	 * @return the created {@code Stream}
 	 * @throws UncheckedIOException
 	 *             if an {@link IOException} occurs while initializing the
-	 *             stream
+	 *             stream or the {@code Folder} does not exist
 	 */
 	Stream<? extends Node> children() throws UncheckedIOException;
 

+ 1 - 0
main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFileSystem.java

@@ -44,6 +44,7 @@ public class CryptoFileSystem extends CryptoFolder implements FileSystem {
 		assert masterkeyFile.exists() : "A CryptoFileSystem can not exist without a masterkey file.";
 		final File backupFile = physicalRoot.file(MASTERKEY_BACKUP_FILENAME);
 		masterkeyFile.copyTo(backupFile);
+		create();
 	}
 
 	private static boolean decryptMasterKeyFile(Cryptor cryptor, File masterkeyFile, CharSequence passphrase) {

+ 7 - 2
main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java

@@ -25,6 +25,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.cryptomator.common.WeakValuedCache;
 import org.cryptomator.crypto.engine.Cryptor;
+import org.cryptomator.filesystem.Deleter;
 import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.Folder;
 import org.cryptomator.filesystem.Node;
@@ -159,8 +160,12 @@ class CryptoFolder extends CryptoNode implements Folder {
 
 	@Override
 	public void delete() {
-		// TODO Auto-generated method stub
-
+		if (!exists()) {
+			return;
+		}
+		Deleter.deleteContent(this);
+		physicalFile().delete();
+		physicalFolder().delete();
 	}
 
 	@Override

+ 2 - 6
main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoFileSystemTest.java

@@ -50,13 +50,9 @@ public class CryptoFileSystemTest {
 		Assert.assertTrue(masterkeyBkupFile.exists());
 		fs.create();
 		Assert.assertTrue(physicalDataRoot.exists());
-		Assert.assertEquals(3, physicalFs.children().count()); // d +
-																// masterkey.cryptomator
-																// +
-																// masterkey.cryptomator.bkup
+		Assert.assertEquals(3, physicalFs.children().count()); // d + masterkey.cryptomator + masterkey.cryptomator.bkup
 		Assert.assertEquals(1, physicalDataRoot.files().count()); // ROOT file
-		Assert.assertEquals(1, physicalDataRoot.folders().count()); // ROOT
-																	// directory
+		Assert.assertEquals(1, physicalDataRoot.folders().count()); // ROOT directory
 	}
 
 	@Test(timeout = 1000)

+ 11 - 4
main/filesystem-inmemory/src/main/java/org/cryptomator/filesystem/inmem/InMemoryFolder.java

@@ -8,6 +8,9 @@
  *******************************************************************************/
 package org.cryptomator.filesystem.inmem;
 
+import static java.lang.String.format;
+
+import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.time.Instant;
 import java.util.Iterator;
@@ -32,7 +35,11 @@ class InMemoryFolder extends InMemoryNode implements Folder {
 
 	@Override
 	public Stream<InMemoryNode> children() {
-		return existingChildren.values().stream();
+		if (exists()) {
+			return existingChildren.values().stream();
+		} else {
+			throw new UncheckedIOException(new IOException(format("Folder %s does not exist", this)));
+		}
 	}
 
 	@Override
@@ -76,11 +83,11 @@ class InMemoryFolder extends InMemoryNode implements Folder {
 		if (target.exists()) {
 			target.delete();
 		}
-		assert!target.exists();
+		assert !target.exists();
 		target.create();
 		this.copyTo(target);
 		this.delete();
-		assert!this.exists();
+		assert !this.exists();
 	}
 
 	@Override
@@ -102,7 +109,7 @@ class InMemoryFolder extends InMemoryNode implements Folder {
 				subFolder.delete();
 			}
 		}
-		assert!this.exists();
+		assert !this.exists();
 	}
 
 	@Override

+ 1 - 1
main/filesystem-inmemory/src/main/java/org/cryptomator/filesystem/inmem/InMemoryNode.java

@@ -41,7 +41,7 @@ class InMemoryNode implements Node {
 
 	@Override
 	public boolean exists() {
-		return parent.children().anyMatch(node -> node.equals(this));
+		return parent.exists() && parent.children().anyMatch(node -> node.equals(this));
 	}
 
 	@Override

+ 15 - 10
main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FileSystemFactories.java

@@ -14,11 +14,10 @@ import org.cryptomator.crypto.engine.impl.CryptorImpl;
 import org.cryptomator.filesystem.FileSystem;
 import org.cryptomator.filesystem.crypto.CryptoFileSystem;
 import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
+import org.cryptomator.filesystem.invariants.FileSystemFactories.FileSystemFactory;
 import org.cryptomator.filesystem.nio.NioFileSystem;
 
-import com.google.common.base.Supplier;
-
-class FileSystemFactories implements Iterable<Supplier<FileSystem>> {
+class FileSystemFactories implements Iterable<FileSystemFactory> {
 
 	private static final SecureRandom RANDOM_MOCK = new SecureRandom() {
 		@Override
@@ -27,13 +26,13 @@ class FileSystemFactories implements Iterable<Supplier<FileSystem>> {
 		}
 	};
 
-	private final List<Supplier<FileSystem>> factories = new ArrayList<>();
+	private final List<FileSystemFactory> factories = new ArrayList<>();
 
 	public FileSystemFactories() {
 		add("NioFileSystem", this::createNioFileSystem);
 		add("InMemoryFileSystem", this::createInMemoryFileSystem);
+		add("CryptoFileSystem(NioFileSystem)", this::createCryptoFileSystemNio);
 		add("CryptoFileSystem(InMemoryFileSystem)", this::createCryptoFileSystemInMemory);
-		// FIXME fails add("CryptoFileSystem(NioFileSystem)", this::createCryptoFileSystemNio);
 	}
 
 	private FileSystem createNioFileSystem() {
@@ -56,11 +55,11 @@ class FileSystemFactories implements Iterable<Supplier<FileSystem>> {
 		return new CryptoFileSystem(createNioFileSystem(), new CryptorImpl(RANDOM_MOCK), "aPassphrase");
 	}
 
-	private void add(String name, Supplier<FileSystem> fileSystemSupplier) {
-		factories.add(new Supplier<FileSystem>() {
+	private void add(String name, FileSystemFactory factory) {
+		factories.add(new FileSystemFactory() {
 			@Override
-			public FileSystem get() {
-				return fileSystemSupplier.get();
+			public FileSystem create() {
+				return factory.create();
 			}
 
 			@Override
@@ -71,8 +70,14 @@ class FileSystemFactories implements Iterable<Supplier<FileSystem>> {
 	}
 
 	@Override
-	public Iterator<Supplier<FileSystem>> iterator() {
+	public Iterator<FileSystemFactory> iterator() {
 		return factories.iterator();
 	}
 
+	public interface FileSystemFactory {
+
+		FileSystem create();
+
+	}
+
 }

+ 21 - 22
main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FileSystemTests.java

@@ -6,6 +6,7 @@ import static org.junit.Assert.assertThat;
 import java.util.Optional;
 
 import org.cryptomator.filesystem.FileSystem;
+import org.cryptomator.filesystem.invariants.FileSystemFactories.FileSystemFactory;
 import org.junit.Rule;
 import org.junit.experimental.theories.DataPoints;
 import org.junit.experimental.theories.Theories;
@@ -13,77 +14,75 @@ import org.junit.experimental.theories.Theory;
 import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 
-import com.google.common.base.Supplier;
-
 @RunWith(Theories.class)
 public class FileSystemTests {
 
 	@DataPoints
-	public static final Iterable<Supplier<FileSystem>> FILE_SYSTEM_FACTORIES = new FileSystemFactories();
+	public static final Iterable<FileSystemFactory> FILE_SYSTEM_FACTORIES = new FileSystemFactories();
 
 	@Rule
 	public final ExpectedException thrown = ExpectedException.none();
 
 	@Theory
-	public void testFileSystemHasNoParent(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
+	public void testFileSystemHasNoParent(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
 
 		assertThat(inTest.parent(), is(Optional.empty()));
 	}
 
 	@Theory
-	public void testFileSystemExists(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
+	public void testFileSystemExists(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
 
 		assertThat(inTest.exists(), is(true));
 	}
 
 	@Theory
-	public void testFileSystemHasNoChildren(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
+	public void testFileSystemHasNoChildren(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
 
 		assertThat(inTest.children().count(), is(0L));
 	}
 
 	@Theory
-	public void testFileSystemHasNoFiles(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
+	public void testFileSystemHasNoFiles(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
 
 		assertThat(inTest.files().count(), is(0L));
 	}
 
 	@Theory
-	public void testFileSystemHasNoFolders(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
+	public void testFileSystemHasNoFolders(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
 
 		assertThat(inTest.folders().count(), is(0L));
 	}
 
 	@Theory
-	public void testFileSystemsFileSystemIsItself(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
+	public void testFileSystemsFileSystemIsItself(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
 
 		assertThat(inTest.fileSystem(), is(inTest));
 	}
 
 	@Theory
-	public void testFileSystemBelongsToSameFilesystemWhenCheckingItself(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
+	public void testFileSystemBelongsToSameFilesystemWhenCheckingItself(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
 
 		assertThat(inTest.belongsToSameFilesystem(inTest), is(true));
 	}
 
 	@Theory
-	public void testFileSystemDoesNotBelongToSameFilesystemWhenCheckingOtherInstance(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
-		FileSystem otherInstance = factory.get();
+	public void testFileSystemDoesNotBelongToSameFilesystemWhenCheckingOtherInstance(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
+		FileSystem otherInstance = factory.create();
 
 		assertThat(inTest.belongsToSameFilesystem(otherInstance), is(false));
 	}
 
 	@Theory
-	public void testFileSystemIsNoAncestorOfItself(Supplier<FileSystem> factory) {
-		FileSystem inTest = factory.get();
+	public void testFileSystemIsNoAncestorOfItself(FileSystemFactory factory) {
+		FileSystem inTest = factory.create();
 
 		assertThat(inTest.isAncestorOf(inTest), is(false));
 	}

+ 133 - 0
main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FolderChildrenTests.java

@@ -0,0 +1,133 @@
+package org.cryptomator.filesystem.invariants;
+
+import static java.util.stream.Collectors.toList;
+import static org.cryptomator.common.test.matcher.ContainsMatcher.containsInAnyOrder;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.empty;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+
+import java.io.UncheckedIOException;
+
+import org.cryptomator.filesystem.FileSystem;
+import org.cryptomator.filesystem.Folder;
+import org.cryptomator.filesystem.invariants.FileSystemFactories.FileSystemFactory;
+import org.cryptomator.filesystem.invariants.SubfolderFactories.SubfolderFactory;
+import org.junit.Rule;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class FolderChildrenTests {
+
+	private static final String FOLDER_NAME = "folderName";
+
+	@DataPoints
+	public static final Iterable<FileSystemFactory> FILE_SYSTEM_FACTORIES = new FileSystemFactories();
+
+	@DataPoints
+	public static final Iterable<SubfolderFactory> SUBFOLDER_FACTORIES = new SubfolderFactories();
+
+	@Rule
+	public final ExpectedException thrown = ExpectedException.none();
+
+	@Theory
+	public void testChildrenThrowsExceptionIfFolderDoesNotExist(FileSystemFactory fileSystemFactory, SubfolderFactory subfolderFactory) {
+		assumeThat(subfolderFactory.createsExistingFolder(), is(false));
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder nonExistingFolder = subfolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+
+		thrown.expect(UncheckedIOException.class);
+
+		nonExistingFolder.children();
+	}
+
+	@Theory
+	public void testFilesThrowsExceptionIfFolderDoesNotExist(FileSystemFactory fileSystemFactory, SubfolderFactory subfolderFactory) {
+		assumeThat(subfolderFactory.createsExistingFolder(), is(false));
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder nonExistingFolder = subfolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+
+		thrown.expect(UncheckedIOException.class);
+
+		nonExistingFolder.files();
+	}
+
+	@Theory
+	public void testFoldersThrowsExceptionIfFolderDoesNotExist(FileSystemFactory fileSystemFactory, SubfolderFactory subfolderFactory) {
+		assumeThat(subfolderFactory.createsExistingFolder(), is(false));
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder nonExistingFolder = subfolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+
+		thrown.expect(UncheckedIOException.class);
+
+		nonExistingFolder.folders();
+	}
+
+	@Theory
+	public void testChildrenIsEmptyForEmptyFolder(FileSystemFactory fileSystemFactory, SubfolderFactory subfolderFactory) {
+		assumeThat(subfolderFactory.createsExistingFolder(), is(true));
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder existingFolder = subfolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+
+		assertThat(existingFolder.children().count(), is(0L));
+	}
+
+	@Theory
+	public void testFilesIsEmptyForEmptyFolder(FileSystemFactory fileSystemFactory, SubfolderFactory subfolderFactory) {
+		assumeThat(subfolderFactory.createsExistingFolder(), is(true));
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder existingFolder = subfolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+
+		assertThat(existingFolder.files().count(), is(0L));
+	}
+
+	@Theory
+	public void testFoldersIsEmptyForEmptyFolder(FileSystemFactory fileSystemFactory, SubfolderFactory subfolderFactory) {
+		assumeThat(subfolderFactory.createsExistingFolder(), is(true));
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder existingFolder = subfolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+
+		assertThat(existingFolder.folders().count(), is(0L));
+	}
+
+	@Theory
+	public void testChildrenContainsCreatedChildFolder(FileSystemFactory fileSystemFactory, SubfolderFactory existingFolderFactory, SubfolderFactory childExistingFolderFactory) {
+		assumeThat(existingFolderFactory.createsExistingFolder(), is(true));
+		assumeThat(childExistingFolderFactory.createsExistingFolder(), is(true));
+
+		String childName = "childFolderName";
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder existingFolder = existingFolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+		Folder childFolder = childExistingFolderFactory.subfolderWithName(existingFolder, childName);
+
+		assertThat(existingFolder.children().collect(toList()), containsInAnyOrder(equalTo(childFolder)));
+	}
+
+	@Theory
+	public void testChildrenDoesNotContainsCreatedAndDeletedChildFolder(FileSystemFactory fileSystemFactory, SubfolderFactory existingFolderFactory, SubfolderFactory childExistingFolderFactory) {
+		assumeThat(existingFolderFactory.createsExistingFolder(), is(true));
+		assumeThat(childExistingFolderFactory.createsExistingFolder(), is(true));
+
+		String childName = "childFolderName";
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder existingFolder = existingFolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+		Folder childFolder = childExistingFolderFactory.subfolderWithName(existingFolder, childName);
+		childFolder.delete();
+
+		assertThat(existingFolder.children().collect(toList()), is(empty()));
+	}
+
+}

+ 52 - 0
main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FolderTests.java

@@ -0,0 +1,52 @@
+package org.cryptomator.filesystem.invariants;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+
+import org.cryptomator.filesystem.FileSystem;
+import org.cryptomator.filesystem.Folder;
+import org.cryptomator.filesystem.invariants.FileSystemFactories.FileSystemFactory;
+import org.cryptomator.filesystem.invariants.SubfolderFactories.SubfolderFactory;
+import org.junit.Rule;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class FolderTests {
+
+	private static final String FOLDER_NAME = "folderName";
+
+	@DataPoints
+	public static final Iterable<FileSystemFactory> FILE_SYSTEM_FACTORIES = new FileSystemFactories();
+
+	@DataPoints
+	public static final Iterable<SubfolderFactory> SUBFOLDER_FACTORIES = new SubfolderFactories();
+
+	@Rule
+	public final ExpectedException thrown = ExpectedException.none();
+
+	@Theory
+	public void testExistingFolderExists(FileSystemFactory fileSystemFactory, SubfolderFactory subfolderFactory) {
+		assumeThat(subfolderFactory.createsExistingFolder(), is(true));
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder existingFolder = subfolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+
+		assertThat(existingFolder.exists(), is(true));
+	}
+
+	@Theory
+	public void testNonExistingFolderDoesntExists(FileSystemFactory fileSystemFactory, SubfolderFactory subfolderFactory) {
+		assumeThat(subfolderFactory.createsExistingFolder(), is(false));
+
+		FileSystem fileSystem = fileSystemFactory.create();
+		Folder existingFolder = subfolderFactory.subfolderWithName(fileSystem, FOLDER_NAME);
+
+		assertThat(existingFolder.exists(), is(false));
+	}
+
+}

+ 112 - 0
main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/SubfolderFactories.java

@@ -0,0 +1,112 @@
+package org.cryptomator.filesystem.invariants;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.cryptomator.filesystem.Folder;
+import org.cryptomator.filesystem.invariants.SubfolderFactories.SubfolderFactory;
+
+class SubfolderFactories implements Iterable<SubfolderFactory> {
+
+	private final List<SubfolderFactory> factories = new ArrayList<>();
+
+	public SubfolderFactories() {
+		addNonExisting("invoke folder", this::invokeFolder);
+		addNonExisting("create and delete", this::createAndDeleteFolder);
+		addNonExisting("delete by moving", this::moveFolderAway);
+
+		addExisting("invoke folder and create", this::invokeFolderAndCreate);
+		addExisting("create by moving", this::createByMoving);
+	}
+
+	private Folder invokeFolder(Folder parent, String name) {
+		return parent.folder(name);
+	}
+
+	private Folder invokeFolderAndCreate(Folder parent, String name) {
+		Folder result = parent.folder(name);
+		result.create();
+		return result;
+	}
+
+	private Folder createAndDeleteFolder(Folder parent, String name) {
+		Folder result = parent.folder(name);
+		result.create();
+		result.delete();
+		return result;
+	}
+
+	private Folder moveFolderAway(Folder parent, String name) {
+		Folder result = parent.folder(name);
+		result.create();
+		Folder target = parent.folder("subfolderFactoryMoveFolderAway");
+		result.moveTo(target);
+		target.delete();
+		return result;
+	}
+
+	private Folder createByMoving(Folder parent, String name) {
+		Folder temporary = parent.folder("subfolderFactoryCreateByMoving");
+		temporary.create();
+		Folder target = parent.folder(name);
+		temporary.moveTo(target);
+		return target;
+	}
+
+	private void addExisting(String name, ExistingSubfolderFactory factory) {
+		factories.add(new ExistingSubfolderFactory() {
+			@Override
+			public Folder subfolderWithName(Folder parent, String name) {
+				return factory.subfolderWithName(parent, name);
+			}
+
+			@Override
+			public String toString() {
+				return name;
+			}
+		});
+	}
+
+	private void addNonExisting(String name, NonExistingSubfolderFactory factory) {
+		factories.add(new NonExistingSubfolderFactory() {
+			@Override
+			public Folder subfolderWithName(Folder parent, String name) {
+				return factory.subfolderWithName(parent, name);
+			}
+
+			@Override
+			public String toString() {
+				return name;
+			}
+		});
+	}
+
+	public interface SubfolderFactory {
+
+		Folder subfolderWithName(Folder parent, String name);
+
+		boolean createsExistingFolder();
+
+	}
+
+	public interface ExistingSubfolderFactory extends SubfolderFactory {
+		@Override
+		default boolean createsExistingFolder() {
+			return true;
+		}
+	}
+
+	public interface NonExistingSubfolderFactory extends SubfolderFactory {
+		@Override
+		default boolean createsExistingFolder() {
+			return false;
+		}
+	}
+
+	@Override
+	public Iterator<SubfolderFactory> iterator() {
+		return factories.iterator();
+	}
+
+}

+ 2 - 0
main/filesystem-nameshortening/src/test/java/org/cryptomator/filesystem/shortening/ShorteningFileSystemTest.java

@@ -41,6 +41,7 @@ public class ShorteningFileSystemTest {
 	public void testMoveLongFolders() {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
 		final Folder metadataRoot = underlyingFs.folder("m");
+		metadataRoot.create();
 		final FileSystem fs = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
 
 		final Folder shortNamedFolder = fs.folder("test");
@@ -56,6 +57,7 @@ public class ShorteningFileSystemTest {
 	public void testMoveLongFiles() throws UncheckedIOException, TimeoutException {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
 		final Folder metadataRoot = underlyingFs.folder("m");
+		metadataRoot.create();
 		final FileSystem fs = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
 
 		final File shortNamedFolder = fs.file("test");

+ 2 - 10
main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/NioFolder.java

@@ -11,10 +11,10 @@ import java.util.stream.Stream;
 
 import org.cryptomator.common.WeakValuedCache;
 import org.cryptomator.common.streams.AutoClosingStream;
+import org.cryptomator.filesystem.Deleter;
 import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.Folder;
 import org.cryptomator.filesystem.Node;
-import org.cryptomator.filesystem.WritableFile;
 
 class NioFolder extends NioNode implements Folder {
 
@@ -131,9 +131,7 @@ class NioFolder extends NioNode implements Folder {
 		if (!exists()) {
 			return;
 		}
-
-		folders().forEach(Folder::delete);
-		files().forEach(NioFolder::deleteFile);
+		Deleter.deleteContent(this);
 		try {
 			nioAccess.delete(path);
 		} catch (IOException e) {
@@ -141,10 +139,4 @@ class NioFolder extends NioNode implements Folder {
 		}
 	}
 
-	private static final void deleteFile(File file) {
-		try (WritableFile writableFile = file.openWritable()) {
-			writableFile.delete();
-		}
-	}
-
 }

+ 5 - 8
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/NioFolderTest.java

@@ -12,6 +12,7 @@ import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -492,7 +493,7 @@ public class NioFolderTest {
 			inTest.delete();
 
 			InOrder inOrder = inOrder(nioAccess, folderChild);
-			inOrder.verify(nioAccess).isDirectory(path);
+			inOrder.verify(nioAccess, times(2)).isDirectory(path);
 			inOrder.verify(nioAccess).list(path);
 			inOrder.verify(folderChild).delete();
 			inOrder.verify(nioAccess).list(path);
@@ -503,8 +504,6 @@ public class NioFolderTest {
 		public void testDeleteInvokesDeleteOnChildFileAndNioAccessDeleteAfterwards() throws IOException {
 			Path fileChildPath = mock(Path.class);
 			NioFile fileChild = mock(NioFile.class);
-			WritableFile writableFile = mock(WritableFile.class);
-			when(fileChild.openWritable()).thenReturn(writableFile);
 			when(nioAccess.isDirectory(path)).thenReturn(true);
 			when(nioAccess.isDirectory(fileChildPath)).thenReturn(false);
 			when(instanceFactory.nioFile(Optional.of(inTest), fileChildPath, nioAccess)).thenReturn(fileChild);
@@ -512,13 +511,11 @@ public class NioFolderTest {
 
 			inTest.delete();
 
-			InOrder inOrder = inOrder(nioAccess, fileChild, writableFile);
-			inOrder.verify(nioAccess).isDirectory(path);
+			InOrder inOrder = inOrder(nioAccess, fileChild);
+			inOrder.verify(nioAccess, times(2)).isDirectory(path);
 			inOrder.verify(nioAccess).list(path);
 			inOrder.verify(nioAccess).list(path);
-			inOrder.verify(fileChild).openWritable();
-			inOrder.verify(writableFile).delete();
-			inOrder.verify(writableFile).close();
+			inOrder.verify(fileChild).delete();
 			inOrder.verify(nioAccess).delete(path);
 		}