Skip to content

Commit 62bfb0c

Browse files
committed
test: align size-limit tests with codebase conventions
- decode rejections use assert.isRejected(p, RangeError, 'substring'), matching test-errors.spec.js (asserts both type and message in one call) - encode writer rejections use expect(...).to.eventually.be.rejectedWith(...), matching test-writer.spec.js, which avoids the documented case where assert.isRejected on a writer.put can throw an uncatchable error in Chrome - reuse the collector / concatBytes helper shape from test-writer.spec.js - drop the standalone RangeError tests; the type is now checked inline per cap
1 parent 9367e53 commit 62bfb0c

2 files changed

Lines changed: 59 additions & 64 deletions

File tree

test/test-decode-limits.spec.js

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,23 @@ async function decodeAll (entry, data, options, chunkSize = 64) {
4242
return count
4343
}
4444

45-
/** @param {Uint8Array[]} arrays */
46-
function concat (...arrays) {
47-
const out = new Uint8Array(arrays.reduce((n, a) => n + a.length, 0))
48-
let offset = 0
49-
for (const a of arrays) {
50-
out.set(a, offset)
51-
offset += a.length
45+
/**
46+
* @param {Uint8Array[]} chunks
47+
*/
48+
function concatBytes (chunks) {
49+
const length = chunks.reduce((p, c) => p + c.length, 0)
50+
const bytes = new Uint8Array(length)
51+
let off = 0
52+
for (const chunk of chunks) {
53+
bytes.set(chunk, off)
54+
off += chunk.length
5255
}
53-
return out
56+
return bytes
5457
}
5558

5659
/** @param {Uint8Array} payload */
5760
function lengthPrefixed (payload) {
58-
return concat(Uint8Array.from(vEncode(payload.length)), payload)
61+
return concatBytes([Uint8Array.from(vEncode(payload.length)), payload])
5962
}
6063

6164
const validV1Header = lengthPrefixed(cbEncode({ version: 1, roots: [] }))
@@ -65,17 +68,17 @@ describe('decode read-size limits', () => {
6568
for (const entry of ENTRIES) {
6669
it(`${entry.name}: header larger than maxHeaderLength`, async () => {
6770
// carBytes' header length prefix declares 99 bytes; cap well below it
68-
await assert.isRejected(decodeAll(entry, carBytes, { maxHeaderLength: 10 }), /maxHeaderLength/)
71+
await assert.isRejected(decodeAll(entry, carBytes, { maxHeaderLength: 10 }), RangeError, 'maxHeaderLength')
6972
})
7073

7174
it(`${entry.name}: block larger than maxBlockLength`, async () => {
7275
// every block in carBytes is at least 4 bytes; cap below that
73-
await assert.isRejected(decodeAll(entry, carBytes, { maxBlockLength: 3 }), /maxBlockLength/)
76+
await assert.isRejected(decodeAll(entry, carBytes, { maxBlockLength: 3 }), RangeError, 'maxBlockLength')
7477
})
7578

7679
it(`${entry.name}: CID larger than maxCidLength`, async () => {
7780
// carBytes' section CIDs are CIDv1 sha2-256 (full CID 36 bytes); cap below that
78-
await assert.isRejected(decodeAll(entry, carBytes, { maxCidLength: 10 }), /maxCidLength/)
81+
await assert.isRejected(decodeAll(entry, carBytes, { maxCidLength: 10 }), RangeError, 'maxCidLength')
7982
})
8083
}
8184
})
@@ -107,7 +110,7 @@ describe('decode read-size limits', () => {
107110
// off-by-one that rejects the exactly-equal block fails this test.
108111
assert.strictEqual(await decodeAll(blockIter, carBytes, { maxBlockLength: max }), total)
109112
// one below: rejected
110-
await assert.isRejected(decodeAll(blockIter, carBytes, { maxBlockLength: max - 1 }), /maxBlockLength/)
113+
await assert.isRejected(decodeAll(blockIter, carBytes, { maxBlockLength: max - 1 }), RangeError, 'maxBlockLength')
111114
})
112115

113116
it('measures the full CID, not just the multihash', async () => {
@@ -124,13 +127,7 @@ describe('decode read-size limits', () => {
124127
// equal to the full CID: allowed, everything decodes
125128
assert.ok(await decodeAll(blockIter, carBytes, { maxCidLength: maxCid }) > 0)
126129
// one below the full CID (still above the 34-byte multihash): rejected
127-
await assert.isRejected(decodeAll(blockIter, carBytes, { maxCidLength: maxCid - 1 }), /maxCidLength/)
128-
})
129-
130-
it('size-limit violations reject with a RangeError', async () => {
131-
await assert.isRejected(decodeAll(blockIter, carBytes, { maxHeaderLength: 10 }), RangeError)
132-
await assert.isRejected(decodeAll(blockIter, carBytes, { maxBlockLength: 3 }), RangeError)
133-
await assert.isRejected(decodeAll(blockIter, carBytes, { maxCidLength: 10 }), RangeError)
130+
await assert.isRejected(decodeAll(blockIter, carBytes, { maxCidLength: maxCid - 1 }), RangeError, 'maxCidLength')
134131
})
135132

136133
describe('rejects from the length prefix before buffering the body', () => {
@@ -140,24 +137,24 @@ describe('decode read-size limits', () => {
140137
const huge = 1_000_000_000
141138

142139
it('header', async () => {
143-
const data = concat(Uint8Array.from(vEncode(huge)), Uint8Array.from([1, 2, 3]))
144-
await assert.isRejected(decodeAll(blockIter, data, { maxHeaderLength: 1000 }), /maxHeaderLength/)
140+
const data = concatBytes([Uint8Array.from(vEncode(huge)), Uint8Array.from([1, 2, 3])])
141+
await assert.isRejected(decodeAll(blockIter, data, { maxHeaderLength: 1000 }), RangeError, 'maxHeaderLength')
145142
})
146143

147144
it('block', async () => {
148145
const cid = rndCid.bytes
149146
// declare a section of huge size but supply only the CID, no block body
150-
const section = concat(Uint8Array.from(vEncode(huge + cid.length)), cid)
151-
const data = concat(validV1Header, section)
152-
await assert.isRejected(decodeAll(blockIter, data, { maxBlockLength: 1000 }), /maxBlockLength/)
147+
const section = concatBytes([Uint8Array.from(vEncode(huge + cid.length)), cid])
148+
const data = concatBytes([validV1Header, section])
149+
await assert.isRejected(decodeAll(blockIter, data, { maxBlockLength: 1000 }), RangeError, 'maxBlockLength')
153150
})
154151

155152
it('CID', async () => {
156153
// CIDv1, raw codec (0x55), sha2-256 (0x12), huge multihash digest length, no digest
157-
const cid = concat(Uint8Array.from([0x01, 0x55, 0x12]), Uint8Array.from(vEncode(huge)))
158-
const section = concat(Uint8Array.from(vEncode(cid.length + 1)), cid)
159-
const data = concat(validV1Header, section)
160-
await assert.isRejected(decodeAll(blockIter, data, { maxCidLength: 1000 }), /maxCidLength/)
154+
const cid = concatBytes([Uint8Array.from([0x01, 0x55, 0x12]), Uint8Array.from(vEncode(huge))])
155+
const section = concatBytes([Uint8Array.from(vEncode(cid.length + 1)), cid])
156+
const data = concatBytes([validV1Header, section])
157+
await assert.isRejected(decodeAll(blockIter, data, { maxCidLength: 1000 }), RangeError, 'maxCidLength')
161158
})
162159
})
163160
})

test/test-encode-limits.spec.js

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
11
/* eslint-env mocha */
22

33
import { encode as cbEncode } from '@ipld/dag-cbor'
4+
import { expect } from 'aegir/chai'
45
import { CarReader } from '../src/reader.js'
56
import { CarWriter } from '../src/writer.js'
67
import { assert, makeData, makeIterable } from './common.js'
78

8-
/** @param {AsyncIterable<Uint8Array>} iterable */
9-
async function collect (iterable) {
10-
const chunks = []
11-
for await (const chunk of iterable) {
12-
chunks.push(chunk)
13-
}
14-
let len = 0
15-
for (const c of chunks) {
16-
len += c.length
17-
}
18-
const out = new Uint8Array(len)
9+
/**
10+
* @param {Uint8Array[]} chunks
11+
*/
12+
function concatBytes (chunks) {
13+
const length = chunks.reduce((p, c) => p + c.length, 0)
14+
const bytes = new Uint8Array(length)
1915
let off = 0
20-
for (const c of chunks) {
21-
out.set(c, off)
22-
off += c.length
16+
for (const chunk of chunks) {
17+
bytes.set(chunk, off)
18+
off += chunk.length
2319
}
24-
return out
20+
return bytes
21+
}
22+
23+
/**
24+
* @param {AsyncIterable<Uint8Array>} iterable
25+
*/
26+
function collector (iterable) {
27+
const chunks = []
28+
const cfn = (async () => {
29+
for await (const chunk of iterable) {
30+
chunks.push(chunk)
31+
}
32+
return concatBytes(chunks)
33+
})()
34+
return cfn
2535
}
2636

2737
/**
@@ -34,7 +44,7 @@ async function collect (iterable) {
3444
*/
3545
async function writeAll (roots, blocks, options) {
3646
const { writer, out } = CarWriter.create(roots, options)
37-
const collection = collect(out)
47+
const collection = collector(out)
3848
const writes = blocks.map((b) => writer.put(b))
3949
writes.push(writer.close())
4050
await Promise.all(writes)
@@ -59,7 +69,7 @@ describe('encode size limits', () => {
5969
describe('maxHeaderLength', () => {
6070
it('rejects a header larger than the cap (via first put)', async () => {
6171
const { writer } = CarWriter.create(roots, { maxHeaderLength: 10 })
62-
await assert.isRejected(writer.put(rawBlocks[0]), /maxHeaderLength/)
72+
await expect(writer.put(rawBlocks[0])).to.eventually.be.rejectedWith(RangeError, /maxHeaderLength/)
6373
})
6474

6575
it('allows a header exactly equal to the cap, rejects one below', async () => {
@@ -69,7 +79,7 @@ describe('encode size limits', () => {
6979
assert.ok(bytes.length > 0)
7080
// one below: rejected from the header
7181
const { writer } = CarWriter.create(roots, { maxHeaderLength: headerLen - 1 })
72-
await assert.isRejected(writer.put(rawBlocks[0]), /maxHeaderLength/)
82+
await expect(writer.put(rawBlocks[0])).to.eventually.be.rejectedWith(RangeError, /maxHeaderLength/)
7383
})
7484
})
7585

@@ -80,7 +90,7 @@ describe('encode size limits', () => {
8090
// pull the single header chunk first to relieve backpressure.
8191
const { writer, out } = CarWriter.create(roots, { maxBlockLength: 3 })
8292
await out[Symbol.asyncIterator]().next()
83-
await assert.isRejected(writer.put(rawBlocks[0]), /maxBlockLength/)
93+
await expect(writer.put(rawBlocks[0])).to.eventually.be.rejectedWith(RangeError, /maxBlockLength/)
8494
})
8595

8696
it('allows a block body exactly equal to the cap', async () => {
@@ -95,7 +105,7 @@ describe('encode size limits', () => {
95105
// the header chunk so writeBlock (where the CID check lives) runs.
96106
const { writer, out } = CarWriter.create(roots, { maxCidLength: 10 })
97107
await out[Symbol.asyncIterator]().next()
98-
await assert.isRejected(writer.put(rawBlocks[0]), /maxCidLength/)
108+
await expect(writer.put(rawBlocks[0])).to.eventually.be.rejectedWith(RangeError, /maxCidLength/)
99109
})
100110

101111
it('measures the full CID, not the multihash', async () => {
@@ -106,7 +116,7 @@ describe('encode size limits', () => {
106116
// only rejects if the cap measures the whole CID
107117
const { writer, out } = CarWriter.create(roots, { maxCidLength: cidLen - 1, maxBlockLength: 1 << 20 })
108118
await out[Symbol.asyncIterator]().next()
109-
await assert.isRejected(writer.put(rawBlocks[0]), /maxCidLength/)
119+
await expect(writer.put(rawBlocks[0])).to.eventually.be.rejectedWith(RangeError, /maxCidLength/)
110120
})
111121

112122
it('does NOT reject a CIDv0 CID below the cap (symmetric with decode)', async () => {
@@ -115,27 +125,15 @@ describe('encode size limits', () => {
115125
})
116126
})
117127

118-
it('size-limit violations reject with a RangeError', async () => {
119-
// header rejects before any write (no drain needed)
120-
await assert.isRejected(CarWriter.create(roots, { maxHeaderLength: 10 }).writer.put(rawBlocks[0]), RangeError)
121-
// block and CID reject inside writeBlock, so drain the header chunk first
122-
const b = CarWriter.create(roots, { maxBlockLength: 3 })
123-
await b.out[Symbol.asyncIterator]().next()
124-
await assert.isRejected(b.writer.put(rawBlocks[0]), RangeError)
125-
const c = CarWriter.create(roots, { maxCidLength: 10 })
126-
await c.out[Symbol.asyncIterator]().next()
127-
await assert.isRejected(c.writer.put(rawBlocks[0]), RangeError)
128-
})
129-
130128
describe('createAppender', () => {
131129
it('enforces maxBlockLength on appended blocks', async () => {
132130
const { writer } = CarWriter.createAppender({ maxBlockLength: 3 })
133-
await assert.isRejected(writer.put(rawBlocks[0]), /maxBlockLength/)
131+
await expect(writer.put(rawBlocks[0])).to.eventually.be.rejectedWith(RangeError, /maxBlockLength/)
134132
})
135133

136134
it('writes normally with no caps', async () => {
137135
const { writer, out } = CarWriter.createAppender()
138-
const collection = collect(out)
136+
const collection = collector(out)
139137
await writer.put(rawBlocks[0])
140138
await writer.close()
141139
const bytes = await collection

0 commit comments

Comments
 (0)