Skip to content

Commit bd74ffa

Browse files
committed
Format
1 parent 6cc2141 commit bd74ffa

File tree

3 files changed

+135
-119
lines changed

3 files changed

+135
-119
lines changed

src/main/java/com/google/cloud/discotoproto3converter/disco/Method.java

Lines changed: 87 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@
2121
import java.util.LinkedHashMap;
2222
import java.util.List;
2323
import java.util.Map;
24-
import java.util.stream.Collectors;
25-
import javax.annotation.Nullable;
2624
import java.util.regex.Matcher;
2725
import java.util.regex.Pattern;
28-
26+
import java.util.stream.Collectors;
27+
import javax.annotation.Nullable;
2928

3029
/**
3130
* Adapted from its counterpart in gapic-generator.
@@ -37,7 +36,7 @@
3736
@AutoValue
3837
public abstract class Method implements Comparable<Method>, Node {
3938

40-
/** Regex for finding the lone subresource pattern `{+FOO}` in a Discovery `path` field.*/
39+
/** Regex for finding the lone subresource pattern `{+FOO}` in a Discovery `path` field. */
4140
private static Pattern PATH_SUBRESOURCE_PATTERN = Pattern.compile("\\{\\+([a-zA-Z0-9]+)\\}");
4241

4342
/**
@@ -51,15 +50,15 @@ public static Method from(DiscoveryNode root, Node parent) {
5150
String httpMethod = root.getString("httpMethod");
5251
String id = root.getString("id");
5352
String path = root.getString("path");
54-
String flatPath = accomodatePathSubresources(path, root.has("flatPath") ? root.getString("flatPath") : path);
53+
String flatPath =
54+
accomodatePathSubresources(path, root.has("flatPath") ? root.getString("flatPath") : path);
5555
String apiVersion = root.getString("apiVersion");
5656

5757
DiscoveryNode parametersNode = root.getObject("parameters");
5858
Map<String, Schema> parameters = new LinkedHashMap<>();
5959
Map<String, Schema> queryParams = new LinkedHashMap<>();
6060
Map<String, Schema> pathParams = new LinkedHashMap<>();
6161

62-
6362
for (String name : root.getObject("parameters").getFieldNames()) {
6463
Schema schema = Schema.from(parametersNode.getObject(name), name, null);
6564
// TODO: Remove these checks once we're sure that parameters can't be objects/arrays.
@@ -129,89 +128,88 @@ public static Method from(DiscoveryNode root, Node parent) {
129128
return thisMethod;
130129
}
131130

132-
/**
133-
* Expands subresource templates in a flatPath using wildcards instead of subresource-field references.
134-
*
135-
* If path contains a segment like {+FOO}, that indicates that
136-
* `FOO` is structured and refers to a sub-resource. In that case,
137-
* the corresponding `flatPath` is presented in Discovery as the
138-
* full template expansion of the subresource, which could itself
139-
* refer to fields from the subresource message but not from the
140-
* request where `flatPath` appears. For example, if the Discovery
141-
* files contains
142-
* "path": "something/{+foo}/random"
143-
* "flatPath": "something/galaxy/{galaxyId}/system/{systemId}/planet/{planetId}/random"
144-
* then this function wildcards the subresource-field references,
145-
* so that flatPath behaves as though it had been specified this
146-
* way (the Discovery file would have asterisks * instead of the
147-
* star ✴ used below because this documentation is in a Java
148-
* comment):
149-
* "flatPath": "something/galaxy/✴/system/✴/planet/✴/random"
150-
*
151-
*
152-
* @param path The template path containing the {+FOO} token denoting a subresource. Only one such subresource is allowed.
153-
* @param flatPath The flattened path whose field references inside the subresource segement will be wildcarded.
154-
* @return The processed string.
155-
* @throws IllegalArgumentException If path has multiple tokens or flatPath doesn't match prefix/suffix.
156-
*/
157-
public static String accomodatePathSubresources(String path, String flatPath) {
158-
// Regex to find {+FOO}, where FOO is alphanumeric.
159-
// We escape the braces and the plus sign. We capture FOO.
160-
Matcher matcher = PATH_SUBRESOURCE_PATTERN.matcher(path);
161-
162-
int matchCount = 0;
163-
while (matcher.find()) {
164-
matchCount++;
165-
}
166-
167-
// Logic Branch 1: No instances of {+FOO}
168-
if (matchCount == 0) {
169-
return flatPath;
170-
}
171-
172-
// Logic Branch 2: More than one instance
173-
if (matchCount > 1) {
174-
throw new IllegalArgumentException("Error: 'path' contains multiple instances of variable expansion tokens.");
175-
}
176-
177-
// Logic Branch 3: Exactly one instance
178-
matcher.reset(); // Reset matcher to retrieve positions
179-
matcher.find();
180-
181-
String tokenName = Name.anyCamel(matcher.group(1)).toLowerUnderscore();
182-
183-
// Extract Prefix and Suffix from 'path'
184-
185-
String prefix = path.substring(0, matcher.start());
186-
String suffix = path.substring(matcher.end());
187-
188-
// Validate 'flatPath' against prefix and suffix
189-
// We must also check that the total length is sufficient to contain both without overlap
190-
if (!flatPath.startsWith(prefix) ||
191-
!flatPath.endsWith(suffix) ||
192-
flatPath.length() < (prefix.length() + suffix.length())) {
193-
throw new IllegalArgumentException("Error: 'flatPath' does not match the structure defined by 'path'.");
194-
}
195-
196-
// Extract subresource
197-
// This is the content between the prefix and the suffix in flatPath
198-
int subresourceStart = prefix.length();
199-
int subresourceEnd = flatPath.length() - suffix.length();
200-
String subresource = flatPath.substring(subresourceStart, subresourceEnd);
201-
202-
// Modify subresource
203-
// Regex: Opening brace {, followed by any character that is NOT a closing brace, followed by }
204-
// This ensures we stop at the *next* closing brace.
205-
// Note that any subresource's empty placeholders `{}` are
206-
// not replaced; this anomalous condition will generate an
207-
// error downstream in generators or GAPICs.
208-
String modifiedSubresource = subresource.replaceAll("\\{[^}]+\\}", "*");
209-
210-
// Reconstruct and return
211-
return prefix + "{" + tokenName + "=" + modifiedSubresource + "}" + suffix;
212-
213-
}
214-
131+
/**
132+
* Expands subresource templates in a flatPath using wildcards instead of subresource-field
133+
* references.
134+
*
135+
* <p>If path contains a segment like {+FOO}, that indicates that `FOO` is structured and refers
136+
* to a sub-resource. In that case, the corresponding `flatPath` is presented in Discovery as the
137+
* full template expansion of the subresource, which could itself refer to fields from the
138+
* subresource message but not from the request where `flatPath` appears. For example, if the
139+
* Discovery files contains "path": "something/{+foo}/random" "flatPath":
140+
* "something/galaxy/{galaxyId}/system/{systemId}/planet/{planetId}/random" then this function
141+
* wildcards the subresource-field references, so that flatPath behaves as though it had been
142+
* specified this way (the Discovery file would have asterisks * instead of the star ✴ used below
143+
* because this documentation is in a Java comment): "flatPath":
144+
* "something/galaxy/✴/system/✴/planet/✴/random"
145+
*
146+
* @param path The template path containing the {+FOO} token denoting a subresource. Only one such
147+
* subresource is allowed.
148+
* @param flatPath The flattened path whose field references inside the subresource segement will
149+
* be wildcarded.
150+
* @return The processed string.
151+
* @throws IllegalArgumentException If path has multiple tokens or flatPath doesn't match
152+
* prefix/suffix.
153+
*/
154+
public static String accomodatePathSubresources(String path, String flatPath) {
155+
// Regex to find {+FOO}, where FOO is alphanumeric.
156+
// We escape the braces and the plus sign. We capture FOO.
157+
Matcher matcher = PATH_SUBRESOURCE_PATTERN.matcher(path);
158+
159+
int matchCount = 0;
160+
while (matcher.find()) {
161+
matchCount++;
162+
}
163+
164+
// Logic Branch 1: No instances of {+FOO}
165+
if (matchCount == 0) {
166+
return flatPath;
167+
}
168+
169+
// Logic Branch 2: More than one instance
170+
if (matchCount > 1) {
171+
throw new IllegalArgumentException(
172+
"Error: 'path' contains multiple instances of variable expansion tokens.");
173+
}
174+
175+
// Logic Branch 3: Exactly one instance
176+
matcher.reset(); // Reset matcher to retrieve positions
177+
matcher.find();
178+
179+
String tokenName = Name.anyCamel(matcher.group(1)).toLowerUnderscore();
180+
181+
// Extract Prefix and Suffix from 'path'
182+
183+
String prefix = path.substring(0, matcher.start());
184+
String suffix = path.substring(matcher.end());
185+
186+
// Validate 'flatPath' against prefix and suffix
187+
// We must also check that the total length is sufficient to contain both without overlap
188+
if (!flatPath.startsWith(prefix)
189+
|| !flatPath.endsWith(suffix)
190+
|| flatPath.length() < (prefix.length() + suffix.length())) {
191+
throw new IllegalArgumentException(
192+
"Error: 'flatPath' does not match the structure defined by 'path'.");
193+
}
194+
195+
// Extract subresource
196+
// This is the content between the prefix and the suffix in flatPath
197+
int subresourceStart = prefix.length();
198+
int subresourceEnd = flatPath.length() - suffix.length();
199+
String subresource = flatPath.substring(subresourceStart, subresourceEnd);
200+
201+
// Modify subresource
202+
// Regex: Opening brace {, followed by any character that is NOT a closing brace, followed by }
203+
// This ensures we stop at the *next* closing brace.
204+
// Note that any subresource's empty placeholders `{}` are
205+
// not replaced; this anomalous condition will generate an
206+
// error downstream in generators or GAPICs.
207+
String modifiedSubresource = subresource.replaceAll("\\{[^}]+\\}", "*");
208+
209+
// Reconstruct and return
210+
return prefix + "{" + tokenName + "=" + modifiedSubresource + "}" + suffix;
211+
}
212+
215213
@Override
216214
public int compareTo(Method other) {
217215
return id().compareTo(other.id());

src/test/java/com/google/cloud/discotoproto3converter/DiscoToProto3ConverterAppTest.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -846,21 +846,12 @@ public void convertSubresources() throws IOException {
846846
Path prefix = Paths.get("google", "cloud", "compute", "v1small");
847847
Path discoveryDocPath =
848848
Paths.get(
849-
"src",
850-
"test",
851-
"resources",
852-
prefix.toString(),
853-
"compute.v1small.subresource.json");
849+
"src", "test", "resources", prefix.toString(), "compute.v1small.subresource.json");
854850
Path generatedFilePath =
855-
Paths.get(
856-
outputDir.toString(), prefix.toString(), "compute.subresource.proto");
851+
Paths.get(outputDir.toString(), prefix.toString(), "compute.subresource.proto");
857852
Path baselineFilePath =
858853
Paths.get(
859-
"src",
860-
"test",
861-
"resources",
862-
prefix.toString(),
863-
"compute.subresource.proto.baseline");
854+
"src", "test", "resources", prefix.toString(), "compute.subresource.proto.baseline");
864855
System.out.printf(
865856
"*** @Test: convertSubresources():\n"
866857
+ " Discovery path: %s\n"
@@ -885,7 +876,6 @@ public void convertSubresources() throws IOException {
885876
assertEquals(baselineBody, actualBody);
886877
}
887878

888-
889879
private static String readFile(Path path) throws IOException {
890880
return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
891881
}

src/test/java/com/google/cloud/discotoproto3converter/disco/MethodTest.java

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,63 +18,81 @@
1818
import static org.junit.Assert.assertEquals;
1919
import static org.junit.Assert.assertThrows;
2020

21-
import com.google.auto.value.AutoValue;
2221
import org.junit.Test;
2322

2423
public class MethodTest {
2524

2625
@Test
2726
public void accomodatePathSubresources_noToken() {
2827
// path does not match regex
29-
assertEquals("projects/p1/zones/z1", Method.accomodatePathSubresources("projects/p1/zones/z1", "projects/p1/zones/z1"));
28+
assertEquals(
29+
"projects/p1/zones/z1",
30+
Method.accomodatePathSubresources("projects/p1/zones/z1", "projects/p1/zones/z1"));
3031
assertEquals("anything", Method.accomodatePathSubresources("no-token", "anything"));
3132
}
3233

3334
@Test
3435
public void accomodatePathSubresources_multipleTokens() {
3536
// path matches regex more than once
36-
assertThrows(IllegalArgumentException.class, () -> Method.accomodatePathSubresources("projects/{+project}/zones/{+zone}", "projects/p1/zones/z1"));
37+
assertThrows(
38+
IllegalArgumentException.class,
39+
() ->
40+
Method.accomodatePathSubresources(
41+
"projects/{+project}/zones/{+zone}", "projects/p1/zones/z1"));
3742
}
3843

3944
@Test
4045
public void accomodatePathSubresources_invalidFlatPathPrefix() {
4146
// path matches once, but flatPath doesn't match prefix
42-
assertThrows(IllegalArgumentException.class, () -> Method.accomodatePathSubresources("projects/{+project}/zones", "other/p1/zones"));
47+
assertThrows(
48+
IllegalArgumentException.class,
49+
() -> Method.accomodatePathSubresources("projects/{+project}/zones", "other/p1/zones"));
4350
}
4451

4552
@Test
4653
public void accomodatePathSubresources_invalidFlatPathSuffix() {
4754
// path matches once, but flatPath doesn't match suffix
48-
assertThrows(IllegalArgumentException.class, () -> Method.accomodatePathSubresources("projects/{+project}/zones", "projects/p1/other"));
55+
assertThrows(
56+
IllegalArgumentException.class,
57+
() -> Method.accomodatePathSubresources("projects/{+project}/zones", "projects/p1/other"));
4958
}
5059

51-
5260
@Test
5361
public void accomodatePathSubresources_flatPathTooShort() {
5462
// path matches once, but flatPath length < prefix + suffix
5563
// prefix="prefix/", suffix="/suffix", combined length = 7 + 7 = 14
5664
// flatPath="prefix/suffix" has length 13.
57-
assertThrows(IllegalArgumentException.class, () -> Method.accomodatePathSubresources("prefix/{+name}/suffix", "prefix/suffix"));
65+
assertThrows(
66+
IllegalArgumentException.class,
67+
() -> Method.accomodatePathSubresources("prefix/{+name}/suffix", "prefix/suffix"));
5868
}
5969

6070
@Test
6171
public void accomodatePathSubresources_standard() {
6272
// Normal variable expansion
63-
assertEquals("projects/{project=my-project}/zones", Method.accomodatePathSubresources("projects/{+project}/zones", "projects/my-project/zones"));
73+
assertEquals(
74+
"projects/{project=my-project}/zones",
75+
Method.accomodatePathSubresources(
76+
"projects/{+project}/zones", "projects/my-project/zones"));
6477
}
6578

6679
@Test
6780
public void accomodatePathSubresources_withSubresourceBraces() {
6881
// Subresource in flatPath contains {foo} tokens which should be replaced by *
69-
assertEquals("projects/{project=*}/zones", Method.accomodatePathSubresources("projects/{+project}/zones", "projects/{project}/zones"));
82+
assertEquals(
83+
"projects/{project=*}/zones",
84+
Method.accomodatePathSubresources("projects/{+project}/zones", "projects/{project}/zones"));
7085
}
7186

7287
@Test
7388
public void accomodatePathSubresources_emptyPlaceholders() {
7489
// Subresource in flatPath contains empty tokens {} which will not
7590
// be replaced. This will lead to errors mainstream in the
7691
// generators or GAPICs.
77-
assertEquals("projects/{project=foo/{}/bar}/zones", Method.accomodatePathSubresources("projects/{+project}/zones", "projects/foo/{}/bar/zones"));
92+
assertEquals(
93+
"projects/{project=foo/{}/bar}/zones",
94+
Method.accomodatePathSubresources(
95+
"projects/{+project}/zones", "projects/foo/{}/bar/zones"));
7896
}
7997

8098
@Test
@@ -86,9 +104,11 @@ public void accomodatePathSubresources_complexSubresource() {
86104
@Test
87105
public void accomodatePathSubresources_structuredSubresource() {
88106
// Multiple path segments subresource
89-
assertEquals("before/{this}/{name=a/*/c/*/e}/after/{that}/goes",
90-
Method.accomodatePathSubresources("before/{this}/{+name}/after/{that}/goes",
91-
"before/{this}/a/{b}/c/{d}/e/after/{that}/goes"));
107+
assertEquals(
108+
"before/{this}/{name=a/*/c/*/e}/after/{that}/goes",
109+
Method.accomodatePathSubresources(
110+
"before/{this}/{+name}/after/{that}/goes",
111+
"before/{this}/a/{b}/c/{d}/e/after/{that}/goes"));
92112
}
93113

94114
@Test
@@ -100,24 +120,32 @@ public void accomodatePathSubresources_emptyPrefixSuffix() {
100120
@Test
101121
public void accomodatePathSubresources_multipleSubresourceBraces() {
102122
// Mix of literal and {} in subresource
103-
assertEquals("prefix/{name=a*c*e}/suffix", Method.accomodatePathSubresources("prefix/{+name}/suffix", "prefix/a{b}c{d}e/suffix"));
123+
assertEquals(
124+
"prefix/{name=a*c*e}/suffix",
125+
Method.accomodatePathSubresources("prefix/{+name}/suffix", "prefix/a{b}c{d}e/suffix"));
104126
}
105127

106128
@Test
107129
public void accomodatePathSubresources_tokenWithNumbers() {
108130
// Alphanumeric token
109-
assertEquals("v1/{var123=val}/v2", Method.accomodatePathSubresources("v1/{+var123}/v2", "v1/val/v2"));
131+
assertEquals(
132+
"v1/{var123=val}/v2", Method.accomodatePathSubresources("v1/{+var123}/v2", "v1/val/v2"));
110133
}
111134

112135
@Test
113136
public void accomodatePathSubresources_camelCaseToken() {
114137
// camelCase token should be converted to snake_case
115-
assertEquals("projects/{my_project=foo}/zones", Method.accomodatePathSubresources("projects/{+myProject}/zones", "projects/foo/zones"));
138+
assertEquals(
139+
"projects/{my_project=foo}/zones",
140+
Method.accomodatePathSubresources("projects/{+myProject}/zones", "projects/foo/zones"));
116141
}
117142

118143
@Test
119144
public void accomodatePathSubresources_noMatchDueToHyphen() {
120145
// {+foo-bar} does not match {+[a-zA-Z0-9]+}
121-
assertEquals("projects/{+foo-bar}/zones", Method.accomodatePathSubresources("projects/{+foo-bar}/zones", "projects/{+foo-bar}/zones"));
146+
assertEquals(
147+
"projects/{+foo-bar}/zones",
148+
Method.accomodatePathSubresources(
149+
"projects/{+foo-bar}/zones", "projects/{+foo-bar}/zones"));
122150
}
123151
}

0 commit comments

Comments
 (0)