From e43294c13db353f6840eaaa45406ae59bbd76d38 Mon Sep 17 00:00:00 2001 From: Pat Garrity Date: Sat, 27 Apr 2024 02:13:01 +0000 Subject: [PATCH] (patch) Full test coverage, adding builds. (#1) Reviewed-on: https://git.garrity.co/garrity-software/gs-blob/pulls/1 --- .forgejo/workflows/pull_request.yaml | 1 + .forgejo/workflows/release.yaml | 1 + mit => LICENSE | 0 build.sbt | 2 +- project/plugins.sbt | 5 ++++ src/main/scala/gs/blob/v0/Blob.scala | 25 +++++++++++++++++++ src/test/scala/gs/blob/v0/BlobTests.scala | 30 +++++++++++++++++++++++ 7 files changed, 63 insertions(+), 1 deletion(-) rename mit => LICENSE (100%) create mode 100644 src/test/scala/gs/blob/v0/BlobTests.scala diff --git a/.forgejo/workflows/pull_request.yaml b/.forgejo/workflows/pull_request.yaml index bba274a..d331681 100644 --- a/.forgejo/workflows/pull_request.yaml +++ b/.forgejo/workflows/pull_request.yaml @@ -61,6 +61,7 @@ jobs: if [ "${{ env.GS_RELEASE_TYPE }}" = "norelease" ]; then echo "Skipping publish due to GS_RELEASE_TYPE=norelease" else + sbtn coverageOff sbtn clean sbtn publish fi diff --git a/.forgejo/workflows/release.yaml b/.forgejo/workflows/release.yaml index 8351605..72fac7d 100644 --- a/.forgejo/workflows/release.yaml +++ b/.forgejo/workflows/release.yaml @@ -68,6 +68,7 @@ jobs: if [ "${{ env.GS_RELEASE_TYPE }}" = "norelease" ]; then echo "Skipping publish for 'norelease' commit." else + sbtn coverageOff sbtn clean sbtn semVerWriteVersionToFile sbtn publish diff --git a/mit b/LICENSE similarity index 100% rename from mit rename to LICENSE diff --git a/build.sbt b/build.sbt index 10dd0b8..631e5be 100644 --- a/build.sbt +++ b/build.sbt @@ -30,6 +30,6 @@ lazy val `gs-blob` = project .settings(name := s"${gsProjectName.value}-v${semVerMajor.value}") .settings( libraryDependencies ++= Seq( - "gs" %% "gs-hex-v0" % "0.1.1" + "gs" %% "gs-hex-v0" % "0.1.3" ) ) diff --git a/project/plugins.sbt b/project/plugins.sbt index 3c02b6a..e897854 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -23,6 +23,11 @@ def selectCredentials(): Credentials = credentials += selectCredentials() +externalResolvers := Seq( + "Garrity Software Mirror" at "https://maven.garrity.co/releases", + "Garrity Software Releases" at "https://maven.garrity.co/gs" +) + addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.11") addSbtPlugin("gs" % "sbt-garrity-software" % "0.3.0") addSbtPlugin("gs" % "sbt-gs-semver" % "0.3.0") diff --git a/src/main/scala/gs/blob/v0/Blob.scala b/src/main/scala/gs/blob/v0/Blob.scala index ad14369..3b4f6ed 100644 --- a/src/main/scala/gs/blob/v0/Blob.scala +++ b/src/main/scala/gs/blob/v0/Blob.scala @@ -49,12 +49,27 @@ object Blob: def fromBase64(data: String): Option[Blob] = scala.util.Try(Base64.getDecoder().decode(data)).toOption + /** Convert the given hex string to a [[Blob]]. + * + * @param data + * The candidate data. + * @return + * The parsed [[Blob]], or `None` if the input is not valid base64. + */ + def fromHex(data: String): Option[Blob] = + HexDecode[Blob].fromHexString(data) + extension (blob: Blob) /** @return * The underlying bytes of this [[Blob]]. */ def toByteArray(): Array[Byte] = blob + /** @return + * Hexadecimal string representation of this [[Blob]]. + */ + def toHex(): String = HexEncode[Blob].toHexString(blob) + /** @return * The base64 representation of this [[Blob]]. */ @@ -65,4 +80,14 @@ object Blob: */ def length(): Int = blob.length + /** Compare this blob to another in O(N) time. Determines if the bytes are + * identical. + * + * @param other + * The blob to compare against. + * @return + * True if the blobs are identical, false otherwise. + */ + def sameBytesAs(other: Blob): Boolean = blob.sameElements(other) + end Blob diff --git a/src/test/scala/gs/blob/v0/BlobTests.scala b/src/test/scala/gs/blob/v0/BlobTests.scala new file mode 100644 index 0000000..7b9a3aa --- /dev/null +++ b/src/test/scala/gs/blob/v0/BlobTests.scala @@ -0,0 +1,30 @@ +package gs.blob.v0 + +class BlobTests extends munit.FunSuite: + + test("should manage arrays of bytes") { + val a1: Array[Byte] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + val b1: Blob = Blob(a1) + val b2: Blob = Blob(a1) + val b3: Blob = Blob(Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) + + assert(b1.sameBytesAs(b2)) + assert(!b1.sameBytesAs(b3)) + assert(b1.length() == 10) + assert(b1.length() == b2.length()) + assert(b1.toByteArray().sameElements(a1)) + } + + test("should support from/to base64") { + val blob: Blob = Blob(Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) + val encoded = blob.toBase64() + val decoded = Blob.fromBase64(encoded) + assert(decoded.map(_.sameBytesAs(blob)) == Some(true)) + } + + test("should support from/to hex") { + val blob: Blob = Blob(Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) + val encoded = blob.toHex() + val decoded = Blob.fromHex(encoded) + assert(decoded.map(_.sameBytesAs(blob)) == Some(true)) + }