mirror of
https://github.com/servo/servo.git
synced 2025-06-23 16:44:33 +01:00
219 lines
6.3 KiB
JavaScript
219 lines
6.3 KiB
JavaScript
'use strict';
|
|
|
|
if (self.importScripts) {
|
|
self.importScripts('/resources/testharness.js');
|
|
}
|
|
|
|
// The purpose of this file is to test for objects, attributes and arguments that should not exist.
|
|
// The test cases are generated from data tables to reduce duplication.
|
|
|
|
// Courtesy of André Bargull. Source is https://esdiscuss.org/topic/isconstructor#content-11.
|
|
function IsConstructor(o) {
|
|
try {
|
|
new new Proxy(o, { construct: () => ({}) })();
|
|
return true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (const func of ['WritableStreamDefaultController', 'WritableStreamDefaultWriter']) {
|
|
test(() => {
|
|
assert_equals(self[func], undefined, `${func} should not be defined`);
|
|
}, `${func} should not be exported on the global object`);
|
|
}
|
|
|
|
// Now get hold of the symbols so we can test their properties.
|
|
self.WritableStreamDefaultController = (() => {
|
|
let controller;
|
|
new WritableStream({
|
|
start(c) {
|
|
controller = c;
|
|
}
|
|
});
|
|
return controller.constructor;
|
|
})();
|
|
self.WritableStreamDefaultWriter = new WritableStream().getWriter().constructor;
|
|
|
|
const expected = {
|
|
WritableStream: {
|
|
constructor: {
|
|
type: 'constructor',
|
|
length: 0
|
|
},
|
|
locked: {
|
|
type: 'getter'
|
|
},
|
|
abort: {
|
|
type: 'method',
|
|
length: 1
|
|
},
|
|
getWriter: {
|
|
type: 'method',
|
|
length: 0
|
|
}
|
|
},
|
|
WritableStreamDefaultController: {
|
|
constructor: {
|
|
type: 'constructor',
|
|
length: 4
|
|
},
|
|
error: {
|
|
type: 'method',
|
|
length: 1
|
|
}
|
|
},
|
|
WritableStreamDefaultWriter: {
|
|
constructor: {
|
|
type: 'constructor',
|
|
length: 1
|
|
},
|
|
closed: {
|
|
type: 'getter'
|
|
},
|
|
desiredSize: {
|
|
type: 'getter'
|
|
},
|
|
ready: {
|
|
type: 'getter'
|
|
},
|
|
abort: {
|
|
type: 'method',
|
|
length: 1
|
|
},
|
|
close: {
|
|
type: 'method',
|
|
length: 0
|
|
},
|
|
releaseLock: {
|
|
type: 'method',
|
|
length: 0
|
|
},
|
|
write: {
|
|
type: 'method',
|
|
length: 1
|
|
}
|
|
}
|
|
};
|
|
|
|
for (const c in expected) {
|
|
const properties = expected[c];
|
|
const prototype = self[c].prototype;
|
|
for (const name in properties) {
|
|
const fullName = `${c}.prototype.${name}`;
|
|
const descriptor = Object.getOwnPropertyDescriptor(prototype, name);
|
|
test(() => {
|
|
const { configurable, enumerable } = descriptor;
|
|
assert_true(configurable, `${name} should be configurable`);
|
|
assert_false(enumerable, `${name} should not be enumerable`);
|
|
}, `${fullName} should have standard properties`);
|
|
const type = properties[name].type;
|
|
switch (type) {
|
|
case 'getter':
|
|
test(() => {
|
|
const { writable, get, set } = descriptor;
|
|
assert_equals(writable, undefined, `${name} should not be a data descriptor`);
|
|
assert_equals(typeof get, 'function', `${name} should have a getter`);
|
|
assert_equals(set, undefined, `${name} should not have a setter`);
|
|
}, `${fullName} should be a getter`);
|
|
break;
|
|
|
|
case 'constructor':
|
|
case 'method':
|
|
test(() => {
|
|
assert_true(descriptor.writable, `${name} should be writable`);
|
|
assert_equals(typeof prototype[name], 'function', `${name} should be a function`);
|
|
assert_equals(prototype[name].length, properties[name].length,
|
|
`${name} should take ${properties[name].length} arguments`);
|
|
if (type === 'constructor') {
|
|
assert_true(IsConstructor(prototype[name]), `${name} should be a constructor`);
|
|
} else {
|
|
assert_false(IsConstructor(prototype[name]), `${name} should not be a constructor`);
|
|
}
|
|
}, `${fullName} should be a ${type}`);
|
|
break;
|
|
}
|
|
}
|
|
test(() => {
|
|
const expectedPropertyNames = Object.keys(properties).sort();
|
|
const actualPropertyNames = Object.getOwnPropertyNames(prototype).sort();
|
|
assert_array_equals(actualPropertyNames, expectedPropertyNames,
|
|
`${c} properties should match expected properties`);
|
|
}, `${c}.prototype should have exactly the expected properties`);
|
|
}
|
|
|
|
const sinkMethods = {
|
|
start: {
|
|
length: 1,
|
|
trigger: () => {}
|
|
},
|
|
write: {
|
|
length: 2,
|
|
trigger: writer => writer.write()
|
|
},
|
|
close: {
|
|
length: 0,
|
|
trigger: writer => writer.close()
|
|
},
|
|
abort: {
|
|
length: 1,
|
|
trigger: writer => writer.abort()
|
|
}
|
|
};
|
|
|
|
for (const method in sinkMethods) {
|
|
const { length, trigger } = sinkMethods[method];
|
|
|
|
// Some semantic tests of how sink methods are called can be found in general.js, as well as in the test files
|
|
// specific to each method.
|
|
promise_test(() => {
|
|
let argCount;
|
|
const ws = new WritableStream({
|
|
[method](...args) {
|
|
argCount = args.length;
|
|
}
|
|
});
|
|
return Promise.resolve(trigger(ws.getWriter())).then(() => {
|
|
assert_equals(argCount, length, `${method} should be called with ${length} arguments`);
|
|
});
|
|
}, `sink method ${method} should be called with the right number of arguments`);
|
|
|
|
promise_test(() => {
|
|
let methodWasCalled = false;
|
|
function Sink() {}
|
|
Sink.prototype = {
|
|
[method]() {
|
|
methodWasCalled = true;
|
|
}
|
|
};
|
|
const ws = new WritableStream(new Sink());
|
|
return Promise.resolve(trigger(ws.getWriter())).then(() => {
|
|
assert_true(methodWasCalled, `${method} should be called`);
|
|
});
|
|
}, `sink method ${method} should be called even when it's located on the prototype chain`);
|
|
|
|
if (method !== 'start') {
|
|
promise_test(t => {
|
|
const unreachedTraps = ['getPrototypeOf', 'setPrototypeOf', 'isExtensible', 'preventExtensions',
|
|
'getOwnPropertyDescriptor', 'defineProperty', 'has', 'set', 'deleteProperty', 'ownKeys',
|
|
'apply', 'construct'];
|
|
const handler = {
|
|
get: t.step_func((target, property) => {
|
|
if (property === 'type') {
|
|
return undefined;
|
|
}
|
|
assert_in_array(property, ['start', method], `only start() and ${method}() should be called`);
|
|
return () => Promise.resolve();
|
|
})
|
|
};
|
|
for (const trap of unreachedTraps) {
|
|
handler[trap] = t.unreached_func(`${trap} should not be trapped`);
|
|
}
|
|
const sink = new Proxy({}, handler);
|
|
const ws = new WritableStream(sink);
|
|
return trigger(ws.getWriter());
|
|
}, `unexpected properties should not be accessed when calling sink method ${method}`);
|
|
}
|
|
}
|
|
|
|
done();
|