Skip to content

Commit

Permalink
fix: prevent resname tokens from matching subcomponents
Browse files Browse the repository at this point in the history
  • Loading branch information
miraleung committed Oct 30, 2020
1 parent e337c6a commit d53ea8a
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,21 @@
package com.google.api.generator.gapic.composer;

import com.google.api.pathtemplate.PathTemplate;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ResourceNameTokenizer {
private static final String SLASH = "/";
private static final String LEFT_BRACE = "{";
private static final String RIGHT_BRACE = "}";
private static final String SLASH = "/";
private static final String EMPTY = "";

private static final String EQUALS_WILDCARD = "=*";
private static final String EQUALS_PATH_WILDCARD = "=**";

static List<List<String>> parseTokenHierarchy(List<String> patterns) {
List<String> nonSlashSepStrings = Arrays.asList("}_{", "}-{", "}.{", "}~{");
Expand All @@ -36,22 +41,38 @@ static List<List<String>> parseTokenHierarchy(List<String> patterns) {
String[] patternTokens = pattern.split(SLASH);
for (String patternToken : patternTokens) {
if (patternToken.startsWith(LEFT_BRACE) && patternToken.endsWith(RIGHT_BRACE)) {
String processedPatternToken = patternToken;
String processedPatternToken =
// Replacement order matters - ensure the first is not a subcomponent of the second.
patternToken.replace(EQUALS_PATH_WILDCARD, EMPTY).replace(EQUALS_WILDCARD, EMPTY);

// Handle non-slash separators.
if (nonSlashSepStrings.stream().anyMatch(s -> patternToken.contains(s))) {
for (String str : nonSlashSepStrings) {
processedPatternToken = processedPatternToken.replace(str, "_");
}
} else {
final int processedPatternTokenLength = processedPatternToken.length();
// Handles wildcards.
processedPatternToken =
List<String> candidateVars =
vars.stream()
.filter(v -> patternToken.contains(v))
.collect(Collectors.toList())
.get(0);
// Check that the token size is within ~3 of the var, to avoid mismatching on
// variables with same-named subcomponents.
// Otherwise, "customer_client_link" will match with "customer".
.filter(
v ->
patternToken.contains(v)
// Accounting for braces.
&& processedPatternTokenLength - v.length() < 3)
.collect(Collectors.toList());
Preconditions.checkState(
!candidateVars.isEmpty(),
String.format(
"No variable candidates found for token %s in pattern %s",
processedPatternToken, pattern));
processedPatternToken = candidateVars.get(0);
}
hierarchy.add(processedPatternToken.replace("{", "").replace("}", ""));
hierarchy.add(
processedPatternToken.replace(LEFT_BRACE, EMPTY).replace(RIGHT_BRACE, EMPTY));
}
}
tokenHierachies.add(hierarchy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ public void parseTokenHierarchy_basic() {
assertThat(tokenHierarchies.get(2)).containsExactly("project", "autoscaling_policy");
}

@Test
public void parseTokenHierarchy_substringsInPattern() {
List<String> patterns =
Arrays.asList(
"customers/{customer}/customerExtensionSettings/{customer_extension_setting}");
List<List<String>> tokenHierarchies = ResourceNameTokenizer.parseTokenHierarchy(patterns);
assertEquals(1, tokenHierarchies.size());
assertThat(tokenHierarchies.get(0)).containsExactly("customer", "customer_extension_setting");
}

@Test
public void parseTokenHierarchy_wildcards() {
List<String> patterns =
Expand Down

0 comments on commit d53ea8a

Please sign in to comment.