Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public class ApiPathImpl extends NormalisedPathImpl implements ApiPath {

private final boolean strictPathMatching;

/** Compiled once per part - the path template is fixed for the lifetime of this instance. */
private final Pattern[] partPatterns;

public ApiPathImpl(@Nonnull final String path, @Nullable final String apiPrefix) {
this(path, apiPrefix, false);
}
Expand All @@ -45,6 +48,10 @@ public ApiPathImpl(@Nonnull final String path,
final boolean strictPathMatching) {
super(path, apiPrefix);
this.strictPathMatching = strictPathMatching;
this.partPatterns = new Pattern[numberOfParts()];
for (int i = 0; i < partPatterns.length; i++) {
partPatterns[i] = compile(quote(part(i)).replaceAll(PARAM_REGEX, "\\\\E(.*?)\\\\Q"), CASE_INSENSITIVE);
}
}

@Override
Expand All @@ -66,9 +73,7 @@ public boolean matches(final NormalisedPath requestPath) {
@Override
public boolean partMatches(final int index, @Nonnull final String requestPathPart) {
requireNonNull(requestPathPart, "A request path part is required");
final String template = part(index);
final Pattern templatePattern = compile(quote(template).replaceAll(PARAM_REGEX, "\\\\E(.*?)\\\\Q"), CASE_INSENSITIVE);
return templatePattern.matcher(requestPathPart).matches();
return partPatterns[index].matcher(requestPathPart).matches();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class ApiPathImplTest {

Expand Down Expand Up @@ -212,6 +213,44 @@ public void matches_doesNotMatches_whenBadParamMatch() {
assertThat(matches("/p1/p2/{param1}-{param2}", "/p1/p2/floop"), is(false));
}

@Test
public void partMatches_matchesLiterally_whenPartContainsRegexMetacharacters() {
assertThat(partMatches("a.b", "a.b"), is(true));
assertThat(partMatches("a.b", "axb"), is(false));
assertThat(partMatches("a+b", "a+b"), is(true));
assertThat(partMatches("a+b", "aab"), is(false));
}

@Test
public void partMatches_throws_whenIndexOutOfRange() {
final ApiPathImpl classUnderTest = new ApiPathImpl("/{id}", null);

assertThrows(IndexOutOfBoundsException.class, () -> classUnderTest.partMatches(1, "foop"));
}

@Test
public void partMatches_isRepeatable_onTheSameInstance() {
final ApiPathImpl classUnderTest = new ApiPathImpl("/{id}/literal/a.b/a+b", null);

assertThat(classUnderTest.partMatches(0, "foop"), is(true));
assertThat(classUnderTest.partMatches(1, "literal"), is(true));
assertThat(classUnderTest.partMatches(1, "LITERAL"), is(true));
assertThat(classUnderTest.partMatches(1, "blarp"), is(false));
assertThat(classUnderTest.partMatches(2, "a.b"), is(true));
assertThat(classUnderTest.partMatches(2, "axb"), is(false));
assertThat(classUnderTest.partMatches(3, "a+b"), is(true));
assertThat(classUnderTest.partMatches(3, "aab"), is(false));
}

@Test
public void matches_isRepeatable_onTheSameInstance() {
final ApiPathImpl classUnderTest = new ApiPathImpl("/p1/{param1}/p3", null);

assertThat(classUnderTest.matches(new NormalisedPathImpl("/p1/foop/p3", null)), is(true));
assertThat(classUnderTest.matches(new NormalisedPathImpl("/p1/foop/P3", null)), is(true));
assertThat(classUnderTest.matches(new NormalisedPathImpl("/p1/foop/blarp", null)), is(false));
}

private static void testParamValueExtraction(final String expression, final String path, final String... expected) {
assertThat(new ApiPathImpl(expression, null).paramValues(0, path).values(),
containsInAnyOrder(stream(expected).map(e -> is(ofNullable(e))).collect(toList())));
Expand Down