Compare commits

..

16 Commits

Author SHA1 Message Date
12ba3bf530 Update README.md 2026-04-16 16:12:39 +00:00
b2d8048713 Upgrade plugin 2026-02-15 14:10:59 +01:00
c366c79d4c refactor utility function name 2026-02-03 23:03:59 +01:00
e08cbb0fa9 fix README
All checks were successful
/ test (pull_request) Successful in 45s
2026-01-21 22:09:31 +01:00
61d6a8e191 implement Base45 2026-01-21 22:04:51 +01:00
6283c2f44d refactor encodings 2026-01-21 22:03:03 +01:00
8290955755 split padding in StreamEncoding to PaddedStreamEncoding 2026-01-20 09:52:58 +01:00
c1b8800e82 implement composition 2026-01-19 19:55:39 +01:00
684b6d78ea implement Base56 and Base58 2026-01-18 22:15:25 +01:00
24c667bc9c implement decode exception 2026-01-18 21:48:18 +01:00
a347bd617c fix 2^n check 2026-01-17 15:50:17 +01:00
a553aa6723 improve test coverage 2026-01-17 13:46:57 +01:00
83fd77c8ee split ci 2026-01-17 12:39:30 +01:00
456f33f2d9 bump version to 1.3.0 2026-01-17 12:36:16 +01:00
55faf1d670 implement numeric encodings, optimize 2026-01-17 12:27:41 +01:00
45d74d9cff improve ci
All checks were successful
/ publish (push) Has been skipped
/ test (push) Successful in 1m13s
2026-01-13 18:02:26 +01:00
36 changed files with 741 additions and 330 deletions

View File

@@ -1,36 +0,0 @@
on:
push:
branches:
- main
env:
INFENDRO__TOKEN: ${{ secrets.TOKEN }}
jobs:
publish:
runs-on: linux
steps:
- uses: actions/checkout@v4
- uses: actions/cache/restore@v4
with:
key: gradle
path: |
~/.gradle/caches/
~/.gradle/wrapper/
~/.konan/
- uses: actions/setup-java@v4
with:
java-version: '24'
distribution: 'temurin'
- run: ./gradlew publish
- uses: actions/cache/save@v4
with:
key: gradle
path: |
~/.gradle/caches/
~/.gradle/wrapper/
~/.konan/

View File

@@ -0,0 +1,47 @@
on:
push:
branches: [ main ]
jobs:
publish:
runs-on: linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '24'
distribution: 'temurin'
- name: Cache Gradle
uses: actions/cache@v4
with:
key: gradle-${{ hashFiles('**/libs.versions.toml') }}
restore-keys: gradle
path: |
~/.gradle/caches/
~/.gradle/wrapper/
- name: Cache Konan
uses: actions/cache@v4
with:
key: konan-${{ hashFiles('**/libs.versions.toml') }}
restore-keys: konan
path: |
~/.konan/
- name: Cache Node
uses: actions/cache@v4
with:
key: node-${{ hashFiles('**/libs.versions.toml') }}
restore-keys: node
path: |
~/.gradle/nodejs
~/.gradle/yarn
- name: Publish
run: ./gradlew publish
env:
INFENDRO__TOKEN: ${{ secrets.TOKEN }}

View File

@@ -0,0 +1,28 @@
on:
pull_request:
branches: [ main ]
jobs:
test:
runs-on: linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '24'
distribution: 'temurin'
- name: Cache Gradle
uses: actions/cache@v4
with:
key: gradle-${{ hashFiles('**/libs.versions.toml') }}
restore-keys: gradle
path: |
~/.gradle/caches/
~/.gradle/wrapper/
- name: Test
run: ./gradlew jvmTest

View File

@@ -1,22 +1,19 @@
# encoding-kt
# encoding.kt
`encoding-kt` is a Kotlin Multiplatform library that provides common `ByteArray` encodings.
`encoding.kt` is a Kotlin Multiplatform library that provides common `ByteArray` encodings.
Supported encodings:
- Base2 (binary)
- Base8 (octal)
- Base16 (hexadecimal)
- Base10 (decimal)
- Base16 (hexadecimal, uppercase/lowercase)
- Base32
- Base64
## Targets
| Target | Status |
|------------------|---------------|
| JVM | Supported |
| JavaScript | Supported |
| Native (Linux) | Supported |
| Native (Windows) | Not Supported |
- Base36
- Base45
- Base56
- Base58
- Base62
- Base64 (standard/URL)
## Installation
@@ -28,24 +25,20 @@ repositories {
}
dependencies {
implementation("com.infendro:encoding:1.2.0")
implementation("com.infendro:encoding:1.3.0")
}
```
## Usage
```kotlin
import com.infendro.encoding.Base16
fun main() {
// the string to encode
val test = "Hello World!"
.encodeToByteArray().asUByteArray()
val test = "Hello World!".encodeToByteArray()
// encode the string with the desired encoding
val encoded = Base16.encode(test)
.asByteArray().decodeToString()
val encoded = Base16.encode(test).decodeToString()
println(encoded) // 48656c6c6f20576f726c6421
println(encoded) // 48656C6C6F20576F726C6421
}
```

View File

@@ -1,8 +1,11 @@
@file:OptIn(ExperimentalWasmDsl::class)
import com.infendro.plugin.infendro
import com.infendro.plugin.token
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
group = "com.infendro"
version = "1.2.0"
version = "1.3.0"
plugins {
alias(libs.plugins.infendro)
@@ -12,10 +15,14 @@ plugins {
kotlin {
jvm()
js {
nodejs()
}
linuxX64()
linuxArm64()
mingwX64()
macosX64()
macosArm64()
js { nodejs() }
wasmJs { nodejs() }
wasmWasi { nodejs() }
repositories {
mavenCentral()
@@ -26,10 +33,6 @@ kotlin {
implementation(libs.test)
}
}
compilerOptions {
freeCompilerArgs.add("-opt-in=kotlin.ExperimentalUnsignedTypes")
}
}
publishing.repositories {

View File

@@ -1,6 +1,6 @@
[versions]
infendro = "1.0.0"
kotlin = "2.2.21"
infendro = "1.1.0"
kotlin = "2.3.0"
[plugins]
infendro = { id = "com.infendro.plugin", version.ref = "infendro" }

View File

@@ -0,0 +1,5 @@
package com.infendro.encoding
private val alphabet = "0123456789".encodeToByteArray()
object Base10 : Encoding by NumericEncoding(alphabet)

View File

@@ -1,16 +1,10 @@
package com.infendro.encoding
object Base16 : Encoding() {
private val CHARACTERS = ubyteArrayOf(
0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U,
0x38U, 0x39U, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U,
)
private val uppercase = "0123456789ABCDEF".encodeToByteArray()
private val lowercase = "0123456789abcdef".encodeToByteArray()
override fun encode(
bytes: UByteArray,
) = encode(bytes, CHARACTERS)
object Base16 : Encoding by StreamEncoding(uppercase) {
val UPPERCASE = this
override fun decode(
bytes: UByteArray,
) = decode(bytes, CHARACTERS)
object LOWERCASE : Encoding by StreamEncoding(lowercase)
}

View File

@@ -1,15 +1,5 @@
package com.infendro.encoding
object Base2 : Encoding() {
private val CHARACTERS = ubyteArrayOf(
0x30U, 0x31U,
)
private val alphabet = "01".encodeToByteArray()
override fun encode(
bytes: UByteArray,
) = encode(bytes, CHARACTERS)
override fun decode(
bytes: UByteArray,
) = decode(bytes, CHARACTERS)
}
object Base2 : Encoding by StreamEncoding(alphabet)

View File

@@ -1,19 +1,6 @@
package com.infendro.encoding
object Base32 : Encoding() {
private val CHARACTERS = ubyteArrayOf(
0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U,
0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U,
0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U,
0x59U, 0x5aU, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U,
)
private const val PADDING: UByte = 0x3dU
private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".encodeToByteArray()
private const val padding = '='.code.toByte()
override fun encode(
bytes: UByteArray,
) = encode(bytes, CHARACTERS, PADDING)
override fun decode(
bytes: UByteArray,
) = decode(bytes, CHARACTERS, PADDING)
}
object Base32 : Encoding by StreamEncoding(alphabet, padding)

View File

@@ -0,0 +1,5 @@
package com.infendro.encoding
private val alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".encodeToByteArray()
object Base36 : Encoding by NumericEncoding(alphabet)

View File

@@ -0,0 +1,51 @@
package com.infendro.encoding
import com.infendro.encoding.exception.IllegalByteException
object Base45 : Encoding {
private val alphabet: ByteArray = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".encodeToByteArray()
private val base: Int = alphabet.size
override fun encode(bytes: ByteArray): ByteArray {
val result = mutableListOf<Byte>()
for (i in bytes.indices step 2) {
val remaining = minOf(bytes.size - i, 2)
var value = 0
for (j in 0..<remaining) {
val byte = bytes[i + j]
value = (value shl 8) or (byte.toInt() and 0xFF)
}
repeat(remaining + 1) {
result += alphabet[value % base]
value /= base
}
}
return result.toByteArray()
}
override fun decode(bytes: ByteArray): ByteArray {
val result = mutableListOf<Byte>()
for (i in bytes.indices step 3) {
val remaining = minOf(bytes.size - i, 3)
var value = 0
for (j in (0..<remaining).reversed()) {
val byte = bytes[i + j]
val index = alphabet.indexOf(byte)
if (index == -1) throw IllegalByteException(byte)
value = value * base + index
}
for (j in (0..<(remaining - 1)).reversed()) {
result += ((value shr (j * 8)) and 0xFF).toByte()
}
}
return result.toByteArray()
}
}

View File

@@ -0,0 +1,5 @@
package com.infendro.encoding
private val alphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz".encodeToByteArray()
object Base56 : Encoding by NumericEncoding(alphabet)

View File

@@ -0,0 +1,5 @@
package com.infendro.encoding
private val alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".encodeToByteArray()
object Base58 : Encoding by NumericEncoding(alphabet)

View File

@@ -0,0 +1,5 @@
package com.infendro.encoding
private val alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".encodeToByteArray()
object Base62 : Encoding by NumericEncoding(alphabet)

View File

@@ -1,23 +1,11 @@
package com.infendro.encoding
object Base64 : Encoding() {
private val CHARACTERS = ubyteArrayOf(
0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U,
0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U,
0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U,
0x59U, 0x5aU, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U,
0x67U, 0x68U, 0x69U, 0x6aU, 0x6bU, 0x6cU, 0x6dU, 0x6eU,
0x6fU, 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U,
0x77U, 0x78U, 0x79U, 0x7aU, 0x30U, 0x31U, 0x32U, 0x33U,
0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U, 0x2bU, 0x2fU,
)
private const val PADDING: UByte = 0x3dU
private val standard = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".encodeToByteArray()
private val url = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".encodeToByteArray()
private const val padding = '='.code.toByte()
override fun encode(
bytes: UByteArray,
) = encode(bytes, CHARACTERS, PADDING)
object Base64 : Encoding by StreamEncoding(standard, padding) {
val STANDARD = this
override fun decode(
bytes: UByteArray,
) = decode(bytes, CHARACTERS, PADDING)
object URL : Encoding by StreamEncoding(url)
}

View File

@@ -1,15 +1,5 @@
package com.infendro.encoding
object Base8 : Encoding() {
private val CHARACTERS = ubyteArrayOf(
0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U,
)
private val alphabet = "01234567".encodeToByteArray()
override fun encode(
bytes: UByteArray,
) = encode(bytes, CHARACTERS)
override fun decode(
bytes: UByteArray,
) = decode(bytes, CHARACTERS)
}
object Base8 : Encoding by StreamEncoding(alphabet)

View File

@@ -1,92 +1,6 @@
package com.infendro.encoding
import com.infendro.encoding.util.lcm
import com.infendro.encoding.util.log2
import kotlin.math.pow
sealed class Encoding {
abstract fun encode(
bytes: UByteArray,
): UByteArray
abstract fun decode(
bytes: UByteArray,
): UByteArray
protected fun encode(
bytes: UByteArray,
characters: UByteArray,
padding: UByte? = null,
): UByteArray {
val length = log2(characters.size).toInt()
val mask = (2.0.pow(length) - 1).toUInt()
val encoded = mutableListOf<UByte>()
var buffer = 0U
var bits = 0
for (byte in bytes) {
buffer = (buffer shl 8) + byte
bits += 8
while (bits >= length) {
val offset = bits - length
val index = (buffer shr offset).toInt()
buffer = buffer and (mask shl offset).inv()
bits -= length
encoded.add(characters[index])
}
}
if (bits > 0) {
buffer = buffer shl (length - bits)
val index = buffer.toInt()
encoded.add(characters[index])
}
if (padding != null) {
val block = lcm(length, 8) / length
while (encoded.size % block != 0) {
encoded.add(padding)
}
}
return encoded.toUByteArray()
}
protected fun decode(
bytes: UByteArray,
characters: UByteArray,
padding: UByte? = null,
): UByteArray {
val length = log2(characters.size).toInt()
val mask = 0xffU
val decoded = mutableListOf<UByte>()
var buffer = 0U
var bits = 0
for (byte in bytes) {
if (byte == padding) break
val index = characters.indexOf(byte)
if (index == -1) throw Exception()
buffer = (buffer shl length) + index.toUByte()
bits += length
if (bits >= 8) {
val offset = bits - 8
val character = (buffer shr offset).toUByte()
buffer = buffer and (mask shl offset).inv()
bits -= 8
decoded.add(character)
}
}
return decoded.toUByteArray()
}
interface Encoding {
fun encode(bytes: ByteArray): ByteArray
fun decode(bytes: ByteArray): ByteArray
}

View File

@@ -0,0 +1,39 @@
package com.infendro.encoding
import com.infendro.encoding.exception.IllegalByteException
import com.infendro.encoding.util.BigInt
class NumericEncoding internal constructor(
private val alphabet: ByteArray,
) : Encoding {
private val base: Int = alphabet.size
override fun encode(bytes: ByteArray): ByteArray {
if (bytes.isEmpty()) return byteArrayOf()
val result = mutableListOf<Byte>()
var x = BigInt.from(bytes)
while (!x.isZero()) {
val (quotient, remainder) = x.divRem(base)
x = quotient
result += alphabet[remainder]
}
return result.asReversed().toByteArray()
}
override fun decode(bytes: ByteArray): ByteArray {
if (bytes.isEmpty()) return byteArrayOf()
var value = BigInt.zero
for (i in 0..<bytes.size) {
val byte = bytes[i]
val index = alphabet.indexOf(byte)
if (index == -1) throw IllegalByteException(byte)
value = value.timesAdd(base, index)
}
return value.toByteArray()
}
}

View File

@@ -0,0 +1,80 @@
package com.infendro.encoding
import com.infendro.encoding.exception.IllegalByteException
import com.infendro.encoding.util.align
import com.infendro.encoding.util.ceilDiv
import com.infendro.encoding.util.lcm
import com.infendro.encoding.util.log2
class StreamEncoding internal constructor(
private val alphabet: ByteArray,
private val padding: Byte? = null,
) : Encoding {
private val base: Int = alphabet.size
private val bits: Int = log2(base).toInt()
private val block: Int = lcm(bits, 8) / bits
private val mask: Int = (0x01 shl bits) - 1
override fun encode(bytes: ByteArray): ByteArray {
val size = when (padding) {
null -> (bytes.size * 8).ceilDiv(bits)
else -> (bytes.size * 8).ceilDiv(bits).align(block)
}
val encoded = ByteArray(size)
var i = 0
var buffer = 0
var bufferBits = 0
for (byte in bytes) {
buffer = (buffer shl 8) or (byte.toInt() and 0xFF)
bufferBits += 8
while (bufferBits >= bits) {
val index = (buffer shr (bufferBits - bits)) and mask
bufferBits -= bits
encoded[i++] = alphabet[index]
}
}
if (bufferBits > 0) {
val index = (buffer shl (bits - bufferBits)) and mask
encoded[i++] = alphabet[index]
}
while (i < encoded.size) {
encoded[i++] = padding!!
}
return encoded
}
override fun decode(bytes: ByteArray): ByteArray {
val end = when (padding) {
null -> bytes.size
else -> when (val index = bytes.indexOf(padding)) {
-1 -> bytes.size
else -> index
}
}
val size = end * bits / 8
val decoded = ByteArray(size)
var i = 0
var buffer = 0
var bufferBits = 0
for (b in 0..<end) {
val byte = bytes[b]
val index = alphabet.indexOf(byte)
if (index == -1) throw IllegalByteException(byte)
buffer = (buffer shl bits) or index
bufferBits += bits
if (bufferBits >= 8) {
val byte = (buffer shr (bufferBits - 8)) and 0xFF
bufferBits -= 8
decoded[i++] = byte.toByte()
}
}
return decoded
}
}

View File

@@ -0,0 +1,5 @@
package com.infendro.encoding.exception
abstract class DecodeException : Exception() {
abstract override val message: String
}

View File

@@ -0,0 +1,12 @@
package com.infendro.encoding.exception
class IllegalByteException(
val byte: Byte,
) : DecodeException() {
override val message: String
get() {
val hex = "0x${byte.toHexString().padStart(2, '0')}"
val char = "'${byte.toInt().toChar()}'"
return "Illegal byte $hex ($char)."
}
}

View File

@@ -0,0 +1,73 @@
package com.infendro.encoding.util
internal class BigInt private constructor(
val words: IntArray,
) {
init {
require(words.isNotEmpty())
}
fun isZero(): Boolean = words.all { it == 0 }
fun timesAdd(multiplier: Int, addend: Int): BigInt {
val product = IntArray(words.size)
var carry = addend
for (i in words.indices) {
val current = (words[i].toLong() and 0xFFFFFFFFL) * multiplier + carry
product[i] = current.toInt()
carry = (current ushr 32).toInt()
}
when {
carry > 0 -> {
val expanded = product.copyOf(product.size + 1)
expanded[product.size] = carry
return BigInt(expanded)
}
else -> return BigInt(product)
}
}
fun divRem(divisor: Int): Pair<BigInt, Int> {
val quotient = IntArray(words.size)
var remainder = 0
for (i in words.indices.reversed()) {
val current = (remainder.toLong() shl 32) or (words[i].toLong() and 0xFFFFFFFFL)
quotient[i] = (current / divisor.toLong()).toInt()
remainder = (current % divisor.toLong()).toInt()
}
when {
quotient.size > 1 && quotient.last() == 0 -> {
val contracted = quotient.copyOfRange(0, quotient.size - 1)
return Pair(BigInt(contracted), remainder)
}
else -> return Pair(BigInt(quotient), remainder)
}
}
fun toByteArray(): ByteArray {
val bytes = ByteArray((words.size * 4) - words.last().countLeadingZeroBytes())
for (i in bytes.indices) {
val (wi, bi) = (bytes.lastIndex - i).divRem(4)
bytes[i] = (words[wi] ushr (bi * 8)).toByte()
}
return bytes
}
companion object {
val zero: BigInt
get() = BigInt(intArrayOf(0))
fun from(bytes: ByteArray): BigInt {
val words = IntArray(bytes.size.ceilDiv(4))
for (i in bytes.indices) {
val (wi, bi) = (bytes.lastIndex - i).divRem(4)
words[wi] = words[wi] or ((bytes[i].toInt() and 0xFF) shl (bi * 8))
}
return BigInt(words)
}
}
}

View File

@@ -0,0 +1,7 @@
package com.infendro.encoding.util
fun Int.divRem(divisor: Int): Pair<Int, Int> =
Pair(this / divisor, this % divisor)
fun Int.countLeadingZeroBytes(): Int =
countLeadingZeroBits() / 8

View File

@@ -2,14 +2,16 @@ package com.infendro.encoding.util
import kotlin.math.log2
internal fun log2(
value: Int,
) = log2(value.toDouble())
internal fun Int.ceilDiv(n: Int): Int =
(this + n - 1) / n
internal fun gcd(
a: Int,
b: Int,
): Int {
internal fun Int.align(n: Int): Int =
ceilDiv(n) * n
internal fun log2(value: Int): Double =
log2(value.toDouble())
internal fun gcd(a: Int, b: Int): Int {
var x = a
var y = b
while (y != 0) {
@@ -20,9 +22,6 @@ internal fun gcd(
return x
}
internal fun lcm(
a: Int,
b: Int,
): Int {
internal fun lcm(a: Int, b: Int): Int {
return (a * b) / gcd(a, b)
}

View File

@@ -0,0 +1,36 @@
package com.infendro.encoding
import kotlin.test.Test
import kotlin.test.assertContentEquals
class `Base10 Test` {
val encoding: Encoding
get() = Base10
val original = "Hello World!".encodeToByteArray()
val encoded = "22405534230753928650781647905".encodeToByteArray()
@Test
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -7,27 +7,30 @@ class `Base16 Test` {
val encoding: Encoding
get() = Base16
val `Hello World!` = ubyteArrayOf(
0x48U, 0x65U, 0x6cU, 0x6cU,
0x6fU, 0x20U, 0x57U, 0x6fU,
0x72U, 0x6cU, 0x64U, 0x21U,
)
val original = "Hello World!".encodeToByteArray()
val encoded = "48656C6C6F20576F726C6421".encodeToByteArray()
@Test
fun `encode empty ByteArray`() {
val expected = ubyteArrayOf()
val actual = encoding.encode(ubyteArrayOf())
assertContentEquals(expected, actual)
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `encode "Hello World!"`() {
val expected = ubyteArrayOf(
0x34U, 0x38U, 0x36U, 0x35U, 0x36U, 0x63U, 0x36U, 0x63U,
0x36U, 0x66U, 0x32U, 0x30U, 0x35U, 0x37U, 0x36U, 0x66U,
0x37U, 0x32U, 0x36U, 0x63U, 0x36U, 0x34U, 0x32U, 0x31U,
)
val actual = encoding.encode(`Hello World!`)
assertContentEquals(expected, actual)
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -7,36 +7,30 @@ class `Base2 Test` {
val encoding: Encoding
get() = Base2
val `Hello World!` = ubyteArrayOf(
0x48U, 0x65U, 0x6cU, 0x6cU,
0x6fU, 0x20U, 0x57U, 0x6fU,
0x72U, 0x6cU, 0x64U, 0x21U,
)
val original = "Hello World!".encodeToByteArray()
val encoded = "010010000110010101101100011011000110111100100000010101110110111101110010011011000110010000100001".encodeToByteArray()
@Test
fun `encode empty ByteArray`() {
val expected = ubyteArrayOf()
val actual = encoding.encode(ubyteArrayOf())
assertContentEquals(expected, actual)
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `encode "Hello World!"`() {
val expected = ubyteArrayOf(
0x30U, 0x31U, 0x30U, 0x30U, 0x31U, 0x30U, 0x30U, 0x30U,
0x30U, 0x31U, 0x31U, 0x30U, 0x30U, 0x31U, 0x30U, 0x31U,
0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x30U, 0x30U,
0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x30U, 0x30U,
0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x31U, 0x31U,
0x30U, 0x30U, 0x31U, 0x30U, 0x30U, 0x30U, 0x30U, 0x30U,
0x30U, 0x31U, 0x30U, 0x31U, 0x30U, 0x31U, 0x31U, 0x31U,
0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x31U, 0x31U,
0x30U, 0x31U, 0x31U, 0x31U, 0x30U, 0x30U, 0x31U, 0x30U,
0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x30U, 0x30U,
0x30U, 0x31U, 0x31U, 0x30U, 0x30U, 0x31U, 0x30U, 0x30U,
0x30U, 0x30U, 0x31U, 0x30U, 0x30U, 0x30U, 0x30U, 0x31U,
)
val actual = encoding.encode(`Hello World!`)
assertContentEquals(expected, actual)
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -7,27 +7,30 @@ class `Base32 Test` {
val encoding: Encoding
get() = Base32
val `Hello World!` = ubyteArrayOf(
0x48U, 0x65U, 0x6cU, 0x6cU,
0x6fU, 0x20U, 0x57U, 0x6fU,
0x72U, 0x6cU, 0x64U, 0x21U,
)
val original = "Hello World!".encodeToByteArray()
val encoded = "JBSWY3DPEBLW64TMMQQQ====".encodeToByteArray()
@Test
fun `encode empty ByteArray`() {
val expected = ubyteArrayOf()
val actual = encoding.encode(ubyteArrayOf())
assertContentEquals(expected, actual)
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `encode "Hello World!"`() {
val expected = ubyteArrayOf(
0x4aU, 0x42U, 0x53U, 0x57U, 0x59U, 0x33U, 0x44U, 0x50U,
0x45U, 0x42U, 0x4cU, 0x57U, 0x36U, 0x34U, 0x54U, 0x4dU,
0x4dU, 0x51U, 0x51U, 0x51U, 0x3dU, 0x3dU, 0x3dU, 0x3dU,
)
val actual = encoding.encode(`Hello World!`)
assertContentEquals(expected, actual)
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -0,0 +1,36 @@
package com.infendro.encoding
import kotlin.test.Test
import kotlin.test.assertContentEquals
class `Base36 Test` {
val encoding: Encoding
get() = Base36
val original = "Hello World!".encodeToByteArray()
val encoded = "2678LX5GVMSV1DRO9B5".encodeToByteArray()
@Test
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -0,0 +1,36 @@
package com.infendro.encoding
import kotlin.test.Test
import kotlin.test.assertContentEquals
class `Base45 Test` {
val encoding: Encoding
get() = Base45
val original = "Hello World!".encodeToByteArray()
val encoded = "%69 VD82EI2B.KESTC".encodeToByteArray()
@Test
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -0,0 +1,36 @@
package com.infendro.encoding
import kotlin.test.Test
import kotlin.test.assertContentEquals
class `Base56 Test` {
val encoding: Encoding
get() = Base56
val original = "Hello World!".encodeToByteArray()
val encoded = "4Q9SNpVv4JrdwvjKj".encodeToByteArray()
@Test
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -0,0 +1,36 @@
package com.infendro.encoding
import kotlin.test.Test
import kotlin.test.assertContentEquals
class `Base58 Test` {
val encoding: Encoding
get() = Base58
val original = "Hello World!".encodeToByteArray()
val encoded = "2NEpo7TZRRrLZSi2U".encodeToByteArray()
@Test
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -0,0 +1,36 @@
package com.infendro.encoding
import kotlin.test.Test
import kotlin.test.assertContentEquals
class `Base62 Test` {
val encoding: Encoding
get() = Base62
val original = "Hello World!".encodeToByteArray()
val encoded = "T8dgcjRGkZ3aysdN".encodeToByteArray()
@Test
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -7,26 +7,30 @@ class `Base64 Test` {
val encoding: Encoding
get() = Base64
val `Hello World!` = ubyteArrayOf(
0x48U, 0x65U, 0x6cU, 0x6cU,
0x6fU, 0x20U, 0x57U, 0x6fU,
0x72U, 0x6cU, 0x64U, 0x21U,
)
val original = "Hello World!".encodeToByteArray()
val encoded = "SGVsbG8gV29ybGQh".encodeToByteArray()
@Test
fun `encode empty ByteArray`() {
val expected = ubyteArrayOf()
val actual = encoding.encode(ubyteArrayOf())
assertContentEquals(expected, actual)
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `encode "Hello World!"`() {
val expected = ubyteArrayOf(
0x53U, 0x47U, 0x56U, 0x73U, 0x62U, 0x47U, 0x38U, 0x67U,
0x56U, 0x32U, 0x39U, 0x79U, 0x62U, 0x47U, 0x51U, 0x68U,
)
val actual = encoding.encode(`Hello World!`)
assertContentEquals(expected, actual)
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}

View File

@@ -7,28 +7,30 @@ class `Base8 Test` {
val encoding: Encoding
get() = Base8
val `Hello World!` = ubyteArrayOf(
0x48U, 0x65U, 0x6cU, 0x6cU,
0x6fU, 0x20U, 0x57U, 0x6fU,
0x72U, 0x6cU, 0x64U, 0x21U,
)
val original = "Hello World!".encodeToByteArray()
val encoded = "22062554330674402566756233062041".encodeToByteArray()
@Test
fun `encode empty ByteArray`() {
val expected = ubyteArrayOf()
val actual = encoding.encode(ubyteArrayOf())
assertContentEquals(expected, actual)
fun `encode empty`() {
val actual = encoding.encode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun `encode "Hello World!"`() {
val expected = ubyteArrayOf(
0x32U, 0x32U, 0x30U, 0x36U, 0x32U, 0x35U, 0x35U, 0x34U,
0x33U, 0x33U, 0x30U, 0x36U, 0x37U, 0x34U, 0x34U, 0x30U,
0x32U, 0x35U, 0x36U, 0x36U, 0x37U, 0x35U, 0x36U, 0x32U,
0x33U, 0x33U, 0x30U, 0x36U, 0x32U, 0x30U, 0x34U, 0x31U,
)
val actual = encoding.encode(`Hello World!`)
assertContentEquals(expected, actual)
fun `decode empty`() {
val actual = encoding.decode(byteArrayOf())
assertContentEquals(byteArrayOf(), actual)
}
@Test
fun encode() {
val actual = encoding.encode(original)
assertContentEquals(encoded, actual)
}
@Test
fun decode() {
val actual = encoding.decode(encoded)
assertContentEquals(original, actual)
}
}