From fceb08d994ccd443f34301146e25a29734b3b10d Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Thu, 4 Jun 2020 00:11:38 +0000 Subject: [PATCH] fix: parse collection wildcards and _deleted-topic_ patterns --- .../google/api/pathtemplate/PathTemplate.java | 21 +++++++++++++--- .../api/pathtemplate/PathTemplateTest.java | 25 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index 970fa510e..45071968c 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -869,8 +869,17 @@ private static ImmutableList parseTemplate(String template) { int pathWildCardBound = 0; for (String seg : Splitter.on('/').trimResults().split(template)) { - if (COMPLEX_DELIMITER_PATTERN.matcher(seg.substring(0, 1)).find() - || COMPLEX_DELIMITER_PATTERN.matcher(seg.substring(seg.length() - 1)).find()) { + // Handle _deleted-topic_ for PubSub. + if (seg.equals("_deleted-topic_")) { + builder.add(Segment.create(SegmentKind.LITERAL, seg)); + continue; + } + + boolean isLastSegment = (template.indexOf(seg) + seg.length()) == template.length(); + boolean isCollectionWildcard = !isLastSegment && (seg.equals("-") || seg.equals("-}")); + if (!isCollectionWildcard + && (COMPLEX_DELIMITER_PATTERN.matcher(seg.substring(0, 1)).find() + || COMPLEX_DELIMITER_PATTERN.matcher(seg.substring(seg.length() - 1)).find())) { throw new ValidationException("parse error: invalid begin or end character in '%s'", seg); } // Disallow zero or multiple delimiters between variable names. @@ -896,7 +905,7 @@ private static ImmutableList parseTemplate(String template) { } Matcher complexPatternDelimiterMatcher = END_SEGMENT_COMPLEX_DELIMITER_PATTERN.matcher(seg); - complexDelimiterFound = complexPatternDelimiterMatcher.find(); + complexDelimiterFound = !isCollectionWildcard && complexPatternDelimiterMatcher.find(); // Look for complex resource names. // Need to handle something like "{user_a}~{user_b}". @@ -915,6 +924,8 @@ private static ImmutableList parseTemplate(String template) { throw new ValidationException( "parse error: invalid binding syntax in '%s'", template); } + } else if (seg.indexOf('-') <= 0 && isCollectionWildcard) { + implicitWildcard = true; } else { // Looking at something like "{name=wildcard}". varName = seg.substring(0, i).trim(); @@ -957,6 +968,10 @@ private static ImmutableList parseTemplate(String template) { } // If the wildcard is implicit, seg will be empty. Just continue. break; + case "-": + builder.add(Segment.WILDCARD); + implicitWildcard = false; + break; default: builder.add(Segment.create(SegmentKind.LITERAL, seg)); } diff --git a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java index 33b9033b8..ccac31f6d 100644 --- a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java +++ b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java @@ -317,6 +317,31 @@ public void complexResourceIdMixedSeparators() { Truth.assertThat(match.get("zone_d")).isEqualTo("europe-west2-b"); } + @Test + public void collectionWildcardMatchingInParent() { + PathTemplate template = PathTemplate.create("v1/publishers/-/books/{book}"); + Map match = + template.match( + "https://example.googleapis.com/v1/publishers/publisher-abc/books/blockchain_for_babies"); + Truth.assertThat(match).isNotNull(); + + template = PathTemplate.create("/v1/{parent=rooms/-}/blurbs/{blurb}"); + match = template.match("https://example.googleapis.com/v1/rooms/den/blurbs/asdf"); + Truth.assertThat(match).isNotNull(); + } + + @Test + public void collectionWildcardMatchingInvalid() { + thrown.expect(ValidationException.class); + PathTemplate.create("v1/publishers/{publisher}/books/-"); + } + + @Test + public void complexResourceIdPubSubDeletedTopic() { + PathTemplate template = PathTemplate.create("_deleted-topic_"); + Truth.assertThat(template).isNotNull(); + } + @Test public void complexResourceIdInParent() { // One parent has a complex resource ID.