Skip to content

Commit

Permalink
Add Validator tests
Browse files Browse the repository at this point in the history
  • Loading branch information
david.geirola committed Apr 8, 2022
1 parent 0a5c353 commit 41b72b6
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 25 deletions.
62 changes: 37 additions & 25 deletions core/src/main/scala/cats/xml/validator/Validator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import cats.kernel.Monoid
import cats.{Contravariant, Eq, Show}
import cats.xml.validator.Validator.must

import scala.util.matching.Regex

trait Validator[T] { $this =>

def apply(t: T): Validator.Result[T]
Expand Down Expand Up @@ -129,55 +131,65 @@ private[validator] sealed trait ValidatorBuilders {
.contramap[String](_.length)
.rewordError(str => s"Length of '$str', expected $expected but is ${str.length}.")

def length(expected: Int): Validator[String] =
max[Int](expected)
def maxLength(maxLen: Int): Validator[String] =
max[Int](maxLen)
.contramap[String](_.length)
.rewordError(str => s"Length of '$str', expected $expected but is ${str.length}.")
.rewordError(str => s"Length of '$str' expected to be <= $maxLen but is ${str.length}.")

def regex(regex: String): Validator[String] =
def minLength(minLen: Int): Validator[String] =
min[Int](minLen)
.contramap[String](_.length)
.rewordError(str => s"Length of '$str' expected to be >= $minLen but is ${str.length}.")

def regex(regex: Regex): Validator[String] =
must[String](str => s"String '$str' doesn't match regex `$regex`.")(
_.matches(regex)
regex.matches(_)
)

// ------------- collections -------------
def isEmpty[T]: Validator[Seq[T]] =
must[Seq[T]](seq => s"Seq${seqToStr(seq)} is not empty.")(
_.isEmpty
def isEmpty[F[X] <: IterableOnce[X]]: Validator[F[Any]] =
must[F[Any]](seq => s"${iterableToStr(seq)} is not empty.")(
_.iterator.isEmpty
)

def nonEmpty[T]: Validator[Seq[T]] =
must[Seq[T]](seq => s"Seq${seqToStr(seq)} is empty.")(
_.nonEmpty
def nonEmpty[F[X] <: IterableOnce[X]]: Validator[F[Any]] =
must[F[Any]](seq => s"${iterableToStr(seq)} is empty.")(
_.iterator.nonEmpty
)

def maxSize[T](maxSize: Int): Validator[Seq[T]] =
must[Seq[T]](seq => s"Seq${seqToStr(seq)} size must be <= $maxSize")(
_.size <= maxSize
def maxSize[F[X] <: IterableOnce[X]](maxSize: Int): Validator[F[Any]] =
must[F[Any]](seq => s"${iterableToStr(seq)} size must be <= $maxSize")(
_.iterator.size <= maxSize
)

def minSize[T](minSize: Int): Validator[Seq[T]] =
must[Seq[T]](seq => s"Seq${seqToStr(seq)} size must be >= $minSize")(
_.size >= minSize
def minSize[F[X] <: IterableOnce[X]](minSize: Int): Validator[F[Any]] =
must[F[Any]](seq => s"${iterableToStr(seq)} size must be >= $minSize")(
_.iterator.size >= minSize
)

// ------------- cats-collections -------------
def maxSizeNel[T: Show](maxSize: Int): Validator[NonEmptyList[T]] =
must[NonEmptyList[T]](seq => s"NonEmptyList${seqToStr(seq.toList)} size must be <= $maxSize")(
must[NonEmptyList[T]](seq =>
s"NonEmptyList${iterableToStr(seq.toList)} size must be <= $maxSize"
)(
_.size <= maxSize
)

def minSizeNel[T: Show](minSize: Int): Validator[NonEmptyList[T]] =
must[NonEmptyList[T]](seq => s"NonEmptyList${seqToStr(seq.toList)} size must be >= $minSize")(
must[NonEmptyList[T]](seq =>
s"NonEmptyList${iterableToStr(seq.toList)} size must be >= $minSize"
)(
_.size >= minSize
)

private def seqToStr[T](seq: Seq[T], limit: Int = 10)(implicit
s: Show[T] = Show.fromToString[T]
): String =
if (seq.size >= limit)
seq.mkString_("[", ", ", "]")
private def iterableToStr[T](itOnce: IterableOnce[T], limit: Int = 10)(implicit
s: Show[T] = Show.fromToString[T]
): String = {
if (itOnce.iterator.size <= limit)
itOnce.iterator.map(_.show).mkString("[", ", ", "]")
else
seq.take(limit).mkString_("[", ", ", "...]")
itOnce.iterator.take(limit).map(_.show).mkString("[", ", ", ",...]")
}
}

private[xml] trait ValidatorInstances {
Expand Down
149 changes: 149 additions & 0 deletions core/src/test/scala/cats/xml/validator/ValidatorSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -353,4 +353,153 @@ class ValidatorInstancesSuite extends munit.ScalaCheckSuite {
expected = Invalid(NonEmptyList.one("Length of '123456', expected 5 but is 6."))
)
}

test("Validator.maxLength") {

val validator = Validator.maxLength(5)
assertEquals(
obtained = validator.apply("12345"),
expected = Valid("12345")
)

assertEquals(
obtained = validator.apply("1234"),
expected = Valid("1234")
)

assertEquals(
obtained = validator.apply("123456"),
expected = Invalid(NonEmptyList.one("Length of '123456' expected to be <= 5 but is 6."))
)
}

test("Validator.minLength") {

val validator = Validator.minLength(5)
assertEquals(
obtained = validator.apply("12345"),
expected = Valid("12345")
)

assertEquals(
obtained = validator.apply("123456"),
expected = Valid("123456")
)

assertEquals(
obtained = validator.apply("1234"),
expected = Invalid(NonEmptyList.one("Length of '1234' expected to be >= 5 but is 4."))
)
}

test("Validator.regex") {

val validator = Validator.regex("""(\w+)@([\w\.]+)""".r)
assertEquals(
obtained = validator.apply("mimmo@gmail.com"),
expected = Valid("mimmo@gmail.com")
)

assertEquals(
obtained = validator.apply("mimmo_gmail.com"),
expected = Invalid(
NonEmptyList.one("String 'mimmo_gmail.com' doesn't match regex `(\\w+)@([\\w\\.]+)`.")
)
)
}

// collections
test("Validator.isEmpty") {
val validatorSeq: Validator[Seq[Any]] = Validator.isEmpty[Seq]
val validatorOption: Validator[Option[Any]] = Validator.isEmpty[Option]

// seq
assertEquals(
obtained = validatorSeq.apply(Nil),
expected = Valid(Nil)
)

assertEquals(
obtained = validatorSeq.apply(Seq(1, 2, 3)),
expected = Invalid(NonEmptyList.one("[1, 2, 3] is not empty."))
)

// option
assertEquals(
obtained = validatorOption.apply(None),
expected = Valid(None)
)

assertEquals(
obtained = validatorOption.apply(Some(1)),
expected = Invalid(NonEmptyList.one("[1] is not empty."))
)
}

test("Validator.nonEmpty") {
val validatorSeq: Validator[Seq[Any]] = Validator.nonEmpty[Seq]
val validatorOption: Validator[Option[Any]] = Validator.nonEmpty[Option]

// seq
assertEquals(
obtained = validatorSeq.apply(Seq(1, 2, 3)),
expected = Valid(Seq(1, 2, 3))
)

assertEquals(
obtained = validatorSeq.apply(Nil),
expected = Invalid(NonEmptyList.one("[] is empty."))
)

// option
assertEquals(
obtained = validatorOption.apply(Some(1)),
expected = Valid(Some(1))
)

assertEquals(
obtained = validatorOption.apply(None),
expected = Invalid(NonEmptyList.one("[] is empty."))
)
}

test("Validator.maxSize") {
val validatorSeq: Validator[Seq[Any]] = Validator.maxSize(2)

// seq
assertEquals(
obtained = validatorSeq.apply(Seq(1, 2)),
expected = Valid(Seq(1, 2))
)

assertEquals(
obtained = validatorSeq.apply(Nil),
expected = Valid(Nil)
)

assertEquals(
obtained = validatorSeq.apply(Seq(1, 2, 3)),
expected = Invalid(NonEmptyList.one("[1, 2, 3] size must be <= 2"))
)
}

test("Validator.minSize") {
val validatorSeq: Validator[Seq[Any]] = Validator.minSize(2)

// seq
assertEquals(
obtained = validatorSeq.apply(Seq(1, 2)),
expected = Valid(Seq(1, 2))
)

assertEquals(
obtained = validatorSeq.apply(Seq(1, 2, 3)),
expected = Valid(Seq(1, 2, 3))
)

assertEquals(
obtained = validatorSeq.apply(Nil),
expected = Invalid(NonEmptyList.one("[] size must be >= 2"))
)
}
}

0 comments on commit 41b72b6

Please sign in to comment.