| 1 | describe("BufferedWriter", () => { |
| 2 | test("basics", () => { |
| 3 | const chunks: Uint8Array[] = []; |
| 4 | const w = new stream.BufferedWriter((d) => chunks.push(d), 16); |
| 5 | |
| 6 | w.u8(1); |
| 7 | w.u16(258); |
| 8 | w.u32(0x04030201); |
| 9 | w.flush(); |
| 10 | |
| 11 | assert.equal(chunks.length, 1); |
| 12 | assert.deepEqual(chunks[0], new Uint8Array([1, 2, 1, 1, 2, 3, 4])); |
| 13 | }); |
| 14 | |
| 15 | test("auto-flush on large write", () => { |
| 16 | const chunks: Uint8Array[] = []; |
| 17 | const w = new stream.BufferedWriter((d) => chunks.push(d), 8); |
| 18 | |
| 19 | w.u32(1); |
| 20 | assert.equal(w.written, 4); |
| 21 | const large = new Uint8Array(20).fill(0xff); |
| 22 | w.write(large); |
| 23 | assert.equal(w.written, 0); |
| 24 | |
| 25 | assert.equal(chunks.length, 2); |
| 26 | assert.equal(chunks[0]!.length, 4); |
| 27 | assert.equal(chunks[1]!.length, 20); |
| 28 | }); |
| 29 | |
| 30 | test("transfer based flush", () => { |
| 31 | const chunks: Uint8Array[] = []; |
| 32 | const w = new stream.BufferedWriter((d) => chunks.push(d), 4); |
| 33 | |
| 34 | w.u8(1); |
| 35 | w.u8(2); |
| 36 | w.u8(3); |
| 37 | w.u8(4); |
| 38 | w.flush(); |
| 39 | w.u8(2); |
| 40 | w.u8(3); |
| 41 | w.u8(4); |
| 42 | w.u8(5); |
| 43 | w[Symbol.dispose](); |
| 44 | |
| 45 | assert.equal(chunks.length, 2); |
| 46 | assert.deepEqual(chunks[0], new Uint8Array([1, 2, 3, 4])); |
| 47 | assert.deepEqual(chunks[1], new Uint8Array([2, 3, 4, 5])); |
| 48 | }); |
| 49 | |
| 50 | test("ensure more than total capacity", () => { |
| 51 | const chunks: Uint8Array[] = []; |
| 52 | const w = new stream.BufferedWriter((d) => chunks.push(d), 2); |
| 53 | assert.equal(w.size, 2); |
| 54 | w.u8(4); |
| 55 | w.ensureUnusedCapacity(8); // flushes [ 4 ] |
| 56 | w.write(new Uint8Array([4, 5, 5, 8, 8, 1, 2])); |
| 57 | assert.equal(w.written, 7); |
| 58 | assert.equal(w.size, 8); |
| 59 | w.u32(42); |
| 60 | w.flush(); |
| 61 | |
| 62 | assert.equal(chunks.length, 3); |
| 63 | assert.deepEqual(chunks[0], new Uint8Array([4])); |
| 64 | assert.deepEqual(chunks[1], new Uint8Array([4, 5, 5, 8, 8, 1, 2])); |
| 65 | assert.deepEqual(chunks[2], new Uint8Array([42, 0, 0, 0])); |
| 66 | }); |
| 67 | |
| 68 | test("varUint", () => { |
| 69 | const chunks: Uint8Array[] = []; |
| 70 | const w = new stream.BufferedWriter((d) => chunks.push(d)); |
| 71 | |
| 72 | w.varUint(0); |
| 73 | w.varUint(127); |
| 74 | w.varUint(128); |
| 75 | w.varUint(16383); |
| 76 | w.flush(); |
| 77 | |
| 78 | assert.deepEqual(chunks[0], new Uint8Array([0, 127, 128, 1, 255, 127])); |
| 79 | }); |
| 80 | |
| 81 | test("dispose", () => { |
| 82 | const chunks: Uint8Array[] = []; |
| 83 | { |
| 84 | using w = new stream.BufferedWriter((d) => chunks.push(d)); |
| 85 | w.u8(42); |
| 86 | } |
| 87 | assert.equal(chunks.length, 1); |
| 88 | assert.equal(chunks[0]![0], 42); |
| 89 | }); |
| 90 | }); |
| 91 | |
| 92 | describe("BufferedReader", () => { |
| 93 | test("basic read", async () => { |
| 94 | const [s, w] = stream.bufferedReadableStream(); |
| 95 | w.u8(1); |
| 96 | w.u16(258); |
| 97 | w.flush(); |
| 98 | w.u32(0x04030201); |
| 99 | w.flush(); |
| 100 | |
| 101 | using r = new stream.BufferedReader(s.getReader()); |
| 102 | assert.equal(await r.u8(), 1); |
| 103 | assert.equal(await r.u16(), 258); |
| 104 | assert.equal(await r.u16(), 0x0201); |
| 105 | assert.equal(await r.u16(), 0x0403); |
| 106 | }); |
| 107 | |
| 108 | test("varUint", async () => { |
| 109 | const [s, w] = stream.bufferedReadableStream(); |
| 110 | w.varUint(0); |
| 111 | w.varUint(127); |
| 112 | w.varUint(128); |
| 113 | w.varUint(16383); |
| 114 | w.varUint(1768210855277); |
| 115 | w.varUint(521); |
| 116 | w.close(); |
| 117 | |
| 118 | using r = new stream.BufferedReader(s.getReader()); |
| 119 | assert.equal(await r.varUint(), 0); |
| 120 | assert.equal(await r.varUint(), 127); |
| 121 | assert.equal(await r.varUint(), 128); |
| 122 | assert.equal(await r.varUint(), 16383); |
| 123 | assert.equal(await r.varUint(), 1768210855277); |
| 124 | assert.equal(await r.varUint(), 521); |
| 125 | }); |
| 126 | |
| 127 | test("cross-chunk read", async () => { |
| 128 | const [s, w] = stream.bufferedReadableStream(); |
| 129 | w.u8(1); |
| 130 | w.flush(); |
| 131 | w.u8(2); |
| 132 | w.flush(); |
| 133 | |
| 134 | using r = new stream.BufferedReader(s.getReader()); |
| 135 | assert.equal(await r.u16(), 0x0201); |
| 136 | }); |
| 137 | |
| 138 | test("readExactly", async () => { |
| 139 | const [s, w] = stream.bufferedReadableStream(); |
| 140 | w.write(new Uint8Array([1, 2, 3, 4, 5])); |
| 141 | w.flush(); |
| 142 | |
| 143 | using r = new stream.BufferedReader(s.getReader()); |
| 144 | const buf = await r.readExactly(3); |
| 145 | assert.deepEqual(buf, new Uint8Array([1, 2, 3])); |
| 146 | assert.equal(await r.u8(), 4); |
| 147 | }); |
| 148 | |
| 149 | test.todo("readExactly cutting chunks", async () => { |
| 150 | const [s, w] = stream.bufferedReadableStream(); |
| 151 | w.write(new Uint8Array([1, 2, 3])); |
| 152 | w.flush(); |
| 153 | w.write(new Uint8Array([4, 5, 6])); |
| 154 | w.flush(); |
| 155 | w.write(new Uint8Array([7, 8, 9])); |
| 156 | w.flush(); |
| 157 | w.write(new Uint8Array([10, 11, 12])); |
| 158 | w.flush(); |
| 159 | |
| 160 | using r = new stream.BufferedReader(s.getReader()); |
| 161 | assert.deepEqual(await r.readExactly(4), new Uint8Array([1, 2, 3, 4])); |
| 162 | assert.deepEqual(await r.readExactly(4), new Uint8Array([5, 6, 7, 8])); |
| 163 | assert.deepEqual(await r.readExactly(4), new Uint8Array([9, 10, 11, 12])); |
| 164 | }); |
| 165 | |
| 166 | test("readUpTo", async () => { |
| 167 | const [s, w] = stream.bufferedReadableStream(); |
| 168 | w.write(new Uint8Array([1, 2])); |
| 169 | w.close(); |
| 170 | |
| 171 | using r = new stream.BufferedReader(s.getReader()); |
| 172 | const buf = await r.readUpTo(10); |
| 173 | assert.equal(buf.length, 2); |
| 174 | }); |
| 175 | |
| 176 | test("stringWithLength", async () => { |
| 177 | const [s, w] = stream.bufferedReadableStream(); |
| 178 | w.stringWithLength("hello"); |
| 179 | w.flush(); |
| 180 | |
| 181 | using r = new stream.BufferedReader(s.getReader()); |
| 182 | assert.equal(await r.stringWithLength(), "hello"); |
| 183 | }); |
| 184 | |
| 185 | test("some numeric types", async () => { |
| 186 | const [s, w] = stream.bufferedReadableStream(); |
| 187 | |
| 188 | w.i8(-1); |
| 189 | w.i16(-1); |
| 190 | w.i32(-1); |
| 191 | w.i64(-1n); |
| 192 | w.u32(4_000_000_000); |
| 193 | w.u64(0xffffffffffffffffn); |
| 194 | w.f16(1.5); |
| 195 | w.f32(1.5); |
| 196 | w.f64(1.5); |
| 197 | w.close(); |
| 198 | |
| 199 | using r = new stream.BufferedReader(s.getReader()); |
| 200 | assert.equal(await r.i8(), -1); |
| 201 | assert.equal(await r.i16(), -1); |
| 202 | assert.equal(await r.i32(), -1); |
| 203 | assert.equal(await r.i64(), -1n); |
| 204 | assert.equal(await r.u32(), 4_000_000_000); |
| 205 | assert.equal(await r.u64(), 0xffffffffffffffffn); |
| 206 | assert.equal(await r.f16(), 1.5); |
| 207 | assert.equal(await r.f32(), 1.5); |
| 208 | assert.equal(await r.f64(), 1.5); |
| 209 | }); |
| 210 | |
| 211 | test("cancel", () => { |
| 212 | let cancelReason: unknown; |
| 213 | const s = new ReadableStream({ |
| 214 | start() {}, |
| 215 | cancel(reason) { |
| 216 | cancelReason = reason; |
| 217 | }, |
| 218 | }); |
| 219 | |
| 220 | const r = new stream.BufferedReader(s.getReader()); |
| 221 | const err = new Error("test cancel"); |
| 222 | r.cancel(err); |
| 223 | |
| 224 | assert.equal(cancelReason, err); |
| 225 | }); |
| 226 | }); |
| 227 | |
| 228 | import { strict as assert } from "node:assert"; |
| 229 | import { describe, test } from "vitest"; |
| 230 | import * as stream from "./stream.ts"; |