Adding some tests for predicates.
This commit is contained in:
parent
fae37780e9
commit
16f8356e2c
5 changed files with 331 additions and 0 deletions
49
src/main/scala/gs/predicate/v0/json/JsonQueryIn.scala
Normal file
49
src/main/scala/gs/predicate/v0/json/JsonQueryIn.scala
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
package gs.predicate.v0.json
|
||||||
|
|
||||||
|
import cats.Applicative
|
||||||
|
import cats.syntax.all.*
|
||||||
|
import gs.predicate.v0.api.Predicate
|
||||||
|
import gs.predicate.v0.json.query.JsonQuery
|
||||||
|
import io.circe.Json
|
||||||
|
|
||||||
|
/** Predicate that matches if the JSON provider contains a JSON blob with the
|
||||||
|
* given key, and that blob contains the given query, and the result of the
|
||||||
|
* query matches one of the given values.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* The name of the JSON value that must satisfy the given query.
|
||||||
|
* @param query
|
||||||
|
* The [[JsonQuery]] that must be satisfied.
|
||||||
|
* @param values
|
||||||
|
* The set of JSON values, such that one value should match the input.
|
||||||
|
*/
|
||||||
|
final class JsonQueryIn[F[_]: Applicative: JsonProvider](
|
||||||
|
val key: String,
|
||||||
|
val query: JsonQuery,
|
||||||
|
val values: Set[Json]
|
||||||
|
) extends Predicate[F]:
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
final override val predicateType: String = JsonQueryIn.PredicateType
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def eval(): F[Predicate.Result] =
|
||||||
|
JsonProvider[F].get(key).map {
|
||||||
|
case None => Predicate.Result.missed()
|
||||||
|
case Some(json) => Predicate.Result(query.eval(json, values.contains))
|
||||||
|
}
|
||||||
|
|
||||||
|
object JsonQueryIn:
|
||||||
|
|
||||||
|
final val PredicateType: String = "json-query-in"
|
||||||
|
|
||||||
|
def apply[F[_]: Applicative: JsonProvider](
|
||||||
|
key: String,
|
||||||
|
query: JsonQuery,
|
||||||
|
values: Set[Json]
|
||||||
|
): JsonQueryIn[F] =
|
||||||
|
new JsonQueryIn[F](key, query, values)
|
||||||
|
|
||||||
|
end JsonQueryIn
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package gs.predicate.v0.json
|
||||||
|
|
||||||
|
import cats.effect.std.MapRef
|
||||||
|
import io.circe.Json
|
||||||
|
|
||||||
|
/** Provides keys and JSON values, given some in-memory map.
|
||||||
|
*
|
||||||
|
* @param map
|
||||||
|
* The underlying map.
|
||||||
|
*/
|
||||||
|
final class MemoryMapJsonProvider[F[_]](
|
||||||
|
private val map: MapRef[F, String, Option[Json]]
|
||||||
|
) extends JsonProvider[F]:
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def get(key: String): F[Option[Json]] =
|
||||||
|
map.apply(key).get
|
||||||
|
|
||||||
|
end MemoryMapJsonProvider
|
||||||
128
src/test/scala/gs/predicate/v0/json/JsonQueryEqualsTests.scala
Normal file
128
src/test/scala/gs/predicate/v0/json/JsonQueryEqualsTests.scala
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
package gs.predicate.v0.json
|
||||||
|
|
||||||
|
import cats.effect.IO
|
||||||
|
import cats.effect.std.MapRef
|
||||||
|
import gs.datagen.v0.Gen
|
||||||
|
import gs.datagen.v0.generators.Size
|
||||||
|
import gs.predicate.v0.api.Predicate
|
||||||
|
import gs.predicate.v0.json.query.JsonQuery
|
||||||
|
import io.circe.Json
|
||||||
|
import support.IOSuite
|
||||||
|
|
||||||
|
class JsonQueryEqualsTests extends IOSuite:
|
||||||
|
|
||||||
|
import JsonQueryEqualsTests.Data
|
||||||
|
import JsonQueryEqualsTests.newProvider
|
||||||
|
|
||||||
|
iotest("should find an exact match against some string value") {
|
||||||
|
val key = Data.keyGen.gen()
|
||||||
|
val value = Data.strValGen.gen()
|
||||||
|
val query = key
|
||||||
|
val blob = Json.obj(
|
||||||
|
key -> value
|
||||||
|
)
|
||||||
|
|
||||||
|
newProvider(Map(key -> blob)).flatMap { provider =>
|
||||||
|
given JsonProvider[IO] = provider
|
||||||
|
val p = JsonQueryEquals[IO](key, JsonQuery.compile(query), value)
|
||||||
|
p.eval().map(result => assertEquals(result, Predicate.Result.matched()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iotest("should fail to match against some non-equal string value") {
|
||||||
|
val key = Data.keyGen.gen()
|
||||||
|
val value = Data.strValGen.gen()
|
||||||
|
val searchValue = Data.strValGen.gen()
|
||||||
|
val query = key
|
||||||
|
val blob = Json.obj(
|
||||||
|
key -> value
|
||||||
|
)
|
||||||
|
|
||||||
|
newProvider(Map(key -> blob)).flatMap { provider =>
|
||||||
|
given JsonProvider[IO] = provider
|
||||||
|
val p = JsonQueryEquals[IO](key, JsonQuery.compile(query), searchValue)
|
||||||
|
p.eval().map(result => assertEquals(result, Predicate.Result.missed()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iotest("should find an exact match against some integer value") {
|
||||||
|
val key = Data.keyGen.gen()
|
||||||
|
val value = Data.intValGen.gen()
|
||||||
|
val query = key
|
||||||
|
val blob = Json.obj(
|
||||||
|
key -> value
|
||||||
|
)
|
||||||
|
|
||||||
|
newProvider(Map(key -> blob)).flatMap { provider =>
|
||||||
|
given JsonProvider[IO] = provider
|
||||||
|
val p = JsonQueryEquals[IO](key, JsonQuery.compile(query), value)
|
||||||
|
p.eval().map(result => assertEquals(result, Predicate.Result.matched()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iotest("should fail to match against some non-equal integer value") {
|
||||||
|
val key = Data.keyGen.gen()
|
||||||
|
val value = Data.intValGen.gen()
|
||||||
|
val searchValue = Data.intValGen.gen()
|
||||||
|
val query = key
|
||||||
|
val blob = Json.obj(
|
||||||
|
key -> value
|
||||||
|
)
|
||||||
|
|
||||||
|
newProvider(Map(key -> blob)).flatMap { provider =>
|
||||||
|
given JsonProvider[IO] = provider
|
||||||
|
val p = JsonQueryEquals[IO](key, JsonQuery.compile(query), searchValue)
|
||||||
|
p.eval().map(result => assertEquals(result, Predicate.Result.missed()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iotest("should find an exact match against some boolean value") {
|
||||||
|
val key = Data.keyGen.gen()
|
||||||
|
val value = Data.boolValGen.gen()
|
||||||
|
val query = key
|
||||||
|
val blob = Json.obj(
|
||||||
|
key -> value
|
||||||
|
)
|
||||||
|
|
||||||
|
newProvider(Map(key -> blob)).flatMap { provider =>
|
||||||
|
given JsonProvider[IO] = provider
|
||||||
|
val p = JsonQueryEquals[IO](key, JsonQuery.compile(query), value)
|
||||||
|
p.eval().map(result => assertEquals(result, Predicate.Result.matched()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iotest("should fail to match against some non-equal boolean value") {
|
||||||
|
val key = Data.keyGen.gen()
|
||||||
|
val value = Json.fromBoolean(true)
|
||||||
|
val searchValue = Json.fromBoolean(false)
|
||||||
|
val query = key
|
||||||
|
val blob = Json.obj(
|
||||||
|
key -> value
|
||||||
|
)
|
||||||
|
|
||||||
|
newProvider(Map(key -> blob)).flatMap { provider =>
|
||||||
|
given JsonProvider[IO] = provider
|
||||||
|
val p = JsonQueryEquals[IO](key, JsonQuery.compile(query), searchValue)
|
||||||
|
p.eval().map(result => assertEquals(result, Predicate.Result.missed()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object JsonQueryEqualsTests:
|
||||||
|
|
||||||
|
object Data:
|
||||||
|
|
||||||
|
val keyGen: Gen[String] = Gen.string.alphaNumeric(Size.between(4, 16))
|
||||||
|
|
||||||
|
val strValGen: Gen[Json] =
|
||||||
|
Gen.string.uppercaseAlpha(Size.fixed(8)).map(Json.fromString)
|
||||||
|
|
||||||
|
val intValGen: Gen[Json] = Gen.integer.inRange(0, 1000).map(Json.fromInt)
|
||||||
|
val boolValGen: Gen[Json] = Gen.boolean().map(Json.fromBoolean)
|
||||||
|
|
||||||
|
end Data
|
||||||
|
|
||||||
|
def newProvider(data: Map[String, Json]): IO[JsonProvider[IO]] =
|
||||||
|
for map <- MapRef.ofSingleImmutableMap[IO, String, Json](data)
|
||||||
|
yield new MemoryMapJsonProvider(map)
|
||||||
|
|
||||||
|
end JsonQueryEqualsTests
|
||||||
68
src/test/scala/gs/predicate/v0/json/JsonQueryInTests.scala
Normal file
68
src/test/scala/gs/predicate/v0/json/JsonQueryInTests.scala
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
package gs.predicate.v0.json
|
||||||
|
|
||||||
|
import cats.effect.IO
|
||||||
|
import cats.effect.std.MapRef
|
||||||
|
import gs.datagen.v0.Gen
|
||||||
|
import gs.datagen.v0.generators.Size
|
||||||
|
import gs.predicate.v0.api.Predicate
|
||||||
|
import gs.predicate.v0.json.query.JsonQuery
|
||||||
|
import io.circe.Json
|
||||||
|
import support.IOSuite
|
||||||
|
|
||||||
|
class JsonQueryInTests extends IOSuite:
|
||||||
|
|
||||||
|
import JsonQueryInTests.Data
|
||||||
|
import JsonQueryInTests.newProvider
|
||||||
|
|
||||||
|
iotest("should find an exact match against some set of values") {
|
||||||
|
val key = Data.keyGen.gen()
|
||||||
|
val value = Data.strValGen.gen()
|
||||||
|
val values = Set(value, Data.strValGen.gen(), Data.intValGen.gen())
|
||||||
|
val query = key
|
||||||
|
val blob = Json.obj(
|
||||||
|
key -> value
|
||||||
|
)
|
||||||
|
|
||||||
|
newProvider(Map(key -> blob)).flatMap { provider =>
|
||||||
|
given JsonProvider[IO] = provider
|
||||||
|
val p = JsonQueryIn[IO](key, JsonQuery.compile(query), values)
|
||||||
|
p.eval().map(result => assertEquals(result, Predicate.Result.matched()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iotest("should fail to match anything within some set of values") {
|
||||||
|
val key = Data.keyGen.gen()
|
||||||
|
val value = Data.strValGen.gen()
|
||||||
|
val searchValues = Set(Data.strValGen.gen())
|
||||||
|
val query = key
|
||||||
|
val blob = Json.obj(
|
||||||
|
key -> value
|
||||||
|
)
|
||||||
|
|
||||||
|
newProvider(Map(key -> blob)).flatMap { provider =>
|
||||||
|
given JsonProvider[IO] = provider
|
||||||
|
val p = JsonQueryIn[IO](key, JsonQuery.compile(query), searchValues)
|
||||||
|
p.eval().map(result => assertEquals(result, Predicate.Result.missed()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end JsonQueryInTests
|
||||||
|
|
||||||
|
object JsonQueryInTests:
|
||||||
|
|
||||||
|
object Data:
|
||||||
|
|
||||||
|
val keyGen: Gen[String] = Gen.string.alphaNumeric(Size.between(4, 16))
|
||||||
|
|
||||||
|
val strValGen: Gen[Json] =
|
||||||
|
Gen.string.uppercaseAlpha(Size.fixed(8)).map(Json.fromString)
|
||||||
|
|
||||||
|
val intValGen: Gen[Json] = Gen.integer.inRange(0, 1000).map(Json.fromInt)
|
||||||
|
|
||||||
|
end Data
|
||||||
|
|
||||||
|
def newProvider(data: Map[String, Json]): IO[JsonProvider[IO]] =
|
||||||
|
for map <- MapRef.ofSingleImmutableMap[IO, String, Json](data)
|
||||||
|
yield new MemoryMapJsonProvider(map)
|
||||||
|
|
||||||
|
end JsonQueryInTests
|
||||||
66
src/test/scala/gs/predicate/v0/kv/ValueInTests.scala
Normal file
66
src/test/scala/gs/predicate/v0/kv/ValueInTests.scala
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
package gs.predicate.v0.kv
|
||||||
|
|
||||||
|
import cats.effect.IO
|
||||||
|
import cats.effect.std.MapRef
|
||||||
|
import gs.datagen.v0.Gen
|
||||||
|
import gs.datagen.v0.generators.Size
|
||||||
|
import gs.predicate.v0.api.Predicate
|
||||||
|
import support.IOSuite
|
||||||
|
|
||||||
|
class ValueInTests extends IOSuite:
|
||||||
|
|
||||||
|
import ValueInTests.Data
|
||||||
|
|
||||||
|
iotest("should find an exact match against some value") {
|
||||||
|
ValueInTests.newProvider(Data.KeyValues).flatMap { provider =>
|
||||||
|
given KeyValueProvider[IO] = provider
|
||||||
|
val p =
|
||||||
|
ValueIn[IO](
|
||||||
|
Data.ExistingKey,
|
||||||
|
Set(
|
||||||
|
Data.ExistingValue,
|
||||||
|
"",
|
||||||
|
Gen.string.alphaNumeric(Size.Fixed(8)).gen()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for result <- p.eval()
|
||||||
|
yield assertEquals(result, Predicate.Result.matched())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iotest("should not find a value if it is not associated to a key") {
|
||||||
|
ValueInTests.newProvider(Data.KeyValues).flatMap { provider =>
|
||||||
|
given KeyValueProvider[IO] = provider
|
||||||
|
val p =
|
||||||
|
ValueIn[IO](Data.ExistingKey, Set(Data.NotExistingValue))
|
||||||
|
for result <- p.eval()
|
||||||
|
yield assertEquals(result, Predicate.Result.missed())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iotest("should not find a key that does not exist within some provider") {
|
||||||
|
ValueInTests.newProvider(Data.KeyValues).flatMap { provider =>
|
||||||
|
given KeyValueProvider[IO] = provider
|
||||||
|
val p = ValueIn[IO](Data.NotExistingKey, Set(""))
|
||||||
|
for result <- p.eval()
|
||||||
|
yield assertEquals(result, Predicate.Result.missed())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ValueInTests:
|
||||||
|
|
||||||
|
object Data:
|
||||||
|
|
||||||
|
val ExistingKey: String = Gen.string.alphaNumeric(Size.Fixed(8)).gen()
|
||||||
|
val NotExistingKey: String = Gen.string.alphaNumeric(Size.Fixed(6)).gen()
|
||||||
|
val ExistingValue: String = Gen.string.alphaNumeric(Size.Fixed(10)).gen()
|
||||||
|
val NotExistingValue: String = Gen.string.alphaNumeric(Size.Fixed(4)).gen()
|
||||||
|
val KeyValues: Map[String, String] = Map(ExistingKey -> ExistingValue)
|
||||||
|
|
||||||
|
end Data
|
||||||
|
|
||||||
|
def newProvider(data: Map[String, String]): IO[KeyValueProvider[IO]] =
|
||||||
|
for map <- MapRef.ofSingleImmutableMap[IO, String, String](data)
|
||||||
|
yield new MemoryMapKeyValueProvider(map)
|
||||||
|
|
||||||
|
end ValueInTests
|
||||||
Loading…
Add table
Reference in a new issue