(patch) series of updates and beginning to write tests
This commit is contained in:
parent
eddc5d5ae8
commit
962cae1268
13 changed files with 117 additions and 9 deletions
|
@ -11,6 +11,6 @@ repos:
|
|||
description: Enforces using only 'LF' line endings.
|
||||
- id: trailing-whitespace
|
||||
- repo: https://git.garrity.co/garrity-software/gs-pre-commit-scala
|
||||
rev: v1.0.0
|
||||
rev: v1.0.1
|
||||
hooks:
|
||||
- id: scalafmt
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// See: https://github.com/scalameta/scalafmt/tags for the latest tags.
|
||||
version = 3.7.17
|
||||
version = 3.8.1
|
||||
runner.dialect = scala3
|
||||
maxColumn = 80
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ lazy val sharedSettings = Seq(
|
|||
|
||||
lazy val testSettings = Seq(
|
||||
libraryDependencies ++= Seq(
|
||||
"org.scalameta" %% "munit" % "1.0.0-M10" % Test
|
||||
"org.scalameta" %% "munit" % "1.0.0-RC1" % Test
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ object AuditedConfiguration:
|
|||
*/
|
||||
def forSources[F[_]: Sync](
|
||||
sources: NonEmptyList[ConfigSource[F]]
|
||||
): F[Configuration[F]] =
|
||||
): F[AuditedConfiguration[F]] =
|
||||
ConfigManifest
|
||||
.standard[F]
|
||||
.map(manifest =>
|
||||
|
@ -119,7 +119,7 @@ object AuditedConfiguration:
|
|||
def withSource(source: ConfigSource[F]): Builder[F] =
|
||||
copy(sources = this.sources.append(source))
|
||||
|
||||
def build(): F[Configuration[F]] =
|
||||
def build(): F[AuditedConfiguration[F]] =
|
||||
ConfigManifest
|
||||
.standard[F]
|
||||
.map(manifest =>
|
||||
|
|
|
@ -6,6 +6,8 @@ package gs.config.v0
|
|||
sealed trait ConfigError
|
||||
|
||||
object ConfigError:
|
||||
given CanEqual[ConfigError, ConfigError] = CanEqual.derived
|
||||
|
||||
/** Attempted to retreive the value for some [[ConfigKey]], but no value could
|
||||
* be found.
|
||||
*
|
||||
|
|
|
@ -24,23 +24,33 @@ object Configurable:
|
|||
): Configurable[A] = C
|
||||
|
||||
given Configurable[String] with
|
||||
/** @inheritDocs
|
||||
*/
|
||||
def parse(raw: String): Option[String] = Some(raw)
|
||||
|
||||
given Configurable[Int] with
|
||||
/** @inheritDocs
|
||||
*/
|
||||
def parse(raw: String): Option[Int] = Try(raw.toInt).toOption
|
||||
|
||||
given Configurable[Long] with
|
||||
/** @inheritDocs
|
||||
*/
|
||||
def parse(raw: String): Option[Long] = Try(raw.toLong).toOption
|
||||
|
||||
given Configurable[Boolean] with
|
||||
/** @inheritDocs
|
||||
*/
|
||||
def parse(raw: String): Option[Boolean] = Try(raw.toBoolean).toOption
|
||||
|
||||
given Configurable[LocalDate] with
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
def parse(raw: String): Option[LocalDate] =
|
||||
Try(LocalDate.parse(raw)).toOption
|
||||
|
||||
given Configurable[Instant] with
|
||||
|
||||
def parse(raw: String): Option[Instant] =
|
||||
Try(Instant.parse(raw)).toOption
|
||||
/** @inheritDocs
|
||||
*/
|
||||
def parse(raw: String): Option[Instant] = Try(Instant.parse(raw)).toOption
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package gs.config.v0
|
||||
|
||||
import cats.data.EitherT
|
||||
import cats.effect.Sync
|
||||
import gs.config.v0.source.ConfigSource
|
||||
|
||||
|
@ -16,6 +17,19 @@ trait Configuration[F[_]]:
|
|||
*/
|
||||
def getValue[A: Configurable](key: ConfigKey[A]): F[Either[ConfigError, A]]
|
||||
|
||||
/** Retrieve a value based on some key. Return an `EitherT` as the response,
|
||||
* rather than `F[Either[ConfigError, A]]`
|
||||
*
|
||||
* @param key
|
||||
* The key that identifies the piece of configuration to retrieve.
|
||||
* @return
|
||||
* The value, or an error if no value is present. Expressed as an
|
||||
* `EitherT`.
|
||||
*/
|
||||
def getValueT[A: Configurable](
|
||||
key: ConfigKey[A]
|
||||
): EitherT[F, ConfigError, A] = EitherT(getValue(key))
|
||||
|
||||
object Configuration:
|
||||
|
||||
/** Start building a new [[AuditedConfiguration]].
|
||||
|
@ -34,7 +48,7 @@ object Configuration:
|
|||
* @return
|
||||
* The new [[Configuration]].
|
||||
*/
|
||||
def auditedEnvironmentOnly[F[_]: Sync]: F[Configuration[F]] =
|
||||
def auditedEnvironmentOnly[F[_]: Sync]: F[AuditedConfiguration[F]] =
|
||||
AuditedConfiguration.forEnvironmentSource[F].build()
|
||||
|
||||
end Configuration
|
||||
|
|
|
@ -9,6 +9,8 @@ sealed trait ConfigQueryResult
|
|||
|
||||
object ConfigQueryResult:
|
||||
|
||||
given CanEqual[ConfigQueryResult, ConfigQueryResult] = CanEqual.derived
|
||||
|
||||
/** Represents a query for some configuration that completed successfully.
|
||||
*
|
||||
* @param source
|
||||
|
|
|
@ -40,9 +40,13 @@ object ConfigSource:
|
|||
|
||||
final class Empty[F[_]: Applicative] extends ConfigSource[F]:
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def getValue(key: ConfigKey[?]): F[Option[String]] =
|
||||
Applicative[F].pure(None)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override val name: String = "empty"
|
||||
|
||||
end ConfigSource
|
||||
|
|
|
@ -8,9 +8,13 @@ import gs.config.v0.ConfigKey
|
|||
*/
|
||||
final class EnvironmentConfigSource[F[_]: Sync] extends ConfigSource[F]:
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def getValue(
|
||||
key: ConfigKey[?]
|
||||
): F[Option[String]] =
|
||||
Sync[F].delay(sys.env.get(key.name.toEnvironmentVariable()))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override val name: String = "environment"
|
||||
|
|
|
@ -16,6 +16,8 @@ final class MemoryConfigSource[F[_]: Applicative](
|
|||
) extends ConfigSource[F]:
|
||||
val id: UUID = UUID.randomUUID()
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def getValue(
|
||||
key: ConfigKey[?]
|
||||
): F[Option[String]] =
|
||||
|
@ -24,4 +26,6 @@ final class MemoryConfigSource[F[_]: Applicative](
|
|||
.get(key.name.toRawString())
|
||||
)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override lazy val name: String = s"in-memory-$id"
|
||||
|
|
17
src/test/scala/gs/config/v0/GsSuite.scala
Normal file
17
src/test/scala/gs/config/v0/GsSuite.scala
Normal file
|
@ -0,0 +1,17 @@
|
|||
package gs.config.v0
|
||||
|
||||
import cats.effect.IO
|
||||
import cats.effect.unsafe.IORuntime
|
||||
|
||||
abstract class GsSuite extends munit.FunSuite:
|
||||
given IORuntime = IORuntime.global
|
||||
|
||||
def iotest(
|
||||
name: String
|
||||
)(
|
||||
body: => IO[Any]
|
||||
)(
|
||||
implicit
|
||||
loc: munit.Location
|
||||
): Unit =
|
||||
test(new munit.TestOptions(name))(body.unsafeRunSync())
|
|
@ -0,0 +1,51 @@
|
|||
package gs.config.v0.audit
|
||||
|
||||
import cats.effect.IO
|
||||
import gs.config.v0.ConfigError
|
||||
import gs.config.v0.ConfigKey
|
||||
import gs.config.v0.ConfigName
|
||||
import gs.config.v0.Configuration
|
||||
import gs.config.v0.GsSuite
|
||||
import gs.config.v0.source.ConfigSource
|
||||
|
||||
class AuditedConfigurationTests extends GsSuite:
|
||||
import AuditedConfigurationTests.*
|
||||
|
||||
iotest(
|
||||
"should not return values, but should record attempts to find, when no config exists"
|
||||
) {
|
||||
for
|
||||
config <- Configuration
|
||||
.audited(ConfigSource.inMemory[IO](Map.empty))
|
||||
.build()
|
||||
string <- config.getValue(Keys.KString)
|
||||
manifest <- config.manifest.snapshot()
|
||||
yield
|
||||
assert(string == Left(ConfigError.MissingValue(Names.KString)))
|
||||
assert(
|
||||
manifest.get(Names.KString) == Some(
|
||||
List(
|
||||
ConfigQueryResult.Failure(
|
||||
sources = List(config.sources.head.name),
|
||||
error = ConfigError.MissingValue(Names.KString)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
object AuditedConfigurationTests:
|
||||
|
||||
object Names:
|
||||
|
||||
val KString: ConfigName = ConfigName("string")
|
||||
|
||||
end Names
|
||||
|
||||
object Keys:
|
||||
|
||||
val KString: ConfigKey[String] = ConfigKey.Required[String](Names.KString)
|
||||
|
||||
end Keys
|
||||
|
||||
end AuditedConfigurationTests
|
Loading…
Add table
Reference in a new issue