// META: script=/resources/test-only-api.js // META: script=/serial/resources/common.js // META: script=resources/automation.js serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); assert_equals(port.writable, null); await port.open({baudRate: 9600}); const writable = port.writable; assert_true(writable instanceof WritableStream); await port.close(); assert_equals(port.writable, null); const writer = writable.getWriter(); const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); await promise_rejects_dom(t, 'InvalidStateError', writer.write(data)); }, 'open() and close() set and unset SerialPort.writable'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); await port.open({baudRate: 9600}); assert_true(port.writable instanceof WritableStream); const writer = port.writable.getWriter(); await promise_rejects_js(t, TypeError, port.close()); writer.releaseLock(); await port.close(); assert_equals(port.writable, null); }, 'Port cannot be closed while writable is locked'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); await port.open({baudRate: 9600}); assert_true(port.writable instanceof WritableStream); const writer = port.writable.getWriter(); const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); let writePromise = writer.write(data); writer.releaseLock(); await fakePort.readable(); let {value, done} = await fakePort.read(); await writePromise; compareArrays(value, data); await port.close(); assert_equals(port.writable, null); }, 'Can write a small amount of data'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); // Select a buffer size smaller than the amount of data transferred. await port.open({baudRate: 9600, bufferSize: 64}); const writer = port.writable.getWriter(); const data = new Uint8Array(1024); // Much larger than bufferSize above. for (let i = 0; i < data.byteLength; ++i) data[i] = i & 0xff; writer.write(data); writer.releaseLock(); await fakePort.readable(); const value = await fakePort.readWithLength(data.byteLength); compareArrays(data, value); await port.close(); }, 'Can write a large amount of data'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); await port.open({baudRate: 9600}); const writable = port.writable; assert_true(writable instanceof WritableStream); let writer = writable.getWriter(); await fakePort.readable(); fakePort.simulateSystemErrorOnWrite(); const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); await promise_rejects_dom(t, 'UnknownError', writer.write(data)); assert_true(port.writable instanceof WritableStream); assert_not_equals(port.writable, writable); writer = port.writable.getWriter(); let writePromise = writer.write(data); writer.releaseLock(); await fakePort.readable(); let {value, done} = await fakePort.read(); await writePromise; compareArrays(value, data); await port.close(); assert_equals(port.writable, null); }, 'System error closes writable and replaces it with a new stream'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); await port.open({baudRate: 9600}); assert_true(port.writable instanceof WritableStream); const writer = port.writable.getWriter(); await fakePort.readable(); fakePort.simulateDisconnectOnWrite(); const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); await promise_rejects_dom(t, 'NetworkError', writer.write(data)); assert_equals(port.writable, null); await port.close(); }, 'Disconnect error closes writable and sets it to null'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); await port.open({baudRate: 9600, bufferSize: 64}); const originalWritable = port.writable; assert_true(originalWritable instanceof WritableStream); let writer = originalWritable.getWriter(); let data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); // The buffer size is large enough to allow this write to complete without // the data being read from the fake port. await writer.write(data); await writer.abort(); assert_true(port.writable instanceof WritableStream); assert_true(port.writable !== originalWritable); writer = port.writable.getWriter(); data = new Uint8Array([9, 10, 11, 12, 13, 14, 15, 16]); const writePromise = writer.write(data); writer.releaseLock(); await fakePort.readable(); const {value, done} = await fakePort.read(); await writePromise; compareArrays(value, data); await port.close(); assert_equals(port.writable, null); }, 'abort() discards the write buffer'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); // Select a buffer size smaller than the amount of data transferred. await port.open({baudRate: 9600, bufferSize: 64}); const writer = port.writable.getWriter(); // Wait for microtasks to execute in order to ensure that the WritableStream // has been set up completely. await Promise.resolve(); const data = new Uint8Array(1024); // Much larger than bufferSize above. for (let i = 0; i < data.byteLength; ++i) data[i] = i & 0xff; const writePromise = promise_rejects_exactly(t, 'Aborting.', writer.write(data)); await writer.abort('Aborting.'); await writePromise; await port.close(); assert_equals(port.writable, null); }, 'abort() does not wait for the write buffer to be cleared'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); // Select a buffer size smaller than the amount of data transferred. await port.open({baudRate: 9600, bufferSize: 64}); const writer = port.writable.getWriter(); const data = new Uint8Array(1024); // Much larger than bufferSize above. for (let i = 0; i < data.byteLength; ++i) data[i] = i & 0xff; const closed = (async () => { await promise_rejects_exactly(t, 'Aborting.', writer.write(data)); writer.releaseLock(); await port.close(); assert_equals(port.writable, null); })(); await writer.abort('Aborting.'); await closed; }, 'Can close while aborting'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); // Select a buffer size smaller than the amount of data transferred. await port.open({baudRate: 9600, bufferSize: 64}); const writer = port.writable.getWriter(); const data = new Uint8Array(1024); // Much larger than bufferSize above. for (let i = 0; i < data.byteLength; ++i) data[i] = i & 0xff; writer.write(data); let readComplete = false; let writePromise = writer.close().then(() => { assert_true(readComplete); }); await fakePort.readable(); let readPromise = fakePort.readWithLength(data.byteLength).then(result => { readComplete = true; return result; }); const value = await readPromise; compareArrays(data, value); await writePromise; await port.close(); }, 'close() waits for the write buffer to be cleared'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); // Select a buffer size smaller than the amount of data transferred. await port.open({baudRate: 9600, bufferSize: 64}); const writer = port.writable.getWriter(); // Wait for microtasks to execute in order to ensure that the WritableStream // has been set up completely. await Promise.resolve(); const data = new Uint8Array(1024); // Much larger than bufferSize above. for (let i = 0; i < data.byteLength; ++i) data[i] = i & 0xff; const writePromise = promise_rejects_exactly(t, 'Aborting.', writer.write(data)); const closePromise = promise_rejects_exactly(t, 'Aborting.', writer.close()); await writer.abort('Aborting.'); await writePromise; await closePromise; await port.close(); assert_equals(port.writable, null); }, 'Can abort while closing'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); await port.open({baudRate: 9600}); assert_true(port.writable instanceof WritableStream); const encoder = new TextEncoderStream(); const streamClosed = encoder.readable.pipeTo(port.writable); const writer = encoder.writable.getWriter(); const writePromise = writer.write('Hello world!'); await fakePort.readable(); const {value, done} = await fakePort.read(); await writePromise; assert_equals('Hello world!', new TextDecoder().decode(value)); await writer.close(); await streamClosed; await port.close(); assert_equals(port.writable, null); }, 'Can pipe a stream to writable'); serial_test(async (t, fake) => { const {port, fakePort} = await getFakeSerialPort(fake); await port.open({baudRate: 9600}); assert_true(port.writable instanceof WritableStream); const transform = new TransformStream(); const readable = transform.readable.pipeThrough(new TextEncoderStream()) .pipeThrough(new TransformStream()) .pipeThrough(new TransformStream()) .pipeThrough(new TransformStream()); const streamClosed = readable.pipeTo(port.writable); const writer = transform.writable.getWriter(); const writePromise = writer.write('Hello world!'); await fakePort.readable(); const {value, done} = await fakePort.read(); await writePromise; assert_equals('Hello world!', new TextDecoder().decode(value)); await writer.close(); await streamClosed; await port.close(); assert_equals(port.writable, null); }, 'Stream closure is observable through a long chain of transformers');