87 lines
3.7 KiB
TypeScript
87 lines
3.7 KiB
TypeScript
import { assert, describe, it } from "@effect/vitest"
|
|
import * as Crypto from "effect/Crypto"
|
|
import * as Effect from "effect/Effect"
|
|
import * as TestClock from "effect/testing/TestClock"
|
|
|
|
const testCrypto = Crypto.make({
|
|
randomBytes: (size) =>
|
|
size === 7 ? Uint8Array.of(0x18, 0, 0, 0, 0, 0, 0) : Uint8Array.from({ length: size }, (_, i) => i),
|
|
digest: (algorithm, data) => Effect.succeed(Uint8Array.of(data.length, algorithm.length))
|
|
})
|
|
|
|
describe("Crypto", () => {
|
|
it("supports string literal digest algorithms", () => {
|
|
const algorithm: Crypto.DigestAlgorithm = "SHA-256"
|
|
assert.strictEqual(algorithm, "SHA-256")
|
|
})
|
|
|
|
it.effect("randomBytes delegates to the service", () =>
|
|
Effect.gen(function*() {
|
|
const crypto = yield* Crypto.Crypto
|
|
const bytes = yield* crypto.randomBytes(4)
|
|
assert.deepStrictEqual(bytes, Uint8Array.of(0, 1, 2, 3))
|
|
}).pipe(Effect.provideService(Crypto.Crypto, testCrypto)))
|
|
|
|
it.effect("random generators delegate to the service", () =>
|
|
Effect.gen(function*() {
|
|
const crypto = yield* Crypto.Crypto
|
|
const random = yield* crypto.random
|
|
const randomInt = yield* crypto.randomInt
|
|
const randomBoolean = yield* crypto.randomBoolean
|
|
const randomBetween = yield* crypto.randomBetween(10, 20)
|
|
const randomBetweenDecimalBounds = yield* crypto.randomBetween(10.5, 20.5)
|
|
const randomIntBetween = yield* crypto.randomIntBetween(1, 6)
|
|
const randomShuffle = yield* crypto.randomShuffle([1, 2, 3])
|
|
|
|
assert.strictEqual(random, 0.75)
|
|
assert.strictEqual(randomInt, 4503599627370497)
|
|
assert.strictEqual(randomBoolean, true)
|
|
assert.strictEqual(randomBetween, 17.5)
|
|
assert.strictEqual(randomBetweenDecimalBounds, 18)
|
|
assert.strictEqual(randomIntBetween, 5)
|
|
assert.deepStrictEqual(randomShuffle, [1, 2, 3])
|
|
}).pipe(Effect.provideService(Crypto.Crypto, testCrypto)))
|
|
|
|
it.effect("randomIntBetween excludes the upper bound in half-open ranges", () =>
|
|
Effect.gen(function*() {
|
|
const crypto = yield* Crypto.Crypto
|
|
const value = yield* crypto.randomIntBetween(1, 6, { halfOpen: true })
|
|
assert.strictEqual(value, 5)
|
|
}).pipe(Effect.provideService(
|
|
Crypto.Crypto,
|
|
Crypto.make({
|
|
randomBytes: (size) => new Uint8Array(size).fill(0xff),
|
|
digest: (_algorithm, data) => Effect.succeed(data)
|
|
})
|
|
)))
|
|
|
|
it.effect("randomUUIDv4 formats UUID bytes from randomBytes", () =>
|
|
Effect.gen(function*() {
|
|
const crypto = yield* Crypto.Crypto
|
|
const uuid = yield* crypto.randomUUIDv4
|
|
assert.strictEqual(uuid, "00010203-0405-4607-8809-0a0b0c0d0e0f")
|
|
}).pipe(Effect.provideService(Crypto.Crypto, testCrypto)))
|
|
|
|
it.effect("randomUUIDv7 formats UUID bytes with the Clock timestamp", () =>
|
|
Effect.gen(function*() {
|
|
yield* TestClock.setTime(0x0123456789ab)
|
|
const crypto = yield* Crypto.Crypto
|
|
const uuid = yield* crypto.randomUUIDv7
|
|
assert.strictEqual(uuid, "01234567-89ab-7607-8809-0a0b0c0d0e0f")
|
|
}).pipe(Effect.provideService(Crypto.Crypto, testCrypto)))
|
|
|
|
it.effect("digest delegates to the service", () =>
|
|
Effect.gen(function*() {
|
|
const crypto = yield* Crypto.Crypto
|
|
const digest = yield* crypto.digest("SHA-256", Uint8Array.of(1, 2, 3))
|
|
assert.deepStrictEqual(digest, Uint8Array.of(3, "SHA-256".length))
|
|
}).pipe(Effect.provideService(Crypto.Crypto, testCrypto)))
|
|
|
|
it.effect("can access a provided custom Crypto service", () =>
|
|
Effect.gen(function*() {
|
|
const crypto = yield* Crypto.Crypto
|
|
const bytes = yield* crypto.randomBytes(1)
|
|
assert.deepStrictEqual(bytes, Uint8Array.of(0))
|
|
}).pipe(Effect.provideService(Crypto.Crypto, testCrypto)))
|
|
})
|