mirror of
https://github.com/servo/servo.git
synced 2025-09-07 05:28:21 +01:00
Update web-platform-tests to revision 81962ac8802223d038b188b6f9cb88a0a9c5beee
This commit is contained in:
parent
fe1a057bd1
commit
24183668c4
1960 changed files with 29853 additions and 10555 deletions
|
@ -0,0 +1,314 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test Handling of Event Insertion
|
||||
</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webaudio/resources/audit-util.js"></script>
|
||||
<script src="/webaudio/resources/audit.js"></script>
|
||||
<script src="/webaudio/resources/audio-param.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
// Use a power of two for the sample rate so there's no round-off in
|
||||
// computing time from frame.
|
||||
let sampleRate = 16384;
|
||||
|
||||
audit.define(
|
||||
{label: 'Insert same event at same time'}, (task, should) => {
|
||||
// Context for testing.
|
||||
let context = new OfflineAudioContext(
|
||||
{length: 16384, sampleRate: sampleRate});
|
||||
|
||||
// The source node to use. Automations will be scheduled here.
|
||||
let src = new ConstantSourceNode(context, {offset: 0});
|
||||
src.connect(context.destination);
|
||||
|
||||
// An array of tests to be done. Each entry specifies the event
|
||||
// type and the event time. The events are inserted in the order
|
||||
// given (in |values|), and the second event should replace the
|
||||
// first, as required by the spec.
|
||||
let testCases = [
|
||||
{
|
||||
event: 'setValueAtTime',
|
||||
frame: RENDER_QUANTUM_FRAMES,
|
||||
values: [99, 1],
|
||||
outputTestFrame: RENDER_QUANTUM_FRAMES,
|
||||
expectedOutputValue: 1
|
||||
},
|
||||
{
|
||||
event: 'linearRampToValueAtTime',
|
||||
frame: 2 * RENDER_QUANTUM_FRAMES,
|
||||
values: [99, 2],
|
||||
outputTestFrame: 2 * RENDER_QUANTUM_FRAMES,
|
||||
expectedOutputValue: 2
|
||||
},
|
||||
{
|
||||
event: 'exponentialRampToValueAtTime',
|
||||
frame: 3 * RENDER_QUANTUM_FRAMES,
|
||||
values: [99, 3],
|
||||
outputTestFrame: 3 * RENDER_QUANTUM_FRAMES,
|
||||
expectedOutputValue: 3
|
||||
},
|
||||
{
|
||||
event: 'setValueCurveAtTime',
|
||||
frame: 3 * RENDER_QUANTUM_FRAMES,
|
||||
values: [[98, 99], [3, 4]],
|
||||
extraArgs: RENDER_QUANTUM_FRAMES / context.sampleRate,
|
||||
outputTestFrame: 4 * RENDER_QUANTUM_FRAMES,
|
||||
expectedOutputValue: 4
|
||||
}
|
||||
];
|
||||
|
||||
testCases.forEach(entry => {
|
||||
entry.values.forEach(value => {
|
||||
let eventTime = entry.frame / context.sampleRate;
|
||||
let message = eventToString(
|
||||
entry.event, value, eventTime, entry.extraArgs);
|
||||
// This is mostly to print out the event that is getting
|
||||
// inserted. It should never ever throw.
|
||||
should(() => {
|
||||
src.offset[entry.event](value, eventTime, entry.extraArgs);
|
||||
}, message).notThrow();
|
||||
});
|
||||
});
|
||||
|
||||
src.start();
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
let audio = audioBuffer.getChannelData(0);
|
||||
|
||||
// Look through the test cases to figure out what the correct
|
||||
// output values should be.
|
||||
testCases.forEach(entry => {
|
||||
let expected = entry.expectedOutputValue;
|
||||
let frame = entry.outputTestFrame;
|
||||
let time = frame / context.sampleRate;
|
||||
should(
|
||||
audio[frame], `Output at frame ${frame} (time ${time})`)
|
||||
.beEqualTo(expected);
|
||||
});
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.define(
|
||||
{
|
||||
label: 'Linear + Expo',
|
||||
description: 'Different events at same time'
|
||||
},
|
||||
(task, should) => {
|
||||
// Should be a linear ramp up to the event time, and after a
|
||||
// constant value because the exponential ramp has ended.
|
||||
let testCase = [
|
||||
{event: 'linearRampToValueAtTime', value: 2, relError: 0},
|
||||
{event: 'setValueAtTime', value: 99},
|
||||
{event: 'exponentialRampToValueAtTime', value: 3},
|
||||
];
|
||||
let eventFrame = 2 * RENDER_QUANTUM_FRAMES;
|
||||
let prefix = 'Linear+Expo: ';
|
||||
|
||||
testEventInsertion(prefix, should, eventFrame, testCase)
|
||||
.then(expectConstant(prefix, should, eventFrame, testCase))
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.define(
|
||||
{
|
||||
label: 'Expo + Linear',
|
||||
description: 'Different events at same time',
|
||||
},
|
||||
(task, should) => {
|
||||
// Should be an exponential ramp up to the event time, and after a
|
||||
// constant value because the linear ramp has ended.
|
||||
let testCase = [
|
||||
{
|
||||
event: 'exponentialRampToValueAtTime',
|
||||
value: 3,
|
||||
relError: 4.2533e-6
|
||||
},
|
||||
{event: 'setValueAtTime', value: 99},
|
||||
{event: 'linearRampToValueAtTime', value: 2},
|
||||
];
|
||||
let eventFrame = 2 * RENDER_QUANTUM_FRAMES;
|
||||
let prefix = 'Expo+Linear: ';
|
||||
|
||||
testEventInsertion(prefix, should, eventFrame, testCase)
|
||||
.then(expectConstant(prefix, should, eventFrame, testCase))
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.define(
|
||||
{
|
||||
label: 'Linear + SetTarget',
|
||||
description: 'Different events at same time',
|
||||
},
|
||||
(task, should) => {
|
||||
// Should be a linear ramp up to the event time, and then a
|
||||
// decaying value.
|
||||
let testCase = [
|
||||
{event: 'linearRampToValueAtTime', value: 3, relError: 0},
|
||||
{event: 'setValueAtTime', value: 100},
|
||||
{event: 'setTargetAtTime', value: 0, extraArgs: 0.1},
|
||||
];
|
||||
let eventFrame = 2 * RENDER_QUANTUM_FRAMES;
|
||||
let prefix = 'Linear+SetTarget: ';
|
||||
|
||||
testEventInsertion(prefix, should, eventFrame, testCase)
|
||||
.then(audioBuffer => {
|
||||
let audio = audioBuffer.getChannelData(0);
|
||||
let prefix = 'Linear+SetTarget: ';
|
||||
let eventTime = eventFrame / sampleRate;
|
||||
let expectedValue = methodMap[testCase[0].event](
|
||||
(eventFrame - 1) / sampleRate, 1, 0, testCase[0].value,
|
||||
eventTime);
|
||||
should(
|
||||
audio[eventFrame - 1],
|
||||
prefix +
|
||||
`At time ${
|
||||
(eventFrame - 1) / sampleRate
|
||||
} (frame ${eventFrame - 1}) output`)
|
||||
.beCloseTo(
|
||||
expectedValue,
|
||||
{threshold: testCase[0].relError || 0});
|
||||
|
||||
// The setValue should have taken effect
|
||||
should(
|
||||
audio[eventFrame],
|
||||
prefix +
|
||||
`At time ${eventTime} (frame ${eventFrame}) output`)
|
||||
.beEqualTo(testCase[1].value);
|
||||
|
||||
// The final event is setTarget. Compute the expected output.
|
||||
let actual = audio.slice(eventFrame);
|
||||
let expected = new Float32Array(actual.length);
|
||||
for (let k = 0; k < expected.length; ++k) {
|
||||
let t = (eventFrame + k) / sampleRate;
|
||||
expected[k] = audioParamSetTarget(
|
||||
t, testCase[1].value, eventTime, testCase[2].value,
|
||||
testCase[2].extraArgs);
|
||||
}
|
||||
should(
|
||||
actual,
|
||||
prefix +
|
||||
`At time ${eventTime} (frame ${
|
||||
eventFrame
|
||||
}) and later`)
|
||||
.beCloseToArray(expected, {relativeThreshold: 1.7807e-7});
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
|
||||
audit.run();
|
||||
|
||||
// Takes a list of |testCases| consisting of automation methods and
|
||||
// schedules them to occur at |eventFrame|. |prefix| is a prefix for
|
||||
// messages produced by |should|.
|
||||
//
|
||||
// Each item in |testCases| is a dictionary with members:
|
||||
// event - the name of automation method to be inserted,
|
||||
// value - the value for the event,
|
||||
// extraArgs - extra arguments if the event needs more than the value
|
||||
// and time (such as setTargetAtTime).
|
||||
function testEventInsertion(prefix, should, eventFrame, testCases) {
|
||||
let context = new OfflineAudioContext(
|
||||
{length: 4 * RENDER_QUANTUM_FRAMES, sampleRate: sampleRate});
|
||||
|
||||
// The source node to use. Automations will be scheduled here.
|
||||
let src = new ConstantSourceNode(context, {offset: 0});
|
||||
src.connect(context.destination);
|
||||
|
||||
// Initialize value to 1 at the beginning.
|
||||
src.offset.setValueAtTime(1, 0);
|
||||
|
||||
// Test automations have this event time.
|
||||
let eventTime = eventFrame / context.sampleRate;
|
||||
|
||||
// Sanity check that context is long enough for the test
|
||||
should(
|
||||
eventFrame < context.length,
|
||||
prefix + 'Context length is long enough for the test')
|
||||
.beTrue();
|
||||
|
||||
// Automations to be tested. The first event should be the actual
|
||||
// output up to the event time. The last event should be the final
|
||||
// output from the event time and onwards.
|
||||
testCases.forEach(entry => {
|
||||
should(
|
||||
() => {
|
||||
src.offset[entry.event](
|
||||
entry.value, eventTime, entry.extraArgs);
|
||||
},
|
||||
prefix +
|
||||
eventToString(
|
||||
entry.event, entry.value, eventTime, entry.extraArgs))
|
||||
.notThrow();
|
||||
});
|
||||
|
||||
src.start();
|
||||
|
||||
return context.startRendering();
|
||||
}
|
||||
|
||||
// Verify output of test where the final value of the automation is
|
||||
// expected to be constant.
|
||||
function expectConstant(prefix, should, eventFrame, testCases) {
|
||||
return audioBuffer => {
|
||||
let audio = audioBuffer.getChannelData(0);
|
||||
|
||||
let eventTime = eventFrame / sampleRate;
|
||||
|
||||
// Compute the expected value of the first automation one frame before
|
||||
// the event time. This is a quick check that the correct automation
|
||||
// was done.
|
||||
let expectedValue = methodMap[testCases[0].event](
|
||||
(eventFrame - 1) / sampleRate, 1, 0, testCases[0].value,
|
||||
eventTime);
|
||||
should(
|
||||
audio[eventFrame - 1],
|
||||
prefix +
|
||||
`At time ${
|
||||
(eventFrame - 1) / sampleRate
|
||||
} (frame ${eventFrame - 1}) output`)
|
||||
.beCloseTo(expectedValue, {threshold: testCases[0].relError});
|
||||
|
||||
// The last event scheduled is expected to set the value for all
|
||||
// future times. Verify that the output has the expected value.
|
||||
should(
|
||||
audio.slice(eventFrame),
|
||||
prefix +
|
||||
`At time ${eventTime} (frame ${
|
||||
eventFrame
|
||||
}) and later, output`)
|
||||
.beConstantValueOf(testCases[testCases.length - 1].value);
|
||||
};
|
||||
}
|
||||
|
||||
// Convert an automation method to a string for printing.
|
||||
function eventToString(method, value, time, extras) {
|
||||
let string = method + '(';
|
||||
string += (value instanceof Array) ? `[${value}]` : value;
|
||||
string += ', ' + time;
|
||||
if (extras) {
|
||||
string += ', ' + extras;
|
||||
}
|
||||
string += ')';
|
||||
return string;
|
||||
}
|
||||
|
||||
// Map between the automation method name and a function that computes the
|
||||
// output value of the automation method.
|
||||
const methodMap = {
|
||||
linearRampToValueAtTime: audioParamLinearRamp,
|
||||
exponentialRampToValueAtTime: audioParamExponentialRamp,
|
||||
setValueAtTime: (t, v) => v
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue