feature/use-case-acceptance-tests-2 #117
@ -12,6 +12,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.TestInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.testcontainers.shaded.org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
@ -35,7 +36,7 @@ public abstract class ScenarioTest extends ContextBasedTest {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return uuid.toString();
|
||||
return ObjectUtils.toString(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,49 @@
|
||||
package net.hostsharing.hsadminng.hs.office.scenarios;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
public class TemplateResolver {
|
||||
|
||||
enum PlaceholderPrefix {
|
||||
RAW('%') {
|
||||
@Override
|
||||
String convert(final Object value) {
|
||||
return value.toString();
|
||||
}
|
||||
},
|
||||
JSON_QUOTED('$'){
|
||||
@Override
|
||||
String convert(final Object value) {
|
||||
return jsonQuoted(value);
|
||||
}
|
||||
},
|
||||
URI_ENCODED('&'){
|
||||
@Override
|
||||
String convert(final Object value) {
|
||||
return URLEncoder.encode(value.toString(), StandardCharsets.UTF_8);
|
||||
}
|
||||
};
|
||||
|
||||
private final char prefixChar;
|
||||
|
||||
PlaceholderPrefix(final char prefixChar) {
|
||||
this.prefixChar = prefixChar;
|
||||
}
|
||||
|
||||
static boolean contains(final char givenChar) {
|
||||
return Arrays.stream(values()).anyMatch(p -> p.prefixChar == givenChar);
|
||||
}
|
||||
|
||||
static PlaceholderPrefix ofPrefixChar(final char givenChar) {
|
||||
return Arrays.stream(values()).filter(p -> p.prefixChar == givenChar).findFirst().orElseThrow();
|
||||
}
|
||||
|
||||
abstract String convert(final Object value);
|
||||
}
|
||||
|
||||
private final String template;
|
||||
private final Map<String, Object> properties;
|
||||
private final StringBuilder resolved = new StringBuilder();
|
||||
@ -21,7 +61,7 @@ public class TemplateResolver {
|
||||
|
||||
private void copy() {
|
||||
while (hasMoreChars()) {
|
||||
if ((currentChar() == '$' || currentChar() == '%') && nextChar() == '{') {
|
||||
if (PlaceholderPrefix.contains(currentChar()) && nextChar() == '{') {
|
||||
startPlaceholder(currentChar());
|
||||
} else {
|
||||
resolved.append(fetchChar());
|
||||
@ -41,7 +81,7 @@ public class TemplateResolver {
|
||||
if (currentChar() == '}') {
|
||||
--nested;
|
||||
placeholder.append(fetchChar());
|
||||
} else if ((currentChar() == '$' || currentChar() == '%') && nextChar() == '{') {
|
||||
} else if (PlaceholderPrefix.contains (currentChar()) && nextChar() == '{') {
|
||||
++nested;
|
||||
placeholder.append(fetchChar());
|
||||
} else {
|
||||
@ -50,11 +90,9 @@ public class TemplateResolver {
|
||||
}
|
||||
final var name = new TemplateResolver(placeholder.toString(), properties).resolve();
|
||||
final var value = propVal(name);
|
||||
if ( intro == '%') {
|
||||
resolved.append(value);
|
||||
} else {
|
||||
resolved.append(optionallyQuoted(value));
|
||||
}
|
||||
resolved.append(
|
||||
PlaceholderPrefix.ofPrefixChar(intro).convert(value)
|
||||
);
|
||||
skipChar('}');
|
||||
}
|
||||
|
||||
@ -104,7 +142,7 @@ public class TemplateResolver {
|
||||
return template.charAt(position+1);
|
||||
}
|
||||
|
||||
private static String optionallyQuoted(final Object value) {
|
||||
private static String jsonQuoted(final Object value) {
|
||||
return switch (value) {
|
||||
case Boolean bool -> bool.toString();
|
||||
case Number number -> number.toString();
|
||||
@ -112,27 +150,4 @@ public class TemplateResolver {
|
||||
default -> "\"" + value + "\"";
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(
|
||||
new TemplateResolver("""
|
||||
etwas davor,
|
||||
|
||||
${einfacher Platzhalter},
|
||||
${verschachtelter %{Name}},
|
||||
|
||||
und nochmal ohne Quotes:
|
||||
|
||||
%{einfacher Platzhalter},
|
||||
%{verschachtelter %{Name}},
|
||||
|
||||
etwas danach.
|
||||
""",
|
||||
Map.ofEntries(
|
||||
Map.entry("Name", "placeholder"),
|
||||
Map.entry("einfacher Platzhalter", "simple placeholder"),
|
||||
Map.entry("verschachtelter placeholder", "nested placeholder")
|
||||
)).resolve());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
package net.hostsharing.hsadminng.hs.office.scenarios;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class TemplateResolverUnitTest {
|
||||
|
||||
@Test
|
||||
void resolveTemplate() {
|
||||
final var resolved = new TemplateResolver("""
|
||||
with optional JSON quotes:
|
||||
|
||||
${boolean},
|
||||
${numeric},
|
||||
${simple placeholder},
|
||||
${nested %{name}},
|
||||
${with-special-chars}
|
||||
|
||||
and without quotes:
|
||||
|
||||
%{boolean},
|
||||
%{numeric},
|
||||
%{simple placeholder},
|
||||
%{nested %{name}},
|
||||
%{with-special-chars}
|
||||
|
||||
and uri-encoded:
|
||||
|
||||
&{boolean},
|
||||
&{numeric},
|
||||
&{simple placeholder},
|
||||
&{nested %{name}},
|
||||
&{with-special-chars}
|
||||
""",
|
||||
Map.ofEntries(
|
||||
Map.entry("name", "placeholder"),
|
||||
Map.entry("boolean", true),
|
||||
Map.entry("numeric", 42),
|
||||
Map.entry("simple placeholder", "einfach"),
|
||||
Map.entry("nested placeholder", "verschachtelt"),
|
||||
Map.entry("with-special-chars", "3&3 AG")
|
||||
)).resolve();
|
||||
|
||||
assertThat(resolved).isEqualTo("""
|
||||
with optional JSON quotes:
|
||||
|
||||
true,
|
||||
42,
|
||||
"einfach",
|
||||
"verschachtelt",
|
||||
"3&3 AG"
|
||||
|
||||
and without quotes:
|
||||
|
||||
true,
|
||||
42,
|
||||
einfach,
|
||||
verschachtelt,
|
||||
3&3 AG
|
||||
|
||||
and uri-encoded:
|
||||
|
||||
true,
|
||||
42,
|
||||
einfach,
|
||||
verschachtelt,
|
||||
3%263+AG
|
||||
""");
|
||||
}
|
||||
}
|
@ -120,7 +120,8 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpGet(final String uriPath) {
|
||||
public final HttpResponse httpGet(final String uriPathWithPlaceholders) {
|
||||
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders);
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.GET()
|
||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||
@ -132,7 +133,8 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpPost(final String uriPath, final JsonTemplate bodyJsonTemplate) {
|
||||
public final HttpResponse httpPost(final String uriPathWithPlaceholders, final JsonTemplate bodyJsonTemplate) {
|
||||
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders);
|
||||
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.POST(BodyPublishers.ofString(requestBody))
|
||||
@ -146,7 +148,8 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpPatch(final String uriPath, final JsonTemplate bodyJsonTemplate) {
|
||||
public final HttpResponse httpPatch(final String uriPathWithPlaceholders, final JsonTemplate bodyJsonTemplate) {
|
||||
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders);
|
||||
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.method(HttpMethod.PATCH.toString(), BodyPublishers.ofString(requestBody))
|
||||
@ -160,7 +163,8 @@ public abstract class UseCase<T extends UseCase<?>> {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public final HttpResponse httpDelete(final String uriPath) {
|
||||
public final HttpResponse httpDelete(final String uriPathWithPlaceholders) {
|
||||
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders);
|
||||
final var request = HttpRequest.newBuilder()
|
||||
.DELETE()
|
||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||
|
Loading…
Reference in New Issue
Block a user