From c8b8a2a71e7d38d7e19d812144ce55646a8e91e0 Mon Sep 17 00:00:00 2001 From: jcamiel Date: Sun, 18 Oct 2020 19:46:02 +0200 Subject: [PATCH] Fix not predicates https://github.com/Orange-OpenSource/hurl/issues/39. --- docs/release/release-notes-1.0.41.md | 4 +- .../ccmd/hurl/core/predicate/PredicateEval.kt | 454 ++++++++++++++++++ .../{run => predicate}/PredicateResult.kt | 2 +- .../orange/ccmd/hurl/core/run/AssertEval.kt | 129 ++++- .../ccmd/hurl/core/run/PredicateEval.kt | 291 ----------- .../hurl/core/predicate/PredicateEvalTest.kt | 107 +++++ .../orange/ccmd/hurl/core/run/AssertTest.kt | 12 +- .../ccmd/hurl/core/run/QueryEvalTest.kt | 2 +- 8 files changed, 687 insertions(+), 314 deletions(-) create mode 100644 hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateEval.kt rename hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/{run => predicate}/PredicateResult.kt (94%) delete mode 100644 hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/PredicateEval.kt create mode 100644 hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateEvalTest.kt diff --git a/docs/release/release-notes-1.0.41.md b/docs/release/release-notes-1.0.41.md index bbef510..88bbdc3 100644 --- a/docs/release/release-notes-1.0.41.md +++ b/docs/release/release-notes-1.0.41.md @@ -6,6 +6,8 @@ ## 🐞 Bug Fixes +- Fix predicates with not qualifier + ## 📔 Documentation ## 🔨 Dependency Upgrades @@ -15,4 +17,4 @@ - Upgrade to SL4J 1.7.30 - Upgrade to Jackson 2.11.3 - Upgrade to jsoup 1.13.1 -- Upgrade Apache HttpComponents 4.5.13 \ No newline at end of file +- Upgrade to Apache HttpComponents 4.5.13 \ No newline at end of file diff --git a/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateEval.kt b/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateEval.kt new file mode 100644 index 0000000..ebe7c32 --- /dev/null +++ b/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateEval.kt @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2020 Orange + * + * Hurl JVM (JVM Runner for https://hurl.dev) + * + * 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 com.orange.ccmd.hurl.core.predicate + +import com.orange.ccmd.hurl.core.run.QueryBooleanResult +import com.orange.ccmd.hurl.core.run.QueryListResult +import com.orange.ccmd.hurl.core.run.QueryNodeSetResult +import com.orange.ccmd.hurl.core.run.QueryNoneResult +import com.orange.ccmd.hurl.core.run.QueryNumberResult +import com.orange.ccmd.hurl.core.run.QueryObjectResult +import com.orange.ccmd.hurl.core.run.QueryResult +import com.orange.ccmd.hurl.core.run.QueryStringResult + +/** + * Evaluates if query result [first] equals string [second]. + * @param first query result to be evaluated + * @param second string to match + * @return the result of predicate + */ +internal fun equalString(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryStringResult -> first.value == second + else -> false + } + val secondText = "equals string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] doesn't equal string [second]. + * @param first query result to be evaluated + * @param second string to match + * @return the result of predicate + */ +internal fun notEqualString(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryStringResult -> first.value != second + else -> true + } + val secondText = "doesn't equal string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] equals boolean [second]. + * @param first query result to be evaluated + * @param second boolean to match + * @return the result of predicate + */ +internal fun equalBool(first: QueryResult, second: Boolean): PredicateResult { + val succeeded = when (first) { + is QueryBooleanResult -> first.value == second + else -> false + } + val secondText = "equals boolean <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] doesn't equal boolean [second]. + * @param first query result to be evaluated + * @param second boolean to match + * @return the result of predicate + */ +internal fun notEqualBool(first: QueryResult, second: Boolean): PredicateResult { + val succeeded = when (first) { + is QueryBooleanResult -> first.value != second + else -> true + } + val secondText = "doesn't equal boolean <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] equals null. + * @param first query result to be evaluated + * @return the result of predicate + */ +internal fun equalNull(first: QueryResult): PredicateResult { + val succeeded = when (first) { + is QueryObjectResult -> first.value == null + else -> false + } + val secondText = "equals " + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] doesn't equal null. + * @param first query result to be evaluated + * @return the result of predicate + */ +internal fun notEqualNull(first: QueryResult): PredicateResult { + val succeeded = when (first) { + is QueryObjectResult -> first.value != null + else -> true + } + val secondText = "doesn't equal " + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] equals number [second]. + * @param first query result to be evaluated + * @param second number to match + * @return the result of predicate + */ +internal fun equalDouble(first: QueryResult, second: Double): PredicateResult { + val succeeded = when (first) { + is QueryNumberResult -> first.value.toDouble() == second + else -> false + } + val secondText = "equals number <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] doesn't equals number [second]. + * @param first query result to be evaluated + * @param second number to match + * @return the result of predicate + */ +internal fun notEqualDouble(first: QueryResult, second: Double): PredicateResult { + val succeeded = when (first) { + is QueryNumberResult -> first.value.toDouble() != second + else -> true + } + val secondText = "doesn't equal number <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + + +internal fun equal(first: QueryResult, second: Any?): PredicateResult { + return when (second) { + is String -> equalString(first = first, second = second) + is Number -> equalDouble(first = first, second = second.toDouble()) + is Boolean -> equalBool(first = first, second = second) + null -> equalNull(first = first) + else -> TODO() + } +} + +internal fun notEqual(first: QueryResult, second: Any?): PredicateResult { + return when (second) { + is String -> notEqualString(first = first, second = second) + is Number -> notEqualDouble(first = first, second = second.toDouble()) + is Boolean -> notEqualBool(first = first, second = second) + null -> notEqualNull(first = first) + else -> TODO() + } +} + +/** + * Evaluates if query result [first] contains the string [second]. + * + * @param first query result to be tested + * @param second substring + * @return the result of predicate + */ +internal fun contain(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryStringResult -> first.value.contains(second) + else -> false + } + val secondText = "contains string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] doesn't contain the string [second]. + * + * @param first query result to be tested + * @param second substring + * @return the result of predicate + */ +internal fun notContain(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryStringResult -> !first.value.contains(second) + else -> false + } + val secondText = "doesn't contain string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container including null. + * @param first query result to be tested + * @return the result of predicate + */ +internal fun includeNull(first: QueryResult): PredicateResult { + val succeeded = when (first) { + is QueryListResult -> null in first.value + else -> false + } + val secondText = "includes " + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container not including null. + * @param first query result to be tested + * @return the result of predicate + */ +internal fun notIncludeNull(first: QueryResult): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryListResult -> null !in first.value + else -> false + } + val secondText = "doesn't include " + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container including number [second]. + * @param first query result to be tested + * @param second number to test + * @return the result of predicate + */ +internal fun includeNumber(first: QueryResult, second: Double): PredicateResult { + val succeeded = when (first) { + is QueryListResult -> second in first.value + .filterIsInstance() + .map { it.toDouble() } + else -> false + } + val secondText = "include number <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container not including number [second]. + * @param first query result to be tested + * @param second number to test + * @return the result of predicate + */ +internal fun notIncludeNumber(first: QueryResult, second: Double): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryListResult -> second !in first.value + .filterIsInstance() + .map { it.toDouble() } + else -> false + } + val secondText = "doesn't include number <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container including boolean [second]. + * @param first query result to be tested + * @param second boolean to test + * @return the result of predicate + */ +internal fun includeBool(first: QueryResult, second: Boolean): PredicateResult { + val succeeded = when (first) { + is QueryListResult -> second in first.value + else -> false + } + val secondText = "include boolean <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container not including boolean [second]. + * @param not boolean, true to inverse the predicate, false otherwise + * @param first query result to be tested + * @param second boolean to test + * @return the result of predicate + */ +internal fun notIncludeBool(first: QueryResult, second: Boolean): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryListResult -> second !in first.value + else -> false + } + val secondText = "doesn't include boolean <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container including string [second]. + * @param first query result to be tested + * @param second string to test + * @return the result of predicate + */ +internal fun includeString(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryListResult -> second in first.value + else -> false + } + val secondText = "include string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container not including string [second]. + * @param first query result to be tested + * @param second string to test + * @return the result of predicate + */ +internal fun notIncludeString(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryListResult -> second !in first.value + else -> false + } + val secondText = "doesn't include string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is a container of size [second]. + * @param first query result to be tested + * @param second size of the container + * @return the result of predicate + */ +internal fun count(first: QueryResult, second: Double): PredicateResult { + val succeeded = when (first) { + is QueryListResult -> first.value.size == second.toInt() + is QueryNodeSetResult -> first.size == second.toInt() + else -> false + } + val secondText = "count equals $second" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] is not a container of size [second]. + * @param first query result to be tested + * @param second size of the container + * @return the result of predicate + */ +internal fun notCount(first: QueryResult, second: Double): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryListResult -> first.value.size != second.toInt() + is QueryNodeSetResult -> first.size != second.toInt() + else -> false + } + val secondText = "count doesn't equals $second" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] starts with string [second]. + * @param first query result to be tested + * @param second prefix + * @return the result of predicate + */ +internal fun startWith(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryStringResult -> first.value.startsWith(second) + else -> false + } + val secondText = "starts with string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] doesn't start with string [second]. + * @param first query result to be tested + * @param second prefix + * @return the result of predicate + */ +internal fun notStartWith(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryStringResult -> !first.value.startsWith(second) + else -> false + } + val secondText = "doesn't start with string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] matches regex [second]. + * @param first query result to be matched + * @param second regex + * @return the result of predicate + */ +internal fun match(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryStringResult -> Regex(pattern = second).containsMatchIn(first.value) + else -> false + } + val secondText = "matches string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + +/** + * Evaluates if query result [first] doesn't match regex [second]. + * @param first query result to be matched + * @param second regex + * @return the result of predicate + */ +internal fun notMatch(first: QueryResult, second: String): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryStringResult -> !Regex(pattern = second).containsMatchIn(first.value) + else -> false + } + val secondText = "doesn't match string <$second>" + return PredicateResult(succeeded = succeeded, first = first.text(), second = secondText) +} + + +/** + * Evaluates if query result [first] exist. + * @param first query result to be evaluated + * @return the result of predicate + */ +internal fun exist(first: QueryResult): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> false + is QueryNodeSetResult -> first.size > 0 + else -> true + } + val second = "anything" + return PredicateResult(succeeded = succeeded, first = first.text(), second = second) +} + +/** + * Evaluates if query result [first] doesn't exist. + * @param first query result to be evaluated + * @return the result of predicate + */ +internal fun notExist(first: QueryResult): PredicateResult { + val succeeded = when (first) { + is QueryNoneResult -> true + is QueryNodeSetResult -> first.size == 0 + else -> false + } + val second = "" + return PredicateResult(succeeded = succeeded, first = first.text(), second = second) +} diff --git a/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/PredicateResult.kt b/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateResult.kt similarity index 94% rename from hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/PredicateResult.kt rename to hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateResult.kt index c260cf0..04d4339 100644 --- a/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/PredicateResult.kt +++ b/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateResult.kt @@ -17,7 +17,7 @@ * */ -package com.orange.ccmd.hurl.core.run +package com.orange.ccmd.hurl.core.predicate data class PredicateResult( diff --git a/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/AssertEval.kt b/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/AssertEval.kt index 86f5496..21bc3f9 100644 --- a/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/AssertEval.kt +++ b/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/AssertEval.kt @@ -39,6 +39,35 @@ import com.orange.ccmd.hurl.core.ast.StartWithPredicate import com.orange.ccmd.hurl.core.ast.Status import com.orange.ccmd.hurl.core.ast.Version import com.orange.ccmd.hurl.core.http.HttpResponse +import com.orange.ccmd.hurl.core.predicate.PredicateResult +import com.orange.ccmd.hurl.core.predicate.contain +import com.orange.ccmd.hurl.core.predicate.count +import com.orange.ccmd.hurl.core.predicate.equal +import com.orange.ccmd.hurl.core.predicate.equalBool +import com.orange.ccmd.hurl.core.predicate.equalDouble +import com.orange.ccmd.hurl.core.predicate.equalNull +import com.orange.ccmd.hurl.core.predicate.equalString +import com.orange.ccmd.hurl.core.predicate.exist +import com.orange.ccmd.hurl.core.predicate.includeBool +import com.orange.ccmd.hurl.core.predicate.includeNull +import com.orange.ccmd.hurl.core.predicate.includeNumber +import com.orange.ccmd.hurl.core.predicate.includeString +import com.orange.ccmd.hurl.core.predicate.match +import com.orange.ccmd.hurl.core.predicate.notContain +import com.orange.ccmd.hurl.core.predicate.notCount +import com.orange.ccmd.hurl.core.predicate.notEqual +import com.orange.ccmd.hurl.core.predicate.notEqualBool +import com.orange.ccmd.hurl.core.predicate.notEqualDouble +import com.orange.ccmd.hurl.core.predicate.notEqualNull +import com.orange.ccmd.hurl.core.predicate.notEqualString +import com.orange.ccmd.hurl.core.predicate.notExist +import com.orange.ccmd.hurl.core.predicate.notIncludeBool +import com.orange.ccmd.hurl.core.predicate.notIncludeNull +import com.orange.ccmd.hurl.core.predicate.notIncludeNumber +import com.orange.ccmd.hurl.core.predicate.notIncludeString +import com.orange.ccmd.hurl.core.predicate.notMatch +import com.orange.ccmd.hurl.core.predicate.notStartWith +import com.orange.ccmd.hurl.core.predicate.startWith import com.orange.ccmd.hurl.core.query.InvalidQueryException import com.orange.ccmd.hurl.core.variable.VariableJar import com.orange.ccmd.hurl.core.template.InvalidVariableException @@ -189,38 +218,110 @@ internal fun Assert.eval(response: HttpResponse, variables: VariableJar): EntryS val predicateFunc = predicate.predicateFunc val result = try { when (predicateFunc) { - is EqualBoolPredicate -> equalBool(not = not, first = first, second = predicateFunc.expr.value) - is EqualNumberPredicate -> equalDouble(not = not, first = first, second = predicateFunc.expr.value) - is EqualNullPredicate -> equalNull(not = not, first = first) + is EqualBoolPredicate -> { + if (not) { + notEqualBool(first = first, second = predicateFunc.expr.value) + } else { + equalBool(first = first, second = predicateFunc.expr.value) + } + } + is EqualNumberPredicate -> { + if (not) { + notEqualDouble(first = first, second = predicateFunc.expr.value) + } else { + equalDouble(first = first, second = predicateFunc.expr.value) + } + } + is EqualNullPredicate -> { + if (not) { + notEqualNull(first = first) + } else { + equalNull(first = first) + } + } is EqualStringPredicate -> { val second = predicateFunc.valueToString(variables = variables) - equalString(not = not, first = first, second = second) + if (not) { + notEqualString(first = first, second = second) + } else { + equalString(first = first, second = second) + } } is EqualExprPredicate -> { val second = predicateFunc.value(variables = variables) - equal(not = not, first = first, second = second.value) + if (not) { + notEqual(first = first, second = second.value) + } else { + equal(first = first, second = second.value) + } } is StartWithPredicate -> { val second = predicateFunc.valueToString(variables = variables) - startWith(not = not, first = first, second = second) + if (not) { + notStartWith(first = first, second = second) + } else { + startWith(first = first, second = second) + } + } + is CountPredicate -> { + if (not) { + notCount(first = first, second = predicateFunc.expr.value) + } else { + count(first = first, second = predicateFunc.expr.value) + } } - is CountPredicate -> count(not = not, first = first, second = predicateFunc.expr.value) is ContainPredicate -> { val second = predicateFunc.valueToString(variables = variables) - contain(not = not, first = first, second = second) + if (not) { + notContain(first = first, second = second) + } else { + contain(first = first, second = second) + } + } + is IncludeBoolPredicate -> { + if (not) { + notIncludeBool(first = first, second = predicateFunc.expr.value) + } else { + includeBool(first = first, second = predicateFunc.expr.value) + } + } + is IncludeNullPredicate -> { + if (not) { + notIncludeNull(first = first) + } else { + includeNull(first = first) + } + } + is IncludeNumberPredicate -> { + if (not) { + notIncludeNumber(first = first, second = predicateFunc.expr.value) + } else { + includeNumber(first = first, second = predicateFunc.expr.value) + } } - is IncludeBoolPredicate -> includeBool(not = not, first = first, second = predicateFunc.expr.value) - is IncludeNullPredicate -> includeNull(not = not, first = first) - is IncludeNumberPredicate -> includeNumber(not = not, first = first, second = predicateFunc.expr.value) is IncludeStringPredicate -> { val second = predicateFunc.valueToString(variables = variables) - includeString(not = not, first = first, second = second) + if (not) { + notIncludeString(first = first, second = second) + } else { + includeString(first = first, second = second) + } } is MatchPredicate -> { val second = predicateFunc.valueToString(variables = variables) - match(not = not, first = first, second = second) + if (not) { + notMatch(first = first, second = second) + } else { + match(first = first, second = second) + } + } + is ExistPredicate -> { + if (not) { + notExist(first = first) + } else { + exist(first = first) + } } - is ExistPredicate -> exist(not = not, first = first) } } catch (e: InvalidVariableException) { return InvalidVariableResult(position = e.position, reason = e.reason) diff --git a/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/PredicateEval.kt b/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/PredicateEval.kt deleted file mode 100644 index 46a4c1d..0000000 --- a/hurl-core/src/main/kotlin/com/orange/ccmd/hurl/core/run/PredicateEval.kt +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2020 Orange - * - * Hurl JVM (JVM Runner for https://hurl.dev) - * - * 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 com.orange.ccmd.hurl.core.run - -/** - * Evaluates if query result [first] equals string [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be evaluated - * @param second string to match - * @return the result of predicate - */ -internal fun equalString(not: Boolean, first: QueryResult, second: String): PredicateResult { - val succeeded = when (first) { - is QueryStringResult -> first.value == second - else -> false - } - val secondText = if (not) { "doesn't equal string <$second>" } else { "equals string <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] equals boolean [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be evaluated - * @param second boolean to match - * @return the result of predicate - */ -internal fun equalBool(not: Boolean, first: QueryResult, second: Boolean): PredicateResult { - val succeeded = when (first) { - is QueryBooleanResult -> first.value == second - else -> false - } - val secondText = if (not) { "doesn't equal boolean <$second>" } else { "equals boolean <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] equals null. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be evaluated - * @return the result of predicate - */ -internal fun equalNull(not: Boolean, first: QueryResult): PredicateResult { - val succeeded = when (first) { - is QueryObjectResult -> first.value == null - else -> false - } - val secondText = if (not) { "doesn't equal " } else { "equals number " } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] equals number [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be evaluated - * @param second number to match - * @return the result of predicate - */ -internal fun equalDouble(not: Boolean, first: QueryResult, second: Double): PredicateResult { - val succeeded = when (first) { - is QueryNumberResult -> first.value.toDouble() == second - else -> false - } - val secondText = if (not) { "doesn't equal number <$second>" } else { "equals number <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -internal fun equal(not: Boolean, first: QueryResult, second: Any?): PredicateResult { - return when (second) { - is String -> equalString(not = not, first = first, second = second) - is Number -> equalDouble(not = not, first = first, second = second.toDouble()) - is Boolean -> equalBool(not = not, first = first, second = second) - null -> equalNull(not = not, first = first) - else -> TODO() - } -} - -/** - * Evaluates if query result [first] contains the string [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be tested - * @param second substring - * @return the result of predicate - */ -internal fun contain(not: Boolean, first: QueryResult, second: String): PredicateResult { - val succeeded = when (first) { - is QueryStringResult -> first.value.contains(second) - else -> false - } - val secondText = if (not) { "doesn't contain string <$second>" } else { "contains string <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] is a container including null. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be tested - * @return the result of predicate - */ -internal fun includeNull(not: Boolean, first: QueryResult): PredicateResult { - val succeeded = when (first) { - is QueryListResult -> null in first.value - else -> false - } - val secondText = if (not) { "doesn't include " } else { "include " } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] is a container including number [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be tested - * @param second number to test - * @return the result of predicate - */ -internal fun includeNumber(not: Boolean, first: QueryResult, second: Double): PredicateResult { - val succeeded = when (first) { - is QueryListResult -> second in first.value - .filterIsInstance() - .map { it.toDouble() } - else -> false - } - val secondText = if (not) { "doesn't include number <$second>" } else { "include number <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] is a container including boolean [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be tested - * @param second boolean to test - * @return the result of predicate - */ -internal fun includeBool(not: Boolean, first: QueryResult, second: Boolean): PredicateResult { - val succeeded = when (first) { - is QueryListResult -> second in first.value - else -> false - } - val secondText = if (not) { "doesn't include boolean <$second>" } else { "include boolean <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] is a container including string [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be tested - * @param second string to test - * @return the result of predicate - */ -internal fun includeString(not: Boolean, first: QueryResult, second: String): PredicateResult { - val succeeded = when (first) { - is QueryListResult -> second in first.value - else -> false - } - val secondText = if (not) { "doesn't include string <$second>" } else { "include string <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] is a container of size [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be tested - * @param second size of the container - * @return the result of predicate - */ -internal fun count(not: Boolean, first: QueryResult, second: Double): PredicateResult { - val succeeded = when (first) { - is QueryListResult -> first.value.size == second.toInt() - is QueryNodeSetResult -> first.size == second.toInt() - else -> false - } - val secondText = if (not) { "count doesn't equals $second" } else { "count equals $second" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] starts with string [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be tested - * @param second prefix - * @return the result of predicate - */ -internal fun startWith(not: Boolean, first: QueryResult, second: String): PredicateResult { - val succeeded = when (first) { - is QueryStringResult -> first.value.startsWith(second) - else -> false - } - val secondText = if (not) { "doesn't start with string <$second>" } else { "starts with string <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] matches regex [second]. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be matched - * @param second regex - * @return the result of predicate - */ -internal fun match(not: Boolean, first: QueryResult, second: String): PredicateResult { - val succeeded = when (first) { - is QueryStringResult -> Regex(pattern = second).containsMatchIn(first.value) - else -> false - } - val secondText = if (not) { "doesn't match string <$second>" } else { "matches string <$second>" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = secondText - ) -} - -/** - * Evaluates if query result [first] exist. - * @param not boolean, true to inverse the predicate, false otherwise - * @param first query result to be evaluated - * @return the result of predicate - */ -internal fun exist(not: Boolean, first: QueryResult): PredicateResult { - val succeeded = when (first) { - is QueryNoneResult -> false - is QueryNodeSetResult -> first.size > 0 - else -> true - } - val second = if (not) { "" } else { "anything" } - return PredicateResult( - succeeded = succeeded xor not, - first = first.text(), - second = second - ) -} \ No newline at end of file diff --git a/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateEvalTest.kt b/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateEvalTest.kt new file mode 100644 index 0000000..ac55171 --- /dev/null +++ b/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/predicate/PredicateEvalTest.kt @@ -0,0 +1,107 @@ +package com.orange.ccmd.hurl.core.predicate + +import com.orange.ccmd.hurl.core.run.QueryBooleanResult +import com.orange.ccmd.hurl.core.run.QueryListResult +import com.orange.ccmd.hurl.core.run.QueryNodeSetResult +import com.orange.ccmd.hurl.core.run.QueryNoneResult +import com.orange.ccmd.hurl.core.run.QueryNumberResult +import com.orange.ccmd.hurl.core.run.QueryObjectResult +import com.orange.ccmd.hurl.core.run.QueryStringResult +import org.junit.jupiter.api.DynamicTest +import org.junit.jupiter.api.TestFactory +import kotlin.test.assertEquals + +class PredicateEvalTest { + + private fun PredicateResult.testName(): String { + return "$first $second $succeeded" + } + + @TestFactory + fun `evaluate predicate`() = listOf( + + equalString(QueryStringResult("toto"), "toto") to true, + equalString(QueryBooleanResult(true), "toto") to false, + notEqualString(QueryStringResult("toto"), "tata") to true, + notEqualString(QueryNumberResult(1), "tata") to true, + + equalBool(QueryBooleanResult(true), true) to true, + equalBool(QueryStringResult("toto"), true) to false, + notEqualBool(QueryBooleanResult(false), true) to true, + notEqualBool(QueryStringResult("toto"), true) to true, + + equalNull(QueryObjectResult(null)) to true, + equalNull(QueryStringResult("toto")) to false, + notEqualNull(QueryObjectResult(null)) to false, + notEqualNull(QueryStringResult("toto")) to true, + + equalDouble(QueryNumberResult(2), 2.0) to true, + equalDouble(QueryStringResult("toto"), 2.0) to false, + notEqualDouble(QueryNumberResult(2), 2.0) to false, + notEqualDouble(QueryStringResult("toto"), 2.0) to true, + + contain(QueryStringResult("toto"), "to") to true, + contain(QueryNumberResult(2), "to") to false, + notContain(QueryStringResult("toto"), "to") to false, + notContain(QueryNumberResult(2), "to") to false, + notContain(QueryNoneResult, "to") to true, + + includeNull(QueryListResult(listOf(1, null))) to true, + includeNull(QueryNumberResult(2)) to false, + notIncludeNull(QueryListResult(listOf(1, null))) to false, + notIncludeNull(QueryNumberResult(2)) to false, + notIncludeNull(QueryNoneResult) to true, + + includeNumber(QueryListResult(listOf(1, null)), 1.0) to true, + includeNumber(QueryNumberResult(2), 1.0) to false, + notIncludeNumber(QueryListResult(listOf(1, null)), 1.0) to false, + notIncludeNumber(QueryNumberResult(2), 1.0) to false, + notIncludeNumber(QueryNoneResult, 1.0) to true, + + includeBool(QueryListResult(listOf(1, true)), true) to true, + includeBool(QueryNumberResult(2), true) to false, + notIncludeBool(QueryListResult(listOf(1, true)), true) to false, + notIncludeBool(QueryNumberResult(2), true) to false, + notIncludeBool(QueryNoneResult, true) to true, + + includeString(QueryListResult(listOf(1, "toto")), "toto") to true, + includeString(QueryNumberResult(2), "toto") to false, + notIncludeString(QueryListResult(listOf(1, "toto")), "toto") to false, + notIncludeString(QueryNumberResult(2), "toto") to false, + notIncludeString(QueryNoneResult, "toto") to true, + + count(QueryListResult(listOf(1, true)), 2.0) to true, + count(QueryNodeSetResult(size = 2), 2.0) to true, + count(QueryStringResult("toto"), 2.0) to false, + notCount(QueryListResult(listOf(1, true)), 2.0) to false, + notCount(QueryNodeSetResult(size = 2), 2.0) to false, + notCount(QueryStringResult("toto"), 2.0) to false, + notCount(QueryNoneResult, 2.0) to true, + + startWith(QueryStringResult("toto"), "to") to true, + startWith(QueryNumberResult(2), "to") to false, + notStartWith(QueryStringResult("toto"), "to") to false, + notStartWith(QueryNumberResult(2), "to") to false, + notStartWith(QueryNoneResult, "to") to true, + + match(QueryStringResult("toto"), "to") to true, + match(QueryNumberResult(2), "to") to false, + notMatch(QueryStringResult("toto"), "to") to false, + notMatch(QueryNumberResult(2), "to") to false, + notMatch(QueryNoneResult, "to") to true, + + exist(QueryNoneResult) to false, + exist(QueryNodeSetResult(size = 0)) to false, + exist(QueryNodeSetResult(size = 42)) to true, + exist(QueryStringResult("toto")) to true, + notExist(QueryNoneResult) to true, + notExist(QueryNodeSetResult(size = 0)) to true, + notExist(QueryNodeSetResult(size = 42)) to false, + notExist(QueryStringResult("toto")) to false, + ).map { (expr, expectedResult) -> + DynamicTest.dynamicTest(expr.testName()) { + assertEquals(expr.succeeded, expectedResult) + } + + } +} diff --git a/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/run/AssertTest.kt b/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/run/AssertTest.kt index 34013e7..877acf8 100644 --- a/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/run/AssertTest.kt +++ b/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/run/AssertTest.kt @@ -339,8 +339,8 @@ internal class AssertTest { actual: list() expected: matches string <.*> """.trimIndent()), - Triple("""jsonpath "$.warnings" not matches ".*"""", true, """ - assert jsonpath not matches succeeded + Triple("""jsonpath "$.warnings" not matches ".*"""", false, """ + assert jsonpath not matches failed actual: list() expected: doesn't match string <.*> """.trimIndent()), @@ -398,8 +398,8 @@ internal class AssertTest { actual: list() expected: starts with string """.trimIndent()), - Triple("""jsonpath "$.warnings" not startsWith "something"""", true, """ - assert jsonpath not startsWith succeeded + Triple("""jsonpath "$.warnings" not startsWith "something"""", false, """ + assert jsonpath not startsWith failed actual: list() expected: doesn't start with string """.trimIndent()), @@ -457,8 +457,8 @@ internal class AssertTest { actual: list() expected: contains string """.trimIndent()), - Triple("""jsonpath "$.warnings" not contains "something"""", true, """ - assert jsonpath not contains succeeded + Triple("""jsonpath "$.warnings" not contains "something"""", false, """ + assert jsonpath not contains failed actual: list() expected: doesn't contain string """.trimIndent()), diff --git a/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/run/QueryEvalTest.kt b/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/run/QueryEvalTest.kt index 46bf098..112dd40 100644 --- a/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/run/QueryEvalTest.kt +++ b/hurl-core/src/test/kotlin/com/orange/ccmd/hurl/core/run/QueryEvalTest.kt @@ -39,7 +39,7 @@ import java.nio.charset.Charset import kotlin.test.assertEquals import kotlin.test.assertNotNull -class QueryEvalTest { +internal class QueryEvalTest { @Test fun `evaluate status-query against a http response`() {