Start to add serde tests

This commit is contained in:
Pat Garrity 2025-11-24 21:34:52 -06:00
parent 16f8356e2c
commit 70976a2610
Signed by: pfm
GPG key ID: 5CA5D21BAB7F3A76
6 changed files with 99 additions and 16 deletions

View file

@ -34,7 +34,7 @@ object And:
def empty[F[_]: Applicative]: Predicate[F] = False[F]
def apply[F[_]: Applicative, A](ps: Predicate[F]*): Predicate[F] =
def apply[F[_]: Applicative](ps: Predicate[F]*): Predicate[F] =
ps.toList match
case Nil => False[F]
case p :: Nil => p

View file

@ -33,7 +33,7 @@ object Or:
def empty[F[_]: Applicative]: Predicate[F] = False[F]
def apply[F[_]: Applicative, A](ps: Predicate[F]*): Predicate[F] =
def apply[F[_]: Applicative](ps: Predicate[F]*): Predicate[F] =
ps.toList match
case Nil => False[F]
case p :: Nil => p

View file

@ -6,6 +6,7 @@ import gs.predicate.v0.api.False
import gs.predicate.v0.api.Or
import gs.predicate.v0.api.Predicate
import gs.predicate.v0.api.True
import gs.predicate.v0.json.JsonProvider
import gs.predicate.v0.kv.KeyExists
import gs.predicate.v0.kv.KeyValueProvider
import gs.predicate.v0.kv.ValueContains
@ -62,29 +63,26 @@ given predicateEncoder[F[_]]: Encoder[Predicate[F]] =
}
/** Given some JSON cursor, decode a logical [[And]] predicate.
*
* TODO: Recursive depth limitations.
*
* @param cursor
* The cursor that points to some JSON value.
* @return
* The [[And]] predicate or a decoding failure.
*/
def decodeAnd[F[_]: Applicative: KeyValueProvider](cursor: HCursor)
: Either[DecodingFailure, And[F]] =
def decodeAnd[F[_]: Applicative: KeyValueProvider: JsonProvider](
cursor: HCursor
): Either[DecodingFailure, And[F]] =
for ps <- cursor.downField(JsonKeys.predicates).as[List[Predicate[F]]]
yield new And(ps)
/** Given some JSON cursor, decode a logical [[Or]] predicate.
*
* TODO: Recursive depth limitations.
*
* @param cursor
* The cursor that points to some JSON value.
* @return
* The [[Or]] predicate or a decoding failure.
*/
def decodeOr[F[_]: Applicative: KeyValueProvider](cursor: HCursor)
def decodeOr[F[_]: Applicative: KeyValueProvider: JsonProvider](cursor: HCursor)
: Either[DecodingFailure, Or[F]] =
for ps <- cursor.downField(JsonKeys.predicates).as[List[Predicate[F]]]
yield new Or(ps)
@ -96,8 +94,9 @@ def decodeOr[F[_]: Applicative: KeyValueProvider](cursor: HCursor)
* @return
* The decoded [[Predicate]] or some decoding failure.
*/
def decodePredicate[F[_]: Applicative: KeyValueProvider](cursor: HCursor)
: Either[DecodingFailure, Predicate[F]] =
def decodePredicate[F[_]: Applicative: KeyValueProvider: JsonProvider](
cursor: HCursor
): Either[DecodingFailure, Predicate[F]] =
for
predicateType <- cursor.downField(JsonKeys.predicateType).as[String]
predicate <- predicateType match
@ -122,6 +121,6 @@ def decodePredicate[F[_]: Applicative: KeyValueProvider](cursor: HCursor)
/** @return
* Generic decoder for any [[Predicate]].
*/
given predicateDecoder[F[_]: Applicative: KeyValueProvider]
given predicateDecoder[F[_]: Applicative: KeyValueProvider: JsonProvider]
: Decoder[Predicate[F]] =
Decoder.instance[Predicate[F]](cursor => decodePredicate[F](cursor))

View file

@ -31,8 +31,8 @@ class AndTests extends IOSuite:
iotest("should return false for an empty list") {
val and = And.empty[IO]
val and2 = And[IO, Any]()
val and3 = And[IO, Any]()
val and2 = And[IO]()
val and3 = And[IO]()
for
result <- and.eval()

View file

@ -31,8 +31,8 @@ class OrTests extends IOSuite:
iotest("should return false for an empty list") {
val or = Or.empty[IO]
val or2 = Or[IO, Any]()
val or3 = Or[IO, Any]()
val or2 = Or[IO]()
val or3 = Or[IO]()
for
result <- or.eval()

View file

@ -0,0 +1,84 @@
package gs.predicate.v0.serde.json
import cats.effect.IO
import gs.predicate.v0.api.And
import gs.predicate.v0.api.False
import gs.predicate.v0.api.Or
import gs.predicate.v0.api.Predicate
import gs.predicate.v0.api.True
import gs.predicate.v0.json.JsonProvider
import gs.predicate.v0.kv.KeyValueProvider
import io.circe.Decoder
import io.circe.Encoder
import io.circe.Json
import munit.FunSuite
class ApiCodecTests extends FunSuite:
test("should serialize and deserialize a True predicate") {
val p = True[IO]
val encoded = Encoder[True[IO]].apply(p)
val decoded = Decoder[True[IO]].decodeJson(encoded)
assertEquals(
encoded,
Json.obj(
(JsonKeys.predicateType, Json.fromString(True.PredicateType))
)
)
assertEquals(decoded.isRight, true)
}
test("should serialize and deserialize a False predicate") {
val p = False[IO]
val encoded = Encoder[False[IO]].apply(p)
val decoded = Decoder[False[IO]].decodeJson(encoded)
assertEquals(
encoded,
Json.obj(
(JsonKeys.predicateType, Json.fromString(False.PredicateType))
)
)
assertEquals(decoded.isRight, true)
}
test("should serialize and deserialize an And predicate") {
given JsonProvider[IO] = JsonProvider.noop[IO]
given KeyValueProvider[IO] = KeyValueProvider.noop[IO]
val t = True[IO]
val f = False[IO]
val trueJson = Encoder[True[IO]].apply(t)
val falseJson = Encoder[False[IO]].apply(f)
val p = And[IO](t, t, f)
val encoded = Encoder[And[IO]].apply(p.asInstanceOf[And[IO]])
val decoded = Decoder[Predicate[IO]].decodeJson(encoded)
assertEquals(
encoded,
Json.obj(
(JsonKeys.predicateType, Json.fromString(And.PredicateType)),
(JsonKeys.predicates, Json.arr(trueJson, trueJson, falseJson))
)
)
assertEquals(decoded.isRight, true)
}
test("should serialize and deserialize an Or predicate") {
given JsonProvider[IO] = JsonProvider.noop[IO]
given KeyValueProvider[IO] = KeyValueProvider.noop[IO]
val t = True[IO]
val f = False[IO]
val trueJson = Encoder[True[IO]].apply(t)
val falseJson = Encoder[False[IO]].apply(f)
val p = Or[IO](t, t, f)
val encoded = Encoder[Or[IO]].apply(p.asInstanceOf[Or[IO]])
val decoded = Decoder[Predicate[IO]].decodeJson(encoded)
assertEquals(
encoded,
Json.obj(
(JsonKeys.predicateType, Json.fromString(Or.PredicateType)),
(JsonKeys.predicates, Json.arr(trueJson, trueJson, falseJson))
)
)
assertEquals(decoded.isRight, true)
}