-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #214 from theiterators/play-circe-instances
Instances support for circe & play-json
- Loading branch information
Showing
11 changed files
with
1,060 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package instances | ||
|
||
import io.circe.{Decoder, Encoder, Json} | ||
import org.scalatest.funsuite.AnyFunSuite | ||
import org.scalatest.matchers.should.Matchers | ||
import pl.iterators.kebs.circe.KebsCirce | ||
import pl.iterators.kebs.instances.net.URIString | ||
|
||
import java.net.URI | ||
|
||
class NetInstancesTests extends AnyFunSuite with Matchers with KebsCirce with URIString { | ||
|
||
test("URI standard format") { | ||
val decoder = implicitly[Decoder[URI]] | ||
val encoder = implicitly[Encoder[URI]] | ||
val value = "iteratorshq.com" | ||
val obj = new URI(value) | ||
|
||
encoder(obj) shouldBe Json.fromString(value) | ||
decoder(Json.fromString(value).hcursor) shouldBe Right(obj) | ||
} | ||
|
||
test("URI wrong format exception") { | ||
val decoder = implicitly[Decoder[URI]] | ||
val value = "not a URI" | ||
|
||
decoder(Json.fromString(value).hcursor) shouldBe a [Left[_, _]] | ||
} | ||
|
||
test("No CaseClass1Rep implicits derived") { | ||
|
||
"implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck | ||
"implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck | ||
} | ||
} |
112 changes: 112 additions & 0 deletions
112
circe/src/test/scala/instances/TimeInstancesMixinTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package instances | ||
|
||
import io.circe.{Decoder, Encoder, Json} | ||
import org.scalatest.funsuite.AnyFunSuite | ||
import org.scalatest.matchers.should.Matchers | ||
import pl.iterators.kebs.circe.KebsCirce | ||
import pl.iterators.kebs.instances.time.LocalDateTimeString | ||
import pl.iterators.kebs.instances.time.mixins.{DurationNanosLong, InstantEpochMilliLong} | ||
import pl.iterators.kebs.instances.{InstanceConverter, TimeInstances} | ||
|
||
import java.time._ | ||
import java.time.format.DateTimeFormatter | ||
|
||
class TimeInstancesMixinTests extends AnyFunSuite with Matchers { | ||
|
||
test("Instant epoch milli format") { | ||
object TimeInstancesProtocol extends KebsCirce with InstantEpochMilliLong | ||
import TimeInstancesProtocol._ | ||
|
||
"implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck | ||
"implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck | ||
|
||
val decoder = implicitly[Decoder[Instant]] | ||
val encoder = implicitly[Encoder[Instant]] | ||
val value = 123456789 | ||
val obj = Instant.ofEpochMilli(value) | ||
|
||
encoder(obj) shouldBe Json.fromInt(value) | ||
decoder(Json.fromInt(value).hcursor) shouldBe Right(obj) | ||
} | ||
|
||
test("Duration nanos format, Instant epoch milli format") { | ||
object TimeInstancesProtocol extends KebsCirce with DurationNanosLong with InstantEpochMilliLong | ||
import TimeInstancesProtocol._ | ||
|
||
"implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck | ||
"implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck | ||
"implicitly[CaseClass1Rep[Duration, Long]]" shouldNot typeCheck | ||
"implicitly[CaseClass1Rep[Long, Duration]]" shouldNot typeCheck | ||
|
||
val decoder_duration = implicitly[Decoder[Duration]] | ||
val encoder_duration = implicitly[Encoder[Duration]] | ||
val value_duration = 123456789 | ||
val obj_duration = Duration.ofNanos(value_duration) | ||
|
||
val decoder_instant = implicitly[Decoder[Instant]] | ||
val encoder_instant = implicitly[Encoder[Instant]] | ||
val value_instant = 123456789 | ||
val obj_instant = Instant.ofEpochMilli(value_instant) | ||
|
||
encoder_duration(obj_duration) shouldBe Json.fromInt(value_duration) | ||
decoder_duration(Json.fromInt(value_duration).hcursor) shouldBe Right(obj_duration) | ||
|
||
encoder_instant(obj_instant) shouldBe Json.fromInt(value_instant) | ||
decoder_instant(Json.fromInt(value_instant).hcursor) shouldBe Right(obj_instant) | ||
} | ||
|
||
test("LocalDateTime custom format using companion object") { | ||
object TimeInstancesProtocol extends KebsCirce with LocalDateTimeString { | ||
val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm") | ||
|
||
override implicit val localDateTimeFormatter: InstanceConverter[LocalDateTime, String] = | ||
InstanceConverter.apply[LocalDateTime, String](_.format(formatter), LocalDateTime.parse(_, formatter)) | ||
} | ||
import TimeInstancesProtocol._ | ||
|
||
"implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck | ||
"implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck | ||
|
||
val encoder = implicitly[Encoder[LocalDateTime]] | ||
val decoder = implicitly[Decoder[LocalDateTime]] | ||
val value = "2007/12/03 10:30" | ||
val obj = LocalDateTime.parse(value, formatter) | ||
|
||
encoder(obj) shouldBe Json.fromString(value) | ||
decoder(Json.fromString(value).hcursor) shouldBe Right(obj) | ||
} | ||
|
||
test("LocalDateTime custom format with error handling") { | ||
object TimeInstancesProtocol extends KebsCirce with TimeInstances { | ||
val pattern = "yyyy/MM/dd HH:mm" | ||
val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern(pattern) | ||
|
||
override implicit val localDateTimeFormatter: InstanceConverter[LocalDateTime, String] = | ||
new InstanceConverter[LocalDateTime, String] { | ||
override def encode(obj: LocalDateTime): String = obj.format(formatter) | ||
override def decode(value: String): LocalDateTime = | ||
try { | ||
LocalDateTime.parse(value, formatter) | ||
} catch { | ||
case e: DateTimeException => | ||
throw new IllegalArgumentException( | ||
s"${classOf[LocalDateTime]} cannot be parsed from $value – should be in format $pattern", | ||
e) | ||
case e: Throwable => throw e | ||
} | ||
} | ||
} | ||
import TimeInstancesProtocol._ | ||
|
||
"implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck | ||
"implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck | ||
|
||
val encoder = implicitly[Encoder[LocalDateTime]] | ||
val decoder = implicitly[Decoder[LocalDateTime]] | ||
val value = "2007/12/03 10:30" | ||
val obj = LocalDateTime.parse(value, formatter) | ||
|
||
encoder(obj) shouldBe Json.fromString(value) | ||
decoder(Json.fromString(value).hcursor) shouldBe Right(obj) | ||
} | ||
} |
Oops, something went wrong.