add Effect tests and mocks

This commit is contained in:
Michael "Z" Goddard 2018-06-07 22:17:05 -04:00
parent 6c8edf52b9
commit e40e6e0b1b
No known key found for this signature in database
GPG key ID: 762CD40DD5349872
7 changed files with 214 additions and 3 deletions

View file

@ -24,8 +24,7 @@
"dependencies": {
"audio-context": "1.0.1",
"minilog": "^3.0.1",
"startaudiocontext": "1.2.1",
"tap": "^12.0.1"
"startaudiocontext": "1.2.1"
},
"devDependencies": {
"babel-core": "^6.24.1",
@ -37,6 +36,7 @@
"json": "^9.0.6",
"travis-after-all": "^1.4.4",
"webpack": "^4.8.0",
"webpack-cli": "^2.0.15"
"webpack-cli": "^2.0.15",
"tap": "^12.0.1"
}
}

View file

@ -0,0 +1,20 @@
const AudioNodeMock = require('./AudioNode');
const AudioParamMock = require('./AudioParam');
class AudioContextMock {
createGain () {
return new AudioNodeMock({
gain: new AudioParamMock({
default: 1,
min: -3,
max: 3
})
});
}
createChannelMerger () {
return new AudioNodeMock();
}
}
module.exports = AudioContextMock;

View file

@ -0,0 +1,12 @@
const AudioContextMock = require('./AudioContext');
const AudioTargetMock = require('./AudioTarget');
class AudioEngineMock extends AudioTargetMock {
constructor () {
super();
this.audioContext = new AudioContextMock();
}
}
module.exports = AudioEngineMock;

View file

@ -0,0 +1,36 @@
class AudioNodeMock {
constructor (params) {
Object.assign(this, params);
this.connected = null;
this.connectedFrom = [];
this._testResult = [];
}
connect (node) {
this.connected = node;
node.connectedFrom.push(this);
}
disconnect () {
if (this.connected !== null) {
this.connectedFrom = this.connectedFrom.filter(connection => connection !== this);
}
this.connected = null;
}
_test (test, message, depth = 0) {
if (this.connected === null) {
this._testResult.push({test, message, depth});
} else {
this.connected._test(test, message, depth + 1);
this._testResult.push(null);
}
}
_result () {
return this._testResult.pop();
}
}
module.exports = AudioNodeMock;

View file

@ -0,0 +1,7 @@
class AudioParamMock {
setTargetAtTime (value /* , start, stop */) {
this.value = value;
}
}
module.exports = AudioParamMock;

View file

@ -0,0 +1,21 @@
const AudioNodeMock = require('./AudioNode');
class AudioTargetMock {
constructor () {
this.inputNode = new AudioNodeMock();
}
connect (target) {
this.inputNode.connect(target.getInputNode());
}
getInputNode () {
return this.inputNode;
}
getSoundPlayers () {
return {};
}
}
module.exports = AudioTargetMock;

115
test/effects/EffectShape.js Normal file
View file

@ -0,0 +1,115 @@
const tap = require('tap');
const PanEffect = require('../../src/effects/PanEffect');
const PitchEffect = require('../../src/effects/PitchEffect');
const VolumeEffect = require('../../src/effects/VolumeEffect');
const AudioEngine = require('../__mocks__/AudioEngine');
const AudioTarget = require('../__mocks__/AudioTarget');
const testEffect = (EffectClass, effectDepth) => {
tap.test(EffectClass.name, t1 => {
t1.plan(3);
t1.test('methods', t2 => {
t2.plan(7);
t2.ok(
'DEFAULT_VALUE' in EffectClass.prototype,
'has DEFAULT_VALUE'
);
t2.type(EffectClass.prototype.initialize, 'function', 'has initialize');
t2.type(EffectClass.prototype.set, 'function', 'has set');
t2.type(EffectClass.prototype.update, 'function', 'has update');
t2.type(EffectClass.prototype.clear, 'function', 'has clear');
t2.type(EffectClass.prototype.connect, 'function', 'has connect');
t2.type(EffectClass.prototype.dispose, 'function', 'has dispose');
t2.end();
});
t1.test('connect', t2 => {
t2.plan(6);
const engine = new AudioEngine();
const target = new AudioTarget();
let effect = new EffectClass(engine, target, null);
target.inputNode._test('stall', 'message does not move');
t2.equal(target.inputNode._result().depth, 0, 'message not sent');
t2.ok(!engine.inputNode._result(), 'message not received');
t2.ok(!engine.inputNode.connected, 'engine not connected');
effect.dispose();
effect = new EffectClass(engine, target, null);
const effect2 = new EffectClass(engine, target, effect);
effect2.connect(engine);
effect.connect(effect2);
target.inputNode._test('move', 'message does move');
t2.ok(!target.inputNode._result(), 'message sent');
t2.equal(engine.inputNode._result().depth, 1, 'message received');
t2.ok(engine.inputNode.connectedFrom.length, 'engine connected');
t2.end();
});
t1.test('lifecycle', t2 => {
t2.plan(18);
const engine = new AudioEngine();
const target = new AudioTarget();
let effect = new EffectClass(engine, target, null);
let effect2 = new EffectClass(engine, target, effect);
target.inputNode._test('stall', 'message does not move');
t2.equal(target.inputNode._result().depth, 0, 'message not sent');
t2.ok(!engine.inputNode._result(), 'message not received');
t2.ok(!engine.inputNode.connected, 'engine not connected');
effect2.connect(engine);
effect.connect(effect2);
target.inputNode._test('move', 'message does move');
t2.ok(!target.inputNode._result(), 'message sent');
t2.equal(engine.inputNode._result().depth, 1, 'message received');
t2.ok(engine.inputNode.connectedFrom.length, 'engine connected');
effect.set(effect.DEFAULT_VALUE - 1);
target.inputNode._test('move', 'message does move');
t2.ok(!target.inputNode._result(), 'message sent');
t2.equal(engine.inputNode._result().depth, 1 + effectDepth, 'message received');
t2.ok(engine.inputNode.connectedFrom.length, 'engine connected');
effect2.set(effect2.DEFAULT_VALUE - 1);
target.inputNode._test('move', 'message does move');
t2.ok(!target.inputNode._result(), 'message sent');
t2.equal(engine.inputNode._result().depth, 1 + (2 * effectDepth), 'message received');
t2.ok(engine.inputNode.connectedFrom.length, 'engine connected');
effect.clear();
target.inputNode._test('move', 'message does move');
t2.ok(!target.inputNode._result(), 'message sent');
t2.equal(engine.inputNode._result().depth, 1 + effectDepth, 'message received');
t2.ok(engine.inputNode.connectedFrom.length, 'engine connected');
effect2.clear();
target.inputNode._test('move', 'message does move');
t2.ok(!target.inputNode._result(), 'message sent');
t2.equal(engine.inputNode._result().depth, 1, 'message received');
t2.ok(engine.inputNode.connectedFrom.length, 'engine connected');
t2.end();
});
t1.end();
});
};
testEffect(PanEffect, 3);
testEffect(PitchEffect, 0);
testEffect(VolumeEffect, 1);