Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 36 additions & 33 deletions encoding/encodeInto.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,44 +78,47 @@
}
].forEach(destinationData => {
["ArrayBuffer", "SharedArrayBuffer"].forEach(arrayBufferOrSharedArrayBuffer => {
test(() => {
// Setup
const bufferLength = testData.destinationLength + destinationData.bufferIncrease;
const destinationOffset = destinationData.destinationOffset;
const destinationLength = testData.destinationLength;
const destinationFiller = destinationData.filler;
const encoder = new TextEncoder();
const buffer = createBuffer(arrayBufferOrSharedArrayBuffer, bufferLength);
const view = new Uint8Array(buffer, destinationOffset, destinationLength);
const fullView = new Uint8Array(buffer);
const control = new Array(bufferLength);
let byte = destinationFiller;
for (let i = 0; i < bufferLength; i++) {
if (destinationFiller === "random") {
byte = Math.floor(Math.random() * 256);
[false, true].forEach(resizable => {
test(() => {
// Setup
const bufferLength = testData.destinationLength + destinationData.bufferIncrease;
const destinationOffset = destinationData.destinationOffset;
const destinationLength = testData.destinationLength;
const destinationFiller = destinationData.filler;
const encoder = new TextEncoder();
const opts = resizable ? { maxByteLength: bufferLength } : undefined;
const buffer = createBuffer(arrayBufferOrSharedArrayBuffer, bufferLength, opts);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we always want the max length to be the buffer length, I think this could be better solved on the createBuffer level. Maybe detect if opts is a boolean is an option?

const view = new Uint8Array(buffer, destinationOffset, destinationLength);
const fullView = new Uint8Array(buffer);
const control = new Array(bufferLength);
let byte = destinationFiller;
for (let i = 0; i < bufferLength; i++) {
if (destinationFiller === "random") {
byte = Math.floor(Math.random() * 256);
}
control[i] = byte;
fullView[i] = byte;
}
control[i] = byte;
fullView[i] = byte;
}

// It's happening
const result = encoder.encodeInto(testData.input, view);
// It's happening
const result = encoder.encodeInto(testData.input, view);

// Basics
assert_equals(view.byteLength, destinationLength);
assert_equals(view.length, destinationLength);
// Basics
assert_equals(view.byteLength, destinationLength);
assert_equals(view.length, destinationLength);

// Remainder
assert_equals(result.read, testData.read);
assert_equals(result.written, testData.written.length);
for (let i = 0; i < bufferLength; i++) {
if (i < destinationOffset || i >= (destinationOffset + testData.written.length)) {
assert_equals(fullView[i], control[i]);
} else {
assert_equals(fullView[i], testData.written[i - destinationOffset]);
// Remainder
assert_equals(result.read, testData.read);
assert_equals(result.written, testData.written.length);
for (let i = 0; i < bufferLength; i++) {
if (i < destinationOffset || i >= (destinationOffset + testData.written.length)) {
assert_equals(fullView[i], control[i]);
} else {
assert_equals(fullView[i], testData.written[i - destinationOffset]);
}
}
}
}, "encodeInto() into " + arrayBufferOrSharedArrayBuffer + " with " + testData.input + " and destination length " + testData.destinationLength + ", offset " + destinationData.destinationOffset + ", filler " + destinationData.filler);
}, "encodeInto() into " + (resizable ? "resizable " : "") + arrayBufferOrSharedArrayBuffer + " with " + testData.input + " and destination length " + testData.destinationLength + ", offset " + destinationData.destinationOffset + ", filler " + destinationData.filler);
})
})
});
});
Expand Down
33 changes: 18 additions & 15 deletions encoding/textdecoder-copy.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@
// META: script=/common/sab.js

["ArrayBuffer", "SharedArrayBuffer"].forEach(arrayBufferOrSharedArrayBuffer => {
test(() => {
const buf = createBuffer(arrayBufferOrSharedArrayBuffer, 2);
const view = new Uint8Array(buf);
const buf2 = createBuffer(arrayBufferOrSharedArrayBuffer, 2);
const view2 = new Uint8Array(buf2);
const decoder = new TextDecoder("utf-8");
view[0] = 0xEF;
view[1] = 0xBB;
view2[0] = 0xBF;
view2[1] = 0x40;
assert_equals(decoder.decode(buf, {stream:true}), "");
view[0] = 0x01;
view[1] = 0x02;
assert_equals(decoder.decode(buf2), "@");
}, "Modify buffer after passing it in (" + arrayBufferOrSharedArrayBuffer + ")");
[false, true].forEach(resizable => {
test(() => {
const opts = resizable ? { maxByteLength: 2 } : undefined;
const buf = createBuffer(arrayBufferOrSharedArrayBuffer, 2, opts);
const view = new Uint8Array(buf);
const buf2 = createBuffer(arrayBufferOrSharedArrayBuffer, 2, opts);
const view2 = new Uint8Array(buf2);
const decoder = new TextDecoder("utf-8");
view[0] = 0xEF;
view[1] = 0xBB;
view2[0] = 0xBF;
view2[1] = 0x40;
assert_equals(decoder.decode(buf, {stream:true}), "");
view[0] = 0x01;
view[1] = 0x02;
assert_equals(decoder.decode(buf2), "@");
}, "Modify buffer after passing it in (" + (resizable ? "resizable " : "") + arrayBufferOrSharedArrayBuffer + ")");
})
});
110 changes: 57 additions & 53 deletions encoding/textdecoder-streaming.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,71 +19,75 @@ var octets = {
};

["ArrayBuffer", "SharedArrayBuffer"].forEach((arrayBufferOrSharedArrayBuffer) => {
Object.keys(octets).forEach(function(encoding) {
for (var len = 1; len <= 5; ++len) {
test(function() {
var encoded = octets[encoding];
[false, true].forEach(resizable => {
Object.keys(octets).forEach(function(encoding) {
for (var len = 1; len <= 5; ++len) {
test(function() {
var encoded = octets[encoding];

var out = '';
var decoder = new TextDecoder(encoding);
for (var i = 0; i < encoded.length; i += len) {
var sub = [];
for (var j = i; j < encoded.length && j < i + len; ++j) {
sub.push(encoded[j]);
var out = '';
var decoder = new TextDecoder(encoding);
for (var i = 0; i < encoded.length; i += len) {
var sub = [];
for (var j = i; j < encoded.length && j < i + len; ++j) {
sub.push(encoded[j]);
}
const opts = resizable ? { maxByteLength: sub.length } : undefined;
var uintArray = new Uint8Array(createBuffer(arrayBufferOrSharedArrayBuffer, sub.length, opts));
uintArray.set(sub);
out += decoder.decode(uintArray, {stream: true});
}
var uintArray = new Uint8Array(createBuffer(arrayBufferOrSharedArrayBuffer, sub.length));
uintArray.set(sub);
out += decoder.decode(uintArray, {stream: true});
}
out += decoder.decode();
assert_equals(out, string);
}, 'Streaming decode: ' + encoding + ', ' + len + ' byte window (' + arrayBufferOrSharedArrayBuffer + ')');
}
});
out += decoder.decode();
assert_equals(out, string);
}, 'Streaming decode: ' + encoding + ', ' + len + ' byte window (' + (resizable ? "resizable " : "") + arrayBufferOrSharedArrayBuffer + ')');
}
});

test(() => {
function bytes(byteArray) {
const view = new Uint8Array(createBuffer(arrayBufferOrSharedArrayBuffer, byteArray.length));
view.set(byteArray);
return view;
}
test(() => {
function bytes(byteArray) {
const opts = resizable ? { maxByteLength: byteArray.length } : undefined;
const view = new Uint8Array(createBuffer(arrayBufferOrSharedArrayBuffer, byteArray.length, opts));
view.set(byteArray);
return view;
}

const decoder = new TextDecoder();
const decoder = new TextDecoder();

assert_equals(decoder.decode(bytes([0xC1]), {stream: true}), "\uFFFD");
assert_equals(decoder.decode(), "");
assert_equals(decoder.decode(bytes([0xC1]), {stream: true}), "\uFFFD");
assert_equals(decoder.decode(), "");

assert_equals(decoder.decode(bytes([0xF5]), {stream: true}), "\uFFFD");
assert_equals(decoder.decode(), "");
assert_equals(decoder.decode(bytes([0xF5]), {stream: true}), "\uFFFD");
assert_equals(decoder.decode(), "");

assert_equals(decoder.decode(bytes([0xE0, 0x41]), {stream: true}), "\uFFFDA");
assert_equals(decoder.decode(bytes([0x42])), "B");
assert_equals(decoder.decode(bytes([0xE0, 0x41]), {stream: true}), "\uFFFDA");
assert_equals(decoder.decode(bytes([0x42])), "B");

assert_equals(decoder.decode(bytes([0xE0, 0x80]), {stream: true}), "\uFFFD\uFFFD");
assert_equals(decoder.decode(bytes([0x80])), "\uFFFD");
assert_equals(decoder.decode(bytes([0xE0, 0x80]), {stream: true}), "\uFFFD\uFFFD");
assert_equals(decoder.decode(bytes([0x80])), "\uFFFD");

assert_equals(decoder.decode(bytes([0xED, 0xA0]), {stream: true}), "\uFFFD\uFFFD");
assert_equals(decoder.decode(bytes([0x80])), "\uFFFD");
assert_equals(decoder.decode(bytes([0xED, 0xA0]), {stream: true}), "\uFFFD\uFFFD");
assert_equals(decoder.decode(bytes([0x80])), "\uFFFD");

assert_equals(decoder.decode(bytes([0xF0, 0x41]), {stream: true}), "\uFFFDA");
assert_equals(decoder.decode(bytes([0x42]), {stream: true}), "B");
assert_equals(decoder.decode(bytes([0x43])), "C");
assert_equals(decoder.decode(bytes([0xF0, 0x41]), {stream: true}), "\uFFFDA");
assert_equals(decoder.decode(bytes([0x42]), {stream: true}), "B");
assert_equals(decoder.decode(bytes([0x43])), "C");

assert_equals(decoder.decode(bytes([0xF0, 0x80]), {stream: true}), "\uFFFD\uFFFD");
assert_equals(decoder.decode(bytes([0x80]), {stream: true}), "\uFFFD");
assert_equals(decoder.decode(bytes([0x80])), "\uFFFD");
assert_equals(decoder.decode(bytes([0xF0, 0x80]), {stream: true}), "\uFFFD\uFFFD");
assert_equals(decoder.decode(bytes([0x80]), {stream: true}), "\uFFFD");
assert_equals(decoder.decode(bytes([0x80])), "\uFFFD");

assert_equals(decoder.decode(bytes([0xF4, 0xA0]), {stream: true}), "\uFFFD\uFFFD");
assert_equals(decoder.decode(bytes([0x80]), {stream: true}), "\uFFFD");
assert_equals(decoder.decode(bytes([0x80])), "\uFFFD");
assert_equals(decoder.decode(bytes([0xF4, 0xA0]), {stream: true}), "\uFFFD\uFFFD");
assert_equals(decoder.decode(bytes([0x80]), {stream: true}), "\uFFFD");
assert_equals(decoder.decode(bytes([0x80])), "\uFFFD");

assert_equals(decoder.decode(bytes([0xF0, 0x90, 0x41]), {stream: true}), "\uFFFDA");
assert_equals(decoder.decode(bytes([0x42])), "B");
assert_equals(decoder.decode(bytes([0xF0, 0x90, 0x41]), {stream: true}), "\uFFFDA");
assert_equals(decoder.decode(bytes([0x42])), "B");

// 4-byte UTF-8 sequences always correspond to non-BMP characters. Here
// we make sure that, although the first 3 bytes are enough to emit the
// lead surrogate, it only gets emitted when the fourth byte is read.
assert_equals(decoder.decode(bytes([0xF0, 0x9F, 0x92]), {stream: true}), "");
assert_equals(decoder.decode(bytes([0xA9])), "\u{1F4A9}");
}, `Streaming decode: UTF-8 chunk tests (${arrayBufferOrSharedArrayBuffer})`);
// 4-byte UTF-8 sequences always correspond to non-BMP characters. Here
// we make sure that, although the first 3 bytes are enough to emit the
// lead surrogate, it only gets emitted when the fourth byte is read.
assert_equals(decoder.decode(bytes([0xF0, 0x9F, 0x92]), {stream: true}), "");
assert_equals(decoder.decode(bytes([0xA9])), "\u{1F4A9}");
}, `Streaming decode: UTF-8 chunk tests (${resizable ? "resizable " : ""}${arrayBufferOrSharedArrayBuffer})`);
})
})
14 changes: 0 additions & 14 deletions webidl/ecmascript-binding/allow-resizable.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,4 @@
new Response(new Uint8Array(rab));
});
}, "APIs without [AllowResizable] throw when passed resizable ArrayBuffers");

test(t => {
const enc = new TextEncoder();

// Fixed-length SABs should not throw
const sab = createBuffer('SharedArrayBuffer', 16);
enc.encodeInto("foobar", new Uint8Array(sab));

const gsab = createBuffer('SharedArrayBuffer', 16, { maxByteLength: 1024 });
// TextEncoder.encodeInto doesn't have [AllowResizable] but has [AllowShared]
assert_throws_js(TypeError, () => {
enc.encodeInto("foobar", new Uint8Array(gsab));
});
}, "APIs with [AllowShared] but without [AllowResizable] throw when passed growable SharedArrayBuffers");
Comment on lines -17 to -30
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No API exists that fulfills these conditions apart from FileSystemSyncAccessHandle.read/write().
I felt like handling this here would be out of scope.

</script>
Loading