/* * Copyright 2017 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.launcher.util; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.spf4j.log.Level; import org.spf4j.test.log.TestLoggers; import org.spf4j.test.matchers.LogMatchers; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.PosixFilePermissions; import java.util.Collections; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.startsWith; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class TestFileUtils { private static final String FILE_NAME = "File"; private static final String DIRECTORY_NAME = "lorem"; private static final String SAMPLE_TEXT = "Lorem Ipsum"; @TempDir public Path tempFolder; @Test public void testCannotCreateDirectory() { final Path directory = tempFolder.resolve(DIRECTORY_NAME); var tempFolderFile = tempFolder.toFile(); assert tempFolderFile.setWritable(false); try { assertThrows(IOException.class, () -> FileUtils.ensureWritableDir(directory) ); } finally { assert tempFolderFile.setWritable(true); // so @TempDir can tidy up } } @Test public void testNotDirectory() throws IOException { var notDirectory = tempFolder.resolve("notADirectory"); Files.createFile(notDirectory); var exc = assertThrows(IOException.class, () -> FileUtils.ensureWritableDir(notDirectory) ); assertThat(exc.getMessage(), startsWith("Not a directory")); } @Test public void testNoPerms() throws IOException { var directory = tempFolder.resolve(DIRECTORY_NAME); Files.createDirectory(directory, PosixFilePermissions.asFileAttribute(Collections.emptySet())); try { var exc = assertThrows(IOException.class, () -> FileUtils.ensureWritableDir(directory) ); assertThat(exc.getMessage(), startsWith("Missing read or write permissions")); } finally { // oh no, @TempDir doesn't know how to delete this! make it writable again. var d = directory.toFile(); assert d.setReadable(true); assert d.setWritable(true); } } @Test public void testDeleteFile() throws IOException { Path directory = tempFolder; Path file = directory.resolve(FILE_NAME); Files.createFile(file); assertTrue(Files.exists(file)); FileUtils.delete(directory); assertFalse(Files.exists(file)); assertFalse(Files.exists(directory)); } @Test public void testDeleteDirectoryContent() throws IOException { Path directory = tempFolder; Path file = directory.resolve(FILE_NAME); Files.createFile(file); assertTrue(Files.exists(file)); FileUtils.deleteDirectoryContent(directory); assertFalse(Files.exists(file)); assertTrue(Files.exists(directory)); } /** * Test that `FileUtils.ensureEmptyDir` creates and empty directory if it does not exist. */ @Test public void testEnsureEmptyDirCreation() throws IOException { Path context = tempFolder; // setup Path dirToTest = context.resolve(DIRECTORY_NAME); assertFalse(Files.exists(dirToTest)); // test FileUtils.ensureEmptyDir(dirToTest); assertTrue(Files.exists(dirToTest)); assertTrue(Files.isDirectory(dirToTest)); assertEquals(0, Files.list(dirToTest).count()); } /** * Test that `FileUtils.ensureEmptyDir` drains (delete all content) if the directory exists. */ @Test public void testEnsureEmptyDirDrain() throws IOException { Path context = tempFolder; // setup Path dirToTest = context.resolve(DIRECTORY_NAME); Path file = dirToTest.resolve(FILE_NAME); Files.createDirectory(dirToTest); Files.createFile(file); // assure directory exists and is not empty assertTrue(Files.exists(dirToTest)); assertTrue(Files.exists(file)); // test FileUtils.ensureEmptyDir(dirToTest); assertTrue(Files.exists(dirToTest)); assertTrue(Files.isDirectory(dirToTest)); assertEquals(0, Files.list(dirToTest).count()); } @Test public void testCopyFolder(@TempDir Path source, @TempDir Path destination) throws IOException { Path fileInSource = source.resolve(FILE_NAME); Files.createFile(fileInSource); assertTrue(Files.exists(fileInSource)); List<String> text = Collections.singletonList(SAMPLE_TEXT); Files.write(fileInSource, text, StandardCharsets.UTF_8); Path fileInDestination = destination.resolve(FILE_NAME); FileUtils.copyFolder(source, destination); assertTrue(Files.exists(fileInDestination)); assertArrayEquals(Files.readAllBytes(fileInSource), Files.readAllBytes(fileInDestination)); } @Test public void testDeleteFileSilently() throws IOException { Path tempFile = tempFolder.resolve(FILE_NAME); Files.createFile(tempFile); assertTrue(Files.exists(tempFile)); FileUtils.deleteFileSilently(tempFile); assertTrue(Files.notExists(tempFile)); } @Test public void testDeleteFileSilentlyWithEmptyDirectory() { assertTrue(Files.exists(tempFolder)); FileUtils.deleteFileSilently(tempFolder); assertTrue(Files.notExists(tempFolder)); } @Test public void testDeleteFileSilentlyWithNonEmptyDirectory() throws IOException { Path tempFile = tempFolder.resolve(FILE_NAME); Files.createFile(tempFile); assertTrue(Files.exists(tempFile)); // DirectoryNotEmptyException will be logged but not thrown var loggedException = TestLoggers.sys().expect("", Level.ERROR, LogMatchers.hasMatchingExtraThrowable(Matchers.instanceOf(DirectoryNotEmptyException.class)) ); FileUtils.deleteFileSilently(tempFolder); assertTrue(Files.exists(tempFolder)); loggedException.assertObservation(); } @Test public void testExtract(@TempDir Path zipDir, @TempDir Path outputDir) throws IOException { final String fileInRoot = "fileInRoot"; final String fileInFolder = "folder/fileInFolder"; final String file1Contents = SAMPLE_TEXT + "1"; final String file2Contents = SAMPLE_TEXT + "2"; /* An archive with this structure is created: * <zip root> * +-- fileInRoot * +-- folder * | +-- fileInFolder */ Path zipFile = zipDir.resolve(FILE_NAME + ".zip"); try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(zipFile))) { zipOutputStream.putNextEntry(new ZipEntry(fileInRoot)); zipOutputStream.write(file1Contents.getBytes()); zipOutputStream.closeEntry(); zipOutputStream.putNextEntry(new ZipEntry(fileInFolder)); zipOutputStream.write(file2Contents.getBytes()); zipOutputStream.closeEntry(); } FileUtils.extractZipTo(zipFile, outputDir); Path extractedFileInRoot = outputDir.resolve(fileInRoot); Path extractedFileInFolder = outputDir.resolve(fileInFolder); assertTrue(Files.exists(extractedFileInRoot)); assertTrue(Files.exists(extractedFileInFolder)); assertEquals(file1Contents, Files.readAllLines(extractedFileInRoot).get(0)); assertEquals(file2Contents, Files.readAllLines(extractedFileInFolder).get(0)); } }