/*
* Copyright 2012-present Facebook, Inc.
*
* 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 com.facebook.buck.io;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import com.facebook.buck.testutil.integration.TemporaryPaths;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
public class MoreFilesTest {
@Rule public TemporaryPaths tmp = new TemporaryPaths();
@Test
public void testDeleteRecursively() throws IOException {
tmp.newFile(".dotfile");
tmp.newFile("somefile");
tmp.newFolder("foo");
tmp.newFile("foo/bar");
tmp.newFolder("foo/baz");
tmp.newFile("foo/baz/biz");
assertEquals("There should be files to delete.", 3, tmp.getRoot().toFile().listFiles().length);
MoreFiles.deleteRecursively(tmp.getRoot());
assertNull(tmp.getRoot().toFile().listFiles());
}
@Test
public void deleteRecursivelyIfExistsShouldNotFailOnNonExistentDir() throws IOException {
FileSystem vfs = Jimfs.newFileSystem(Configuration.unix());
Path fakeTmpDir = vfs.getPath("/tmp/fake-tmp-dir");
MoreFiles.deleteRecursivelyIfExists(fakeTmpDir.resolve("nonexistent"));
}
@Test
public void deleteRecursivelyIfExistsDeletesDirectory() throws IOException {
FileSystem vfs = Jimfs.newFileSystem(Configuration.unix());
Path fakeTmpDir = vfs.getPath("/tmp/fake-tmp-dir");
Path dirToDelete = fakeTmpDir.resolve("delete-me");
Path childDir = dirToDelete.resolve("child-dir");
Files.createDirectories(childDir);
MoreFiles.deleteRecursivelyIfExists(dirToDelete);
assertThat(Files.exists(dirToDelete), is(false));
}
@Test
public void deleteRecursivelyContentsOnlyLeavesParentDirectory() throws IOException {
FileSystem vfs = Jimfs.newFileSystem(Configuration.unix());
Path fakeTmpDir = vfs.getPath("/tmp/fake-tmp-dir");
Path dirToDelete = fakeTmpDir.resolve("delete-me");
Path childDir = dirToDelete.resolve("child-dir");
Files.createDirectories(childDir);
MoreFiles.deleteRecursivelyWithOptions(
dirToDelete, EnumSet.of(MoreFiles.DeleteRecursivelyOptions.DELETE_CONTENTS_ONLY));
assertThat(Files.exists(dirToDelete), is(true));
assertThat(Files.exists(childDir), is(false));
}
@Test
public void testWriteLinesToFile() throws IOException {
Path outputFile = tmp.newFile("output.txt");
ImmutableList<String> lines =
ImmutableList.of("The", "quick brown fox", "jumps over", "the lazy dog.");
MoreFiles.writeLinesToFile(lines, outputFile);
List<String> observedLines = Files.readAllLines(outputFile, Charsets.UTF_8);
assertEquals(lines, observedLines);
}
@Test
public void testSortFilesByAccessTime() throws IOException {
Path dir = tmp.newFolder();
Path fileW = dir.resolve("w");
Path fileX = dir.resolve("x");
Path fileY = dir.resolve("y");
Path fileZ = dir.resolve("z");
Files.write(fileW, "w".getBytes(UTF_8));
Files.write(fileX, "x".getBytes(UTF_8));
Files.write(fileY, "y".getBytes(UTF_8));
Files.write(fileZ, "z".getBytes(UTF_8));
Files.setAttribute(fileW, "lastAccessTime", FileTime.fromMillis(9000));
Files.setAttribute(fileX, "lastAccessTime", FileTime.fromMillis(0));
Files.setAttribute(fileY, "lastAccessTime", FileTime.fromMillis(1000));
Files.setAttribute(fileZ, "lastAccessTime", FileTime.fromMillis(2000));
File[] files = dir.toFile().listFiles();
MoreFiles.sortFilesByAccessTime(files);
assertEquals(
"Files short be sorted from most recently accessed to least recently accessed.",
ImmutableList.of(fileW.toFile(), fileZ.toFile(), fileY.toFile(), fileX.toFile()),
Arrays.asList(files));
}
@Test
public void testMakeExecutable() throws IOException {
Path file = tmp.newFile();
// If the file system does not support the executable permission, skip the test
assumeTrue(file.toFile().setExecutable(false));
assertFalse("File should not be executable", file.toFile().canExecute());
MoreFiles.makeExecutable(file);
assertTrue("File should be executable", file.toFile().canExecute());
assumeTrue(file.toFile().setExecutable(true));
assertTrue("File should be executable", Files.isExecutable(file));
MoreFiles.makeExecutable(file);
assertTrue("File should be executable", Files.isExecutable(file));
}
@Test
public void testMakeExecutableOnPosix() throws IOException {
assumeTrue(FileSystems.getDefault().supportedFileAttributeViews().contains("posix"));
Path file = tmp.newFile();
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("r--------"));
MoreFiles.makeExecutable(file);
assertEquals(
"Owner's execute permission should have been set",
"r-x------",
PosixFilePermissions.toString(Files.getPosixFilePermissions(file)));
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("---r-----"));
MoreFiles.makeExecutable(file);
assertEquals(
"Group's execute permission should have been set",
"---r-x---",
PosixFilePermissions.toString(Files.getPosixFilePermissions(file)));
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("------r--"));
MoreFiles.makeExecutable(file);
assertEquals(
"Others' execute permission should have been set",
"------r-x",
PosixFilePermissions.toString(Files.getPosixFilePermissions(file)));
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("r--r--r--"));
MoreFiles.makeExecutable(file);
assertEquals(
"All execute permissions should have been set",
"r-xr-xr-x",
PosixFilePermissions.toString(Files.getPosixFilePermissions(file)));
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("r-xrw-rwx"));
MoreFiles.makeExecutable(file);
assertEquals(
"Only group's execute permission should have been set",
"r-xrwxrwx",
PosixFilePermissions.toString(Files.getPosixFilePermissions(file)));
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("-w---x-wx"));
MoreFiles.makeExecutable(file);
assertEquals(
"No permissions should have been changed",
"-w---x-wx",
PosixFilePermissions.toString(Files.getPosixFilePermissions(file)));
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("---------"));
MoreFiles.makeExecutable(file);
assertEquals(
"No permissions should have been changed",
"---------",
PosixFilePermissions.toString(Files.getPosixFilePermissions(file)));
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("rwxrwxrwx"));
MoreFiles.makeExecutable(file);
assertEquals(
"No permissions should have been changed",
"rwxrwxrwx",
PosixFilePermissions.toString(Files.getPosixFilePermissions(file)));
}
@Test
public void concatenatingNoFilesReturnsFalse() throws IOException {
FileSystem vfs = Jimfs.newFileSystem(Configuration.unix());
Path outputPath = vfs.getPath("logs.txt");
boolean collected = MoreFiles.concatenateFiles(outputPath, ImmutableList.of());
assertThat(collected, is(false));
assertThat(Files.exists(outputPath), is(false));
}
@Test
public void concatenatingTwoEmptyFilesReturnsFalse() throws Exception {
FileSystem vfs = Jimfs.newFileSystem(Configuration.unix());
Path fooPath = vfs.getPath("foo.txt");
Files.write(fooPath, new byte[0]);
Path barPath = vfs.getPath("bar.txt");
Files.write(barPath, new byte[0]);
Path outputPath = vfs.getPath("logs.txt");
boolean concatenated =
MoreFiles.concatenateFiles(outputPath, ImmutableList.of(fooPath, barPath));
assertThat(concatenated, is(false));
assertThat(Files.exists(outputPath), is(false));
}
@Test
public void concatenatingTwoNonEmptyFilesReturnsTrueAndWritesConcatenatedFile() throws Exception {
FileSystem vfs = Jimfs.newFileSystem(Configuration.unix());
Path fooPath = vfs.getPath("foo.txt");
Files.write(fooPath, "hello world\n".getBytes(UTF_8));
Path barPath = vfs.getPath("bar.txt");
Files.write(barPath, "goodbye world\n".getBytes(UTF_8));
Path outputPath = vfs.getPath("logs.txt");
boolean concatenated =
MoreFiles.concatenateFiles(outputPath, ImmutableList.of(fooPath, barPath));
assertThat(concatenated, is(true));
assertThat(
Files.readAllLines(outputPath, UTF_8),
Matchers.equalTo(ImmutableList.of("hello world", "goodbye world")));
}
}