Skip to content

Commit

Permalink
feat(utils): add new functions to convert base64 strings (#300)
Browse files Browse the repository at this point in the history
* feat(utils): add new functions to convert base64 strings

re #299

* docs(utils): fix comments with right type name

re #299

* docs(utils): add more documentation for unexpected results

re #299

* test(utils): add test for non-ascii characters

re #299

* test(utils): add test for non-text arbitrary data

re #299
  • Loading branch information
cedoor authored Jun 13, 2024
1 parent bbe8803 commit 1b14668
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 2 deletions.
50 changes: 49 additions & 1 deletion packages/utils/src/conversions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/

import { Buffer } from "buffer"
import { requireBigInt, requireBigNumberish, requireHexadecimal, requireTypes } from "./error-handlers"
import { requireBigInt, requireBigNumberish, requireHexadecimal, requireString, requireTypes } from "./error-handlers"
import { isBuffer, isHexadecimal, isUint8Array } from "./type-checks"
import { BigNumber, BigNumberish } from "./types"

Expand Down Expand Up @@ -220,3 +220,51 @@ export function bufferToHexadecimal(value: Buffer | Uint8Array): string {

return Buffer.from(value).toString("hex")
}

/**
* Converts bytes to a base64 string. It accepts 'Buffer' or 'Uint8Array'.
* @param value The bytes to convert.
* @returns The converted base64 string.
*/
export function bufferToBase64(value: Buffer | Uint8Array): string {
requireTypes(value, "value", ["Buffer", "Uint8Array"])

return Buffer.from(value).toString("base64")
}

/**
* Converts a base64 string to bytes (i.e. a buffer). This function does not check
* if the input value is a valid base64 string. If there are unsupported characters
* they will be ignored.
* @param value The base64 string to convert.
* @returns The converted buffer.
*/
export function base64ToBuffer(value: string): Buffer {
requireString(value, "value")

return Buffer.from(value, "base64")
}

/**
* Converts text (utf8) to a base64 string.
* @param value The text to convert.
* @returns The converted base64 string.
*/
export function textToBase64(value: string): string {
requireString(value, "value")

return Buffer.from(value, "utf8").toString("base64")
}

/**
* Converts a base64 string to text (utf8). This function does not check
* if the input value is a valid base64 string. If there are unsupported characters
* they could be ignored and the result may be unexpected.
* @param value The base64 string to convert.
* @returns The converted text.
*/
export function base64ToText(value: string): string {
requireString(value, "value")

return Buffer.from(value, "base64").toString("utf8")
}
77 changes: 76 additions & 1 deletion packages/utils/tests/conversions.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { Buffer } from "buffer"
import {
base64ToBuffer,
base64ToText,
beBigIntToBuffer,
beBufferToBigInt,
bigIntToHexadecimal,
bigNumberishToBigInt,
bigNumberishToBuffer,
bufferToBase64,
bufferToHexadecimal,
hexadecimalToBigInt,
hexadecimalToBuffer,
leBigIntToBuffer,
leBufferToBigInt
leBufferToBigInt,
textToBase64
} from "../src/conversions"

describe("Conversions", () => {
Expand Down Expand Up @@ -170,6 +174,77 @@ describe("Conversions", () => {
})
})

describe("# base64ToBuffer / bufferToBase64", () => {
const testBase64 = "SGVsbG8sIFdvcmxkIQ=="
const testText = "Hello, World!"

it("Should convert a base64 string to a buffer", async () => {
const result = base64ToBuffer(testBase64)

expect(result.toString("utf8")).toBe(testText)
})

it("Should convert a buffer to a base64 string", async () => {
const result = bufferToBase64(Buffer.from(testText))

expect(result).toBe(testBase64)
})

it("Should ignore unsupported characters in the base64 string", async () => {
const result = base64ToBuffer("#@. Unsupported characters .@#")

expect(bufferToBase64(result)).toBe("Unsupportedcharacter")
})

it("Should convert other base64 representations to a buffer", async () => {
const empty = ""
// Binary Data with Null and Escape Characters.
const random = "QUJDREVGR0hJSktMTU5PUFBbU09aW15gYQ=="
// Image data (PNG).
const image =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAAEklEQVR42mP8/5/hP4P8P4//fwYAAAD//wAHOVjsXAAAAABJRU5ErkJggg=="
// Audio data (WAV).
const audio = "UklGRjgAAABXQVZFZm10IBAAAAABAAEARKwAABCxAgAEABAAZGF0YQAAAAA="

expect(bufferToBase64(base64ToBuffer(empty))).toBe(empty)
expect(bufferToBase64(base64ToBuffer(random))).toBe(random)
expect(bufferToBase64(base64ToBuffer(image))).toBe(image)
expect(bufferToBase64(base64ToBuffer(audio))).toBe(audio)
})
})

describe("# base64ToText / textToBase64", () => {
const testBase64 = "SGVsbG8sIFdvcmxkIQ=="
const testText = "Hello, World!"

it("Should convert a base64 string to a text", async () => {
const result = base64ToText(testBase64)

expect(result).toBe(testText)
})

it("Should convert a text to a base64 string", async () => {
const result = textToBase64(testText)

expect(result).toBe(testBase64)
})

it("Should not correctly convert a base64 string with invalid characters", async () => {
const result = base64ToText("#@. Unsupported characters .@#")

expect(textToBase64(result)).not.toBe("Unsupportedcharacter")
expect(textToBase64(result)).not.toBe("#@. Unsupported characters .@#")
})

it("Should support and correctly convert text with non-ASCII characters", async () => {
const nonASCII = "🔥 БД Ω 好 ت 本"

const result = textToBase64(nonASCII)

expect(base64ToText(result)).toBe(nonASCII)
})
})

describe("BigInt to/from Buffer Conversions", () => {
it("Should support little-endian conversions", async () => {
const in1 = Buffer.from(testBytes1)
Expand Down

0 comments on commit 1b14668

Please sign in to comment.