Create a tmp directory recursive and touch an empty file in that directory. Delete all that were created after - krickert/search-api GitHub Wiki

package example;

import java.io.IOException;
import java.nio.file.*;
import java.util.Objects;

public class DirectoryProcessor {

    /**
     * Processes a directory and file as follows:
     * <ol>
     *   <li>Ensures the directory path and prefix are not null.</li>
     *   <li>If the directory exists, verifies it is writable; if not, throws an exception.</li>
     *   <li>If the directory does not exist, creates it recursively; if creation fails, throws an exception.</li>
     *   <li>Writes a file named {@code prefix + "01.txt"} in that directory.</li>
     *   <li>Deletes that file and, if the directory was created by this method, deletes it along with any empty parent directories.</li>
     *   <li>Finally, ensures the directory exists and creates an empty file with the name exactly equal to {@code prefix}.</li>
     * </ol>
     *
     * @param dirPath the directory path
     * @param prefix the file prefix
     * @throws IOException if any file operation fails
     */
    public static void process(Path dirPath, String prefix) throws IOException {
        // Validate inputs
        Objects.requireNonNull(dirPath, "Directory path must not be null");
        Objects.requireNonNull(prefix, "Prefix must not be null");

        boolean created = false;
        if (Files.exists(dirPath)) {
            if (!Files.isDirectory(dirPath)) {
                throw new IllegalArgumentException("The given path is not a directory: " + dirPath);
            }
            if (!Files.isWritable(dirPath)) {
                throw new IOException("Directory is not writable: " + dirPath);
            }
        } else {
            // Attempt to create the directory recursively
            Files.createDirectories(dirPath);
            created = true;
        }

        // Write a file named "<prefix>01.txt" with sample content
        Path file01 = dirPath.resolve(prefix + "01.txt");
        Files.writeString(file01, "Sample content");

        // Delete the file
        Files.delete(file01);

        // If we created the directory, delete it and any empty parent directories
        if (created) {
            deleteRecursivelyIfEmpty(dirPath);
        }

        // Ensure the directory exists again
        if (!Files.exists(dirPath)) {
            Files.createDirectories(dirPath);
        }

        // Create an empty file with the exact name provided as prefix
        Path finalFile = dirPath.resolve(prefix);
        Files.createFile(finalFile);
    }

    /**
     * Deletes the given directory and then climbs up the parent chain, deleting
     * directories that are empty.
     *
     * @param dir the starting directory
     * @throws IOException if deletion fails
     */
    private static void deleteRecursivelyIfEmpty(Path dir) throws IOException {
        Path current = dir;
        while (current != null && Files.isDirectory(current) && isEmptyDirectory(current)) {
            Files.delete(current);
            current = current.getParent();
        }
    }

    /**
     * Checks whether the given directory is empty.
     *
     * @param dir the directory to check
     * @return true if the directory is empty; false otherwise
     * @throws IOException if an I/O error occurs
     */
    private static boolean isEmptyDirectory(Path dir) throws IOException {
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
            return !stream.iterator().hasNext();
        }
    }

    // Main method for demonstration purposes
    public static void main(String[] args) {
        try {
            Path directory = Paths.get("testDir/subDir");
            String prefix = "myFile";
            process(directory, prefix);
            System.out.println("Process completed successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Below is a complete JUnit 5 test class using AssertJ and the JUnit‑Jupiter @TempDir annotation. This test class covers the following scenarios for our directory processing code:

  1. Non‑existent directory:
    When the directory does not exist, the method creates it recursively, writes and deletes a temporary file, and finally creates an empty file using the prefix.

  2. Existing directory:
    When the directory exists, the method verifies it’s writable and creates the final empty file.

  3. Null inputs:
    The method throws a NullPointerException if the directory path or prefix is null.

  4. Invalid directory type:
    If the provided path is a file (not a directory), an IllegalArgumentException is thrown.

Below is the test code:

package example;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.assertj.core.api.Assertions.*;

class DirectoryProcessorTest {

    @Test
    void testProcessCreatesDirectoryAndFinalFileWhenDirectoryDoesNotExist(@TempDir Path tempDir) throws IOException {
        // Create a subdirectory path that does not exist
        Path nonExistentDir = tempDir.resolve("nonexistent/subdir");
        String prefix = "testPrefix";

        // Execute the process method
        DirectoryProcessor.process(nonExistentDir, prefix);

        // Verify the directory now exists
        assertThat(Files.exists(nonExistentDir)).isTrue();
        // Verify that the final file (with name equal to prefix) exists and is empty
        Path finalFile = nonExistentDir.resolve(prefix);
        assertThat(Files.exists(finalFile)).isTrue();
        assertThat(Files.size(finalFile)).isEqualTo(0);
    }

    @Test
    void testProcessWorksWhenDirectoryAlreadyExists(@TempDir Path tempDir) throws IOException {
        // Create an existing directory
        Path existingDir = tempDir.resolve("existingDir");
        Files.createDirectories(existingDir);
        String prefix = "existingPrefix";

        // Execute the process method
        DirectoryProcessor.process(existingDir, prefix);

        // Verify the directory still exists and the final file is created
        assertThat(Files.exists(existingDir)).isTrue();
        Path finalFile = existingDir.resolve(prefix);
        assertThat(Files.exists(finalFile)).isTrue();
        assertThat(Files.size(finalFile)).isEqualTo(0);
    }

    @Test
    void testProcessThrowsExceptionForNullDirectory() {
        String prefix = "prefix";
        assertThatThrownBy(() -> DirectoryProcessor.process(null, prefix))
            .isInstanceOf(NullPointerException.class)
            .hasMessageContaining("Directory path must not be null");
    }

    @Test
    void testProcessThrowsExceptionForNullPrefix(@TempDir Path tempDir) {
        Path anyDir = tempDir.resolve("anyDir");
        assertThatThrownBy(() -> DirectoryProcessor.process(anyDir, null))
            .isInstanceOf(NullPointerException.class)
            .hasMessageContaining("Prefix must not be null");
    }

    @Test
    void testProcessThrowsExceptionWhenPathIsNotDirectory(@TempDir Path tempDir) throws IOException {
        // Create a file instead of a directory
        Path filePath = tempDir.resolve("notADir.txt");
        Files.createFile(filePath);
        String prefix = "prefix";
        assertThatThrownBy(() -> DirectoryProcessor.process(filePath, prefix))
            .isInstanceOf(IllegalArgumentException.class)
            .hasMessageContaining("is not a directory");
    }
}

Explanation

  • @TempDir:
    Provides a temporary directory that is automatically cleaned up by JUnit 5.

  • AssertJ Assertions:
    We use assertThat, assertThatThrownBy, and other AssertJ methods for fluent assertions.

  • Test Scenarios:
    Each test method validates one aspect of the DirectoryProcessor.process method:

    • When the target directory doesn’t exist, the method creates it, processes the file, and creates the final empty file.
    • When the directory exists, the method leaves it intact and creates the final file.
    • Null inputs and invalid directory types throw the expected exceptions.

This test class, together with the earlier provided DirectoryProcessor implementation, should give you a good starting point for testing your file/directory handling logic using JUnit 5 and AssertJ.

⚠️ **GitHub.com Fallback** ⚠️