Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Matcher for recursively comparing directories?

I'm writing unit tests for IM- and exporting files. I need to test the resulting directory recursively byte by byte. I implemented a routine for flat directories by myself and know how to do this recursively also. But I don't want to reinvent the wheel.

So is there something like the following examples?

Matchers.matches(Path actual, equalsRecursive(Path value));

or

FileAssertions.equalsRecursive(Path actual, Path value);
like image 634
Andreas Avatar asked Aug 04 '15 08:08

Andreas


People also ask

How do I compare two directories in differences?

Click on the “Select Files or Folders” tab in the far left, to start a new comparison. Each comparison you run opens in a new tab. To start a new comparison, click on the “Select Files or Folders” tab in the far left, change the targets and click “Compare” again.

Can diff compare directories?

Normally diff reports subdirectories common to both directories without comparing subdirectories' files, but if you use the -r or --recursive option, it compares every corresponding pair of files in the directory trees, as many levels deep as they go.

How do you check if two directories are the same Linux?

Normally, to compare two files in Linux, we use the diff – a simple and original Unix command-line tool that shows you the difference between two computer files; compares files line by line and it is easy to use, comes with pre-installed on most if not all Linux distributions.


2 Answers

I am not aware of such a Matcher. So, IMO you will have to do it yourself. 2 options I could think of are as follows:

  1. Use Apache Commons FileUtils in order to

    1.1. make sure that each and every file/sub-directory(recursive call goes here) exists inside the directory currently being tested. For each subdir get a collection of files, iterate and use directoryContains method for the corresponding subdir.

    1.2 make sure that the content of 2 corresponding files are equal using contentEquals method. I am not sure what happens if you pass 2 directories to this method.

  2. Second option: if you run your tests on Linux box you can run a Linux command from Java using Runtime.exec()docs are here. The single command you need to run is diff -r <directory1> <directory2>

Good luck!

like image 193
aviad Avatar answered Oct 21 '22 06:10

aviad


Didn't found anything. So i programmed it by myself. It's not very sophisticated and slow for large files, but seems to work.

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;

import org.junit.Assert;

/**
 * Assertion for recursively testing directories.
 * 
 * @author andreas
 */
public class AssertFile {

private AssertFile() {
    throw new RuntimeException("This class should not be instantiated");
}

/**
 * Asserts that two directories are recursively equal. If they are not, an {@link AssertionError} is thrown with the
 * given message.<br/>
 * There will be a binary comparison of all files under expected with all files under actual. File attributes will
 * not be considered.<br/>
 * Missing or additional files are considered an error.<br/>
 * 
 * @param expected
 *            Path expected directory
 * @param actual
 *            Path actual directory
 */
public static final void assertPathEqualsRecursively(final Path expected, final Path actual) {
    Assert.assertNotNull(expected);
    Assert.assertNotNull(actual);
    final Path absoluteExpected = expected.toAbsolutePath();
    final Path absoluteActual = actual.toAbsolutePath();
    try {
        Files.walkFileTree(expected, new FileVisitor<Path>() {

            @Override
            public FileVisitResult preVisitDirectory(Path expectedDir, BasicFileAttributes attrs)
                    throws IOException {
                Path relativeExpectedDir = absoluteExpected.relativize(expectedDir.toAbsolutePath());
                Path actualDir = absoluteActual.resolve(relativeExpectedDir);

                if (!Files.exists(actualDir)) {
                    Assert.fail(String.format("Directory \'%s\' missing in target.", expectedDir.getFileName()));
                }

                Assert.assertEquals(String.format("Directory size of \'%s\' differ. ", relativeExpectedDir),
                        expectedDir.toFile().list().length, actualDir.toFile().list().length);

                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path expectedFile, BasicFileAttributes attrs) throws IOException {
                Path relativeExpectedFile = absoluteExpected.relativize(expectedFile.toAbsolutePath());
                Path actualFile = absoluteActual.resolve(relativeExpectedFile);

                if (!Files.exists(actualFile)) {
                    Assert.fail(String.format("File \'%s\' missing in target.", expectedFile.getFileName()));
                }
                Assert.assertEquals(String.format("File size of \'%s\' differ. ", relativeExpectedFile),
                        Files.size(expectedFile), Files.size(actualFile));
                Assert.assertArrayEquals(String.format("File content of \'%s\' differ. ", relativeExpectedFile),
                        Files.readAllBytes(expectedFile), Files.readAllBytes(actualFile));

                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                Assert.fail(exc.getMessage());
                return FileVisitResult.TERMINATE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }

        });
    } catch (IOException e) {
        Assert.fail(e.getMessage());
    }
}

}
like image 28
Andreas Avatar answered Oct 21 '22 05:10

Andreas