Skip to content

Commit

Permalink
Merge b1d5c11 into ee06c69
Browse files Browse the repository at this point in the history
  • Loading branch information
jcazevedo committed Sep 18, 2019
2 parents ee06c69 + b1d5c11 commit 5bec9d9
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 37 deletions.
8 changes: 3 additions & 5 deletions modules/cats/build.sbt
@@ -1,11 +1,9 @@
name := "pureconfig-cats"

crossScalaVersions ~= { _.filterNot(_.startsWith("2.13")) }

libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "2.0.0",
"org.typelevel" %% "cats-laws" % "2.0.0" % "test",
"org.typelevel" %% "discipline" % "0.11.1" % "test")
"org.typelevel" %% "cats-core" % "2.0.0",
"org.typelevel" %% "cats-laws" % "2.0.0" % "test",
"org.typelevel" %% "discipline-scalatest" % "1.0.0-M1" % "test")

developers := List(
Developer("derekmorr", "Derek Morr", "morr.derek@gmail.com", url("https://github.com/derekmorr")),
Expand Down
Expand Up @@ -39,9 +39,9 @@ package object cats {
writer.contramap(_.toSortedMap)

// For emptiable foldables not covered by TraversableOnce reader/writer, e.g. Chain.
implicit def lowPriorityNonReducibleReader[T, F[_]: Foldable: Alternative](implicit reader: ConfigReader[TraversableOnce[T]]): Exported[ConfigReader[F[T]]] =
implicit def lowPriorityNonReducibleReader[T, F[_]: Foldable: Alternative](implicit reader: ConfigReader[List[T]]): Exported[ConfigReader[F[T]]] =
Exported(reader.map(to => (to foldRight Alternative[F].empty[T])(_.pure[F] <+> _)))
implicit def lowPriorityNonReducibleWriter[T, F[_]: Foldable: Alternative](implicit writer: ConfigWriter[TraversableOnce[T]]): Exported[ConfigWriter[F[T]]] =
implicit def lowPriorityNonReducibleWriter[T, F[_]: Foldable: Alternative](implicit writer: ConfigWriter[List[T]]): Exported[ConfigWriter[F[T]]] =
Exported(writer.contramap(_.toList))

implicit def nonEmptyChainReader[T](implicit reader: ConfigReader[Chain[T]]): ConfigReader[NonEmptyChain[T]] =
Expand Down
Expand Up @@ -7,15 +7,16 @@ import cats.instances.unit._
import cats.kernel.laws.discipline.SemigroupTests
import cats.laws.discipline._
import com.typesafe.config.ConfigValue
import org.scalatest.{ FunSuite, Matchers }
import org.scalatest.Matchers
import org.scalatest.funsuite.AnyFunSuite
import org.typelevel.discipline.scalatest.Discipline
import pureconfig._
import pureconfig.error.ConfigReaderFailures
import pureconfig.module.cats.arbitrary._
import pureconfig.module.cats.eq._
import pureconfig.module.cats.instances._

class CatsLawsSuite extends FunSuite with Matchers with Discipline {
class CatsLawsSuite extends AnyFunSuite with Matchers with Discipline {
checkAll("ConfigReader[Int]", ApplicativeErrorTests[ConfigReader, ConfigReaderFailures].applicativeError[Int, Int, Int])
checkAll("ConfigWriter[Int]", ContravariantSemigroupalTests[ConfigWriter].contravariantSemigroupal[Int, Int, Int])
checkAll("ConfigConvert[Int]", InvariantSemigroupalTests[ConfigConvert].invariantSemigroupal[Int, Int, Int])
Expand Down
56 changes: 47 additions & 9 deletions modules/cats/src/test/scala/pureconfig/module/cats/CatsSuite.scala
Expand Up @@ -5,25 +5,63 @@ import cats.implicits._
import com.typesafe.config.ConfigFactory.parseString
import pureconfig.generic.auto._
import pureconfig.syntax._
import pureconfig.{ BaseSuite, ConfigConvertChecks }

import pureconfig.{ BaseSuite, ConfigConvertChecks, ConfigReader, ConfigWriter }
import scala.collection.immutable.{ SortedMap, SortedSet }

class CatsSuite extends BaseSuite with ConfigConvertChecks {
import com.typesafe.config.{ ConfigRenderOptions, ConfigValue }
import org.scalatest.flatspec.AnyFlatSpec
import scala.reflect.runtime.universe._

import org.scalactic.Equality
import org.scalatest.matchers.Matcher
import org.scalatest.{ EitherValues, Matchers }
import pureconfig.error.{ ConfigReaderFailures, ConfigValueLocation, ConvertFailure, FailureReason }

class CatsSuite extends AnyFlatSpec with Matchers with EitherValues {

// `discipline-scalatest` currently depends on a snapshot version of ScalaTest which doesn't provide FlatSpec. We have
// the following checks under `ConfigConvertChecks` of our `tests` package, which requires types extending it to
// extend from `FlatSpec`. Since we can't extend `ConfigConvertChecks` here, the relevant checks are copied for
// convenience. We should be able to remove them once a stable version of `discipline-scalatest` is released and we
// update ScalaTest.
def checkRead[T: Equality](reprsToValues: (ConfigValue, T)*)(implicit cr: ConfigReader[T], tpe: TypeTag[T]): Unit =
for ((repr, value) <- reprsToValues) {
it should s"read the value $value of type ${tpe.tpe} from ${repr.render(ConfigRenderOptions.concise())}" in {
cr.from(repr).right.value shouldEqual value
}
}

def checkWrite[T: Equality](valuesToReprs: (T, ConfigValue)*)(implicit cw: ConfigWriter[T], tpe: TypeTag[T]): Unit =
for ((value, repr) <- valuesToReprs) {
it should s"write the value $value of type ${tpe.tpe} to ${repr.render(ConfigRenderOptions.concise())}" in {
cw.to(value) shouldEqual repr
}
}

def checkReadWrite[T: ConfigReader: ConfigWriter: TypeTag: Equality](reprsValues: (ConfigValue, T)*): Unit = {
checkRead[T](reprsValues: _*)
checkWrite[T](reprsValues.map(_.swap): _*)
}

def failWith(
reason: FailureReason,
path: String,
location: Option[ConfigValueLocation] = None): Matcher[ConfigReader.Result[Any]] =
be(Left(ConfigReaderFailures(ConvertFailure(reason, location, path), Nil)))

case class Numbers(numbers: NonEmptyList[Int])
case class NumVec(numbers: NonEmptyVector[Int])
case class NumSet(numbers: NonEmptySet[Int])
case class NumMap(numbers: NonEmptyMap[String, Int])
case class NumChain(numbers: NonEmptyChain[Int])

checkReadWrite[Numbers](parseString(s"""{ numbers: [1,2,3] }""").root() Numbers(NonEmptyList(1, List(2, 3))))
checkReadWrite[NumVec](parseString(s"""{ numbers: [1,2,3] }""").root() NumVec(NonEmptyVector(1, Vector(2, 3))))
checkReadWrite[NumSet](parseString(s"""{ numbers: [1,2,3] }""").root() NumSet(NonEmptySet(1, SortedSet(2, 3))))
checkReadWrite[NumMap](parseString(s"""{
checkReadWrite[Numbers](parseString(s"""{ numbers: [1,2,3] }""").root() -> Numbers(NonEmptyList(1, List(2, 3))))
checkReadWrite[NumVec](parseString(s"""{ numbers: [1,2,3] }""").root() -> NumVec(NonEmptyVector(1, Vector(2, 3))))
checkReadWrite[NumSet](parseString(s"""{ numbers: [1,2,3] }""").root() -> NumSet(NonEmptySet(1, SortedSet(2, 3))))
checkReadWrite[NumMap](parseString(s"""{
numbers {"1": 1, "2": 2, "3": 3 }
}""").root() NumMap(NonEmptyMap(("1", 1), SortedMap("2" 2, "3" 3))))
checkReadWrite[NumChain](parseString(s"""{ numbers: [1,2,3] }""").root() NumChain(NonEmptyChain(1, 2, 3)))
}""").root() -> NumMap(NonEmptyMap(("1", 1), SortedMap("2" -> 2, "3" -> 3))))
checkReadWrite[NumChain](parseString(s"""{ numbers: [1,2,3] }""").root() -> NumChain(NonEmptyChain(1, 2, 3)))

it should "return an EmptyTraversableFound when reading empty lists into NonEmptyList" in {
val config = parseString("{ numbers: [] }")
Expand Down
@@ -1,8 +1,8 @@
package pureconfig.module.cats

import cats.Eq
import cats.instances.either._
import cats.instances.tuple._
import cats.kernel.instances.either._
import cats.kernel.instances.tuple._
import com.typesafe.config.ConfigValue
import org.scalacheck.Arbitrary
import pureconfig._
Expand Down
20 changes: 5 additions & 15 deletions project/Dependencies.scala
Expand Up @@ -3,32 +3,22 @@ import sbt.Keys._

object Dependencies {

private[this] def onScala213(onScala213: String, onOthers: String) = Def.setting {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => onScala213
case _ => onOthers
}
}

object Version {
val shapeless = "2.3.3"
val typesafeConfig = "1.3.4"

val scalaTest = "3.0.8"

// cats will only be compatible with scalacheck 1.14 on 2.x
val scalaCheck = onScala213("1.14.0", "1.13.5")
val scalaCheckShapeless = onScala213("1.2.3", "1.1.8")
val scalaCheck = "1.14.1"
val scalaCheckShapeless = "1.2.3"
}

val shapeless = "com.chuusai" %% "shapeless" % Version.shapeless
val typesafeConfig = "com.typesafe" % "config" % Version.typesafeConfig

// testing libraries
val scalaTest = "org.scalatest" %% "scalatest" % Version.scalaTest % "test"
val scalaCheck = Def.setting { "org.scalacheck" %% "scalacheck" % Version.scalaCheck.value % "test" }
val scalaCheckShapeless = Def.setting {
"com.github.alexarchambault" %%
s"scalacheck-shapeless_${onScala213("1.14", "1.13").value}" % Version.scalaCheckShapeless.value % "test"
}
val scalaCheck = "org.scalacheck" %% "scalacheck" % Version.scalaCheck % "test"
val scalaCheckShapeless =
"com.github.alexarchambault" %% s"scalacheck-shapeless_1.14" % Version.scalaCheckShapeless % "test"
}
4 changes: 2 additions & 2 deletions tests/build.sbt
Expand Up @@ -6,7 +6,7 @@ crossScalaVersions ~= { _ :+ "2.13.0" }

libraryDependencies ++= Seq(
scalaTest,
scalaCheck.value,
scalaCheckShapeless.value)
scalaCheck,
scalaCheckShapeless)

skip in publish := true

0 comments on commit 5bec9d9

Please sign in to comment.