//
// Copyright © 2014, David Tesler (https://github.com/protobufel)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
package com.github.protobufel.common.files;
import static com.github.protobufel.common.files.ContextPathMatchers.getHierarchicalMatcher;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.isA;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeThat;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.FromDataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import com.github.protobufel.common.files.ContextPathMatchers.HierarchicalMatcher;
@RunWith(Theories.class)
public class ContextPathMatchersTest {
@DataPoints("patterns")
public static final String[] SYNTAX_AND_PATTERNS = new String[] {
"glob:part1/pa?rt2/*/**/last*part.*",
"regex:[^/]*/text.{1,5}[.]txt",
"bad:any:)how"
};
@DataPoints("pathTypes")
public static final Class<?>[] PATH_TYPES = new Class<?>[] {
String.class,
File.class,
Path.class,
ArrayList.class // non-standard class with public default constructor, yet, should be okay!
};
@SuppressWarnings("null")
@Rule
public ExpectedException thrown = ExpectedException.none();
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Theory
public void getPathMatcherWithGoodDataIsOk(
final @FromDataPoints("patterns") String syntaxAndPattern,
final boolean isUnix, final boolean allowDirs, boolean allowFiles,
final Class<?> pathType) {
//Given
assumeThat((!allowDirs && !allowFiles), is(false));
assumeThat(syntaxAndPattern, anyOf(startsWith("glob:"), startsWith("regex:")));
assumeThat(Arrays.asList(String.class, File.class, Path.class).contains(pathType), is(true));
getPathMatcherWithGoodDataIsGoodHelper(syntaxAndPattern, isUnix, allowDirs, allowFiles,
pathType, true);
}
@Theory
public void getPathMatcherWithUnAssumedPathTypeIsOk(
final @FromDataPoints("patterns") String syntaxAndPattern,
final boolean isUnix, final boolean allowDirs, boolean allowFiles,
final Class<?> pathType) {
//Given
assumeThat((!allowDirs && !allowFiles), is(false));
assumeThat(syntaxAndPattern, anyOf(startsWith("glob:"), startsWith("regex:")));
assumeThat(Arrays.asList(String.class, File.class, Path.class).contains(pathType), is(false));
getPathMatcherWithGoodDataIsGoodHelper(syntaxAndPattern, isUnix, allowDirs, allowFiles,
pathType, false);
}
@Theory
public void getPathMatcherWithBadSyntaxProhibited(
final @FromDataPoints("patterns") String syntaxAndPattern,
final boolean isUnix, final boolean allowDirs, boolean allowFiles,
final Class<?> pathType) {
//Given
assumeThat((!allowDirs && !allowFiles), is(false));
assumeThat(syntaxAndPattern, is(not(anyOf(startsWith("glob:"), startsWith("regex:")))));
assumeThat(Arrays.asList(String.class, File.class, Path.class).contains(pathType), is(true));
//Then
thrown.expect(isA(UnsupportedOperationException.class));
thrown.expectMessage(containsString(syntaxAndPattern.split(":", 2)[0]));
//When
getHierarchicalMatcher(syntaxAndPattern, isUnix, allowDirs, allowFiles, pathType);
}
@Theory
public void getPathMatcherWithAllowDirsAndAllowFilesBothFalseProhibited(
final @FromDataPoints("patterns") String syntaxAndPattern,
final boolean isUnix, final boolean allowDirs, boolean allowFiles,
final Class<?> pathType) {
//Given
assumeThat((!allowDirs && !allowFiles), is(true));
assumeThat(syntaxAndPattern, is(anyOf(startsWith("glob:"), startsWith("regex:"))));
assumeThat(Arrays.asList(String.class, File.class, Path.class).contains(pathType), is(true));
//Then
thrown.expect(isA(IllegalArgumentException.class));
thrown.expectMessage(containsString("allowDirs and allowFiles cannot be both false"));
//When
getHierarchicalMatcher(syntaxAndPattern, isUnix, allowDirs, allowFiles, pathType);
}
private <T> void getPathMatcherWithGoodDataIsGoodHelper(
final String syntaxAndPattern,
final boolean isUnix, final boolean allowDirs, boolean allowFiles,
final Class<T> pathType, final boolean isAssumedPathType) {
//When
final HierarchicalMatcher<T> actualMatcher = getHierarchicalMatcher(syntaxAndPattern, isUnix,
allowDirs, allowFiles, pathType);
//Then
assertThat(actualMatcher, is(not(nullValue())));
assertThat(actualMatcher.isAllowDirs(), is(allowDirs));
assertThat(actualMatcher.isAllowFiles(), is(allowFiles));
assertThat(actualMatcher.isEmpty(), is(false));
assertThat(actualMatcher.toString(), is(not(nullValue())));
assertThat(actualMatcher.toString(), allOf(
containsString(actualMatcher.getPattern()),
containsString("allowDirs"),
containsString("allowFiles"),
containsString("flags")));
assertThat(actualMatcher.getPattern(), is(not(nullValue())));
final String patternNoSyntax = syntaxAndPattern.split(":", 2)[1];
if (syntaxAndPattern.startsWith("regex:")) {
if (isUnix) {
assertThat(actualMatcher.getPattern(), is(equalTo(patternNoSyntax)));
} else {
assertThat(actualMatcher.getPattern(), is(not(equalTo(patternNoSyntax))));
}
}
// all ContextHierarchicalMatcher's methods should not produce exceptions!
actualMatcher.matches(getValidInstanceOf(pathType, isAssumedPathType), PathContexts.<T>emptyPathContext());
actualMatcher.matchesDirectory(getValidInstanceOf(pathType, isAssumedPathType), PathContexts.<T>emptyPathContext());
}
@SuppressWarnings("null")
private <T> T getValidInstanceOf(Class<T> pathType, final boolean isAssumedPathType) {
if (pathType == String.class) {
return pathType.cast("");
} else if (pathType == Path.class) {
return pathType.cast(Paths.get(""));
} else if (pathType == File.class) {
return pathType.cast(Paths.get("").toFile());
} else if (!isAssumedPathType) {
try {
return pathType.getConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
} else { // we should not be here!
throw new RuntimeException("an unexpected pathType");
}
}
}