diff --git a/src/main/scala/com/lectra/kapoeira/glue/Asserts.scala b/src/main/scala/com/lectra/kapoeira/glue/Asserts.scala index 44bcef7..822f740 100644 --- a/src/main/scala/com/lectra/kapoeira/glue/Asserts.scala +++ b/src/main/scala/com/lectra/kapoeira/glue/Asserts.scala @@ -63,6 +63,21 @@ object Asserts extends Matchers with LazyLogging { } ) + def approxEqual(assertionContext: AssertionContext, alias: String, jsonExpression: String, expected: String, approxRange: String):Assertion = + assertKafkaOutput( + assertionContext, + alias, + jsonExpression, + { actual => ( + for{ + x <- actual.double() + expected <- JsonExpr(expected).value.double() + approx <- JsonExpr(approxRange).value.double() + } yield{ x should equal ( expected +- approx ) } + ).fold(fail(s"${actual} equal ${expected} +- ${approxRange}"))(identity) + } + ) + def matchExactObject( assertionContext: AssertionContext, alias: String, @@ -150,6 +165,11 @@ object Asserts extends Matchers with LazyLogging { implicit class JsonNodeOps(val jsonNode: JsonNode) { + def double():Option[Double] ={ + val none = (_:Any) => Option.empty[Double] + jsonNode.fold(obj = none, arr = none, number = Some(_), strng = none, bln = none, bin = none, nullOrUndef = none) + } + def fold[T]( obj: JsonNode => T, arr: JsonNode => T, diff --git a/src/main/scala/com/lectra/kapoeira/glue/FeaturesStepDefinitions.scala b/src/main/scala/com/lectra/kapoeira/glue/FeaturesStepDefinitions.scala index 7e00f60..19e0176 100644 --- a/src/main/scala/com/lectra/kapoeira/glue/FeaturesStepDefinitions.scala +++ b/src/main/scala/com/lectra/kapoeira/glue/FeaturesStepDefinitions.scala @@ -176,7 +176,7 @@ class FeaturesStepDefinitions } // ASSERT - And("^assert\\s+(\\S+)\\s+(\\S+)\\s*==\\s*(.*)\\s*$") { + And("^assert\\s+(\\S+)\\s+(\\S+)\\s*==\\s*([^+-]*)\\s*$") { (alias: String, jsonExpression: String, expected: String) => logger.debug( s"Assert Step : (alias,jsonExpression,expected) ($alias,$jsonExpression,$expected)" @@ -226,6 +226,21 @@ class FeaturesStepDefinitions ) } + And("""^assert\s+(\S+)\s+(\$\S*)\s*==\s+([+-.eE0-9]+)\s+\+\-\s+([+-.eE0-9]+)\s*$""") { + (alias: String, jsonExpression: String, expectedJsonNumber: String,approximationJsonNumber:String) => + val interpolatedExpectedJson = + backgroundContext.substituteVariablesIn(expectedJsonNumber) + val interpolatedApproximationJson = + backgroundContext.substituteVariablesIn(approximationJsonNumber) + Asserts.approxEqual( + assertionContext, + alias, + jsonExpression, + interpolatedExpectedJson, + interpolatedApproximationJson + ) + } + And("^assert\\s+var\\s+(\\S+)\\s+(\\$\\S*)\\s+match\\s+object\\s+(.*)$") { (variableName: String, jsonExpression: String, expectedJson: String) => val interpolatedExpectedJson = diff --git a/src/test/resources/features/assertions.feature b/src/test/resources/features/assertions.feature index b507bc3..d78bc04 100644 --- a/src/test/resources/features/assertions.feature +++ b/src/test/resources/features/assertions.feature @@ -19,10 +19,19 @@ Feature: assertions | topic_out | key1_${uuid} | aliasHeaders2.1 | value2.1 | | topic_out | key2_${uuid} | aliasHeaders2.2 | value2.2 | | topic_out | key3_${uuid} | aliasHeaders2.3 | value2.3 | + | topic_out | key4_${uuid} | aliasHeaders2.4 | value2.4 | And assert value2.1 $.qux == 42 And assert value2.2 $ has size 2 And assert value2.2 $ == [3,4] And assert value2.3 $ == "value2.3" + And assert value2.4 $.foo == 12.0038209653823934567890123456789 + And assert value2.4 $.foo == 12.0 +- 0.1 + And assert value2.4 $.foo == 12.1 +- 0.1 + And assert value2.4 $.foo == 12.0038 +- 1E-4 + And assert value2.4 $.foo == 12.0037 +- 1E-3 + And assert value2.4 $.foo == 12.0039 +- 1E-3 + And assert value2.4 $.foo == 12.003 +- 1E-3 + And assert value2.4 $.foo == 12.004 +- 1E-3 And assert aliasHeaders2.1 $ == {"foo":"bar","baz":"42"} And assert aliasHeaders2.1 $.foo == "bar" diff --git a/src/test/resources/features/records/keyheadersvalue.dat b/src/test/resources/features/records/keyheadersvalue.dat index ec2fdc5..b43e52f 100644 --- a/src/test/resources/features/records/keyheadersvalue.dat +++ b/src/test/resources/features/records/keyheadersvalue.dat @@ -1,3 +1,4 @@ key1_${uuid}#{"qux":42}#{"foo":"bar","baz":42} key2_${uuid}#[3,4]#{"foo":"bar","baz":[1,2]} key3_${uuid}#value2.3#{"foo":"bar"} +key4_${uuid}#{"foo":12.0038209653823934567890123456789}#{"foo":"bar"} diff --git a/src/test/scala/com/lectra/kapoeira/glue/AssertsTest.scala b/src/test/scala/com/lectra/kapoeira/glue/AssertsTest.scala index dc863ab..8a93751 100644 --- a/src/test/scala/com/lectra/kapoeira/glue/AssertsTest.scala +++ b/src/test/scala/com/lectra/kapoeira/glue/AssertsTest.scala @@ -33,6 +33,31 @@ class AssertsTest extends AnyFlatSpec with Matchers with MockFactory { behavior of "Asserts" + it should "assert approximatively equals on numbers" in { + val backgroundContext = mock[BackgroundContext] + val assertionContext = new AssertionContext(WhenStepsLive(backgroundContext, recordConsume, KapoeiraProducer.run _)) + val consumerRecord = + new ConsumerRecord("topic", 0, 0, "key", """{"foo": 12.003820965382393}""".getBytes.asInstanceOf[Any]) + val valueAlias = "valueAlias" + val keyValueRecord = KeyValueWithAliasesRecord("topic", "key", valueAlias) + (backgroundContext + .consumeTopic(_: String, _: Map[String, Int])(_: RecordConsumer)) + .expects(*, *, *) + .returning(Map("key" -> Seq(consumerRecord))) + val expectedConsumedRecords = List(keyValueRecord) + assertionContext.launchConsumption(expectedConsumedRecords) + + Asserts.approxEqual(assertionContext, valueAlias, "$.foo", "12.0038","0.0001" ) + Asserts.approxEqual(assertionContext, valueAlias, "$.foo", "12.0038","1E-4" ) + Asserts.approxEqual(assertionContext, valueAlias, "$.foo", "12.0037","1E-3" ) + Asserts.approxEqual(assertionContext, valueAlias, "$.foo", "12.0039","1E-3" ) + Asserts.approxEqual(assertionContext, valueAlias, "$.foo", "12.003","1E-3" ) + Asserts.approxEqual(assertionContext, valueAlias, "$.foo", "12.004","1E-3" ) + Asserts.approxEqual(assertionContext, valueAlias, "$.foo", "12.0","0.1" ) + Asserts.approxEqual(assertionContext, valueAlias, "$.foo", "12.1","0.1" ) + + } + it should "assert equality on literals" in { val backgroundContext = mock[BackgroundContext] val assertionContext = new AssertionContext(WhenStepsLive(backgroundContext, recordConsume, KapoeiraProducer.run _))