Skip to content

Commit

Permalink
Refactor UrlTemplate to support optional paths
Browse files Browse the repository at this point in the history
  • Loading branch information
Toilal committed Nov 23, 2016
1 parent 74b3413 commit a29ea72
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 65 deletions.
27 changes: 27 additions & 0 deletions docs/docs.md
Expand Up @@ -456,6 +456,33 @@ public class MyPage extends FluentPage {
} }
``` ```


It's possible to define parameters in FluentPage url using `{[?][/path/]parameter}` syntax.
If it starts with `?`, it means that the parameter is optional. Path can be included in the braces so it
is removed when parameter value is not defined.

```java
@PageUrl("/document/{document}{?/page/page}{?/format}")
public class DocumentPage extends FluentPage {
...
}
```

Parameter values are given in order to `isAt` and `go` methods.

```java
@Page
private DocumentPage page;

@Test
public void test() {
page.go(267) // go to "/document/267"
page.go(174, 3) // go to "/document/174/page/3"
page.go(124, 1, "pdf") // go to "/document/124/page/1/pdf"
page.go(124, null, "html") // go to "/document/124/html"
page.isAt(174, 3) // Assert that current url is "/document/174/page/3"
}
```

Create your own methods to easily fill out forms, go to another or whatever else may be needed in your test. Create your own methods to easily fill out forms, go to another or whatever else may be needed in your test.


```java ```java
Expand Down
Expand Up @@ -11,25 +11,25 @@
public class UrlParameter { public class UrlParameter {


private final String name; private final String name;
private boolean optional; private final String group;
private final String path;
private final String match;
private final boolean optional;


/**
* Creates a new parameter
*
* @param name parameter name
*/
public UrlParameter(final String name) {
this.name = name;
}


/** /**
* Creates a new parameter * Creates a new parameter
* *
* @param name parameter name * @param name parameter name
* @param group parameter match group
* @param path parameter path
* @param optional optional parameter * @param optional optional parameter
*/ */
public UrlParameter(final String name, final boolean optional) { public UrlParameter(final String name, final String group, final String path, final String match, final boolean optional) {
this.name = name; this.name = name;
this.group = group;
this.path = path;
this.match = match;
this.optional = optional; this.optional = optional;
} }


Expand Down
Expand Up @@ -15,13 +15,11 @@
* A simple template engine for URL parameters. * A simple template engine for URL parameters.
*/ */
public class UrlTemplate { public class UrlTemplate {
private static final Pattern FORMAT_REGEX = Pattern.compile("\\{(.+?)\\}"); private static final Pattern PARAM_REGEX = Pattern.compile("\\{(.+?)\\}");
private static final Pattern FORMAT_REGEX_OPTIONAL = Pattern.compile("/?\\{\\?(.+?)\\}");
private final String template; private final String template;


private final List<String> parameterNames = new ArrayList<>(); private final List<String> parameterNames = new ArrayList<>();
private final Map<String, UrlParameter> parameters = new LinkedHashMap<>(); private final Map<String, UrlParameter> parameters = new LinkedHashMap<>();
private final Map<String, String> parameterGroups = new LinkedHashMap<>();
private final Map<UrlParameter, String> properties = new LinkedHashMap<>(); private final Map<UrlParameter, String> properties = new LinkedHashMap<>();


/** /**
Expand All @@ -31,17 +29,35 @@ public class UrlTemplate {
*/ */
public UrlTemplate(final String template) { public UrlTemplate(final String template) {
this.template = template; this.template = template;
final Matcher matcher = FORMAT_REGEX.matcher(template); final Matcher matcher = PARAM_REGEX.matcher(template);
while (matcher.find()) { while (matcher.find()) {
final String match = matcher.group(0);
final String group = matcher.group(1); final String group = matcher.group(1);
final UrlParameter parameter;
if (group.startsWith("?")) { final boolean optional = group.startsWith("?");
parameter = new UrlParameter(group.substring(1), true); final int lastIndex = group.lastIndexOf('/');

final String parameterName;
final String path;
if (lastIndex > -1 && lastIndex < group.length()) {
path = group.substring(optional ? 1 : 0, lastIndex + 1);
parameterName = group.substring(lastIndex + 1);
} else if (group.startsWith("?")) {
path = null;
parameterName = group.substring(1);
} else { } else {
parameter = new UrlParameter(group, false); path = null;
parameterName = group;
}

final UrlParameter parameter = new UrlParameter(parameterName, group, path, match, optional);

if (parameters.containsKey(parameter.getName())) {
throw new IllegalStateException(
String.format("Multiple parameters are defined with the same name (%s).", parameter.getName()));
} }

parameters.put(parameter.getName(), parameter); parameters.put(parameter.getName(), parameter);
parameterGroups.put(parameter.getName(), Pattern.quote(group));
parameterNames.add(parameter.getName()); parameterNames.add(parameter.getName());
} }
} }
Expand Down Expand Up @@ -121,28 +137,29 @@ public String render() {
String rendered = template; String rendered = template;
for (final UrlParameter parameter : parameters.values()) { for (final UrlParameter parameter : parameters.values()) {
final Object value = properties.get(parameter); final Object value = properties.get(parameter);
if (value == null) { final String group = parameter.getGroup();
if (parameter.isOptional()) { if (value == null && !parameter.isOptional()) {
rendered = rendered.replaceAll(String.format("/\\{%s\\}", parameterGroups.get(parameter.getName())), ""); throw new IllegalArgumentException(String.format("Value for parameter %s is missing.", parameter));
} else {
throw new IllegalArgumentException(String.format("Value for parameter %s is missing.", parameter));
}
} else { } else {
rendered = rendered rendered = rendered.replaceAll(Pattern.quote(String.format("{%s}", group)),
.replaceAll(String.format("\\{%s\\}", parameterGroups.get(parameter.getName())), String.valueOf(value)); buildRenderReplacement(parameter, value == null ? null : String.valueOf(value)));
} }


} return rendered;
}

private String buildRenderReplacement(final UrlParameter parameter, final String value) {
if (value == null || value.isEmpty()) {
return "";
} }
return rendered; final String path = parameter.getPath();
if (path != null) {
return path + value;
}
return value;
} }


/** private String buildParsePattern() {
* Get properties from string
*
* @param input string
* @return properties
*/
public ParsedUrlTemplate parse(final String input) {
String fixedTemplate = template; String fixedTemplate = template;
if (fixedTemplate.startsWith("/")) { if (fixedTemplate.startsWith("/")) {
fixedTemplate = fixedTemplate.replaceFirst("/", "/?"); fixedTemplate = fixedTemplate.replaceFirst("/", "/?");
Expand All @@ -156,6 +173,25 @@ public ParsedUrlTemplate parse(final String input) {
fixedTemplate = fixedTemplate + "/?"; fixedTemplate = fixedTemplate + "/?";
} }



for (final UrlParameter parameter : parameters.values()) {
String replacementPattern = "%s([^/]+)";
if (parameter.isOptional()) {
replacementPattern = "(?:" + replacementPattern + ")?";
}
fixedTemplate = fixedTemplate.replaceAll(Pattern.quote(parameter.getMatch()), String.format(replacementPattern, parameter.getPath() == null ? "" : parameter.getPath()));
}

return fixedTemplate;
}

/**
* Get properties from string
*
* @param input string
* @return properties
*/
public ParsedUrlTemplate parse(final String input) {
String noQueryInput = input; String noQueryInput = input;
List<NameValuePair> queryParameters = new ArrayList<>(); List<NameValuePair> queryParameters = new ArrayList<>();


Expand All @@ -168,8 +204,7 @@ public ParsedUrlTemplate parse(final String input) {
throw new IllegalArgumentException(e.getMessage(), e); throw new IllegalArgumentException(e.getMessage(), e);
} }


final Pattern pathRegex = Pattern.compile(fixedTemplate.replaceAll(FORMAT_REGEX_OPTIONAL.pattern(), "(?:/([^/]+))?") final Pattern pathRegex = Pattern.compile(buildParsePattern());
.replaceAll(FORMAT_REGEX.pattern(), "([^/]+)"));


final Matcher matcher = pathRegex.matcher(noQueryInput); final Matcher matcher = pathRegex.matcher(noQueryInput);
final boolean matches = matcher.matches(); final boolean matches = matcher.matches();
Expand Down

0 comments on commit a29ea72

Please sign in to comment.