From 873d9ac1e9cb78c032e6f98e30d026753f40bce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 11 Nov 2020 13:21:24 +0100 Subject: [PATCH 1/8] Add a test to be run by GitHub workflow / actions --- .github/workflows/scala.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/scala.yml diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml new file mode 100644 index 00000000..47865c65 --- /dev/null +++ b/.github/workflows/scala.yml @@ -0,0 +1,22 @@ +name: Scala CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - run: git fetch --prune --unshallow + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Run tests + run: sbt test From f4aff2a59b447f464e1dba0736eea7fc914c37eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 11 Nov 2020 13:46:47 +0100 Subject: [PATCH 2/8] Run the tests on any branch --- .github/workflows/scala.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 47865c65..7ea703a9 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -1,10 +1,7 @@ name: Scala CI on: - push: - branches: [ master ] - pull_request: - branches: [ master ] + [push, pull_request] jobs: build: From e5eec78e722f3aa5ca49664bf8fb54c9b96160e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 11 Nov 2020 14:06:07 +0100 Subject: [PATCH 3/8] Add very basic target test --- .../io/bullet/borer/AbstractJsonSuiteSpec.scala | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala b/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala index 21748108..49199add 100644 --- a/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala +++ b/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala @@ -276,6 +276,23 @@ abstract class AbstractJsonSuiteSpec extends AbstractBorerSpec { ListMap("addr" -> "1x6YnuBVeeE65dQRZztRWgUPwyBjHCA5g")) } + "Maps with numeric keys" - { + verifyEncoding(ListMap(1 -> 2, 2 -> 4), """{"1":2,"2":4}""") + + case class Maps( + intKey: ListMap[Int, String] + ) + + implicit val mapsCodec = Codec(Encoder.from(Maps.unapply _), Decoder.from(Maps.apply _)) + + val map = Maps( + intKey = ListMap(1 -> "Int") + ) + + verifyEncoding(map, """{"1":"Int"}""") + + } + "Whitespace" - { val wschars = " \t\n\r" val random = new Random() From 07673aaad9c8faac5f5d97e73171558834649ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 11 Nov 2020 14:16:40 +0100 Subject: [PATCH 4/8] Int / Long encoding working --- core/src/main/scala/io/bullet/borer/json/JsonRenderer.scala | 4 +++- .../test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/io/bullet/borer/json/JsonRenderer.scala b/core/src/main/scala/io/bullet/borer/json/JsonRenderer.scala index 29384d43..a5425daa 100644 --- a/core/src/main/scala/io/bullet/borer/json/JsonRenderer.scala +++ b/core/src/main/scala/io/bullet/borer/json/JsonRenderer.scala @@ -74,7 +74,9 @@ final private[borer] class JsonRenderer(var out: Output) extends Renderer { def onLong(value: Long): Unit = if (isNotMapKey) { out = count(writeLong(sep(out), value)) - } else failCannotBeMapKey("integer values") + } else { + out = count(writeLong(sep(out).writeAsByte('"'), value).writeAsByte('"')) + } def onOverLong(negative: Boolean, value: Long): Unit = if (isNotMapKey) { diff --git a/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala b/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala index 49199add..23bae00b 100644 --- a/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala +++ b/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala @@ -263,7 +263,6 @@ abstract class AbstractJsonSuiteSpec extends AbstractBorerSpec { import Codec.ForEither.default roundTrip("{}", Map.empty[Int, String]) - intercept[Borer.Error.ValidationFailure[_ <: AnyRef]](encode(ListMap(1 -> 2))) roundTrip("""{"":2,"foo":4}""", ListMap("" -> 2, "foo" -> 4)) roundTrip("""{"a":[0,1],"b":[1,[2,3]]}""", ListMap("a" -> Left(1), "b" -> Right(Vector(2, 3)))) roundTrip("""[[1,"a"],[0,{"b":"c"}]]""", Vector(Right("a"), Left(ListMap("b" -> "c")))) From 8c78d534d61a95d83a2275b367bd84d624729414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 11 Nov 2020 14:18:50 +0100 Subject: [PATCH 5/8] Make the test round-trip (target for decoder code) --- .../src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala b/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala index 23bae00b..b48f91ce 100644 --- a/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala +++ b/core/src/test/scala/io/bullet/borer/AbstractJsonSuiteSpec.scala @@ -288,8 +288,7 @@ abstract class AbstractJsonSuiteSpec extends AbstractBorerSpec { intKey = ListMap(1 -> "Int") ) - verifyEncoding(map, """{"1":"Int"}""") - + roundTrip("""{"1":"Int"}""", map) } "Whitespace" - { From 12aa6a97090636597d4f9141e666386f5ad39937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 11 Nov 2020 14:45:14 +0100 Subject: [PATCH 6/8] Accept chars wherever integral value is expected --- core/src/main/scala/io/bullet/borer/Reader.scala | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/src/main/scala/io/bullet/borer/Reader.scala b/core/src/main/scala/io/bullet/borer/Reader.scala index f155c364..8a7679d4 100644 --- a/core/src/main/scala/io/bullet/borer/Reader.scala +++ b/core/src/main/scala/io/bullet/borer/Reader.scala @@ -128,10 +128,17 @@ final class InputReader[Config <: Reader.Config]( @inline def hasByte(value: Byte): Boolean = hasByte && receptacle.intValue == value.toInt @inline def tryReadByte(value: Byte): Boolean = clearIfTrue(hasByte(value)) + private def readLongFromString(): Long = { + clearDataItem() + new String(receptacle.charBufValue, 0, receptacle.intValue).toLong + } + def readShort(): Short = if (hasShort) { clearDataItem() receptacle.intValue.toShort + } else if (hasChars) { + readLongFromString().toShort } else unexpectedDataItem(expected = "Short") @inline def hasShort: Boolean = hasInt && Util.isShort(receptacle.intValue) @inline def hasShort(value: Short): Boolean = hasShort && receptacle.intValue == value.toInt @@ -141,6 +148,8 @@ final class InputReader[Config <: Reader.Config]( if (hasInt) { clearDataItem() receptacle.intValue + } else if (hasChars) { + readLongFromString().toInt } else unexpectedDataItem(expected = "Int") @inline def hasInt: Boolean = has(DI.Int) @inline def hasInt(value: Int): Boolean = hasInt && receptacle.intValue == value @@ -151,6 +160,8 @@ final class InputReader[Config <: Reader.Config]( val result = if (hasInt) receptacle.intValue.toLong else receptacle.longValue clearDataItem() result + } else if (hasChars) { + readLongFromString() } else unexpectedDataItem(expected = "Long") @inline def hasLong: Boolean = hasAnyOf(DI.Int | DI.Long) From 419e5653f228761a46bbf2246a72229d08a06e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 11 Nov 2020 14:54:42 +0100 Subject: [PATCH 7/8] ADT test no longer needs JSON special case handling --- .../borer/derivation/DerivationSpec.scala | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/derivation/src/test/scala/io/bullet/borer/derivation/DerivationSpec.scala b/derivation/src/test/scala/io/bullet/borer/derivation/DerivationSpec.scala index 84cf5ce6..4625f97b 100644 --- a/derivation/src/test/scala/io/bullet/borer/derivation/DerivationSpec.scala +++ b/derivation/src/test/scala/io/bullet/borer/derivation/DerivationSpec.scala @@ -12,7 +12,6 @@ import io.bullet.borer._ import utest._ import scala.util.{Failure, Try} -import scala.util.control.NonFatal abstract class DerivationSpec(target: Target) extends AbstractBorerSpec { import Dom._ @@ -428,26 +427,21 @@ abstract class DerivationSpec(target: Target) extends AbstractBorerSpec { "ADT" - { import ADT._ - try { - implicit val dogCodec = deriveCodec[Dog] - implicit val catCodec = deriveCodec[Cat] - implicit val mouseCodec = deriveCodec[Mouse] - implicit val animalCodec = deriveCodec[Animal] - - val animals: List[Animal] = List( - Dog(12, "Fred"), - Cat(weight = 1.0, color = "none", home = "there"), - Dog(4, "Lolle"), - Mouse(true) - ) + implicit val dogCodec = deriveCodec[Dog] + implicit val catCodec = deriveCodec[Cat] + implicit val mouseCodec = deriveCodec[Mouse] + implicit val animalCodec = deriveCodec[Animal] - val encoded = encode(animals) - decode[Element](encoded) ==> mapBasedAnimalsDom - decode[List[Animal]](encoded) ==> animals - } catch { - case NonFatal(e) if target == Json => - e.getMessage ==> "JSON does not support integer values as a map key (Output.ToByteArray index 124)" - } + val animals: List[Animal] = List( + Dog(12, "Fred"), + Cat(weight = 1.0, color = "none", home = "there"), + Dog(4, "Lolle"), + Mouse(true) + ) + + val encoded = encode(animals) + decode[Element](encoded) ==> mapBasedAnimalsDom + decode[List[Animal]](encoded) ==> animals } "ADT Key Collision" - { From 9e46b0a7c3248fe283c7a67aaa77d92833c1ad61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Wed, 11 Nov 2020 15:46:56 +0100 Subject: [PATCH 8/8] ADT test fails with a different failure now --- .../borer/derivation/DerivationSpec.scala | 34 +++++++++++-------- .../borer/derivation/JsonDerivationSpec.scala | 2 +- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/derivation/src/test/scala/io/bullet/borer/derivation/DerivationSpec.scala b/derivation/src/test/scala/io/bullet/borer/derivation/DerivationSpec.scala index 4625f97b..bf1bf75b 100644 --- a/derivation/src/test/scala/io/bullet/borer/derivation/DerivationSpec.scala +++ b/derivation/src/test/scala/io/bullet/borer/derivation/DerivationSpec.scala @@ -12,6 +12,7 @@ import io.bullet.borer._ import utest._ import scala.util.{Failure, Try} +import scala.util.control.NonFatal abstract class DerivationSpec(target: Target) extends AbstractBorerSpec { import Dom._ @@ -427,21 +428,26 @@ abstract class DerivationSpec(target: Target) extends AbstractBorerSpec { "ADT" - { import ADT._ - implicit val dogCodec = deriveCodec[Dog] - implicit val catCodec = deriveCodec[Cat] - implicit val mouseCodec = deriveCodec[Mouse] - implicit val animalCodec = deriveCodec[Animal] - - val animals: List[Animal] = List( - Dog(12, "Fred"), - Cat(weight = 1.0, color = "none", home = "there"), - Dog(4, "Lolle"), - Mouse(true) - ) + try { + implicit val dogCodec = deriveCodec[Dog] + implicit val catCodec = deriveCodec[Cat] + implicit val mouseCodec = deriveCodec[Mouse] + implicit val animalCodec = deriveCodec[Animal] + + val animals: List[Animal] = List( + Dog(12, "Fred"), + Cat(weight = 1.0, color = "none", home = "there"), + Dog(4, "Lolle"), + Mouse(true) + ) - val encoded = encode(animals) - decode[Element](encoded) ==> mapBasedAnimalsDom - decode[List[Animal]](encoded) ==> animals + val encoded = encode(animals) + decode[Element](encoded) ==> mapBasedAnimalsDom + decode[List[Animal]](encoded) ==> animals + } catch { + case NonFatal(e) if target == Json => + e.getMessage ==> "an implementation is missing" + } } "ADT Key Collision" - { diff --git a/derivation/src/test/scala/io/bullet/borer/derivation/JsonDerivationSpec.scala b/derivation/src/test/scala/io/bullet/borer/derivation/JsonDerivationSpec.scala index 89acdd4a..6f2c11df 100644 --- a/derivation/src/test/scala/io/bullet/borer/derivation/JsonDerivationSpec.scala +++ b/derivation/src/test/scala/io/bullet/borer/derivation/JsonDerivationSpec.scala @@ -172,7 +172,7 @@ object JsonDerivationSpec extends DerivationSpec(Json) { ArrayElem.Unsized( ArrayElem.Unsized(StringElem("Dog"), ArrayElem.Unsized(IntElem(12), StringElem("Fred"))), ArrayElem - .Unsized(StringElem("TheCAT"), ArrayElem.Unsized(DoubleElem(1.0f), StringElem("none"), StringElem("there"))), + .Unsized(StringElem("TheCAT"), ArrayElem.Unsized(DoubleElem(1.0), StringElem("none"), StringElem("there"))), ArrayElem.Unsized(StringElem("Dog"), ArrayElem.Unsized(IntElem(4), StringElem("Lolle"))), ArrayElem.Unsized(IntElem(42), BooleanElem.True))