mirror of
https://github.com/servo/servo.git
synced 2025-08-16 19:05:33 +01:00
Update web-platform-tests to revision 157b71e48394fb63f91fa497be429c3543b0ab03
This commit is contained in:
parent
ea32495504
commit
ae09310953
43 changed files with 874 additions and 287 deletions
|
@ -0,0 +1,299 @@
|
|||
// META global=worker
|
||||
|
||||
// This test checks that DecompressionStream behaves according to the standard
|
||||
// when the input is corrupted. To avoid a combinatorial explosion in the
|
||||
// number of tests, we only mutate one field at a time, and we only test
|
||||
// "interesting" values.
|
||||
|
||||
'use strict';
|
||||
|
||||
// The many different cases are summarised in this data structure.
|
||||
const expectations = [
|
||||
{
|
||||
format: 'deflate',
|
||||
|
||||
// Decompresses to 'expected output'.
|
||||
baseInput: [120, 156, 75, 173, 40, 72, 77, 46, 73, 77, 81, 200, 47, 45, 41,
|
||||
40, 45, 1, 0, 48, 173, 6, 36],
|
||||
|
||||
// See RFC1950 for the definition of the various fields used by deflate:
|
||||
// https://tools.ietf.org/html/rfc1950.
|
||||
fields: [
|
||||
{
|
||||
// The function of this field. This matches the name used in the RFC.
|
||||
name: 'CMF',
|
||||
|
||||
// The offset of the field in bytes from the start of the input.
|
||||
offset: 0,
|
||||
|
||||
// The length of the field in bytes.
|
||||
length: 1,
|
||||
|
||||
cases: [
|
||||
{
|
||||
// The value to set the field to. If the field contains multiple
|
||||
// bytes, all the bytes will be set to this value.
|
||||
value: 0,
|
||||
|
||||
// The expected result. 'success' means the input is decoded
|
||||
// successfully. 'error' means that the stream will be errored.
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'FLG',
|
||||
offset: 1,
|
||||
length: 1,
|
||||
|
||||
// FLG contains a 4-bit checksum (FCHECK) which is calculated in such a
|
||||
// way that there are 4 valid values for this field.
|
||||
cases: [
|
||||
{
|
||||
value: 218,
|
||||
result: 'success'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
result: 'success'
|
||||
},
|
||||
{
|
||||
value: 94,
|
||||
result: 'success'
|
||||
},
|
||||
{
|
||||
// The remaining 252 values cause an error.
|
||||
value: 157,
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'DATA',
|
||||
// In general, changing any bit of the data will trigger a checksum
|
||||
// error. Only the last byte does anything else.
|
||||
offset: 18,
|
||||
length: 1,
|
||||
cases: [
|
||||
{
|
||||
value: 4,
|
||||
result: 'success'
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'ADLER',
|
||||
offset: -4,
|
||||
length: 4,
|
||||
cases: [
|
||||
{
|
||||
value: 255,
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
format: 'gzip',
|
||||
|
||||
// Decompresses to 'expected output'.
|
||||
baseInput: [31, 139, 8, 0, 0, 0, 0, 0, 0, 3, 75, 173, 40, 72, 77, 46, 73,
|
||||
77, 81, 200, 47, 45, 41, 40, 45, 1, 0, 176, 1, 57, 179, 15, 0,
|
||||
0, 0],
|
||||
|
||||
// See RFC1952 for the definition of the various fields used by gzip:
|
||||
// https://tools.ietf.org/html/rfc1952.
|
||||
fields: [
|
||||
{
|
||||
name: 'ID',
|
||||
offset: 0,
|
||||
length: 2,
|
||||
cases: [
|
||||
{
|
||||
value: 255,
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'CM',
|
||||
offset: 2,
|
||||
length: 1,
|
||||
cases: [
|
||||
{
|
||||
value: 0,
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'FLG',
|
||||
offset: 3,
|
||||
length: 1,
|
||||
cases: [
|
||||
{
|
||||
value: 1, // FTEXT
|
||||
result: 'success'
|
||||
},
|
||||
{
|
||||
value: 2, // FHCRC
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'MTIME',
|
||||
offset: 4,
|
||||
length: 4,
|
||||
cases: [
|
||||
{
|
||||
// Any value is valid for this field.
|
||||
value: 255,
|
||||
result: 'success'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'XFL',
|
||||
offset: 8,
|
||||
length: 1,
|
||||
cases: [
|
||||
{
|
||||
// Any value is accepted.
|
||||
value: 255,
|
||||
result: 'success'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'OS',
|
||||
offset: 9,
|
||||
length: 1,
|
||||
cases: [
|
||||
{
|
||||
// Any value is accepted.
|
||||
value: 128,
|
||||
result: 'success'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'DATA',
|
||||
|
||||
// The last byte of the data is the most interesting.
|
||||
offset: 26,
|
||||
length: 1,
|
||||
cases: [
|
||||
{
|
||||
value: 3,
|
||||
result: 'error'
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
result: 'success'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'CRC',
|
||||
offset: -8,
|
||||
length: 4,
|
||||
cases: [
|
||||
{
|
||||
// Any change will error the stream.
|
||||
value: 0,
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'ISIZE',
|
||||
offset: -4,
|
||||
length: 4,
|
||||
cases: [
|
||||
{
|
||||
// A mismatch will error the stream.
|
||||
value: 1,
|
||||
result: 'error'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
async function tryDecompress(input, format) {
|
||||
const ds = new DecompressionStream(format);
|
||||
const reader = ds.readable.getReader();
|
||||
const writer = ds.writable.getWriter();
|
||||
writer.write(input).catch(() => {});
|
||||
writer.close().catch(() => {});
|
||||
let out = [];
|
||||
while (true) {
|
||||
try {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
out = out.concat(Array.from(value));
|
||||
} catch (e) {
|
||||
return { result: 'error' };
|
||||
}
|
||||
}
|
||||
const expectedOutput = 'expected output';
|
||||
if (out.length !== expectedOutput.length) {
|
||||
return { result: 'corrupt' };
|
||||
}
|
||||
for (let i = 0; i < out.length; ++i) {
|
||||
if (out[i] !== expectedOutput.charCodeAt(i)) {
|
||||
return { result: 'corrupt' };
|
||||
}
|
||||
}
|
||||
return { result: 'success' };
|
||||
}
|
||||
|
||||
function corruptInput(input, offset, length, value) {
|
||||
const output = new Uint8Array(input);
|
||||
if (offset < 0) {
|
||||
offset += input.length;
|
||||
}
|
||||
for (let i = offset; i < offset + length; ++i) {
|
||||
output[i] = value;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
for (const { format, baseInput, fields } of expectations) {
|
||||
promise_test(async () => {
|
||||
const { result } = await tryDecompress(new Uint8Array(baseInput), format);
|
||||
assert_equals(result, 'success', 'decompression should succeed');
|
||||
}, `the unchanged input for '${format}' should decompress successfully`);
|
||||
|
||||
promise_test(async () => {
|
||||
const truncatedInput = new Uint8Array(baseInput.slice(0, -1));
|
||||
const { result } = await tryDecompress(truncatedInput, format);
|
||||
assert_equals(result, 'error', 'decompression should fail');
|
||||
}, `truncating the input for '${format}' should give an error`);
|
||||
|
||||
promise_test(async () => {
|
||||
const extendedInput = new Uint8Array(baseInput.concat([0]));
|
||||
const { result } = await tryDecompress(extendedInput, format);
|
||||
assert_equals(result, 'error', 'decompression should fail');
|
||||
}, `trailing junk for '${format}' should give an error`);
|
||||
|
||||
for (const { name, offset, length, cases } of fields) {
|
||||
for (const { value, result } of cases) {
|
||||
promise_test(async () => {
|
||||
const corruptedInput = corruptInput(baseInput, offset, length, value);
|
||||
const { result: actual } =
|
||||
await tryDecompress(corruptedInput, format);
|
||||
assert_equals(actual, result, 'result should match');
|
||||
}, `format '${format}' field ${name} should be ${result} for ${value}`);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue