feat: better image handling (auto resize & max size constraints) (#26401)
This commit is contained in:
78
packages/opencode/test/image/image.test.ts
Normal file
78
packages/opencode/test/image/image.test.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Cause, Effect, Exit, Layer } from "effect"
|
||||
import { Image } from "@/image/image"
|
||||
import { MessageID, PartID, SessionID } from "@/session/schema"
|
||||
import { TestConfig } from "../fixture/config"
|
||||
import { testEffect } from "../lib/effect"
|
||||
|
||||
const it = testEffect(Layer.mergeAll(Image.layer.pipe(Layer.provide(TestConfig.layer()))))
|
||||
const tiny = testEffect(
|
||||
Layer.mergeAll(
|
||||
Image.layer.pipe(
|
||||
Layer.provide(TestConfig.layer({ get: () => Effect.succeed({ attachment: { image: { max_base64_bytes: 1 } } }) })),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
function part(mime: string, data: string) {
|
||||
return {
|
||||
id: PartID.ascending(),
|
||||
messageID: MessageID.ascending(),
|
||||
sessionID: SessionID.make("ses_test"),
|
||||
type: "file" as const,
|
||||
mime,
|
||||
url: `data:${mime};base64,${data}`,
|
||||
}
|
||||
}
|
||||
|
||||
describe("Image", () => {
|
||||
it.effect("normalizes generated png and jpeg attachments", () =>
|
||||
Effect.gen(function* () {
|
||||
const photon = yield* Effect.promise(() => import("@silvia-odwyer/photon-node"))
|
||||
const source = new photon.PhotonImage(
|
||||
new Uint8Array(Array.from({ length: 64 * 64 * 4 }, (_, index) => (index % 4 === 3 ? 255 : index % 251))),
|
||||
64,
|
||||
64,
|
||||
)
|
||||
const image = yield* Image.Service
|
||||
const results = yield* Effect.all([
|
||||
image.normalize(part("image/png", Buffer.from(source.get_bytes()).toString("base64"))),
|
||||
image.normalize(part("image/jpeg", Buffer.from(source.get_bytes_jpeg(90)).toString("base64"))),
|
||||
])
|
||||
|
||||
source.free()
|
||||
expect(results.map((result) => result.url.startsWith(`data:${result.mime};base64,`))).toEqual([true, true])
|
||||
expect(results.every((result) => result.mime === "image/png" || result.mime === "image/jpeg")).toBe(true)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("accepts webp attachments that are already within limits", () =>
|
||||
Effect.gen(function* () {
|
||||
const image = yield* Image.Service
|
||||
const input = part("image/webp", "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA")
|
||||
|
||||
expect(yield* image.normalize(input)).toEqual(input)
|
||||
}),
|
||||
)
|
||||
|
||||
tiny.effect("fails with a typed size error when no resized candidate fits", () =>
|
||||
Effect.gen(function* () {
|
||||
const photon = yield* Effect.promise(() => import("@silvia-odwyer/photon-node"))
|
||||
const source = new photon.PhotonImage(new Uint8Array(Array.from({ length: 4 }, () => 255)), 1, 1)
|
||||
const image = yield* Image.Service
|
||||
const exit = yield* image.normalize(part("image/png", Buffer.from(source.get_bytes()).toString("base64"))).pipe(Effect.exit)
|
||||
|
||||
source.free()
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) {
|
||||
const error = Cause.squash(exit.cause)
|
||||
expect(error).toBeInstanceOf(Image.SizeError)
|
||||
if (error instanceof Image.SizeError) {
|
||||
expect(error.width).toBe(1)
|
||||
expect(error.height).toBe(1)
|
||||
expect(error.max).toBe(1)
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
})
|
||||
Reference in New Issue
Block a user