ok(true, "Should be able to write without an active reader");
await port.close();
});
add_task(async function testLargeDataTransfer() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600, bufferSize: 2048 });
const writer = port.writable.getWriter();
const largeData = new Uint8Array(1024);
for (let i = 0; i < largeData.length; i++) {
largeData[i] = i % 256;
}
const reader = port.readable.getReader();
let received = new Uint8Array(0);
while (received.length < largeData.length) {
const { value, done } = await reader.read();
ok(!done, "Read should not be done");
const combined = new Uint8Array(received.length + value.length);
combined.set(received);
combined.set(value, received.length);
received = combined;
}
is(received.length, largeData.length, "Should receive same amount of data");
let allMatch = true;
for (let i = 0; i < received.length; i++) {
if (received[i] !== largeData[i]) {
allMatch = false;
break;
}
}
ok(allMatch, "All bytes should match");
reader.releaseLock();
await port.close();
});
// Regression test: verify no data is lost when bufferSize is small. The
// continuous read loop reads all available bytes from the OS buffer regardless
// of bufferSize, so individual chunks may exceed bufferSize.
add_task(async function testNoDataLossWithSmallBufferSize() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600, bufferSize: 64 });
const writer = port.writable.getWriter();
const totalBytes = 256;
const largeData = new Uint8Array(totalBytes);
for (let i = 0; i < totalBytes; i++) {
largeData[i] = i % 256;
}
await writer.write(largeData);
writer.releaseLock();
const reader = port.readable.getReader();
let received = new Uint8Array(0);
while (received.length < totalBytes) {
const { value, done } = await reader.read();
ok(!done, "Read should not be done while data remains");
ok(!!value.length, "Each read should return some data");
const combined = new Uint8Array(received.length + value.length);
combined.set(received);
combined.set(value, received.length);
received = combined;
}
is(received.length, totalBytes, "Should receive all bytes despite small buffer size");
let allMatch = true;
for (let i = 0; i < totalBytes; i++) {
if (received[i] !== largeData[i]) {
allMatch = false;
info("Mismatch at byte " + i + ": expected " + largeData[i] + " got " + received[i]);
break;
}
}
ok(allMatch, "All bytes should match (no data lost between capped reads)");
reader.releaseLock();
await port.close();
});
add_task(async function testBYOBReaderBasic() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600 });
const { value } = await reader.read(buffer);
ok(value, "Should receive data into Uint16Array");
is(value.byteLength, testData.byteLength, "Should receive all bytes");
is(buffer.byteLength, 0, "Original buffer should be detached after BYOB read");
reader.releaseLock();
await port.close();
});
add_task(async function testBYOBReaderWithOffset() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600 });
const arrayBuffer = new ArrayBuffer(64);
const view = new Uint8Array(arrayBuffer, 16, 32);
const { value } = await reader.read(view);
ok(value, "Should receive data into view with offset");
ok(value.byteOffset >= 16, "View should maintain offset");
const decoder = new TextDecoder();
const received = decoder.decode(value);
is(received, "Test", "Should receive correct data");
reader.releaseLock();
await port.close();
});
add_task(async function testBYOBReaderPartialRead() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600 });
const { value } = await reader.read(largeBuffer);
ok(value, "Should receive data");
is(value.byteLength, smallData.byteLength, "Should only fill buffer with available data");
is(value[0], 0x42, "First byte should match");
is(value[1], 0x43, "Second byte should match");
is(largeBuffer.byteLength, 0, "Original buffer should be detached after BYOB read");
reader.releaseLock();
await port.close();
});
add_task(async function testBYOBReaderLargeTransfer() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600, bufferSize: 2048 });
const writer = port.writable.getWriter();
const largeData = new Uint8Array(1024);
for (let i = 0; i < largeData.length; i++) {
largeData[i] = i % 256;
}
await writer.write(largeData);
writer.releaseLock();
const reader = port.readable.getReader({ mode: "byob" });
let received = new Uint8Array(0);
let buffer = new Uint8Array(2048);
while (received.length < largeData.length) {
const { value } = await reader.read(buffer);
ok(value, "Should receive data");
const combined = new Uint8Array(received.length + value.byteLength);
combined.set(received);
combined.set(new Uint8Array(value.buffer, value.byteOffset, value.byteLength), received.length);
received = combined;
buffer = new Uint8Array(value.buffer);
}
is(received.length, largeData.length, "Should receive all data");
let allMatch = largeData.every((val, i) => val === received[i]);
ok(allMatch, "All bytes should match with BYOB reader");
reader.releaseLock();
await port.close();
});
add_task(async function testReaderReleaseLockCancelsRead() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600 });
const reader = port.readable.getReader();
let readPromise = reader.read();
reader.releaseLock();
await Assert.rejects(
readPromise,
e => e.name === "TypeError" && e.message.toLowerCase().includes("lock"), "Read after releaseLock should throw TypeError mentioning lock"
);
await port.close();
});
add_task(async function testReaderCannotReadAfterReleaseLock() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600 });
// Per spec, the old writable is spent; the getter lazily creates a fresh one.
const writable2 = port.writable;
ok(writable2, "Should get a new writable after writer.close()");
isnot(writable2, writable1, "New writable should be a different object");
ok(port.readable, "Readable should still be available after writer close");
let reader = port.readable.getReader();
let receivedText = "";
const expected1 = "FirstWrite";
while (receivedText.length < expected1.length) {
const { value, done } = await reader.read();
if (done) break;
if (value) receivedText += decoder.decode(value, { stream: true });
}
is(receivedText, expected1, "Should receive first written data");
reader.releaseLock();
// Write again with new writer on the fresh writable.
writer = writable2.getWriter();
await writer.write(encoder.encode("SecondWrite"));
writer.releaseLock();
reader = port.readable.getReader();
receivedText = "";
const expected2 = "SecondWrite";
while (receivedText.length < expected2.length) {
const { value, done } = await reader.read();
if (done) break;
if (value) receivedText += decoder.decode(value, { stream: true });
}
is(receivedText, expected2, "Should receive second written data on fresh writable");
reader.releaseLock();
await port.close();
});
add_task(async function testReadableRecreatedAfterCancel() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600 });
const encoder = new TextEncoder();
const decoder = new TextDecoder();
let writer = port.writable.getWriter();
await writer.write(encoder.encode("FirstRead"));
writer.releaseLock();
const readable1 = port.readable;
const reader1 = readable1.getReader();
ok(reader1, "Should get first reader");
const { value: value1 } = await reader1.read();
ok(value1, "Should read data from first reader");
const text1 = decoder.decode(value1);
is(text1, "FirstRead", "Should receive first data");
// Per spec, the old readable is spent; the getter lazily creates a fresh one.
// Writable should still be available.
ok(port.writable, "Writable should still be available after readable cancel");
const readable2 = port.readable;
ok(readable2, "Should get a new readable after cancel");
isnot(readable2, readable1, "New readable should be a different object");
// Write data, then abort to discard transmit buffers.
await writer.write(encoder.encode("Discarded"));
await writer.abort();
ok(true, "Abort should succeed after write");
// Per spec, the old writable is spent; the getter creates a fresh one.
ok(port.writable, "Should get fresh writable after abort");
isnot(port.writable, writable1, "Fresh writable should differ from original");
ok(port.readable, "Readable should still be available after writable abort");
await port.close();
});
add_task(async function testCancelDiscardsReceiveBuffers() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600 });
const encoder = new TextEncoder();
// Write some data that will loop back to the read buffer.
let writer = port.writable.getWriter();
await writer.write(encoder.encode("ReceiveData"));
writer.releaseLock();
// Cancel the readable stream to discard receive buffers.
const readable1 = port.readable;
const reader = readable1.getReader();
await reader.cancel();
ok(true, "Cancel should succeed");
// Per spec, the old readable is spent; the getter creates a fresh one.
reader.releaseLock();
ok(port.readable, "Should get fresh readable after cancel");
isnot(port.readable, readable1, "Fresh readable should differ from original");
await port.close();
});
add_task(async function testCancelThenAbort() {
SpecialPowers.wrap(document).notifyUserGestureActivation();
const port = await navigator.serial.requestPort({ filters: [] });
await port.open({ baudRate: 9600 });
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.