Skip to content

Commit

Permalink
Atomic instance for circe BiggerDecimal
Browse files Browse the repository at this point in the history
See #36.
  • Loading branch information
durban committed Jan 20, 2017
1 parent 9c40538 commit 1078c83
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 12 deletions.
55 changes: 55 additions & 0 deletions circe/src/main/scala/io/sigs/seals/circe/Atoms.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2017 Daniel Urban
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sigs.seals
package circe

import java.util.UUID

import io.circe.numbers.BiggerDecimal

trait Atoms {

implicit val atomicForBiggerDecimal: Atomic[BiggerDecimal] =
Atoms.AtomicForBiggerDecimal
}

object Atoms extends Atoms {

// Note: this is defined in the object (and
// not the trait), because this way serialization
// and deserialization of this Atomic instance
// preserves object identity.
private[Atoms] object AtomicForBiggerDecimal
extends Atomic[BiggerDecimal]
with Atomic.FallbackBinary[BiggerDecimal] {

val description: String =
"BiggerDecimal"

val uuid: UUID =
UUID.fromString("5c3d07fd-2f45-4f7b-af52-eeba62b95aa1")

def stringRepr(a: BiggerDecimal): String =
a.toString

def fromString(s: String): Either[Atomic.Error, BiggerDecimal] = {
BiggerDecimal.parseBiggerDecimal(s).toRight(
left = Atomic.InvalidData(s"not a BiggerDecimal: '${s}'")
)
}
}
}
57 changes: 57 additions & 0 deletions circe/src/test/scala/io/sigs/seals/circe/AtomicLawsSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2017 Daniel Urban
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sigs.seals
package circe

import cats.Eq

import io.circe.numbers.BiggerDecimal

import org.scalacheck.{ Arbitrary, Gen }

class AtomicLawsSpec extends tests.BaseLawsSpec {

import Atoms._

implicit val eqBiggerDecimal: Eq[BiggerDecimal] =
Eq.fromUniversalEquals

implicit def arbBiggerDecimal(
implicit
arbBd: Arbitrary[BigDecimal],
arbBi: Arbitrary[BigInt],
arbDbl: Arbitrary[Double]
): Arbitrary[BiggerDecimal] = Arbitrary {
Gen.oneOf(
// fits into a BigDecimal:
arbBd.arbitrary.map { x =>
BiggerDecimal.fromBigDecimal(x.underlying)
},
// doesn't fit into a BigDecimal:
arbBi.arbitrary.map { n =>
val str = s"${n}e${n max Int.MaxValue.toLong + 1L}"
BiggerDecimal.parseBiggerDecimal(str).getOrElse {
core.impossible(s"cannot parse BiggerDecimal from '${str}'")
}
},
// can contain negative zero:
arbDbl.arbitrary.map(d => BiggerDecimal.fromDouble(- d))
)
}

checkAtomicLaws[BiggerDecimal]("BiggerDecimal")
}
38 changes: 38 additions & 0 deletions circe/src/test/scala/io/sigs/seals/circe/AtomsSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2017 Daniel Urban
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sigs.seals
package circe

import io.circe.numbers.BiggerDecimal

import circe.Atoms._
import circe.Codecs._

class AtomsSpec extends BaseJsonSpec {

"Atomic[BiggerDecimal]" in {
val bds = List(
BiggerDecimal.fromLong(0L),
BiggerDecimal.NegativeZero,
// this is too big for a BigDecimal:
BiggerDecimal.parseBiggerDecimal(s"9999e${Int.MaxValue.toLong * 2}").getOrElse(fail)
)
for (bd <- bds) {
checkJson(bd)
}
}
}
14 changes: 13 additions & 1 deletion tests/src/test/scala/io/sigs/seals/tests/BaseLawsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,32 @@ package tests
import java.util.UUID

import cats.Eq
import cats.kernel.laws._

import org.scalatest.FunSuite
import org.scalacheck.{ Arbitrary, Gen }
import org.scalacheck.util.Buildable
import org.typelevel.discipline.scalatest.Discipline

import laws.{ AnyLaws, AtomicLaws }

trait BaseLawsSpec
extends FunSuite
with Discipline
with laws.TestEqInstances {
with laws.TestEqInstances
with laws.TestArbInstances {

implicit val eqForUuid: Eq[UUID] =
Eq.fromUniversalEquals

def checkAtomicLaws[A](name: String)(implicit a: Arbitrary[A], e: Eq[A], at: Atomic[A]): Unit = {
checkAll(s"Atomic[$name].AnyLaws.any", AnyLaws[Atomic[A]].any)
checkAll(s"Atomic[$name].AnyLaws.equalitySerializability", AnyLaws[Atomic[A]].equalitySerializability)
checkAll(s"Atomic[$name].AnyLaws.referenceEquality", AnyLaws[Atomic[A]].referenceEquality)
checkAll(s"Atomic[$name].OrderLaws.eqv", OrderLaws[Atomic[A]].eqv)
checkAll(s"Atomic[$name].AtomicLaws.roundtrip", AtomicLaws[A].roundtrip)
}

/**
* Some generators fail to produce
* instances quite frequently. When
Expand Down
13 changes: 2 additions & 11 deletions tests/src/test/scala/io/sigs/seals/tests/LawsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,10 @@ import org.scalacheck.{ Arbitrary, Cogen }

import io.sigs.seals.laws._

import TestArbInstances._
import TestArbInstances.forTestData._

class LawsSpec extends BaseLawsSpec {

import forTestData._

checkEnvelopeLaws[TestTypes.adts.defs.Adt1]("Adt1")
checkEnvelopeLaws[TestTypes.adts.recursive.IntList]("IntList")

Expand Down Expand Up @@ -151,14 +150,6 @@ class LawsSpec extends BaseLawsSpec {
)
}

def checkAtomicLaws[A](name: String)(implicit a: Arbitrary[A], e: Eq[A], at: Atomic[A]): Unit = {
checkAll(s"Atomic[$name].AnyLaws.any", AnyLaws[Atomic[A]].any)
checkAll(s"Atomic[$name].AnyLaws.equalitySerializability", AnyLaws[Atomic[A]].equalitySerializability)
checkAll(s"Atomic[$name].AnyLaws.referenceEquality", AnyLaws[Atomic[A]].referenceEquality)
checkAll(s"Atomic[$name].OrderLaws.eqv", OrderLaws[Atomic[A]].eqv)
checkAll(s"Atomic[$name].AtomicLaws.roundtrip", AtomicLaws[A].roundtrip)
}

def checkKleeneLaws[F[_], A](name: String)(
implicit
arbA: Arbitrary[A],
Expand Down

0 comments on commit 1078c83

Please sign in to comment.