now use ??? and allow infix notiation for two optional values

This commit is contained in:
Michael Hoennig 2024-11-01 16:32:51 +01:00
parent 82900d7a80
commit bd9c79a39d
4 changed files with 37 additions and 29 deletions

View File

@ -69,7 +69,6 @@ public abstract class ScenarioTest extends ContextBasedTest {
@AfterEach @AfterEach
void cleanup() { // final TestInfo testInfo void cleanup() { // final TestInfo testInfo
properties.clear(); properties.clear();
// FIXME: Delete all aliases as well to force HTTP GET queries in each scenario?
testReport.close(); testReport.close();
} }

View File

@ -1,5 +1,7 @@
package net.hostsharing.hsadminng.hs.office.scenarios; package net.hostsharing.hsadminng.hs.office.scenarios;
import org.apache.commons.lang3.StringUtils;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
@ -8,13 +10,15 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class TemplateResolver { public class TemplateResolver {
private final static Pattern pattern = Pattern.compile(",\\s*([}\\]])", Pattern.MULTILINE);
private final static Pattern pattern = Pattern.compile(",(\\s*})", Pattern.MULTILINE);
private static final String IF_NOT_FOUND_SYMBOL = "???";
enum PlaceholderPrefix { enum PlaceholderPrefix {
RAW('%') { RAW('%') {
@Override @Override
String convert(final Object value) { String convert(final Object value) {
return value.toString(); return value != null ? value.toString() : "";
} }
}, },
JSON_QUOTED('$'){ JSON_QUOTED('$'){
@ -26,7 +30,7 @@ public class TemplateResolver {
URI_ENCODED('&'){ URI_ENCODED('&'){
@Override @Override
String convert(final Object value) { String convert(final Object value) {
return URLEncoder.encode(value.toString(), StandardCharsets.UTF_8); return value != null ? URLEncoder.encode(value.toString(), StandardCharsets.UTF_8) : "";
} }
}; };
@ -59,21 +63,26 @@ public class TemplateResolver {
String resolve() { String resolve() {
final var resolved = copy(); final var resolved = copy();
final var withoutDroppedLines = removeDroppedLinkes(resolved); final var withoutDroppedLines = dropLinesWithNullProperties(resolved);
final var result = removeSpareCommas(withoutDroppedLines); final var result = removeDanglingCommas(withoutDroppedLines);
return result; return result;
} }
private static String removeSpareCommas(final String withoutDroppedLines) { private static String removeDanglingCommas(final String withoutDroppedLines) {
return pattern.matcher(withoutDroppedLines).replaceAll("$1"); return pattern.matcher(withoutDroppedLines).replaceAll("$1");
} }
private String removeDroppedLinkes(final String text) { private String dropLinesWithNullProperties(final String text) {
return Arrays.stream(text.split("\n")) return Arrays.stream(text.split("\n"))
.filter(line -> !line.contains("<<<drop line>>")) .filter(TemplateResolver::keepLine)
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
} }
private static boolean keepLine(final String line) {
final var trimmed = line.trim();
return !trimmed.endsWith("null,") && !trimmed.endsWith("null");
}
private String copy() { private String copy() {
while (hasMoreChars()) { while (hasMoreChars()) {
if (PlaceholderPrefix.contains(currentChar()) && nextChar() == '{') { if (PlaceholderPrefix.contains(currentChar()) && nextChar() == '{') {
@ -113,23 +122,21 @@ public class TemplateResolver {
} }
private Object propVal(final String name) { private Object propVal(final String name) {
if (name.endsWith("??")) { if (name.endsWith(IF_NOT_FOUND_SYMBOL)) {
final String pureName = name.substring(0, name.length() - "??".length()); final String pureName = name.substring(0, name.length() - IF_NOT_FOUND_SYMBOL.length());
final var val = properties.get(pureName); return properties.get(pureName);
} else if (name.contains(IF_NOT_FOUND_SYMBOL)) {
final var parts = StringUtils.split(name, IF_NOT_FOUND_SYMBOL);
final var head = properties.get(parts[0]);
final var tail = properties.get(parts[1]);
return head != null ? head : tail; // FIXME: What if tail is null as well?
} else {
final var val = properties.get(name);
if (val == null) { if (val == null) {
return "<<<drop line>>"; throw new IllegalStateException("Missing required property: " + name);
} }
return val; return val;
} }
if (name.endsWith("?")) {
final String pureName = name.substring(0, name.length() - "?".length());
return properties.get(pureName);
}
final var val = properties.get(name);
if (val == null) {
throw new IllegalStateException("Missing required property: " + name);
}
return val;
} }
private void skipChar(final char expectedChar) { private void skipChar(final char expectedChar) {

View File

@ -57,7 +57,9 @@ public class TestReport {
} }
public void close() { public void close() {
markdownReport.close(); if (markdownReport != null) {
markdownReport.close();
}
} }
private static Object orderNumber(final Method method) { private static Object orderNumber(final Method method) {

View File

@ -28,13 +28,13 @@ public class CreatePartner extends UseCase<CreatePartner> {
"Even in production data we expect this query to return just a single result." // TODO.impl: add constraint? "Even in production data we expect this query to return just a single result." // TODO.impl: add constraint?
); );
obtain("Partner-Person", () -> obtain("Person: %{tradeName???%{givenName???} %{familyName???}}", () ->
httpPost("/api/hs/office/persons", usingJsonBody(""" httpPost("/api/hs/office/persons", usingJsonBody("""
{ {
"personType": ${personType}, "personType": ${personType???},
"tradeName": ${tradeName??}, "tradeName": ${tradeName???},
"givenName": ${givenName??}, "givenName": ${givenName???},
"familyName": ${familyName??} "familyName": ${familyName???}
} }
""")) """))
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON) .expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
@ -57,7 +57,7 @@ public class CreatePartner extends UseCase<CreatePartner> {
"partnerNumber": ${partnerNumber}, "partnerNumber": ${partnerNumber},
"partnerRel": { "partnerRel": {
"anchorUuid": ${Person: Hostsharing eG}, "anchorUuid": ${Person: Hostsharing eG},
"holderUuid": ${Partner-Person}, "holderUuid": ${Person: %{tradeName???%{givenName???} %{familyName???}}},
"contactUuid": ${Contact: %{contactCaption}} "contactUuid": ${Contact: %{contactCaption}}
}, },
"details": { "details": {