/* * SFTPFileSystemDirectoryStreamTest.java * Copyright 2016 Rob Spoor * * 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.github.robtimus.filesystems.sftp; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.everyItem; import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.nio.file.DirectoryIteratorException; import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream.Filter; import java.nio.file.Path; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.junit.jupiter.api.Test; import com.github.robtimus.filesystems.Messages; @SuppressWarnings({ "nls", "javadoc" }) public class SFTPFileSystemDirectoryStreamTest extends AbstractSFTPFileSystemTest { @Test public void testIterator() throws IOException { final int count = 100; List<Matcher<? super String>> matchers = new ArrayList<>(); for (int i = 0; i < count; i++) { matchers.add(equalTo("file" + i)); addFile("/foo/file" + i); } List<String> names = new ArrayList<>(); try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/foo"), AcceptAllFilter.INSTANCE)) { for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) { names.add(iterator.next().getFileName().toString()); } } assertThat(names, containsInAnyOrder(matchers)); } @Test public void testFilteredIterator() throws IOException { final int count = 100; List<Matcher<? super String>> matchers = new ArrayList<>(); for (int i = 0; i < count; i++) { if (i % 2 == 1) { matchers.add(equalTo("file" + i)); } addFile("/foo/file" + i); } List<String> names = new ArrayList<>(); Filter<Path> filter = new PatternFilter("file\\d*[13579]"); try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/foo"), filter)) { for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) { names.add(iterator.next().getFileName().toString()); } } assertThat(names, containsInAnyOrder(matchers)); } @Test public void testCloseWhileIterating() throws IOException { final int count = 100; // there is no guaranteed order, just a count for (int i = 0; i < count; i++) { addFile("/foo/file" + i); } Matcher<String> matcher = new TypeSafeDiagnosingMatcher<String>() { private final Pattern pattern = Pattern.compile("file\\d+"); @Override protected boolean matchesSafely(String item, Description mismatchDescription) { return item != null && pattern.matcher(item).matches(); } @Override public void describeTo(Description description) { description .appendText("matches ") .appendValue(pattern); } }; int expectedCount = count / 2; List<String> names = new ArrayList<>(); try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/foo"), AcceptAllFilter.INSTANCE)) { int index = 0; for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) { if (++index == count / 2) { stream.close(); } names.add(iterator.next().getFileName().toString()); } } assertEquals(expectedCount, names.size()); assertThat(names, everyItem(matcher)); } @Test public void testIteratorAfterClose() throws IOException { try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/"), AcceptAllFilter.INSTANCE)) { stream.close(); IllegalStateException exception = assertThrows(IllegalStateException.class, stream::iterator); assertEquals(Messages.directoryStream().closed().getMessage(), exception.getMessage()); } } @Test public void testIteratorAfterIterator() throws IOException { try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/"), AcceptAllFilter.INSTANCE)) { stream.iterator(); IllegalStateException exception = assertThrows(IllegalStateException.class, stream::iterator); assertEquals(Messages.directoryStream().iteratorAlreadyReturned().getMessage(), exception.getMessage()); } } @Test public void testDeleteWhileIterating() throws IOException { final int count = 100; List<Matcher<? super String>> matchers = new ArrayList<>(); addDirectory("/foo"); for (int i = 0; i < count; i++) { matchers.add(equalTo("file" + i)); addFile("/foo/file" + i); } List<String> names = new ArrayList<>(); try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/foo"), AcceptAllFilter.INSTANCE)) { int index = 0; for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) { if (++index < count / 2) { delete("/foo"); } names.add(iterator.next().getFileName().toString()); } } assertThat(names, containsInAnyOrder(matchers)); } @Test public void testDeleteChildrenWhileIterating() throws IOException { final int count = 100; List<Matcher<? super String>> matchers = new ArrayList<>(); addDirectory("/foo"); for (int i = 0; i < count; i++) { matchers.add(equalTo("file" + i)); addFile("/foo/file" + i); } List<String> names = new ArrayList<>(); try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/foo"), AcceptAllFilter.INSTANCE)) { int index = 0; for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) { if (++index < count / 2) { for (int i = 0; i < count; i++) { delete("/foo/file" + i); } assertEquals(0, getChildCount("/foo")); } names.add(iterator.next().getFileName().toString()); } } assertThat(names, containsInAnyOrder(matchers)); } @Test public void testDeleteBeforeIterator() throws IOException { final int count = 100; List<Matcher<? super String>> matchers = new ArrayList<>(); addDirectory("/foo"); for (int i = 0; i < count; i++) { // the entries are collected before the iteration starts matchers.add(equalTo("file" + i)); addFile("/foo/file" + i); } List<String> names = new ArrayList<>(); try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/foo"), AcceptAllFilter.INSTANCE)) { delete("/foo"); for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) { names.add(iterator.next().getFileName().toString()); } } assertThat(names, containsInAnyOrder(matchers)); } @Test public void testThrowWhileIterating() throws IOException { addFile("/foo"); try (DirectoryStream<Path> stream = fileSystem.newDirectoryStream(createPath("/"), ThrowingFilter.INSTANCE)) { DirectoryIteratorException exception = assertThrows(DirectoryIteratorException.class, () -> { for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); ) { iterator.next(); } }); assertThat(exception.getCause(), instanceOf(IOException.class)); } } private static final class AcceptAllFilter implements Filter<Path> { private static final AcceptAllFilter INSTANCE = new AcceptAllFilter(); @Override public boolean accept(Path entry) { return true; } } private static final class PatternFilter implements Filter<Path> { private final Pattern pattern; private PatternFilter(String regex) { pattern = Pattern.compile(regex); } @Override public boolean accept(Path entry) { return pattern.matcher(entry.getFileName().toString()).matches(); } } private static final class ThrowingFilter implements Filter<Path> { private static final ThrowingFilter INSTANCE = new ThrowingFilter(); @Override public boolean accept(Path entry) throws IOException { throw new IOException(); } } }