package co.codewizards.cloudstore.core.oio.nio;
import static org.assertj.core.api.Assertions.*;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import co.codewizards.cloudstore.core.oio.File;
import co.codewizards.cloudstore.core.oio.FileFactory;
import co.codewizards.cloudstore.core.oio.IoFileFactory;
import co.codewizards.cloudstore.core.oio.nio.NioFileFactory;
@RunWith(value = Parameterized.class)
public class FileTest {
private static final Random RANDOM = new Random();
private final FileFactory fileFactory;
private File file = null;
private final File testBaseDir;
/** One map for each reflection-test, to compare the two implementations. */
private static Map<String, String> resultsFile = new ConcurrentHashMap<String, String>();
private static Map<String, String> resultsTempDir = new ConcurrentHashMap<String, String>();
private static Map<String, String> resultsTempFile = new ConcurrentHashMap<String, String>();
/** One extra map for manual added test results. */
private static Map<String, String> resultsManuallyAdded = new ConcurrentHashMap<String, String>();
public FileTest(final FileFactory fileFactory) {
this.fileFactory = fileFactory;
testBaseDir = getTestRepositoryBaseDir();
}
@AfterClass
public static void afterClass() throws IOException {
checkResultMap(resultsFile);
checkResultMap(resultsTempDir);
checkResultMap(resultsTempFile);
}
private static void checkResultMap(final Map<String, String> results) {
if (!results.isEmpty()) {
System.err.println("These results are different:");
for (final Entry<String, String> e : results.entrySet()) {
System.err.println(e.getKey() + "=" + e.getValue());
}
fail("Each result should have been removed on equality!");
}
}
@Before
public void beforeTestMethod() throws IOException {
if (file != null && file.exists()) {
final boolean delete = file.delete();
if (!delete)
throw new IllegalStateException("Could not delete file");
}
file = createFile("");
final boolean createNewFile = file.createNewFile();
if (!createNewFile) {
throw new IllegalStateException("Could not create file " + file);
}
System.out.println("beforeTestMethod: file: " + file);
}
@Test
public final void create() throws IOException {
final File f = createFile("asdf");
final boolean createNewFile = f.createNewFile();
assertThat(createNewFile).isTrue();
assertThat(f.exists()).isTrue();
}
@Test
public final void delete() throws IOException {
assertThat(file.exists()).isTrue();
final boolean delete = file.delete();
assertThat(delete).isTrue();
assertThat(file.exists()).isFalse();
}
/***** BEGIN some static value assertions, to check changes in implementation *****/
@Test
public final void canExecute_file() throws IOException {
final boolean canExecute = file.canExecute();
assertThat(canExecute).isFalse();
}
@Test
public final void canExecute_tmpFile() throws IOException {
final boolean canExecute = fileFactory.createTempFile("asdf1", "qwer").canExecute();
assertThat(canExecute).isFalse();
}
@Test
public final void canExecute_tmpDir() throws IOException {
final boolean canExecute = fileFactory.createTempDirectory("asdf2").canExecute();
assertThat(canExecute).isTrue();
}
@Test
public final void canRead() throws IOException {
final boolean canRead = file.canRead();
assertThat(canRead).isTrue();
}
@Test
public final void canRead_tmpFile() throws IOException {
final boolean canRead = fileFactory.createTempFile("asdf1", "qwer").canRead();
assertThat(canRead).isTrue();
}
@Test
public final void canRead_tmpDir() throws IOException {
final boolean canRead = fileFactory.createTempDirectory("asdf2").canRead();
assertThat(canRead).isTrue();
}
@Test
public final void canWrite() throws IOException {
final boolean canWrite = file.canWrite();
assertThat(canWrite).isTrue();
}
@Test
public final void canWrite_tmpFile() throws IOException {
final boolean canWrite = fileFactory.createTempFile("asdf1", "qwer").canWrite();
assertThat(canWrite).isTrue();
}
@Test
public final void canWrite_tmpDir() throws IOException {
final boolean canWrite = fileFactory.createTempDirectory("asdf2").canWrite();
assertThat(canWrite).isTrue();
}
@Test
public final void isAbsolute_file() throws IOException {
final boolean canWrite = file.isAbsolute();
assertThat(canWrite).isFalse();
}
@Test
public final void isAbsolute_tmpFile() throws IOException {
final boolean canWrite = fileFactory.createTempFile("asdf1", "qwer").isAbsolute();
assertThat(canWrite).isTrue();
}
@Test
public final void isAbsolute_tmpDir() throws IOException {
final boolean canWrite = fileFactory.createTempDirectory("asdf2").isAbsolute();
assertThat(canWrite).isTrue();
}
/***** END some static value assertions, to check changes in implementation *****/
/***** BEGIN rename/move/copy/ *****/
@Test
public final void rename_file() throws IOException {
final File dest = createFile("rename-dest0");
final boolean renamed = file.renameTo(dest);
assertThat(renamed).isTrue();
}
@Test
public final void rename_tmpFile() throws IOException {
final File tmpFile = fileFactory.createTempFile("asdf1", "qwer");
final File dest = createFile("rename-dest1-" + Math.abs(RANDOM.nextInt())).getAbsoluteFile();
final boolean renamed = tmpFile.renameTo(dest);
// the result is system dependent (plz see {@link java.io.File#renameTo(java.io.File)})
compareResults(resultsManuallyAdded, "rename_tmpFile", Boolean.toString(renamed));
final File tmpDestFile = fileFactory.createTempFile("asdf1-dest", "qwer");
final boolean renamedTmp = tmpFile.renameTo(tmpDestFile);
compareResults(resultsManuallyAdded, "rename_tmpFile_renamedTmp", Boolean.toString(renamedTmp));
}
@Test
public final void rename_tmpDir() throws IOException {
final File tmpDir = fileFactory.createTempDirectory("asdf2");
final File dest = createFile("rename-dest2-" + Math.abs(RANDOM.nextInt())).getAbsoluteFile();
final boolean renamed = tmpDir.renameTo(dest);
// the result is system dependent (plz see {@link java.io.File#renameTo(java.io.File)})
compareResults(resultsManuallyAdded, "rename_tmpFile", Boolean.toString(renamed));
final File tmpDestDir = fileFactory.createTempDirectory("asdf2-dest");
final boolean renamedTmp = tmpDir.renameTo(tmpDestDir);
compareResults(resultsManuallyAdded, "rename_tmpFile_renamedTmp", Boolean.toString(renamedTmp));
}
@Test
public final void move_file() throws IOException {
final String destName = "move-dest0";
final File dest = createFile(destName);
file.move(dest.getAbsoluteFile());
assertThat(dest.getAbsolutePath()).contains(destName);
assertThat(dest.exists()).isTrue();
assertThat(file.exists()).isFalse();
}
@Test
public final void move_tmpFile_differentPartitions() throws IOException {
final File tmpFile = fileFactory.createTempFile("asdf1", "qwer");
final String prefix = "move-dest1-" + Math.abs(RANDOM.nextInt());
final File dest = createFile(prefix).getAbsoluteFile();
// move works even between partitions
tmpFile.move(dest);
assertThat(dest.exists()).isTrue();
assertThat(tmpFile.exists()).isFalse();
}
@Test
public final void move_tmpDir_samePartition() throws IOException {
final File tmpDir = fileFactory.createTempDirectory("asdf2");
final File dest = fileFactory.createTempDirectory("asdf2-dest2").getAbsoluteFile();
// move works even between partitions
try {
tmpDir.move(dest);
} catch (final Exception e) {
//ignore the exception, just check the equality of both results.
}
compareResults(resultsManuallyAdded, "move_tmpDir_samePartition_tmpDir.exists", Boolean.toString(tmpDir.exists()));
compareResults(resultsManuallyAdded, "move_tmpDir_samePartition_tmpDir.listFiles", getListFilesCount(tmpDir));
compareResults(resultsManuallyAdded, "move_tmpDir_samePartition_dest.exists", Boolean.toString(dest.exists()));
compareResults(resultsManuallyAdded, "move_tmpDir_samePartition_dest.listFiles", getListFilesCount(dest));
}
@Test
public final void move_tmpDir_recursive_differentPartitions() throws IOException {
//source is in /tmp
final File tmpDir = fileFactory.createTempDirectory("asdf3");
final File childFile = fileFactory.createFile(tmpDir, "childFile");
final boolean createNewFile = childFile.createNewFile();
final File childDir = fileFactory.createFile(tmpDir, "childDir");
final boolean mkdir = childDir.mkdir();
if (!createNewFile || !mkdir)
throw new IllegalStateException("Test setup failed");
// destination is in target-folder
final String prefix = "move-dest2-" + Math.abs(RANDOM.nextInt());
final File dest = createFile(prefix).getAbsoluteFile();
try {
// result of move depends on partitioning of the tmp-folder.
tmpDir.move(dest);
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_differentPartitions_moveWorks", Boolean.TRUE.toString());
} catch (final IOException e) {
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_differentPartitions_moveWorks", Boolean.FALSE.toString());
}
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_differentPartitions_destExists", Boolean.toString(dest.exists()));
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_differentPartitions_tmpDirListFilesSize", getListFilesCount(tmpDir));
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_differentPartitions_destListFilesSize", getListFilesCount(dest));
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_differentPartitions_tmpDirExists", Boolean.toString(tmpDir.exists()));
}
@Test
public final void move_tmpDir_recursive_samePartition() throws IOException {
final File tmpDir = fileFactory.createTempDirectory("asdf2");
final File childFile = fileFactory.createFile(tmpDir, "childFile");
final boolean createNewFile = childFile.createNewFile();
final File childDir = fileFactory.createFile(tmpDir, "childDir");
final boolean mkdir = childDir.mkdir();
if (!createNewFile || !mkdir)
throw new IllegalStateException("Test setup failed");
final File dest = fileFactory.createTempFile("dest-prefix", "dest-suffix", fileFactory.createTempDirectory("destination-asdf3"));
// move works even between partitions
try {
tmpDir.move(dest);
} catch (final Exception e) {
//ignore the exception, just check the equality of both results.
}
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_samePartition_tmpDir.exists", Boolean.toString(tmpDir.exists()));
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_samePartition_tmpDir.listFiles", getListFilesCount(tmpDir));
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_samePartition_dest.exists", Boolean.toString(dest.exists()));
compareResults(resultsManuallyAdded, "move_tmpDir_recursive_samePartition_dest.listFiles", getListFilesCount(dest));
}
/** Returns listFiles.length as String or appropriate describing String. */
private String getListFilesCount(final File dest) {
if (!dest.exists())
return "!exists";
final File[] listFiles = dest.listFiles();
if (listFiles == null)
return "null";
return Integer.toString(listFiles.length);
}
@Test
public final void copy_file() throws IOException {
final String destName = "copy-dest0";
final File dest = createFile(destName);
file.copyToCopyAttributes(dest.getAbsoluteFile());
assertThat(dest.getAbsolutePath()).contains(destName);
assertThat(dest.exists()).isTrue();
compareAttributes(file, dest);
}
@Test
public final void copy_tmpFile() throws IOException {
final File tmpFile = fileFactory.createTempFile("asdf1", "qwer");
assertThat(tmpFile.exists()).isTrue();
final String prefix = "copy-dest1-" + Math.abs(RANDOM.nextInt());
final File dest = createFile(prefix).getAbsoluteFile();
tmpFile.copyToCopyAttributes(dest);
assertThat(tmpFile.exists()).isTrue();
assertThat(dest.exists()).isTrue();
compareAttributes(tmpFile, dest);
}
@Test
public final void copy_tmpDir() throws IOException {
final File tmpDir = fileFactory.createTempDirectory("asdf2");
final String prefix = "copy-dest2-" + Math.abs(RANDOM.nextInt());
final File dest = createFile(prefix).getAbsoluteFile();
tmpDir.copyToCopyAttributes(dest);
assertThat(dest.exists()).isTrue();
compareAttributes(tmpDir, dest);
}
@Test
public final void copy_tmpDir_checkNonRecursive() throws IOException {
final File tmpDir = fileFactory.createTempDirectory("asdf2");
final File childFile = fileFactory.createFile(tmpDir, "childFile");
final boolean createNewFile = childFile.createNewFile();
final File childDir = fileFactory.createFile(tmpDir, "childDir");
final boolean mkdir = childDir.mkdir();
if (!createNewFile || !mkdir)
throw new IllegalStateException("Test setup failed");
final String prefix = "copy-dest2-" + Math.abs(RANDOM.nextInt());
final File dest = createFile(prefix).getAbsoluteFile();
tmpDir.copyToCopyAttributes(dest);
assertThat(dest.exists()).isTrue();
assertThat(dest.listFiles()).isEmpty();
compareAttributes(tmpDir, dest);
}
/***** END move/copy/rename *****/
/***** BEGIN Compare the two implementations: check methods with boolean return values with no arguments *****/
@Test
public final void compareBooleanReturnResults_file() throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
for (final Method method : File.class.getDeclaredMethods()) {
final File file = createFile("cf");
final Class<?> returnType = method.getReturnType();
if (!returnType.equals(Boolean.TYPE)) {
continue;
}
// check methods without parameters
final Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length > 0) {
continue;
}
final String name = method.getName();
final Boolean b = (Boolean) method.invoke(file);
compareResults(resultsFile, name, Boolean.toString(b));
}
}
@Test
public final void compareBooleanReturnResults_tempFile() throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
for (final Method method : File.class.getDeclaredMethods()) {
final File file = fileFactory.createTempFile("ctf-asdf", "ctf-qwer");
final Class<?> returnType = method.getReturnType();
if (!returnType.equals(Boolean.TYPE)) {
continue;
}
// check methods without parameters
final Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length > 0) {
continue;
}
final String name = method.getName();
final Boolean b = (Boolean) method.invoke(file);
compareResults(resultsTempFile, name, Boolean.toString(b));
}
}
@Test
public final void compareBooleanReturnResults_tempDir() throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
for (final Method method : File.class.getDeclaredMethods()) {
final File file = fileFactory.createTempDirectory("ctd");
final Class<?> returnType = method.getReturnType();
if (!returnType.equals(Boolean.TYPE)) {
continue;
}
// check methods without parameters
final Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length > 0) {
continue;
}
final String name = method.getName();
final Boolean b = (Boolean) method.invoke(file);
compareResults(resultsTempDir, name, Boolean.toString(b));
}
}
/***** END Compare the two implementations: check methods with boolean return values with no arguments *****/
@Test
public void lastModifiedNoFollow() {
final long tolerance = 1000;
long lastModified = file.lastModified();
final long currentTimeMillis = System.currentTimeMillis();
assertThat(lastModified).isBetween(currentTimeMillis - tolerance, currentTimeMillis + tolerance);
final long newLastModified = currentTimeMillis - 60 * 1000;
file.setLastModifiedNoFollow(newLastModified);
lastModified = file.lastModified();
assertThat(lastModified).isBetween(newLastModified - tolerance, newLastModified + tolerance);
}
@Test
public void relativize() throws IOException {
final File root = fileFactory.createTempDirectory("root");
final File childFileA1 = fileFactory.createFile(root, "childFileA1");
assertThat(childFileA1.mkdir()).isTrue();
final File childFileA2 = fileFactory.createFile(childFileA1, "childFileA2");
assertThat(childFileA2.createNewFile()).isTrue();
final File childFileB1 = fileFactory.createFile(root, "childFileB1");
assertThat(childFileB1.mkdir()).isTrue();
final File childFileB2 = fileFactory.createFile(childFileB1, "childFileB2");
assertThat(childFileB2.createNewFile()).isTrue();
assertThat(childFileB2.relativize(root)).isEqualTo("../..");
assertThat(childFileB1.relativize(root)).isEqualTo("..");
assertThat(childFileA2.relativize(root)).isEqualTo("../..");
assertThat(childFileA1.relativize(root)).isEqualTo("..");
assertThat(childFileB2.relativize(childFileA1)).isEqualTo("../../" + "childFileA1");
assertThat(childFileB2.relativize(childFileA2)).isEqualTo("../../" + "childFileA1" + "/" + "childFileA2");
assertThat(childFileB1.relativize(childFileA1)).isEqualTo("../" + "childFileA1");
assertThat(childFileB1.relativize(childFileA2)).isEqualTo("../" + "childFileA1" + "/" + "childFileA2");
}
private void compareAttributes(final File source, final File target) {
assertThat(source.isDirectory()).isEqualTo(target.isDirectory());
assertThat(source.isFile()).isEqualTo(target.isFile());
assertThat(source.canExecute()).isEqualTo(target.canExecute());
assertThat(source.canWrite()).isEqualTo(target.canWrite());
assertThat(source.canRead()).isEqualTo(target.canRead());
}
private void compareResults(final Map<String, String> results, final String key, final String value) {
final String earlierResult = results.get(key);
if (earlierResult == null) {
results.put(key, value);
} else {
if (earlierResult.equals(value)) {
results.remove(key);
} else {
fail("compareResults: " + key + " was '" + value + "' instead of '" + earlierResult + "';"
+ " current factory=" + fileFactory.getClass().getSimpleName());
}
}
}
/**
* Creates a file object, but does not make the according IO store/create
* operation. Appends the name of the factory to the prefix.
* <p/>
* Uses a directory in the projects target-folder.
*/
private File createFile(final String prefix) {
// System.out.println("fileFactory="
// + fileFactory.getClass().getSimpleName());
final long id = Math.abs(RANDOM.nextInt());
final File f = fileFactory.createFile(testBaseDir, prefix + "-" + id
+ "-" + fileFactory.getClass().getSimpleName());
// System.out.println("created file: " + f);
return f;
}
protected File getTestRepositoryBaseDir() {
final File dir = fileFactory.createFile(fileFactory
.createFile("target"), this.getClass().getSimpleName());
dir.mkdirs();
return dir;
}
@Parameterized.Parameters(name = "{index}:{0}:{1}")
public static Collection<Object[]> instancesToTest() {
return Arrays.asList(new Object[] { new NioFileFactory() },
new Object[] { new IoFileFactory() });
}
}