package io.github.azagniotov.stubby4j.yaml; import io.github.azagniotov.stubby4j.stubs.StubbableAuthorizationType; import io.github.azagniotov.stubby4j.utils.FileUtils; import org.eclipse.jetty.http.HttpMethod; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; /** * Please refer to the accompanied unit tests for usage examples. */ public final class YAMLBuilder { private static final String TWO_SPACE = String.format("%1$2s", ""); private static final String THREE_SPACE = String.format("%1$3s", ""); private static final String SIX_SPACE = String.format("%s%s", THREE_SPACE, THREE_SPACE); private static final String NINE_SPACE = String.format("%s%s", SIX_SPACE, THREE_SPACE); private static final String TWELVE_SPACE = String.format("%s%s", NINE_SPACE, THREE_SPACE); private final static String REQUEST = String.format("-%s%s", TWO_SPACE, "request:"); private final static String RESPONSE = String.format("%s%s", THREE_SPACE, "response:"); private final static String HEADERS = String.format("%s%s", SIX_SPACE, "headers:"); private final static String SEQUENCE_RESPONSE_HEADERS = String.format("%s%s", NINE_SPACE, "headers: "); private final static String QUERY = String.format("%s%s", SIX_SPACE, "query:"); private final static String METHOD = String.format("%s%s", SIX_SPACE, "method: "); private final static String TEMP_METHOD_PLACEHOLDER_TOKEN = "METHOD_TOKEN"; private final static String STATUS = String.format("%s%s", SIX_SPACE, "status: "); private final static String SEQUENCE_RESPONSE_STATUS = String.format("%s-%s%s", SIX_SPACE, TWO_SPACE, "status: "); private final static String FILE = String.format("%s%s", SIX_SPACE, "file: "); private final static String SEQUENCE_RESPONSE_FILE = String.format("%s%s", NINE_SPACE, "file: "); private final static String URL = String.format("%s%s", SIX_SPACE, "url: "); private final static String ONELINEPOST = String.format("%s%s", SIX_SPACE, "post: "); private final static String MULTILINEPOST = String.format("%s%s%s", SIX_SPACE, "post: >", FileUtils.BR); private final static String ONELINEBODY = String.format("%s%s", SIX_SPACE, "body: "); private final static String SEQUENCE_RESPONSE_ONELINEBODY = String.format("%s%s", NINE_SPACE, "body: "); private final static String MULTILINEBODY = String.format("%s%s%s", SIX_SPACE, "body: >", FileUtils.BR); private final static String SEQUENCE_RESPONSE_MULTILINEBODY = String.format("%s%s%s", NINE_SPACE, "body: >", FileUtils.BR); private final static String NL = FileUtils.BR; private final static String REQUEST_HEADERS_KEY = String.format("%s-%s", REQUEST, HEADERS); private final static String REQUEST_QUERY_KEY = String.format("%s-%s", REQUEST, QUERY); private final static String RESPONSE_HEADERS_KEY = String.format("%s-%s", RESPONSE, HEADERS); private final static String RESPONSE_QUERY_KEY = String.format("%s-%s", RESPONSE, QUERY); private static final StringBuilder REQUEST_STRING_BUILDER = new StringBuilder(); private static final StringBuilder RESPONSE_STRING_BUILDER = new StringBuilder(); final Set<String> storedStubbedMethods = new LinkedHashSet<>(); final Set<String> unusedNodes = new HashSet<String>() {{ add(REQUEST_HEADERS_KEY); add(REQUEST_QUERY_KEY); add(RESPONSE_HEADERS_KEY); add(RESPONSE_QUERY_KEY); add(RESPONSE_QUERY_KEY); }}; public YAMLBuilder() { } public Request newStubbedRequest() { return new Request(); } public final class Request { public Request() { REQUEST_STRING_BUILDER.setLength(0); REQUEST_STRING_BUILDER.append(REQUEST).append(NL); } public Request withMethodGet() { return appendTemporaryMethodPlaceholderStoreMethod(HttpMethod.GET.asString()); } public Request withMethodPut() { return appendTemporaryMethodPlaceholderStoreMethod(HttpMethod.PUT.asString()); } public Request withMethodPost() { return appendTemporaryMethodPlaceholderStoreMethod(HttpMethod.POST.asString()); } public Request withMethodHead() { return appendTemporaryMethodPlaceholderStoreMethod(HttpMethod.HEAD.asString()); } public Request withUrl(final String value) { REQUEST_STRING_BUILDER.append(URL).append(value).append(NL); return this; } private Request appendTemporaryMethodPlaceholderStoreMethod(final String methodName) { if (REQUEST_STRING_BUILDER.indexOf(METHOD) == -1) { REQUEST_STRING_BUILDER.append(METHOD).append(TEMP_METHOD_PLACEHOLDER_TOKEN).append(NL); } storedStubbedMethods.add(methodName); return this; } public Request withHeaders(final String key, final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, key); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Request withHeaderContentType(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "content-type"); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Request withHeaderContentLength(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "content-length"); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Request withHeaderContentLanguage(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "content-language"); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Request withHeaderContentEncoding(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "content-encoding"); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Request withHeaderAuthorizationBasic(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, StubbableAuthorizationType.BASIC.asYAMLProp()); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Request withHeaderAuthorizationBearer(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, StubbableAuthorizationType.BEARER.asYAMLProp()); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Request withHeaderAuthorizationCustom(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, StubbableAuthorizationType.CUSTOM.asYAMLProp()); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } private void checkHeadersNodeRequired() { if (unusedNodes.contains(REQUEST_HEADERS_KEY)) { REQUEST_STRING_BUILDER.append(HEADERS).append(NL); unusedNodes.remove(REQUEST_HEADERS_KEY); } } public Request withLiteralPost(final String post) { REQUEST_STRING_BUILDER.append(ONELINEPOST).append(post).append(NL); return this; } public Request withFoldedPost(final String post) { final String tabbedPost = String.format("%s%s", NINE_SPACE, post); REQUEST_STRING_BUILDER.append(MULTILINEPOST).append(tabbedPost).append(NL); return this; } public Request withFile(final String value) { REQUEST_STRING_BUILDER.append(FILE).append(value).append(NL); return this; } public Request withQuery(final String key, final String value) { if (unusedNodes.contains(REQUEST_QUERY_KEY)) { REQUEST_STRING_BUILDER.append(QUERY).append(NL); unusedNodes.remove(REQUEST_QUERY_KEY); } final String tabbedKey = String.format("%s%s: ", NINE_SPACE, key); REQUEST_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Response newStubbedResponse() { return new Response(); } public String toString() { return REQUEST_STRING_BUILDER.toString(); } } public final class Response { public Response() { RESPONSE_STRING_BUILDER.setLength(0); RESPONSE_STRING_BUILDER.append(RESPONSE).append(NL); } public Response withLineBreak() { RESPONSE_STRING_BUILDER.append(NL); return this; } public Response withStatus(final String value) { RESPONSE_STRING_BUILDER.append(STATUS).append(value).append(NL); return this; } public Response withSequenceResponseStatus(final String value) { RESPONSE_STRING_BUILDER.append(SEQUENCE_RESPONSE_STATUS).append(value).append(NL); return this; } public Response withFile(final String value) { RESPONSE_STRING_BUILDER.append(FILE).append(value).append(NL); return this; } public Response withSequenceResponseFile(final String value) { RESPONSE_STRING_BUILDER.append(SEQUENCE_RESPONSE_FILE).append(value).append(NL); return this; } public Response withLiteralBody(final String body) { RESPONSE_STRING_BUILDER.append(ONELINEBODY).append(body).append(NL); return this; } public Response withSequenceResponseLiteralBody(final String body) { RESPONSE_STRING_BUILDER.append(SEQUENCE_RESPONSE_ONELINEBODY).append(body).append(NL); return this; } public Response withFoldedBody(final String body) { final String tabbedBody = String.format("%s%s", NINE_SPACE, body); RESPONSE_STRING_BUILDER.append(MULTILINEBODY).append(tabbedBody).append(NL); return this; } public Response withSequenceResponseFoldedBody(final String body) { final String tabbedBody = String.format("%s%s", TWELVE_SPACE, body); RESPONSE_STRING_BUILDER.append(SEQUENCE_RESPONSE_MULTILINEBODY).append(tabbedBody).append(NL); return this; } public Response withHeaders(final String key, final String value) { if (unusedNodes.contains(RESPONSE_HEADERS_KEY)) { RESPONSE_STRING_BUILDER.append(HEADERS).append(NL); unusedNodes.remove(RESPONSE_HEADERS_KEY); } final String tabbedKey = String.format("%s%s: ", NINE_SPACE, key); RESPONSE_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Response withHeaderContentType(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "content-type"); RESPONSE_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Response withHeaderPragma(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "pragma"); RESPONSE_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Response withHeaderContentLength(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "content-length"); RESPONSE_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Response withHeaderContentLanguage(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "content-language"); RESPONSE_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Response withHeaderContentEncoding(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "content-encoding"); RESPONSE_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public Response withHeaderLocation(final String value) { checkHeadersNodeRequired(); final String tabbedKey = String.format("%s%s: ", NINE_SPACE, "location"); RESPONSE_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } private void checkHeadersNodeRequired() { if (unusedNodes.contains(RESPONSE_HEADERS_KEY)) { RESPONSE_STRING_BUILDER.append(HEADERS).append(NL); unusedNodes.remove(RESPONSE_HEADERS_KEY); } } public Response withSequenceResponseHeaders(final String key, final String value) { RESPONSE_STRING_BUILDER.append(SEQUENCE_RESPONSE_HEADERS).append(NL); final String tabbedKey = String.format("%s%s: ", TWELVE_SPACE, key); RESPONSE_STRING_BUILDER.append(tabbedKey).append(value).append(NL); return this; } public String build() { final String rawRequestString = REQUEST_STRING_BUILDER.toString(); final String cleansedRequestString = rawRequestString.replaceAll(TEMP_METHOD_PLACEHOLDER_TOKEN, storedStubbedMethods.toString()); final String yaml = String.format("%s%s%s", cleansedRequestString, NL, RESPONSE_STRING_BUILDER.toString()).trim(); unusedNodes.clear(); unusedNodes.add(REQUEST_HEADERS_KEY); unusedNodes.add(REQUEST_QUERY_KEY); unusedNodes.add(RESPONSE_HEADERS_KEY); unusedNodes.add(RESPONSE_QUERY_KEY); storedStubbedMethods.clear(); return yaml; } } }