|
1 | | -import { expect, test } from "vitest"; |
| 1 | +import { expect, test, vi } from "vitest"; |
2 | 2 | import { |
3 | 3 | BraintrustStream, |
4 | 4 | BraintrustStreamChunk, |
@@ -103,3 +103,64 @@ test("final value passthrough with abort", async () => { |
103 | 103 | "This operation was aborted", |
104 | 104 | ); |
105 | 105 | }); |
| 106 | + |
| 107 | +async function collectFinalValue( |
| 108 | + chunks: (string | Uint8Array | BraintrustStreamChunk)[], |
| 109 | +) { |
| 110 | + const final = vi.fn(); |
| 111 | + const error = vi.fn(); |
| 112 | + const emitted: BraintrustStreamChunk[] = []; |
| 113 | + const input = new ReadableStream({ |
| 114 | + start(controller) { |
| 115 | + for (const chunk of chunks) controller.enqueue(chunk); |
| 116 | + controller.close(); |
| 117 | + }, |
| 118 | + }); |
| 119 | + await input |
| 120 | + .pipeThrough(createFinalValuePassThroughStream(final, error)) |
| 121 | + .pipeTo( |
| 122 | + new WritableStream({ |
| 123 | + write(chunk) { |
| 124 | + emitted.push(chunk); |
| 125 | + }, |
| 126 | + }), |
| 127 | + ); |
| 128 | + return { final, error, emitted }; |
| 129 | +} |
| 130 | + |
| 131 | +test.each(["é", "€", "🧠", "Пам’ять 🧠 漢字"])( |
| 132 | + "final value and forwarded text preserve every UTF-8 split: %s", |
| 133 | + async (text) => { |
| 134 | + const bytes = new TextEncoder().encode(text); |
| 135 | + for (let split = 1; split < bytes.length; split++) { |
| 136 | + const { final, error, emitted } = await collectFinalValue([ |
| 137 | + bytes.subarray(0, split), |
| 138 | + new Uint8Array(), |
| 139 | + bytes.subarray(split), |
| 140 | + ]); |
| 141 | + expect(final).toHaveBeenCalledExactlyOnceWith(text); |
| 142 | + expect(error).not.toHaveBeenCalled(); |
| 143 | + expect(emitted.map((chunk) => chunk.data).join("")).toBe(text); |
| 144 | + } |
| 145 | + }, |
| 146 | +); |
| 147 | + |
| 148 | +test.each([ |
| 149 | + { chunks: [Uint8Array.of(0xf0, 0x9f)], expected: "�" }, |
| 150 | + { chunks: [Uint8Array.of(0xf0), Uint8Array.of(0x9f)], expected: "�" }, |
| 151 | + { |
| 152 | + chunks: [ |
| 153 | + Uint8Array.of(0xc3), |
| 154 | + { type: "text_delta", data: "middle" } as const, |
| 155 | + Uint8Array.of(0xa9), |
| 156 | + ], |
| 157 | + expected: "�middle�", |
| 158 | + }, |
| 159 | +])( |
| 160 | + "final value replaces incomplete byte runs: $expected", |
| 161 | + async ({ chunks, expected }) => { |
| 162 | + const { final, emitted } = await collectFinalValue(chunks); |
| 163 | + expect(final).toHaveBeenCalledExactlyOnceWith(expected); |
| 164 | + expect(emitted.map((chunk) => chunk.data).join("")).toBe(expected); |
| 165 | + }, |
| 166 | +); |
0 commit comments