// Flags: --expose-internals 'use strict'; require('../common'); const assert = require('assert'); const { test } = require('node:test'); const vm = require('vm'); const { converters } = require('internal/webidl'); const TYPED_ARRAY_CTORS = [ Uint8Array, Int8Array, Uint8ClampedArray, Uint16Array, Int16Array, Uint32Array, Int32Array, Float16Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array, ]; function createGrowableSharedArrayBufferView(Ctor) { const buffer = createGrowableSharedArrayBuffer(); const view = new Ctor(buffer); return view; } function createGrowableSharedArrayBuffer() { const buffer = new SharedArrayBuffer(0, { maxByteLength: 1 }); assert.strictEqual(buffer.growable, true); return buffer; } test('BufferSource accepts ArrayBuffer', () => { const ab = new ArrayBuffer(8); assert.strictEqual(converters.BufferSource(ab), ab); }); test('BufferSource accepts all TypedArray kinds', () => { for (const Ctor of TYPED_ARRAY_CTORS) { const ta = new Ctor(4); assert.strictEqual(converters.BufferSource(ta), ta); } }); test('BufferSource accepts Buffer', () => { const buf = Buffer.alloc(8); assert.strictEqual(converters.BufferSource(buf), buf); }); test('BufferSource accepts DataView', () => { const dv = new DataView(new ArrayBuffer(8)); assert.strictEqual(converters.BufferSource(dv), dv); }); test('BufferSource accepts cross-realm buffer sources', () => { const context = vm.createContext(); { const ab = vm.runInContext('new ArrayBuffer(0)', context); assert.strictEqual(converters.BufferSource(ab), ab); } { const dv = vm.runInContext('new DataView(new ArrayBuffer(0))', context); assert.strictEqual(converters.BufferSource(dv), dv); } for (const Ctor of TYPED_ARRAY_CTORS) { const ta = vm.runInContext( `new ${Ctor.name}(new ArrayBuffer(0))`, context, ); assert.strictEqual(converters.BufferSource(ta), ta); } }); test('BufferSource accepts ArrayBuffer subclass instance', () => { class MyAB extends ArrayBuffer {} const sub = new MyAB(8); assert.strictEqual(converters.BufferSource(sub), sub); }); test('BufferSource accepts TypedArray with null prototype', () => { const ta = new Uint8Array(4); Object.setPrototypeOf(ta, null); assert.strictEqual(converters.BufferSource(ta), ta); }); test('BufferSource accepts DataView with null prototype', () => { const dv = new DataView(new ArrayBuffer(4)); Object.setPrototypeOf(dv, null); assert.strictEqual(converters.BufferSource(dv), dv); }); test('BufferSource accepts ArrayBuffer with null prototype', () => { const ab = new ArrayBuffer(4); Object.setPrototypeOf(ab, null); assert.strictEqual(converters.BufferSource(ab), ab); }); test('BufferSource rejects SharedArrayBuffer', () => { assert.throws( () => converters.BufferSource(new SharedArrayBuffer(4)), { code: 'ERR_INVALID_ARG_TYPE' }, ); }); test('BufferSource rejects SAB-backed TypedArray', () => { const view = new Uint8Array(new SharedArrayBuffer(4)); assert.throws( () => converters.BufferSource(view), { code: 'ERR_INVALID_ARG_TYPE' }, ); assert.throws( () => converters.BufferSource(view, { allowShared: true }), { code: 'ERR_INVALID_ARG_TYPE' }, ); }); test('BufferSource rejects SAB-backed DataView', () => { const dv = new DataView(new SharedArrayBuffer(4)); assert.throws( () => converters.BufferSource(dv), { code: 'ERR_INVALID_ARG_TYPE' }, ); assert.throws( () => converters.BufferSource(dv, { allowShared: true }), { code: 'ERR_INVALID_ARG_TYPE' }, ); }); test('BufferSource rejects SAB view whose buffer prototype was reassigned', () => { const sab = new SharedArrayBuffer(4); Object.setPrototypeOf(sab, ArrayBuffer.prototype); const view = new Uint8Array(sab); assert.throws( () => converters.BufferSource(view), { code: 'ERR_INVALID_ARG_TYPE' }, ); }); test('BufferSource accepts a detached ArrayBuffer', () => { const ab = new ArrayBuffer(8); structuredClone(ab, { transfer: [ab] }); assert.strictEqual(ab.byteLength, 0); assert.strictEqual(converters.BufferSource(ab), ab); }); test('BufferSource rejects resizable ArrayBuffer by default', () => { const ab = new ArrayBuffer(0, { maxByteLength: 1 }); assert.throws( () => converters.BufferSource(ab), { code: 'ERR_INVALID_ARG_TYPE' }, ); }); test('BufferSource handles resizable-backed views with explicit options', () => { for (const Ctor of [DataView, ...TYPED_ARRAY_CTORS]) { { const view = new Ctor(new ArrayBuffer(0, { maxByteLength: 1 })); assert.throws( () => converters.BufferSource(view), { code: 'ERR_INVALID_ARG_TYPE' }, ); } { const view = new Ctor(new ArrayBuffer(0, { maxByteLength: 1 })); assert.throws( () => converters.BufferSource(view, { allowResizable: false }), { code: 'ERR_INVALID_ARG_TYPE' }, ); } { const view = new Ctor(new ArrayBuffer(0, { maxByteLength: 1 })); assert.strictEqual(converters.BufferSource(view, { allowResizable: true, }), view); } } }); test('BufferSource rejects SAB-backed views with explicit options', () => { for (const Ctor of [DataView, ...TYPED_ARRAY_CTORS]) { const view = createGrowableSharedArrayBufferView(Ctor); assert.throws( () => converters.BufferSource(view, { allowShared: true, allowResizable: true, }), { code: 'ERR_INVALID_ARG_TYPE' }, ); } }); test('AllowSharedBufferSource accepts ArrayBuffer and SharedArrayBuffer', () => { const ab = new ArrayBuffer(8); const sab = new SharedArrayBuffer(8); assert.strictEqual(converters.AllowSharedBufferSource(ab), ab); assert.strictEqual(converters.AllowSharedBufferSource(sab), sab); }); test('AllowSharedBufferSource accepts cross-realm buffers', () => { const context = vm.createContext(); const ab = vm.runInContext('new ArrayBuffer(0)', context); const sab = vm.runInContext('new SharedArrayBuffer(0)', context); assert.strictEqual(converters.AllowSharedBufferSource(ab), ab); assert.strictEqual(converters.AllowSharedBufferSource(sab), sab); }); test('AllowSharedBufferSource accepts ArrayBuffer and SharedArrayBuffer views', () => { const abView = new Uint8Array(new ArrayBuffer(8)); const sabView = new Uint8Array(new SharedArrayBuffer(8)); const abDataView = new DataView(new ArrayBuffer(8)); const sabDataView = new DataView(new SharedArrayBuffer(8)); assert.strictEqual(converters.AllowSharedBufferSource(abView), abView); assert.strictEqual(converters.AllowSharedBufferSource(sabView), sabView); assert.strictEqual( converters.AllowSharedBufferSource(abDataView), abDataView); assert.strictEqual( converters.AllowSharedBufferSource(sabDataView), sabDataView); }); test('AllowSharedBufferSource handles resizable buffers with explicit options', () => { const ab = new ArrayBuffer(0, { maxByteLength: 1 }); const views = [new Uint8Array(ab), new DataView(ab)]; assert.throws( () => converters.AllowSharedBufferSource(ab), { code: 'ERR_INVALID_ARG_TYPE' }, ); for (const view of views) { assert.throws( () => converters.AllowSharedBufferSource(view), { code: 'ERR_INVALID_ARG_TYPE' }, ); } assert.strictEqual(converters.AllowSharedBufferSource(ab, { allowResizable: true, }), ab); for (const view of views) { assert.strictEqual(converters.AllowSharedBufferSource(view, { allowResizable: true, }), view); } }); test('AllowSharedBufferSource handles growable shared buffers with explicit ' + 'options', () => { const sab = createGrowableSharedArrayBuffer(); const views = [new Uint8Array(sab), new DataView(sab)]; assert.throws( () => converters.AllowSharedBufferSource(sab), { code: 'ERR_INVALID_ARG_TYPE' }, ); for (const view of views) { assert.throws( () => converters.AllowSharedBufferSource(view), { code: 'ERR_INVALID_ARG_TYPE' }, ); } assert.strictEqual(converters.AllowSharedBufferSource(sab, { allowResizable: true, }), sab); for (const view of views) { assert.strictEqual(converters.AllowSharedBufferSource(view, { allowResizable: true, }), view); } }); test('BufferSource rejects objects with a forged @@toStringTag', () => { const fake = { [Symbol.toStringTag]: 'Uint8Array' }; assert.throws( () => converters.BufferSource(fake), { code: 'ERR_INVALID_ARG_TYPE' }, ); }); for (const value of [null, undefined, 0, 1, 1n, '', 'x', true, Symbol('s'), [], {}, () => {}]) { test(`BufferSource rejects ${typeof value} ${String(value)}`, () => { assert.throws( () => converters.BufferSource(value), { code: 'ERR_INVALID_ARG_TYPE' }, ); }); test(`AllowSharedBufferSource rejects ${typeof value} ${String(value)}`, () => { assert.throws( () => converters.AllowSharedBufferSource(value), { code: 'ERR_INVALID_ARG_TYPE' }, ); }); }