Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
fr.speekha.httpmocker.sax.XmlSerialization.kt Maven / Gradle / Ivy
/*
* Copyright 2019-2021 David Blanc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fr.speekha.httpmocker.sax
import fr.speekha.httpmocker.model.Matcher
import fr.speekha.httpmocker.model.NamedParameter
import fr.speekha.httpmocker.model.NetworkError
import fr.speekha.httpmocker.model.RequestTemplate
import fr.speekha.httpmocker.model.ResponseDescriptor
import fr.speekha.httpmocker.serialization.BODY
import fr.speekha.httpmocker.serialization.CODE
import fr.speekha.httpmocker.serialization.DELAY
import fr.speekha.httpmocker.serialization.ERROR
import fr.speekha.httpmocker.serialization.EXACT_MATCH
import fr.speekha.httpmocker.serialization.EXCEPTION_TYPE
import fr.speekha.httpmocker.serialization.HEADER
import fr.speekha.httpmocker.serialization.HOST
import fr.speekha.httpmocker.serialization.MEDIA_TYPE
import fr.speekha.httpmocker.serialization.METHOD
import fr.speekha.httpmocker.serialization.PARAM
import fr.speekha.httpmocker.serialization.PATH
import fr.speekha.httpmocker.serialization.PORT
import fr.speekha.httpmocker.serialization.PROTOCOL
import fr.speekha.httpmocker.serialization.REQUEST
import fr.speekha.httpmocker.serialization.RESPONSE
import fr.speekha.httpmocker.serialization.URL
internal fun List.toXml() = XML_PREFACE + writeTags("scenarios", 0) {
toXml { it.toXml(1) }
}
private fun Matcher.toXml(indent: Int): String = writeTags("case", indent) {
val subIndent = indent + 1
writeTagList(
request.toXml(subIndent),
response?.toXml(subIndent).orEmpty(),
error?.toXml(subIndent).orEmpty()
)
}
private fun RequestTemplate.toXml(indentation: Int): String =
writeTags(REQUEST, indentation, exactMatchAttribute()) {
val subIndentation = indentation + 1
writeTagList(
writeUrl(getUrlAttributes(), params, subIndentation),
writeHeaders(headers, subIndentation),
if (body.isNullOrEmpty()) "" else writeCData(BODY, subIndentation, body = body)
)
}
private fun RequestTemplate.getUrlAttributes(): List> = listOf(
PROTOCOL to protocol,
METHOD to method,
HOST to host,
PORT to port,
PATH to path
)
private fun RequestTemplate.exactMatchAttribute() =
listOf(EXACT_MATCH to true).takeIf { exactMatch } ?: emptyList()
private fun ResponseDescriptor.toXml(indentation: Int): String = writeTags(
RESPONSE,
indentation,
listOf(DELAY to delay, CODE to code, MEDIA_TYPE to mediaType)
) {
val subIndentation = indentation + 1
writeTagList(
writeHeaders(headers, subIndentation),
writeCData("body", subIndentation, listOf("file" to bodyFile), body)
)
}
private fun NetworkError.toXml(indent: Int): String = writeCData(
tag = ERROR,
indentation = indent,
attributes = listOf(EXCEPTION_TYPE to exceptionType),
body = message
)
private fun writeUrl(
attributes: List>,
params: List,
indent: Int
): String = if (attributes.any { it.second != null } || params.isNotEmpty()) {
writeTags(URL, indent, attributes) { params.toXml(indent + 1) }
} else {
""
}
private fun writeHeaders(headers: List, indent: Int): String = if (headers.isEmpty()) {
""
} else {
headers.toXml { it.toXml(indent) }
}
private fun NamedParameter.toXml(indent: Int): String =
writeCData(HEADER, indent, listOf("name" to name), value)
private fun List.toXml(indent: Int): String = toXml {
writeCData(PARAM, indent, listOf("name" to it.name), it.value)
}
private fun writeTags(
tag: String,
indentation: Int,
attributes: List> = emptyList(),
body: () -> String?
): String {
val content = body()
val processedContent =
if (content.isNullOrEmpty()) null else "\n$content\n${indent(indentation)}"
return writeTag(tag, indentation, attributes, processedContent)
}
private fun writeTag(
tag: String,
indentation: Int,
attributes: List> = emptyList(),
body: String? = null
): String = if (body != null || attributes.filter { it.second != null }.isNotEmpty()) {
StringBuilder(indent(indentation))
.append("<")
.append(tag)
.append(
attributes.filter { it.second != null }
.joinToString("") { (name, value) -> " $name=\"$value\"" }
)
.append(body?.let { ">$it$tag>" } ?: " />").toString()
} else {
""
}
private fun Iterable.toXml(format: (T) -> String? = { it?.toString() }): String =
mapNotNull(format)
.filter { it.isNotEmpty() }
.joinToString("\n")
private fun writeTagList(
vararg tags: T,
format: (T) -> String? = { it?.toString() }
): String = tags.map { it }.toXml(format)
private fun writeCData(
tag: String,
indentation: Int,
attributes: List> = emptyList(),
body: String? = null
): String {
val formatBody = if (body?.contains("[<>]".toRegex()) == true) "" else body
return StringBuilder(indent(indentation))
.append("<")
.append(tag)
.append(
attributes.filter { it.second != null }
.joinToString("") { (name, value) -> " $name=\"$value\"" }
)
.append(body?.let { ">$formatBody$tag>" } ?: " />").toString()
}
private fun indent(spaces: Int) = " ".repeat(spaces * SPACE_PER_TAB)
private fun String?.orEmpty() = this ?: ""
private const val XML_PREFACE = "\n"
private const val SPACE_PER_TAB: Int = 4