Skip to content

Commit

Permalink
2024.0.5
Browse files Browse the repository at this point in the history
  • Loading branch information
toronik committed May 24, 2024
1 parent 7021edb commit ccc77b2
Show file tree
Hide file tree
Showing 20 changed files with 144 additions and 36 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ buildscript {
ext.kotlin_version = '1.9.22'
ext.klogging_version = '3.0.4'
ext.jacksonKt_version = '2.14.1'
ext.libVersion = '2024.0.4'
ext.libVersion = '2024.0.5'
repositories {
mavenCentral()
maven {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ package io.github.adven27.concordion.extensions.exam.core

import ch.qos.logback.classic.turbo.TurboFilter
import com.github.jknack.handlebars.Handlebars
import com.github.jknack.handlebars.ValueResolver
import com.github.jknack.handlebars.context.JavaBeanValueResolver
import com.github.jknack.handlebars.context.MapValueResolver
import com.github.jknack.handlebars.context.MethodValueResolver
import io.github.adven27.concordion.extensions.exam.core.handlebars.EvaluatorValueResolver
import io.github.adven27.concordion.extensions.exam.core.handlebars.HANDLEBARS
import io.github.adven27.concordion.extensions.exam.core.json.DefaultObjectMapperProvider
import io.github.adven27.concordion.extensions.exam.core.logger.LoggerLevelFilter
Expand Down Expand Up @@ -33,6 +38,7 @@ import java.util.function.Consumer

class ExamExtension(private vararg var plugins: ExamPlugin) : ConcordionExtension {
private var focusOnError: Boolean = true
private var enableLoggingFormatterExtension: Boolean = true
private var nodeMatcher: NodeMatcher = DEFAULT_NODE_MATCHER
private var skipDecider: SkipDecider = SkipDecider.NoSkip()

Expand Down Expand Up @@ -61,6 +67,12 @@ class ExamExtension(private vararg var plugins: ExamPlugin) : ConcordionExtensio
return this
}

@Suppress("unused")
fun withHandlebarResolvers(vararg resolvers: ValueResolver): ExamExtension {
HANDLEBAR_RESOLVERS = resolvers.toList().toTypedArray()
return this
}

@Suppress("unused")
fun withHandlebar(fn: Consumer<Handlebars>): ExamExtension {
fn.accept(HANDLEBARS)
Expand All @@ -82,6 +94,12 @@ class ExamExtension(private vararg var plugins: ExamPlugin) : ConcordionExtensio
return this
}

@Suppress("unused")
fun enableLoggingFormatterExtension(enabled: Boolean): ExamExtension {
enableLoggingFormatterExtension = enabled
return this
}

@Suppress("unused")
fun runOnlyExamplesWithPathsContains(vararg substrings: String): ExamExtension {
skipDecider = object : SkipDecider {
Expand Down Expand Up @@ -128,7 +146,9 @@ class ExamExtension(private vararg var plugins: ExamPlugin) : ConcordionExtensio

TopButtonExtension().addTo(ex)
// TocbotExtension().addTo(ex)
LoggingFormatterExtension().addTo(ex)
if (enableLoggingFormatterExtension) {
LoggingFormatterExtension().addTo(ex)
}
// ex.withThrowableListener(ErrorListener())
if (focusOnError) {
ex.withSpecificationProcessingListener(FocusOnErrorsListener())
Expand Down Expand Up @@ -160,6 +180,14 @@ class ExamExtension(private vararg var plugins: ExamPlugin) : ConcordionExtensio
"before" to Before()
)

@JvmField
var HANDLEBAR_RESOLVERS = arrayOf<ValueResolver>(
EvaluatorValueResolver.INSTANCE,
JavaBeanValueResolver.INSTANCE,
MethodValueResolver.INSTANCE,
MapValueResolver.INSTANCE
)

@JvmField
var JACKSON_2_OBJECT_MAPPER_PROVIDER: Jackson2ObjectMapperProvider = DefaultObjectMapperProvider()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.adven27.concordion.extensions.exam.core.commands

import io.github.adven27.concordion.extensions.exam.core.html.html
import org.concordion.api.AbstractCommand
import org.concordion.api.CommandCall
import org.concordion.api.Element
Expand All @@ -18,7 +19,7 @@ class EchoCommand : AbstractCommand() {
Check.isFalse(commandCall.hasChildCommands(), "Nesting commands inside an 'echo' is not supported")
val result = evaluator.evaluate(commandCall.expression)
val element = commandCall.element.takeUnless { it.localName == "td" && it.hasChildren() }
?: commandCall.element.childElements[0]
?: commandCall.html().deepestChild().el
if (result != null) {
element.appendText(result.toString())
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ open class EqCommand(val verifier: ContentVerifier) : AssertEqualsCommand() {
val verifier = verifier(command)
val await = AwaitConfig.build(command)
val html = command.html()
val expected = eval.resolve(html.text())
val expected = eval.resolve(html.deepestChild().text())
var lastFailed: Result<Content>? = null
val result = await?.let { c ->
runCatching {
Expand Down Expand Up @@ -57,10 +57,10 @@ open class EqCommand(val verifier: ContentVerifier) : AssertEqualsCommand() {
}
}

private fun actual(evaluator: Evaluator, command: CommandCall): String =
protected fun actual(evaluator: Evaluator, command: CommandCall): String =
objectToString(evaluator.evaluate(command.expression))

private fun renderError(error: Fail, await: AwaitConfig?) = errorMessage(
protected fun renderError(error: Fail, await: AwaitConfig?) = errorMessage(
message = await?.timeoutMessage(error) ?: error.details,
html = div("class" to "${error.type} failure")(
Html("del", error.expected, "class" to "expected"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.github.jknack.handlebars.Formatter
import com.github.jknack.handlebars.Handlebars
import com.github.jknack.handlebars.Helper
import com.github.jknack.handlebars.Options
import io.github.adven27.concordion.extensions.exam.core.ExamExtension.Companion.HANDLEBAR_RESOLVERS
import io.github.adven27.concordion.extensions.exam.core.handlebars.date.DateHelpers
import io.github.adven27.concordion.extensions.exam.core.handlebars.matchers.MatcherHelpers
import io.github.adven27.concordion.extensions.exam.core.handlebars.matchers.PLACEHOLDER_TYPE
Expand Down Expand Up @@ -46,9 +47,10 @@ class HelperMissing : Helper<Any?> {
}
}

@Suppress("SpreadOperator")
private fun Handlebars.resolve(eval: Any?, placeholder: String): Any? = compileInline(placeholder).let { template ->
HELPER_RESULTS.clear()
template.apply(Context.newBuilder(eval).resolver(EvaluatorValueResolver.INSTANCE).build()).let {
template.apply(Context.newBuilder(eval).resolver(*HANDLEBAR_RESOLVERS).build()).let {
if (HELPER_RESULTS.size == 1 && placeholder.singleHelper()) HELPER_RESULTS.single() else it
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,6 @@ enum class DateHelpers(
abstract operator fun invoke(context: Any?, options: Options): Any?

companion object {
private val AT = LocalDateTime.now()
val AT = LocalDateTime.now()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package io.github.adven27.concordion.extensions.exam.core.handlebars.matchers

import com.github.jknack.handlebars.Options
import io.github.adven27.concordion.extensions.exam.core.handlebars.ExamHelper
import io.github.adven27.concordion.extensions.exam.core.handlebars.date.DateHelpers
import io.github.adven27.concordion.extensions.exam.core.utils.DateFormattedAndWithin.Companion.PARAMS_SEPARATOR
import io.github.adven27.concordion.extensions.exam.core.utils.ldt
import io.github.adven27.concordion.extensions.exam.core.utils.parseDate
import io.github.adven27.concordion.extensions.exam.core.utils.toLocalDate
import io.github.adven27.concordion.extensions.exam.core.utils.toLocalDateTime
import java.time.LocalDate
import java.time.format.DateTimeFormatter
Expand Down Expand Up @@ -119,7 +120,7 @@ enum class MatcherHelpers(
) {
override fun invoke(context: Any?, options: Options): Any =
"\${${placeholderType(options.context)}-unit.matches:$name}$context" +
"$PARAMS_SEPARATOR${options.param(0, Date()).toLocalDateTime()}"
"$PARAMS_SEPARATOR${ldt(options.param(0, DateHelpers.AT))}"
},
formattedAs(
example = "{{formattedAs \"yyyy-MM-dd'T'hh:mm:ss\"}}",
Expand All @@ -138,7 +139,7 @@ enum class MatcherHelpers(
when (context) {
is Date -> DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(context.toLocalDateTime())
is String -> "\${${placeholderType(options.context)}-unit.matches:formattedAndWithin}ISO_LOCAL" +
"$PARAMS_SEPARATOR$context$PARAMS_SEPARATOR${options.param(0, Date()).toLocalDateTime()}"
"$PARAMS_SEPARATOR$context$PARAMS_SEPARATOR${ldt(options.param(0, DateHelpers.AT))}"

else -> "\${${placeholderType(options.context)}-unit.matches:formattedAs}ISO_LOCAL"
}
Expand All @@ -153,7 +154,7 @@ enum class MatcherHelpers(
is Date -> DateTimeFormatter.ISO_LOCAL_DATE.format(context.toLocalDateTime())
is String ->
"\${${placeholderType(options.context)}-unit.matches:formattedAndWithin}$ISO_LOCAL_DATE_FORMAT" +
"$PARAMS_SEPARATOR$context$PARAMS_SEPARATOR${options.param(0, Date()).toLocalDate()}"
"$PARAMS_SEPARATOR$context$PARAMS_SEPARATOR${ldt(options.param(0, DateHelpers.AT))}"

else -> "\${${placeholderType(options.context)}-unit.matches:formattedAs}$ISO_LOCAL_DATE_FORMAT"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import io.github.adven27.concordion.extensions.exam.core.utils.toDate
import java.time.LocalDate

/* ktlint-disable enum-entry-name-case */
@Suppress("EnumNaming", "EnumEntryNameCase")
@Suppress("EnumNaming", "EnumEntryNameCase", "MagicNumber")
enum class MiscHelpers(
override val example: String,
override val context: Map<String, Any?> = emptyMap(),
Expand Down Expand Up @@ -85,6 +85,15 @@ enum class MiscHelpers(
.recover { if (it is PathNotFoundException) null else throw it }
.getOrThrow()
},
math("{{math '+' 1 2}}", mapOf(), 3.0) {
override fun invoke(context: Any?, options: Options) = when (context.toString()) {
"+" -> options.params.reduce { acc, next -> acc.toString().toDouble() + next.toString().toDouble() }
"-" -> options.params.reduce { acc, next -> acc.toString().toDouble() - next.toString().toDouble() }
"*" -> options.params.reduce { acc, next -> acc.toString().toDouble() * next.toString().toDouble() }
"/" -> options.params.reduce { acc, next -> acc.toString().toDouble() / next.toString().toDouble() }
else -> error("Unsupported math operation: $context. Supported: +, - , *, /.")
}
},
prop("{{prop 'system.property' 'optional default'}}", mapOf(), "optional default") {
override fun invoke(context: Any?, options: Options) = System.getProperty(context.toString(), options.param(0))
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@ class Html(val el: Element) {
"style" to if (decorate) "text-decoration: underline grey dashed !important;" else ""
)

fun deepestChild(): Html {
var c = this
while (c.childs().isNotEmpty()) {
c = c.childs()[0]
}
return c
}

fun removeClass(name: String): Html {
el.addAttribute(
"class",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,10 @@ fun date(item: Any?, pattern: String? = null): Result<ZonedDateTime> = try {
} catch (expected: Exception) {
Result.failure(expected)
}

fun ldt(item: Any?): LocalDateTime = when (item) {
is ZonedDateTime -> item.toLocalDateTime()
is LocalDateTime -> item
is Date -> item.toLocalDateTime()
else -> item.toString().parseDate().toLocalDateTime()
}
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ open class RowComparator {
@Suppress("unused")
open class DbHelpers(protected val dbTester: DbTester) {

fun dbCount(context: Any, options: Options) = dbTester.connection.getRowCount(context.toString())

protected fun queryStringFrom(table: String, target: String, filter: Map<String, Any>): String =
dbTester.useStatement {
it.query(target, table, filter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.github.adven27.concordion.extensions.exam.db.commands

import io.github.adven27.concordion.extensions.exam.core.commands.ExamCommand.Context
import io.github.adven27.concordion.extensions.exam.core.html.Html
import io.github.adven27.concordion.extensions.exam.core.resolve
import io.github.adven27.concordion.extensions.exam.db.DbTester
import io.github.adven27.concordion.extensions.exam.db.builder.DataSetBuilder
import io.github.adven27.concordion.extensions.exam.db.builder.ExamTable
Expand All @@ -23,13 +24,18 @@ open class DbSetTableParser : DbSetCommand.Parser {

private fun table(context: Context): ITable {
val builder = DataSetBuilder()
val tableName = context.expression
val tableName = parseTableName(context)
context.el.let { parseCols(it) to parseValues(it) }.let { (cols, rows) ->
rows.forEach { row -> builder.newRowTo(tableName).withFields(cols.zip(row).toMap()).add() }
return ExamTable(tableFrom(builder.build(), tableName), context.eval)
}
}

private fun parseTableName(context: Context) = context.eval.resolve(
context.expression.takeUnless { it.isBlank() }
?: requireNotNull(context.el.childOrNull("caption")?.text()) { "Absent table name" }
)

private fun tableFrom(dataSet: IDataSet, tableName: String) =
if (dataSet.tableNames.isEmpty()) DefaultTable(tableName) else dataSet.getTable(tableName)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package io.github.adven27.concordion.extensions.exam.db.commands.check

import io.github.adven27.concordion.extensions.exam.core.commands.ExamCommand.Context
import io.github.adven27.concordion.extensions.exam.core.html.Html
import io.github.adven27.concordion.extensions.exam.core.resolve
import io.github.adven27.concordion.extensions.exam.db.DbTester.TableExpectation
import io.github.adven27.concordion.extensions.exam.db.builder.DataSetBuilder
import io.github.adven27.concordion.extensions.exam.db.builder.ExamTable
import io.github.adven27.concordion.extensions.exam.db.commands.DbCommand.Companion.DS
import io.github.adven27.concordion.extensions.exam.db.commands.DbCommand.Companion.ORDER_BY
import io.github.adven27.concordion.extensions.exam.db.commands.DbCommand.Companion.WHERE
import org.concordion.api.Evaluator
import org.dbunit.dataset.Column
import org.dbunit.dataset.DefaultTable
Expand Down Expand Up @@ -36,12 +39,18 @@ class DbCheckParser : DbCheckCommand.Parser {
caption = context.el.firstOrNull("caption")?.text(),
expectation = TableExpectation(
ds = context[DS],
table = table(context.expression, context.el, context.eval),
orderBy = context["orderBy"]?.split(",")?.map { it.trim() }?.toSet() ?: setOf(),
table = table(parseTableName(context), context.el, context.eval),
where = context[WHERE] ?: "",
orderBy = context[ORDER_BY]?.split(",")?.map { it.trim() }?.toSet() ?: setOf(),
await = context.awaitConfig
)
)

private fun parseTableName(context: Context) = context.eval.resolve(
context.expression.takeUnless { it.isBlank() }
?: requireNotNull(context.el.childOrNull("caption")?.text()) { "Absent table name" }
)

private fun toColumns(cols: List<String>) = cols.map { Column(it, DataType.UNKNOWN) }.toTypedArray()

private fun cols(html: Html) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ package io.github.adven27.concordion.extensions.exam.mq.commands

import io.github.adven27.concordion.extensions.exam.core.Content
import io.github.adven27.concordion.extensions.exam.core.commands.ExamCommand.Context
import io.github.adven27.concordion.extensions.exam.core.html.Html
import io.github.adven27.concordion.extensions.exam.core.resolve
import io.github.adven27.concordion.extensions.exam.mq.MqTester.TypedMessage

open class MqCheckParser : MqCheckCommand.Parser, BaseParser() {
override fun parse(context: Context) = MqCheckCommand.Expected(
queue = context.expression,
queue = parseQueue(context),
messages = elements(context.el).mapNotNull { parse(it, context.eval)?.toCheckMessage() },
exact = context[MqCheckCommand.CONTAINS]?.let { it.lowercase() == "exact" } ?: true,
await = context.awaitConfig
)

private fun parseQueue(context: Context) = context.eval.resolve(
context.expression.takeUnless { it.isBlank() }
?: requireNotNull(parseTitle(context.el)) { "Absent queue name" }
)

private fun parseTitle(html: Html) = html.childOrNull("caption")?.text()

private fun ParsedMessage.toCheckMessage() =
ExpectedMessage(requireNotNull(content), verifier ?: content.type, headers, params)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
package io.github.adven27.concordion.extensions.exam.mq.commands

import io.github.adven27.concordion.extensions.exam.core.commands.ExamCommand.Context
import io.github.adven27.concordion.extensions.exam.core.html.Html
import io.github.adven27.concordion.extensions.exam.core.resolve
import io.github.adven27.concordion.extensions.exam.mq.MqTester.TypedMessage

open class MqSetParser : MqSetCommand.Parser, BaseParser() {
override fun parse(context: Context) = MqSetCommand.Model(
queue = context.expression,
queue = parseQueue(context),
messages = elements(context.el).mapNotNull { item ->
parse(item, context.eval)?.let { TypedMessage(requireNotNull(it.content), it.headers, it.params) }
}
)

private fun parseQueue(context: Context) = context.eval.resolve(
context.expression.takeUnless { it.isBlank() }
?: requireNotNull(parseTitle(context.el)) { "Absent queue name" }
)

private fun parseTitle(html: Html) = with(html) {
when {
localName() == "table" -> childOrNull("caption")?.text()
localName() == "code" -> parent().parent().parent().childOrNull { it.hasClass("title") }?.text()
else -> parent().childOrNull { it.hasClass("title") }?.text()
}
}
}
Loading

0 comments on commit ccc77b2

Please sign in to comment.