Skip to content

Commit

Permalink
Add duration type (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
ignaciomosca authored and afsalthaj committed Dec 7, 2019
1 parent 3466d90 commit 819bda3
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 21 deletions.
4 changes: 4 additions & 0 deletions zio-config/src/main/scala/zio/config/ConfigDescriptor.scala
@@ -1,5 +1,7 @@
package zio.config

import scala.concurrent.duration.Duration

import java.net.URI
import zio.config.ConfigDescriptor.Default
import zio.config.ConfigDescriptor.OrElseEither
Expand Down Expand Up @@ -157,6 +159,8 @@ object ConfigDescriptor {
ConfigDescriptor.Source(path, ConfigSource.empty, PropertyType.BigDecimalType) ? "value of type bigdecimal"
def uri(path: String): ConfigDescriptor[String, String, URI] =
ConfigDescriptor.Source(path, ConfigSource.empty, PropertyType.UriType) ? "value of type uri"
def duration(path: String): ConfigDescriptor[String, String, Duration] =
ConfigDescriptor.Source(path, ConfigSource.empty, PropertyType.DurationType) ? "value of type duration"
def nested[K, V, A](path: K)(desc: ConfigDescriptor[K, V, A]): ConfigDescriptor[K, V, A] =
ConfigDescriptor.Nested(desc, path)
}
7 changes: 7 additions & 0 deletions zio-config/src/main/scala/zio/config/PropertyType.scala
Expand Up @@ -4,6 +4,7 @@ import java.net.URI

import zio.config.PropertyType.PropertyReadError

import scala.concurrent.duration.Duration
import scala.util.{ Failure, Success, Try }

trait PropertyType[V, A] {
Expand Down Expand Up @@ -79,6 +80,12 @@ object PropertyType {
def write(value: URI): String = value.toString
}

case object DurationType extends PropertyType[String, Duration] {
def read(value: String): Either[PropertyReadError[String], Duration] =
attempt(Duration.apply(value), _ => PropertyReadError(value, "duration"))
def write(value: Duration): String = value.toString
}

private def attempt[A, E](a: => A, f: Throwable => E): Either[E, A] =
Try(a) match {
case Success(value) => Right(value)
Expand Down
83 changes: 62 additions & 21 deletions zio-config/src/test/scala/zio/config/CoproductTest.scala
Expand Up @@ -8,18 +8,19 @@ import CoproductTestUtils._
import zio.random.Random
import zio.test.Assertion._
import zio.test._
import scala.concurrent.duration.Duration

object CoproductTest
extends BaseSpec(
suite("Coproduct support")(
testM("left element satisfied") {
checkM(genTestParams) { p =>
assertM(readLeft(p), isLeft(equalTo((EnterpriseAuth(Ldap(p.vLdap), DbUrl(p.vDbUrl))))))
assertM(readLeft(p), isLeft(equalTo(EnterpriseAuth(Ldap(p.vLdap), DbUrl(p.vDbUrl)))))
}
},
testM("right element satisfied") {
checkM(genTestParams) { p =>
assertM(readRight(p), isRight(equalTo(PasswordAuth(p.vUser, p.vCount, p.vFactor))))
assertM(readRight(p), isRight(equalTo(PasswordAuth(p.vUser, p.vCount, p.vFactor, Duration(p.vCodeValid)))))
}
},
testM("should accumulate all errors") {
Expand All @@ -34,7 +35,7 @@ object CoproductTest
},
testM("left and right both populated should choose left") {
checkM(genTestParams) { p =>
assertM(readChooseLeftFromBoth(p), isLeft(equalTo((EnterpriseAuth(Ldap(p.vLdap), DbUrl(p.vDbUrl))))))
assertM(readChooseLeftFromBoth(p), isLeft(equalTo(EnterpriseAuth(Ldap(p.vLdap), DbUrl(p.vDbUrl)))))
}
}
)
Expand All @@ -43,7 +44,7 @@ object CoproductTest
object CoproductTestUtils {
final case class Ldap(value: String) extends AnyVal
final case class EnterpriseAuth(ldap: Ldap, dburl: DbUrl)
final case class PasswordAuth(user: String, count: Int, factor: Float)
final case class PasswordAuth(user: String, count: Int, factor: Float, codeValid: Duration)

final case class TestParams(
kLdap: String,
Expand All @@ -55,7 +56,9 @@ object CoproductTestUtils {
kCount: String,
vCount: Int,
kFactor: String,
vFactor: Float
vFactor: Float,
kCodeValid: String,
vCodeValid: String
)

val genTestParams: Gen[Random, TestParams] =
Expand All @@ -70,7 +73,22 @@ object CoproductTestUtils {
vCount <- Gen.anyInt
kDbUrlLocal <- genSymbol(1, 20).filter(s => s != kLdap && s != kDbUrl && s != kUser && s != kCount)
vDbUrlLocal <- Gen.anyFloat
} yield TestParams(kLdap, vLdap, kDbUrl, vDbUrl, kUser, vUser, kCount, vCount, kDbUrlLocal, vDbUrlLocal)
kCValid <- genNonEmptyString(15)
vCValid <- genDuration(5)
} yield TestParams(
kLdap,
vLdap,
kDbUrl,
vDbUrl,
kUser,
vUser,
kCount,
vCount,
kDbUrlLocal,
vDbUrlLocal,
kCValid,
vCValid
)

def readLeft(p: TestParams) = {
val enterprise =
Expand All @@ -80,11 +98,16 @@ object CoproductTestUtils {
)

val password =
(string(p.kUser) |@| int(p.kCount) |@| float(p.kFactor))(PasswordAuth.apply, PasswordAuth.unapply)
(string(p.kUser) |@| int(p.kCount) |@| float(p.kFactor) |@| duration(p.kCodeValid))(
PasswordAuth.apply,
PasswordAuth.unapply
)

val authConfig = enterprise.orElseEither(password)

read(authConfig from ConfigSource.fromMap(Map(p.kLdap -> p.vLdap, p.kDbUrl -> p.vDbUrl)))
read(
authConfig from ConfigSource.fromMap(Map(p.kLdap -> p.vLdap, p.kDbUrl -> p.vDbUrl))
)
}

def readRight(p: TestParams) = {
Expand All @@ -95,13 +118,23 @@ object CoproductTestUtils {
)

val password =
(string(p.kUser) |@| int(p.kCount) |@| float(p.kFactor))(PasswordAuth.apply, PasswordAuth.unapply)
(string(p.kUser) |@| int(p.kCount) |@| float(p.kFactor) |@| duration(p.kCodeValid))(
PasswordAuth.apply,
PasswordAuth.unapply
)

val authConfig = enterprise.orElseEither(password)

read(
authConfig from
ConfigSource.fromMap(Map(p.kUser -> p.vUser, p.kCount -> p.vCount.toString, p.kFactor -> p.vFactor.toString))
ConfigSource.fromMap(
Map(
p.kUser -> p.vUser,
p.kCount -> p.vCount.toString,
p.kFactor -> p.vFactor.toString,
p.kCodeValid -> p.vCodeValid
)
)
)
}

Expand All @@ -115,18 +148,22 @@ object CoproductTestUtils {
)

val password =
(string(p.kUser) |@| int(p.kCount) |@| float(p.kFactor))(PasswordAuth.apply, PasswordAuth.unapply)
(string(p.kUser) |@| int(p.kCount) |@| float(p.kFactor) |@| duration(p.kCodeValid))(
PasswordAuth.apply,
PasswordAuth.unapply
)

val authConfig = enterprise.orElseEither(password)

read(
authConfig from
ConfigSource.fromMap(
Map(
p.kDbUrl -> p.vDbUrl,
p.kUser -> p.vUser,
p.kCount -> p.vCount.toString,
p.kFactor -> "notafloat"
p.kDbUrl -> p.vDbUrl,
p.kUser -> p.vUser,
p.kCount -> p.vCount.toString,
p.kFactor -> "notafloat",
p.kCodeValid -> p.vCodeValid
)
)
).either
Expand All @@ -140,19 +177,23 @@ object CoproductTestUtils {
)

val password =
(string(p.kUser) |@| int(p.kCount) |@| float(p.kFactor))(PasswordAuth.apply, PasswordAuth.unapply)
(string(p.kUser) |@| int(p.kCount) |@| float(p.kFactor) |@| duration(p.kCodeValid))(
PasswordAuth.apply,
PasswordAuth.unapply
)

val authConfig = enterprise.orElseEither(password)

read(
authConfig from
ConfigSource.fromMap(
Map(
p.kLdap -> p.vLdap,
p.kDbUrl -> p.vDbUrl,
p.kUser -> p.vUser,
p.kCount -> p.vCount.toString,
p.kFactor -> p.vFactor.toString
p.kLdap -> p.vLdap,
p.kDbUrl -> p.vDbUrl,
p.kUser -> p.vUser,
p.kCount -> p.vCount.toString,
p.kFactor -> p.vFactor.toString,
p.kCodeValid -> p.vCodeValid
)
)
)
Expand Down
7 changes: 7 additions & 0 deletions zio-config/src/test/scala/zio/config/helpers.scala
Expand Up @@ -14,8 +14,15 @@ object helpers {
s <- Gen.listOfN(n)(Gen.alphaNumericChar)
} yield s.mkString

def genNumber(min: Int, max: Int): Gen[Random, Int] =
for {
n <- Gen.int(min, max)
} yield n

def genNonEmptyString(length: Int): Gen[Random, String] = genSymbol(1, length)

def genDuration(length: Int): Gen[Random, String] = genNumber(1, length).map(days => s"$days day")

val genId: Gen[Random, Id] = genSymbol(1, 5).map(Id)

val genDbUrl: Gen[Random, DbUrl] = genNonEmptyString(20).map(DbUrl)
Expand Down

0 comments on commit 819bda3

Please sign in to comment.