Skip to content

Commit

Permalink
Adding FiniteDuration instances (#2544)
Browse files Browse the repository at this point in the history
* Adding FiniteDuration instances

* Adding finiteDuration instances to cats core

* not duplicating, just re-using an instance

* Adding instances where they need to go

* Adding tests to LawTests and a FiniteDurationSuite

* Fixing regex error

* Fixing bin incompatibility
  • Loading branch information
Calvin Brown authored and Luka Jacobowitz committed Oct 7, 2018
1 parent 4880fd0 commit ee2b5ee
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 2 deletions.
1 change: 1 addition & 0 deletions core/src/main/scala/cats/instances/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ trait AllInstancesBinCompat1

trait AllInstancesBinCompat2
extends DurationInstances
with FiniteDurationInstances
9 changes: 9 additions & 0 deletions core/src/main/scala/cats/instances/finiteDuration.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package cats
package instances

import scala.concurrent.duration.FiniteDuration

trait FiniteDurationInstances extends cats.kernel.instances.FiniteDurationInstances {
implicit val catsStdShowForFiniteDuration: Show[FiniteDuration] =
Show.fromToString[FiniteDuration]
}
1 change: 1 addition & 0 deletions core/src/main/scala/cats/instances/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ package object instances {
object eq extends EqInstances
object equiv extends EquivInstances
object float extends FloatInstances
object finiteDuration extends FiniteDurationInstances
object function extends FunctionInstances with FunctionInstancesBinCompat0
object future extends FutureInstances
object int extends IntInstances
Expand Down
33 changes: 32 additions & 1 deletion kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Arbitrary.arbitrary
import org.scalactic.anyvals.{ PosInt, PosZInt }
import org.scalatest.FunSuite

import scala.concurrent.duration.Duration
import scala.concurrent.duration.{ Duration, FiniteDuration }
import scala.collection.immutable.{BitSet, Queue}
import scala.util.Random

Expand Down Expand Up @@ -47,6 +47,20 @@ object KernelCheck {
Gen.choose(-n * 86400000000000L, n * 86400000000000L).map(Duration(_, NANOSECONDS))))
}

implicit val arbitraryFiniteDuration: Arbitrary[FiniteDuration] = {
// max range is +/- 292 years, but we give ourselves some extra headroom
// to ensure that we can add these things up. they crash on overflow.
val n = (292L * 365) / 50
Arbitrary(Gen.oneOf(
Gen.choose(-n, n).map(FiniteDuration(_, DAYS)),
Gen.choose(-n * 24L, n * 24L).map(FiniteDuration(_, HOURS)),
Gen.choose(-n * 1440L, n * 1440L).map(FiniteDuration(_, MINUTES)),
Gen.choose(-n * 86400L, n * 86400L).map(FiniteDuration(_, SECONDS)),
Gen.choose(-n * 86400000L, n * 86400000L).map(FiniteDuration(_, MILLISECONDS)),
Gen.choose(-n * 86400000000L, n * 86400000000L).map(FiniteDuration(_, MICROSECONDS)),
Gen.choose(-n * 86400000000000L, n * 86400000000000L).map(FiniteDuration(_, NANOSECONDS))))
}

// this instance is not available in scalacheck 1.13.2.
// remove this once a newer version is available.
implicit val cogenBigInt: Cogen[BigInt] =
Expand Down Expand Up @@ -78,6 +92,19 @@ object KernelCheck {
case NANOSECONDS => 6128745701389500153L
})
}

implicit val cogenFiniteDuration: Cogen[FiniteDuration] =
Cogen[Long].contramap { d =>
d.length * (d.unit match {
case DAYS => -6307593037248227856L
case HOURS => -3527447467459552709L
case MINUTES => 5955657079535371609L
case SECONDS => 5314272869665647192L
case MILLISECONDS => -2025740217814855607L
case MICROSECONDS => -2965853209268633779L
case NANOSECONDS => 6128745701389500153L
})
}
}

class Tests extends FunSuite with Discipline {
Expand Down Expand Up @@ -132,6 +159,7 @@ class Tests extends FunSuite with Discipline {
checkAll("PartialOrder[BitSet]", PartialOrderTests[BitSet].partialOrder)
checkAll("Order[BigInt]", OrderTests[BigInt].order)
checkAll("Order[Duration]", OrderTests[Duration].order)
checkAll("Order[FiniteDuration]", OrderTests[FiniteDuration].order)
checkAll("Order[UUID]", OrderTests[UUID].order)
checkAll("Order[List[Int]]", OrderTests[List[Int]] .order)
checkAll("Order[Option[String]]", OrderTests[Option[String]].order)
Expand Down Expand Up @@ -187,6 +215,8 @@ class Tests extends FunSuite with Discipline {
checkAll("CommutativeGroup[BigInt]", SerializableTests.serializable(CommutativeGroup[BigInt]))
checkAll("CommutativeGroup[Duration]", CommutativeGroupTests[Duration].commutativeGroup)
checkAll("CommutativeGroup[Duration]", SerializableTests.serializable(CommutativeGroup[Duration]))
checkAll("CommutativeGroup[FiniteDuration]", CommutativeGroupTests[FiniteDuration].commutativeGroup)
checkAll("CommutativeGroup[FiniteDuration]", SerializableTests.serializable(CommutativeGroup[FiniteDuration]))


checkAll("Hash[Unit]" , HashTests[Unit].hash)
Expand All @@ -198,6 +228,7 @@ class Tests extends FunSuite with Discipline {
checkAll("Hash[Char]" , HashTests[Char].hash)
checkAll("Hash[Int]" , HashTests[Int].hash)
checkAll("Hash[Duration]", HashTests[Duration].hash)
checkAll("Hash[FiniteDuration]", HashTests[FiniteDuration].hash)

// NOTE: Do not test for Float/Double/Long. These types'
// `##` is different from `hashCode`. See [[scala.runtime.Statics.anyHash]].
Expand Down
5 changes: 4 additions & 1 deletion kernel/src/main/scala/cats/kernel/instances/all.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats.kernel
package instances

package object all extends AllInstances
package object all extends AllInstances with AllInstancesBinCompat0

trait AllInstances
extends BigDecimalInstances
Expand Down Expand Up @@ -34,3 +34,6 @@ trait AllInstances
with UnitInstances
with UUIDInstances
with VectorInstances


trait AllInstancesBinCompat0 extends FiniteDurationInstances
32 changes: 32 additions & 0 deletions kernel/src/main/scala/cats/kernel/instances/finiteDuration.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cats.kernel
package instances

import scala.concurrent.duration.{ Duration, FiniteDuration }


trait FiniteDurationInstances {
implicit val catsKernelStdOrderForFiniteDuration: Order[FiniteDuration] with Hash[FiniteDuration] = new FiniteDurationOrder
implicit val catsKernelStdGroupForFiniteDuration: CommutativeGroup[FiniteDuration] = new FiniteDurationGroup
}
class FiniteDurationOrder extends Order[FiniteDuration] with Hash[FiniteDuration] {
def hash(x: FiniteDuration): Int = x.hashCode()

def compare(x: FiniteDuration, y: FiniteDuration): Int = x compare y

override def eqv(x: FiniteDuration, y: FiniteDuration): Boolean = x == y
override def neqv(x: FiniteDuration, y: FiniteDuration): Boolean = x != y
override def gt(x: FiniteDuration, y: FiniteDuration): Boolean = x > y
override def gteqv(x: FiniteDuration, y: FiniteDuration): Boolean = x >= y
override def lt(x: FiniteDuration, y: FiniteDuration): Boolean = x < y
override def lteqv(x: FiniteDuration, y: FiniteDuration): Boolean = x <= y

override def min(x: FiniteDuration, y: FiniteDuration): FiniteDuration = x min y
override def max(x: FiniteDuration, y: FiniteDuration): FiniteDuration = x max y
}

class FiniteDurationGroup extends CommutativeGroup[FiniteDuration] {
def empty: FiniteDuration = Duration.Zero
def inverse(x: FiniteDuration): FiniteDuration = -x
def combine(x: FiniteDuration, y: FiniteDuration): FiniteDuration = x + y
override def remove(x: FiniteDuration, y: FiniteDuration): FiniteDuration = x - y
}
15 changes: 15 additions & 0 deletions tests/src/test/scala/cats/tests/FiniteDurationSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cats
package tests

import cats.laws.discipline.SerializableTests

import scala.concurrent.duration.{ DurationInt, FiniteDuration }

class FiniteDurationSuite extends CatsSuite {
checkAll("Show[FiniteDuration]", SerializableTests.serializable(Show[FiniteDuration]))

test("show works for FiniteDuration"){
Show[FiniteDuration].show(23.minutes) should ===("23 minutes")
Show[FiniteDuration].show(10.seconds) should === ("10 seconds")
}
}

0 comments on commit ee2b5ee

Please sign in to comment.