Skip to content

Commit

Permalink
Close #104 - Add isZero to Monoid
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin-lee committed Oct 14, 2019
1 parent 3ab7fab commit 372a292
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 33 deletions.
2 changes: 2 additions & 0 deletions src/main/scala/just/fp/Monoid.scala
Expand Up @@ -9,6 +9,8 @@ import just.fp.SemiGroup.{BigDecimalSemiGroup, BigIntSemiGroup, ByteSemiGroup, C
trait Monoid[A] extends SemiGroup[A] {
def zero: A

def isZero(a: A)(implicit E: Equal[A]): Boolean = Equal[A].equal(a, zero)

@SuppressWarnings(Array("org.wartremover.warts.ImplicitParameter"))
trait MonoidLaw {
/*
Expand Down
4 changes: 2 additions & 2 deletions src/test/scala/just/fp/ApplicativeSpec.scala
Expand Up @@ -39,7 +39,7 @@ object ApplicativeSpec extends Properties {
}

object ListApplicativeLaws {
def genList: Gen[List[Int]] = Gens.genList(Gens.genIntFromMinToMax, 20)
def genList: Gen[List[Int]] = Gens.genList(Gens.genIntFromMinToMax, 0, 20)

def laws: Property =
Specs.applicativeLaws.laws[List](
Expand All @@ -50,7 +50,7 @@ object ApplicativeSpec extends Properties {
}

object VectorApplicativeLaws {
def genVector: Gen[Vector[Int]] = Gens.genVector(Gens.genIntFromMinToMax, 20)
def genVector: Gen[Vector[Int]] = Gens.genVector(Gens.genIntFromMinToMax, 0, 20)

def laws: Property =
Specs.applicativeLaws.laws[Vector](
Expand Down
4 changes: 2 additions & 2 deletions src/test/scala/just/fp/FunctorSpec.scala
Expand Up @@ -37,7 +37,7 @@ object FunctorSpec extends Properties {
}

object ListFunctorLaws {
def genList: Gen[List[Int]] = Gens.genList(Gens.genIntFromMinToMax, 20)
def genList: Gen[List[Int]] = Gens.genList(Gens.genIntFromMinToMax, 0, 20)

def laws: Property =
Specs.functorLaws.laws[List](
Expand All @@ -47,7 +47,7 @@ object FunctorSpec extends Properties {
}

object VectorFunctorLaws {
def genVector: Gen[Vector[Int]] = Gens.genVector(Gens.genIntFromMinToMax, 20)
def genVector: Gen[Vector[Int]] = Gens.genVector(Gens.genIntFromMinToMax, 0, 20)

def laws: Property =
Specs.functorLaws.laws[Vector](
Expand Down
32 changes: 19 additions & 13 deletions src/test/scala/just/fp/Gens.scala
Expand Up @@ -176,40 +176,46 @@ object Gens {
(x, y)
}

def genBigInt: Gen[BigInt] =
genLongFromMinToMax.map(BigInt(_))
def genBigIntFromMinToMaxLong: Gen[BigInt] =
genBigInt(Long.MinValue, Long.MaxValue)

def genBigInt(min: Long, max: Long): Gen[BigInt] =
genLong(min, max).map(BigInt(_))

def genDifferentBigIntPair: Gen[(BigInt, BigInt)] = for {
n1 <- genBigInt
n2 <- genBigInt.map(x => if (x === n1) x + BigInt(1) else x)
n1 <- genBigIntFromMinToMaxLong
n2 <- genBigIntFromMinToMaxLong.map(x => if (x === n1) x + BigInt(1) else x)
} yield {
(n1, n2)
}

def genBigDecimal: Gen[BigDecimal] =
def genBigDecimalFromMinToMaxFloatLong: Gen[BigDecimal] =
genBigDecimal(Float.MinValue, Float.MaxValue, Long.MinValue, Long.MaxValue)

def genBigDecimal(min: Float, max: Float, longMin: Long, longMax: Long): Gen[BigDecimal] =
Gen.choice1(
/*
* MathContext.UNLIMITED should be used due to https://github.com/scala/bug/issues/11590
*/
genDoubleFromMinToMax.map(BigDecimal(_, java.math.MathContext.UNLIMITED))
, genBigInt.map(BigDecimal(_, java.math.MathContext.UNLIMITED))
genDouble(min.toDouble, max.toDouble).map(BigDecimal(_, java.math.MathContext.UNLIMITED))
, genBigInt(longMin, longMax).map(BigDecimal(_, java.math.MathContext.UNLIMITED))
)

def genDifferentBigDecimalPair: Gen[(BigDecimal, BigDecimal)] = for {
n1 <- genBigDecimal
n2 <- genBigDecimal.map(x => if (x === n1) x + BigDecimal(1) else x)
n1 <- genBigDecimalFromMinToMaxFloatLong
n2 <- genBigDecimalFromMinToMaxFloatLong.map(x => if (x === n1) x + BigDecimal(1) else x)
} yield {
(n1, n2)
}

def genAToMonadA[M[_], A](genF: Gen[A => A])(implicit m: Monad[M]): Gen[A => M[A]] =
genF.map(f => x => m.pure(f(x)))

def genList[A](genA: Gen[A], length: Int): Gen[List[A]] =
genA.list(Range.linear(0, length))
def genList[A](genA: Gen[A], min: Int, max: Int): Gen[List[A]] =
genA.list(Range.linear(min, max))

def genVector[A](genA: Gen[A], length: Int): Gen[Vector[A]] =
genA.list(Range.linear(0, length)).map(_.toVector)
def genVector[A](genA: Gen[A], min: Int, max: Int): Gen[Vector[A]] =
genA.list(Range.linear(min, max)).map(_.toVector)

@SuppressWarnings(Array("org.wartremover.warts.ImplicitParameter"))
def genFuture[A](
Expand Down
4 changes: 2 additions & 2 deletions src/test/scala/just/fp/MonadSpec.scala
Expand Up @@ -41,7 +41,7 @@ object MonadSpec extends Properties {
}

object ListMonadLaws {
def genList: Gen[List[Int]] = Gens.genList(Gens.genIntFromMinToMax, 20)
def genList: Gen[List[Int]] = Gens.genList(Gens.genIntFromMinToMax, 0, 20)

def laws: Property =
Specs.monadLaws.laws[List](
Expand All @@ -53,7 +53,7 @@ object MonadSpec extends Properties {
}

object VectorMonadLaws {
def genVector: Gen[Vector[Int]] = Gens.genVector(Gens.genIntFromMinToMax, 20)
def genVector: Gen[Vector[Int]] = Gens.genVector(Gens.genIntFromMinToMax, 0, 20)

def laws: Property =
Specs.monadLaws.laws[Vector](
Expand Down
42 changes: 38 additions & 4 deletions src/test/scala/just/fp/MonoidSpec.scala
Expand Up @@ -9,22 +9,56 @@ import hedgehog.runner._
*/
object MonoidSpec extends Properties {

import just.fp.syntax._

override def tests: List[Test] = List(
property("testOptionMonoidLaw", OptionMonoidLaws.laws)
, example("test OptionMonoid.isZero zero case", testIsZero(none[Int]))
, property("test OptionMonoid.isZero non-zero case", testNonZero(Gens.genIntFromMinToMax.map(_.some)))
, property("testListMonoidLaw", ListMonoidLaws.laws)
, example("test ListMonoid.isZero zero case", testIsZero(List.empty[Int]))
, property("test ListMonoid.isZero non-zero case", testNonZero(Gens.genList(Gens.genIntFromMinToMax, 1, 10)))
, property("testVectorMonoidLaw", VectorMonoidLaws.laws)
, example("test VectorMonoid.isZero zero case", testIsZero(Vector.empty[Int]))
, property("test VectorMonoid.isZero non-zero case", testNonZero(Gens.genVector(Gens.genIntFromMinToMax, 1, 10)))
, property("testStringMonoidLaw", StringMonoidLaws.laws)
, example("test StringMonoid.isZero zero case", testIsZero(""))
, property("test StringMonoid.isZero non-zero case", testNonZero(Gen.constant("a").flatMap(c => Gens.genUnicodeString.map(c + _))))
, property("testByteMonoidLaw", ByteMonoidLaws.laws)
, example("test ByteMonoid.isZero zero case", testIsZero(0.toByte))
, property("test ByteMonoid.isZero non-zero case", testNonZero(Gens.genByte(1, Byte.MaxValue)))
, property("testShortMonoidLaw", ShortMonoidLaws.laws)
, example("test ShortMonoid.isZero zero case", testIsZero(0.toShort))
, property("test ShortMonoid.isZero non-zero case", testNonZero(Gens.genShort(1, Short.MaxValue)))
, property("testCharMonoidLaw", CharMonoidLaws.laws)
, example("test CharMonoid.isZero zero case", testIsZero(0.toChar))
, property("test CharMonoid.isZero non-zero case", testNonZero(Gens.genChar(1, Char.MaxValue)))
, property("testIntMonoidLaw", IntMonoidLaws.laws)
, example("test IntMonoid.isZero zero case", testIsZero(0))
, property("test IntMonoid.isZero non-zero case", testNonZero(Gens.genInt(1, Int.MaxValue)))
, property("testLongMonoidLaw", LongMonoidLaws.laws)
, example("test LongMonoid.isZero zero case", testIsZero(0L))
, property("test LongMonoid.isZero non-zero case", testNonZero(Gens.genLong(1L, Long.MaxValue)))
, property("testBigIntMonoidLaw", BigIntMonoidLaws.laws)
, example("test BigIntMonoid.isZero zero case", testIsZero(BigInt(0)))
, property("test BigIntMonoid.isZero non-zero case", testNonZero(Gens.genBigInt(1L, Long.MaxValue)))
, property("testBigDecimalMonoidLaw", BigDecimalMonoidLaws.laws)
, example("test BigDecimalMonoid.isZero zero case", testIsZero(BigDecimal(0)))
, property("test BigDecimalMonoid.isZero non-zero case", testNonZero(Gens.genBigDecimal(1F, Float.MaxValue, 1L, Long.MaxValue)))
)

def testIsZero[A : Monoid : Equal](monoid: A): Result = {
Result.diffNamed("=== isZero Not true ===", Monoid[A], monoid)(_.isZero(_))
}

def testNonZero[A : Monoid : Equal](genA: Gen[A]): Property = for {
monoid <- genA.log("monoid")
} yield {
Result.diffNamed("=== isZero Not false ===", Monoid[A], monoid)(!_.isZero(_))
}

object ListMonoidLaws {
def genList: Gen[List[Int]] = Gens.genList(Gens.genIntFromMinToMax, 20)
def genList: Gen[List[Int]] = Gens.genList(Gens.genIntFromMinToMax, 0, 20)

def laws: Property =
Specs.monoidLaws.laws[List[Int]](
Expand All @@ -33,7 +67,7 @@ object MonoidSpec extends Properties {
}

object VectorMonoidLaws {
def genVector: Gen[Vector[Int]] = Gens.genVector(Gens.genIntFromMinToMax, 20)
def genVector: Gen[Vector[Int]] = Gens.genVector(Gens.genIntFromMinToMax, 0, 20)

def laws: Property =
Specs.monoidLaws.laws[Vector[Int]](
Expand Down Expand Up @@ -105,7 +139,7 @@ object MonoidSpec extends Properties {
}

object BigIntMonoidLaws {
def genBigInt: Gen[BigInt] = Gens.genBigInt
def genBigInt: Gen[BigInt] = Gens.genBigIntFromMinToMaxLong

def laws: Property =
Specs.monoidLaws.laws[BigInt](
Expand All @@ -114,7 +148,7 @@ object MonoidSpec extends Properties {
}

object BigDecimalMonoidLaws {
def genBigDecimal: Gen[BigDecimal] = Gens.genBigDecimal
def genBigDecimal: Gen[BigDecimal] = Gens.genBigDecimalFromMinToMaxFloatLong

def laws: Property =
Specs.monoidLaws.laws[BigDecimal](
Expand Down
4 changes: 2 additions & 2 deletions src/test/scala/just/fp/syntax/EqualSyntaxSpec.scala
Expand Up @@ -22,8 +22,8 @@ object EqualSyntaxSpec extends Properties {
, property("test Float === Float", testTripleEquals(Gens.genAllFloatNoNaN))
, property("test Double === Double", testTripleEquals(Gens.genAllDoubleNoNaN))
, property("test String === String", testTripleEquals(Gens.genUnicodeString))
, property("test BigInt === BigInt", testTripleEquals(Gens.genBigInt))
, property("test BigDecimal === BigDecimal", testTripleEquals(Gens.genBigDecimal))
, property("test BigInt === BigInt", testTripleEquals(Gens.genBigIntFromMinToMaxLong))
, property("test BigDecimal === BigDecimal", testTripleEquals(Gens.genBigDecimalFromMinToMaxFloatLong))
, property("test Boolean !== Boolean", testNotDoubleEquals(Gens.genDifferentBooleanPair))
, property("test Int !== Int", testNotDoubleEquals(Gens.genDifferentIntPair))
, property("test Short !== Short", testNotDoubleEquals(Gens.genDifferentShortPair))
Expand Down
16 changes: 8 additions & 8 deletions src/test/scala/just/fp/syntax/SemiGroupSyntaxSpec.scala
Expand Up @@ -13,27 +13,27 @@ object SemiGroupSyntaxSpec extends Properties {

override def tests: List[Test] = List(
property("test Option |+| Option", testPlus(Gens.genOption(Gens.genIntFromMinToMax)))
, property("test List |+| List", testPlus(Gens.genList(Gens.genIntFromMinToMax, 10)))
, property("test Vector |+| Vector", testPlus(Gens.genVector(Gens.genIntFromMinToMax, 10)))
, property("test List |+| List", testPlus(Gens.genList(Gens.genIntFromMinToMax, 0, 10)))
, property("test Vector |+| Vector", testPlus(Gens.genVector(Gens.genIntFromMinToMax, 0, 10)))
, property("test String |+| String", testPlus(Gens.genUnicodeString))
, property("test Byte |+| Byte", testPlus(Gens.genByteFromMinToMax))
, property("test Short |+| Short", testPlus(Gens.genShortFromMinToMax))
, property("test Char |+| Char", testPlus(Gens.genCharFromMinToMax))
, property("test Int |+| Int", testPlus(Gens.genIntFromMinToMax))
, property("test Long |+| Long", testPlus(Gens.genLongFromMinToMax))
, property("test BigInt |+| BigInt", testPlus(Gens.genBigInt))
, property("test BigDecimal |+| BigDecimal", testPlus(Gens.genBigDecimal))
, property("test BigInt |+| BigInt", testPlus(Gens.genBigIntFromMinToMaxLong))
, property("test BigDecimal |+| BigDecimal", testPlus(Gens.genBigDecimalFromMinToMaxFloatLong))
, property("test Option.mappend(Option)", testMappend(Gens.genOption(Gens.genIntFromMinToMax)))
, property("test List.mappend(List)", testMappend(Gens.genList(Gens.genIntFromMinToMax, 10)))
, property("test Vector.mappend(Vector)", testMappend(Gens.genVector(Gens.genIntFromMinToMax, 10)))
, property("test List.mappend(List)", testMappend(Gens.genList(Gens.genIntFromMinToMax, 0, 10)))
, property("test Vector.mappend(Vector)", testMappend(Gens.genVector(Gens.genIntFromMinToMax, 0, 10)))
, property("test String.mappend(String)", testMappend(Gens.genUnicodeString))
, property("test Byte.mappend(Byte)", testMappend(Gens.genByteFromMinToMax))
, property("test Short.mappend(Short)", testMappend(Gens.genShortFromMinToMax))
, property("test Char.mappend(Char)", testMappend(Gens.genCharFromMinToMax))
, property("test Int.mappend(Int)", testMappend(Gens.genIntFromMinToMax))
, property("test Long.mappend(Long)", testMappend(Gens.genLongFromMinToMax))
, property("test BigInt.mappend(BigInt)", testMappend(Gens.genBigInt))
, property("test BigDecimal.mappend(BigDecimal)", testMappend(Gens.genBigDecimal))
, property("test BigInt.mappend(BigInt)", testMappend(Gens.genBigIntFromMinToMaxLong))
, property("test BigDecimal.mappend(BigDecimal)", testMappend(Gens.genBigDecimalFromMinToMaxFloatLong))
)

def testPlus[A: SemiGroup](genA: Gen[A]): Property = for {
Expand Down

0 comments on commit 372a292

Please sign in to comment.