From fead25ab5929500f0fd4716b304f078390ee3e89 Mon Sep 17 00:00:00 2001 From: Sema Date: Thu, 12 Sep 2019 02:01:47 -0400 Subject: [PATCH] Async error messages --- javascript/JZZ.js | 84 +++++++++++++------------ test/async.js | 152 +++++++++++++++++++++++++++++++++++++--------- test/tests.js | 16 ++--- 3 files changed, 177 insertions(+), 75 deletions(-) diff --git a/javascript/JZZ.js b/javascript/JZZ.js index 59ec7bc..9c00067 100644 --- a/javascript/JZZ.js +++ b/javascript/JZZ.js @@ -29,36 +29,23 @@ this._orig = this; this._ready = false; this._queue = []; - this._err = []; + this._log = []; } _R.prototype._exec = function() { while (this._ready && this._queue.length) { var x = this._queue.shift(); - if (this._orig._bad) { - if (this._orig._hope && x[0] == _or) { - this._orig._hope = false; - x[0].apply(this, x[1]); - } - else if (this._orig._hope && x[0] == _then) { - x[0].apply(this, x[1]); - } - else { - this._orig._hope = false; - } - } - else if (x[0] != _or) { - x[0].apply(this, x[1]); - } + x[0].apply(this, x[1]); } }; _R.prototype._push = function(func, arg) { this._queue.push([func, arg]); _R.prototype._exec.apply(this); }; _R.prototype._slip = function(func, arg) { this._queue.unshift([func, arg]); }; _R.prototype._pause = function() { this._ready = false; }; _R.prototype._resume = function() { this._ready = true; _R.prototype._exec.apply(this); }; - _R.prototype._break = function(err) { this._orig._bad = true; this._orig._hope = true; if (err) this._orig._err.push(err); }; + _R.prototype._break = function(err) { this._orig._bad = true; this._orig._log.push(err || 'Unknown JZZ error'); }; _R.prototype._repair = function() { this._orig._bad = false; }; _R.prototype._crash = function(err) { this._break(err); this._resume(); }; - _R.prototype.err = function() { return _clone(this._err); }; + _R.prototype._err = function() { return this._log[this._log.length - 1]; }; + _R.prototype.log = function() { return _clone(this._log); }; _R.prototype._image = function() { var F = function() {}; F.prototype = this._orig; var ret = new F(); @@ -75,13 +62,16 @@ }; function _then(good, bad) { if (this._bad) { - if (bad instanceof Function) bad.apply(this, [new Error(this._err.length ? this._err[this._err.length - 1] : 'JZZ error')]); + if (bad instanceof Function) bad.apply(this, [new Error(this._err())]); } else { if (good instanceof Function) good.apply(this, [this]); } } - function _wait(obj, delay) { setTimeout(function() { obj._resume(); }, delay); } + function _wait(obj, delay) { + if (this._bad) obj._crash(this._err()); + else setTimeout(function() { obj._resume(); }, delay); + } _R.prototype.wait = function(delay) { if (!delay) return this; var ret = this._image(); @@ -97,9 +87,17 @@ return ret[name].apply(ret, arg); }; } - function _and(q) { if (q instanceof Function) q.apply(this); else console.log(q); } + function _and(q) { + if (!this._bad) { + if (q instanceof Function) q.apply(this); else console.log(q); + } + } _R.prototype.and = function(func) { this._push(_and, [func]); return this._thenable(); }; - function _or(q) { if (q instanceof Function) q.apply(this); else console.log(q); } + function _or(q) { + if (this._bad) { + if (q instanceof Function) q.apply(this); else console.log(q); + } + } _R.prototype.or = function(func) { this._push(_or, [func]); return this._thenable(); }; _R.prototype._info = {}; @@ -254,7 +252,7 @@ _outsW = _jzz._info.outputs; } function _refresh() { - _engine._refresh(this); + if (!this._bad) _engine._refresh(this); } _J.prototype.refresh = function() { this._push(_refresh, []); @@ -296,14 +294,16 @@ else msg = 'Port "' + q + '" not found'; port._crash(msg); } - function _openMidiOut(port, arg) { - var arr = _filterList(arg, _outs); - if (!arr.length) { _notFound(port, arg); return; } - var pack = function(x) { return function() { x.engine._openOut(this, x.name); }; }; - for (var i = 0; i < arr.length; i++) arr[i] = pack(arr[i]); - port._slip(_tryAny, [arr]); - port._resume(); + if (this._bad) port._crash(this._err()); + else { + var arr = _filterList(arg, _outs); + if (!arr.length) { _notFound(port, arg); return; } + var pack = function(x) { return function() { x.engine._openOut(this, x.name); }; }; + for (var i = 0; i < arr.length; i++) arr[i] = pack(arr[i]); + port._slip(_tryAny, [arr]); + port._resume(); + } } _J.prototype.openMidiOut = function(arg) { var port = new _M(); @@ -318,12 +318,15 @@ }; function _openMidiIn(port, arg) { - var arr = _filterList(arg, _ins); - if (!arr.length) { _notFound(port, arg); return; } - var pack = function(x) { return function() { x.engine._openIn(this, x.name); }; }; - for (var i = 0; i < arr.length; i++) arr[i] = pack(arr[i]); - port._slip(_tryAny, [arr]); - port._resume(); + if (this._bad) port._crash(this._err()); + else { + var arr = _filterList(arg, _ins); + if (!arr.length) { _notFound(port, arg); return; } + var pack = function(x) { return function() { x.engine._openIn(this, x.name); }; }; + for (var i = 0; i < arr.length; i++) arr[i] = pack(arr[i]); + port._slip(_tryAny, [arr]); + port._resume(); + } } _J.prototype.openMidiIn = function(arg) { var port = new _M(); @@ -338,8 +341,11 @@ }; function _onChange(watcher, arg) { - watcher._slip(_connectW, [arg]); - watcher._resume(); + if (this._bad) watcher._crash(); + else { + watcher._slip(_connectW, [arg]); + watcher._resume(); + } } _J.prototype.onChange = function(arg) { if (!this._orig._watcher) this._orig._watcher = new _W(); @@ -378,7 +384,7 @@ return msg; }; _M.prototype._receive = function(msg) { this._emit(this._filter(msg)); }; - function _receive(msg) { this._receive(msg); } + function _receive(msg) { if (!this._bad) this._receive(msg); } _M.prototype.send = function() { this._push(_receive, [MIDI.apply(null, arguments)]); return this._thenable(); diff --git a/test/async.js b/test/async.js index 222b1b1..3da1e9d 100644 --- a/test/async.js +++ b/test/async.js @@ -5,6 +5,22 @@ describe('async calls', function() { var broke = 'We broke it!'; var notexisting = 'Not existing port'; var notfound = 'Port "Not existing port" not found'; + var midi_in_name = 'Widget MIDI-In'; + var midi_in_impl = { + _info: function(name) { return { name: name }; }, + _openIn: function(port, name) { + port._info = this._info(name); + port._resume(); + } + }; + var midi_out_name = 'Widget MIDI-Out'; + var midi_out_impl = { + _info: function(name) { return { name: name }; }, + _openOut: function(port, name) { + port._info = this._info(name); + port._resume(); + } + }; it('await JZZ()', async function() { await JZZ(); @@ -13,7 +29,23 @@ describe('async calls', function() { it('await JZZ() / throw', async function() { var msg; try { - await JZZ().and(function() { this._break(broke); }); + await JZZ().and(function() { this._break(); }); + } + catch (err) { + msg = err.message; + JZZ()._repair(); + } + assert.equal(msg, 'Unknown JZZ error'); + }); + + it('await JZZ().or()', async function() { + await JZZ().or(function() { assert.equal(true, false); }); + }); + + it('await JZZ().or() / throw', async function() { + var msg; + try { + await JZZ().and(function() { this._break(broke); }).or(function() {}); } catch (err) { msg = err.message; @@ -22,12 +54,28 @@ describe('async calls', function() { assert.equal(msg, broke); }); - it('await JZZ().then(...)', async function() { + it('await JZZ().and()', async function() { + await JZZ().and(function() {}); + }); + + it('await JZZ().and() / throw', async function() { + var msg; + try { + await JZZ().and(function() { this._break(broke); }).and(function() {}); + } + catch (err) { + msg = err.message; + JZZ()._repair(); + } + assert.equal(msg, broke); + }); + + it('await JZZ().then()', async function() { await JZZ().then(function() {}); await JZZ().then(undefined, function() {}); }); - it('await JZZ().then(...) / throw', async function() { + it('await JZZ().then() / throw', async function() { var msg; try { await JZZ().and(function() { this._break(broke); }).then(function() {}); @@ -47,24 +95,28 @@ describe('async calls', function() { JZZ()._repair(); }); - it('await JZZ().wait(...)', async function() { + it('await JZZ().wait()', async function() { await JZZ().wait(1); }); - it('await JZZ().openMidiIn(...)', async function() { - var name = 'Widget MIDI-In'; - var widget = { - _info: function(name) { return { name: name }; }, - _openIn: function(port, name) { - port._info = this._info(name); - port._resume(); - } - }; - JZZ.lib.registerMidiIn(name, widget); - await JZZ().openMidiIn(name); + it('await JZZ().wait() / throw', async function() { + var msg; + try { + await JZZ().and(function() { this._break(broke); }).wait(1); + } + catch (err) { + msg = err.message; + } + assert.equal(msg, broke); + JZZ()._repair(); + }); + + it('await JZZ().openMidiIn()', async function() { + JZZ.lib.registerMidiIn(midi_in_name, midi_in_impl); + await JZZ().openMidiIn(midi_in_name); }); - it('await JZZ().openMidiIn(...) / throw', async function() { + it('await JZZ().openMidiIn() / throw 1', async function() { var msg; try { var jzz = await JZZ(); @@ -76,20 +128,24 @@ describe('async calls', function() { assert.equal(msg, notfound); }); - it('await JZZ().openMidiOut(...)', async function() { - var name = 'Widget MIDI-Out'; - var widget = { - _info: function(name) { return { name: name }; }, - _openOut: function(port, name) { - port._info = this._info(name); - port._resume(); - } - }; - JZZ.lib.registerMidiOut(name, widget); - await JZZ().openMidiOut(name); + it('await JZZ().openMidiIn() / throw 2', async function() { + var msg; + try { + await JZZ().and(function() { this._break(broke); }).wait(1).openMidiIn(notexisting); + } + catch (err) { + msg = err.message; + } + assert.equal(msg, broke); + JZZ()._repair(); + }); + + it('await JZZ().openMidiOut()', async function() { + JZZ.lib.registerMidiOut(midi_out_name, midi_out_impl); + await JZZ().openMidiOut(midi_out_name); }); - it('await JZZ().openMidiOut(...) / throw', async function() { + it('await JZZ().openMidiOut() / throw 1', async function() { var msg; try { var jzz = await JZZ(); @@ -101,4 +157,44 @@ describe('async calls', function() { assert.equal(msg, notfound); }); + it('await JZZ().openMidiOut() / throw 2', async function() { + var msg; + try { + await JZZ().and(function() { this._break(broke); }).wait(1).openMidiOut(notexisting); + } + catch (err) { + msg = err.message; + } + assert.equal(msg, broke); + JZZ()._repair(); + }); + + it('await JZZ().openMidiOut().noteOn()', async function() { + JZZ.lib.registerMidiOut(midi_out_name, midi_out_impl); + await JZZ().openMidiOut(midi_out_name).wait(1).noteOn(0, 0x40, 0x7f); + }); + + it('await JZZ().openMidiOut().noteOn() / throw 1', async function() { + JZZ.lib.registerMidiOut(midi_out_name, midi_out_impl); + var msg; + try { + await JZZ().openMidiOut(midi_out_name).wait(1).noteOn(0, 0xff, 0xff); + } + catch (err) { + msg = err.message; + } + assert.equal(msg, 'Bad MIDI value: 255'); + }); + + it('await JZZ().openMidiOut().noteOn() / throw 2', async function() { + var msg; + try { + await JZZ().openMidiOut(notexisting).wait(1).noteOn(0, 0x40, 0x7f); + } + catch (err) { + msg = err.message; + } + assert.equal(msg, notfound); + }); + }); diff --git a/test/tests.js b/test/tests.js index 58214fe..4a171ce 100644 --- a/test/tests.js +++ b/test/tests.js @@ -517,7 +517,7 @@ module.exports = function(JZZ, PARAMS, DRIVER) { }); } function onFail(err) { console.log('requestMIDIAccess failed!', err); } - setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 10); + setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 20); }); }, @@ -536,7 +536,7 @@ module.exports = function(JZZ, PARAMS, DRIVER) { setTimeout(function() { src.connect(); }, 10); } function onFail(err) { console.log('requestMIDIAccess failed!', err); } - setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 10); + setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 20); }); }, @@ -562,7 +562,7 @@ module.exports = function(JZZ, PARAMS, DRIVER) { setTimeout(function() { src.disconnect(); }, 10); } function onFail(err) { console.log('requestMIDIAccess failed!', err); } - setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 10); + setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 20); }); }, @@ -634,7 +634,7 @@ module.exports = function(JZZ, PARAMS, DRIVER) { setTimeout(call0, 10); } function onFail(err) { console.log('requestMIDIAccess failed!', err); } - setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 10); + setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 20); }); }, @@ -661,7 +661,7 @@ module.exports = function(JZZ, PARAMS, DRIVER) { }); } function onFail(err) { console.log('requestMIDIAccess failed!', err); } - setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 10); + setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 20); }); }, @@ -680,7 +680,7 @@ module.exports = function(JZZ, PARAMS, DRIVER) { setTimeout(function() { dst.connect(); }, 10); } function onFail(err) { console.log('requestMIDIAccess failed!', err); } - setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 10); + setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 20); }); }, @@ -705,7 +705,7 @@ module.exports = function(JZZ, PARAMS, DRIVER) { setTimeout(function() { dst.disconnect(); }, 10); } function onFail(err) { console.log('requestMIDIAccess failed!', err); } - setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 10); + setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 20); }); }, @@ -767,7 +767,7 @@ module.exports = function(JZZ, PARAMS, DRIVER) { setTimeout(call0, 10); } function onFail(err) { console.log('requestMIDIAccess failed!', err); } - setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 10); + setTimeout(function() { JZZ.requestMIDIAccess().then(onSuccess, onFail); }, 20); }); },