diff --git a/src/main/java/com/google/api/pathtemplate/PathTemplate.java b/src/main/java/com/google/api/pathtemplate/PathTemplate.java index 45071968c..dd133461a 100644 --- a/src/main/java/com/google/api/pathtemplate/PathTemplate.java +++ b/src/main/java/com/google/api/pathtemplate/PathTemplate.java @@ -200,6 +200,11 @@ private static Segment create(SegmentKind kind, String value) { return new AutoValue_PathTemplate_Segment(kind, value, ""); } + /** Creates a segment of given kind, value, and complex separator. */ + private static Segment create(SegmentKind kind, String value, String complexSeparator) { + return new AutoValue_PathTemplate_Segment(kind, value, complexSeparator); + } + private static Segment wildcardCreate(String complexSeparator) { return new AutoValue_PathTemplate_Segment( SegmentKind.WILDCARD, @@ -737,10 +742,13 @@ private String instantiate(Map values, boolean allowPartial) { boolean continueLast = true; // Whether to not append separator boolean skip = false; // Whether we are substituting a binding and segments shall be skipped. ListIterator iterator = segments.listIterator(); + String prevSeparator = ""; while (iterator.hasNext()) { Segment seg = iterator.next(); if (!skip && !continueLast) { - result.append(seg.separator()); + String separator = prevSeparator.isEmpty() ? seg.separator() : prevSeparator; + result.append(separator); + prevSeparator = seg.complexSeparator().isEmpty() ? seg.separator() : seg.complexSeparator(); } continueLast = false; switch (seg.kind()) { @@ -1066,7 +1074,7 @@ private static List parseComplexResourceId(String seg) { currIteratorIndex < separatorIndices.size() ? separatorIndices.get(currIteratorIndex) : ""; - segments.add(Segment.create(SegmentKind.BINDING, subVarName)); + segments.add(Segment.create(SegmentKind.BINDING, subVarName, complexDelimiter)); segments.add(Segment.wildcardCreate(complexDelimiter)); segments.add(Segment.END_BINDING); subVarName = null; diff --git a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java index ccac31f6d..dc90b65ba 100644 --- a/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java +++ b/src/test/java/com/google/api/pathtemplate/PathTemplateTest.java @@ -37,6 +37,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Set; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -377,6 +378,26 @@ public void complexResourceIdInParent() { Truth.assertThat(match.get("cell2")).isEqualTo("broomba"); } + @Test + public void complexResourcePathTemplateVariables() { + String pattern = + "projects/{foo}_{bar}/zones/{zone_a}-{zone_b}_{zone_c}/machines/{cell1}.{cell2}"; + PathTemplate template = PathTemplate.create(pattern); + Set variables = template.vars(); + Truth.assertThat(variables) + .containsExactly("foo", "bar", "zone_a", "zone_b", "zone_c", "cell1", "cell2"); + + pattern = "projects/{foo}_{bar}/zones/*"; + template = PathTemplate.create(pattern); + Map match = + template.match("https://www.googleapis.com/compute/v1/projects/foo1_bar2/zones/azone"); + Truth.assertThat(match).isNotNull(); + Truth.assertThat(match.get("foo")).isEqualTo("foo1"); + Truth.assertThat(match.get("bar")).isEqualTo("bar2"); + variables = template.vars(); + System.out.println("DEL: vars: " + variables); + } + @Test public void complexResourceBasicInvalidIds() { thrown.expect(ValidationException.class); @@ -575,6 +596,57 @@ public void instantiateWithUnusualCharactersNoEncoding() { Truth.assertThat(instance).isEqualTo("bar/asdf:;`~,.<>[]!@#$%^&*()"); } + @Test + public void instantiateWithComplexResourceId_basic() { + PathTemplate template = PathTemplate.create("projects/{project}/zones/{zone_a}~{zone_b}"); + String instance = + template.instantiate("project", "a/b/c", "zone_a", "apple", "zone_b", "baseball"); + Truth.assertThat(instance).isEqualTo("projects/a%2Fb%2Fc/zones/apple~baseball"); + } + + @Test + public void instantiateWithComplexResourceId_mixedSeparators() { + PathTemplate template = + PathTemplate.create( + "projects/{project}/zones/{zone_a}~{zone_b}.{zone_c}-{zone_d}~{zone_e}"); + String instance = + template.instantiate( + "project", + "a/b/c", + "zone_a", + "apple", + "zone_b", + "baseball/basketball", + "zone_c", + "cat/kitty", + "zone_d", + "dog/hound", + "zone_e", + "12345"); + Truth.assertThat(instance) + .isEqualTo( + "projects/a%2Fb%2Fc/zones/apple~baseball%2Fbasketball.cat%2Fkitty-dog%2Fhound~12345"); + } + + @Test + public void instantiateWithComplexResourceId_mixedSeparatorsInParent() { + PathTemplate template = + PathTemplate.create("projects/{project_a}~{project_b}.{project_c}/zones/{zone_a}~{zone_b}"); + String instance = + template.instantiate( + "project_a", + "a/b/c", + "project_b", + "foo", + "project_c", + "bar", + "zone_a", + "apple", + "zone_b", + "baseball"); + Truth.assertThat(instance).isEqualTo("projects/a%2Fb%2Fc~foo.bar/zones/apple~baseball"); + } + // Other // =====