Merge pull request #239 from hybridgroup/remove/connection-and-device-classes
Remove Connection and Device classes. :shipit: 🚀
This commit is contained in:
commit
4500824f30
|
@ -23,7 +23,33 @@ var Adaptor = module.exports = function Adaptor(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
this.connection = opts.connection;
|
|
||||||
|
// the Robot the adaptor belongs to
|
||||||
|
this.robot = opts.robot;
|
||||||
|
|
||||||
|
// some default options
|
||||||
|
this.host = opts.host;
|
||||||
|
this.port = opts.port;
|
||||||
|
|
||||||
|
// misc. details provided in args hash
|
||||||
|
this.details = {};
|
||||||
|
|
||||||
|
for (var opt in opts) {
|
||||||
|
if (['robot', 'name', 'adaptor'].indexOf(opt) < 0) {
|
||||||
|
this.details[opt] = opts[opt];
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.subclass(Adaptor, Basestar);
|
Utils.subclass(Adaptor, Basestar);
|
||||||
|
|
||||||
|
// Public: Expresses the Connection in JSON format
|
||||||
|
//
|
||||||
|
// Returns an Object containing Connection data
|
||||||
|
Adaptor.prototype.toJSON = function() {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
adaptor: this.constructor.name || this.name,
|
||||||
|
details: this.details
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -42,7 +42,7 @@ var load = function load(req, res, next) {
|
||||||
};
|
};
|
||||||
|
|
||||||
router.get("/", function(req, res) {
|
router.get("/", function(req, res) {
|
||||||
res.json({ MCP: Cylon });
|
res.json({ MCP: Cylon.toJSON() });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/commands", function(req, res) {
|
router.get("/commands", function(req, res) {
|
||||||
|
@ -102,12 +102,12 @@ router.get("/robots/:robot/devices/:device/events/:event", load, function(req, r
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/robots/:robot/devices/:device/commands", load, function(req, res) {
|
router.get("/robots/:robot/devices/:device/commands", load, function(req, res) {
|
||||||
res.json({ commands: Object.keys(req.device.driver.commands) });
|
res.json({ commands: Object.keys(req.device.commands) });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.all("/robots/:robot/devices/:device/commands/:command", load, function(req, res) {
|
router.all("/robots/:robot/devices/:device/commands/:command", load, function(req, res) {
|
||||||
var command = req.device.driver.commands[req.params.command];
|
var command = req.device.commands[req.params.command];
|
||||||
var result = command.apply(req.device.driver, req.commandParams);
|
var result = command.apply(req.device, req.commandParams);
|
||||||
res.json({ result: result });
|
res.json({ result: result });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -69,24 +69,23 @@ Basestar.prototype.defineEvent = function(opts) {
|
||||||
|
|
||||||
// Public: Creates an event handler that proxies events from an adaptor's
|
// Public: Creates an event handler that proxies events from an adaptor's
|
||||||
// 'connector' (reference to whatever module is actually talking to the hw)
|
// 'connector' (reference to whatever module is actually talking to the hw)
|
||||||
// to the adaptor's associated connection.
|
// to the adaptor
|
||||||
//
|
//
|
||||||
// opts - hash of opts to be passed to defineEvent()
|
// opts - hash of opts to be passed to defineEvent()
|
||||||
//
|
//
|
||||||
// Returns this.connector
|
// Returns this.connector
|
||||||
Basestar.prototype.defineAdaptorEvent = function(opts) {
|
Basestar.prototype.defineAdaptorEvent = function(opts) {
|
||||||
return this._proxyEvents(opts, this.connector, this.connection);
|
return this._proxyEvents(opts, this.connector, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Public: Creates an event handler that proxies events from an device's
|
// Public: Creates an event handler that proxies events from an driver's
|
||||||
// 'connector' (reference to whatever module is actually talking to the hw)
|
// adaptor to the driver
|
||||||
// to the device's associated connection.
|
|
||||||
//
|
//
|
||||||
// opts - hash of opts to be passed to defineEvent()
|
// opts - hash of opts to be passed to defineEvent()
|
||||||
//
|
//
|
||||||
// Returns this.connection
|
// Returns this.connection
|
||||||
Basestar.prototype.defineDriverEvent = function(opts) {
|
Basestar.prototype.defineDriverEvent = function(opts) {
|
||||||
return this._proxyEvents(opts, this.connection, this.device);
|
return this._proxyEvents(opts, this.adaptor, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Basestar.prototype._proxyEvents = function(opts, source, target) {
|
Basestar.prototype._proxyEvents = function(opts, source, target) {
|
||||||
|
|
|
@ -8,18 +8,15 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
|
||||||
|
|
||||||
var Registry = require('./registry'),
|
var Registry = require('./registry'),
|
||||||
Config = require('./config'),
|
Config = require('./config'),
|
||||||
Logger = require('./logger'),
|
Logger = require('./logger');
|
||||||
Utils = require('./utils');
|
|
||||||
|
|
||||||
var testMode = function() {
|
var testMode = function() {
|
||||||
return process.env.NODE_ENV === 'test' && Config.testMode;
|
return process.env.NODE_ENV === 'test' && Config.testMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Public: Creates a new Connection
|
// Public: Creates a new Adaptor and returns it.
|
||||||
//
|
//
|
||||||
// opts - hash of acceptable params:
|
// opts - hash of acceptable params:
|
||||||
// robot - Robot the Connection belongs to
|
// robot - Robot the Connection belongs to
|
||||||
|
@ -28,81 +25,17 @@ var testMode = function() {
|
||||||
// port - string port to use for the Connection
|
// port - string port to use for the Connection
|
||||||
//
|
//
|
||||||
// Returns the newly set-up connection
|
// Returns the newly set-up connection
|
||||||
var Connection = module.exports = function Connection(opts) {
|
module.exports = function Connection(opts) {
|
||||||
opts = opts || {};
|
|
||||||
|
|
||||||
this.connect = this.connect.bind(this);
|
|
||||||
|
|
||||||
this.robot = opts.robot;
|
|
||||||
this.name = opts.name;
|
|
||||||
this.port = opts.port;
|
|
||||||
this.adaptor = this.initAdaptor(opts);
|
|
||||||
|
|
||||||
this.details = {};
|
|
||||||
|
|
||||||
for (var opt in opts) {
|
|
||||||
if (['robot', 'name', 'adaptor', 'connection'].indexOf(opt) < 0) {
|
|
||||||
this.details[opt] = opts[opt];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Utils.subclass(Connection, EventEmitter);
|
|
||||||
|
|
||||||
// Public: Expresses the Connection in JSON format
|
|
||||||
//
|
|
||||||
// Returns an Object containing Connection data
|
|
||||||
Connection.prototype.toJSON = function() {
|
|
||||||
return {
|
|
||||||
name: this.name,
|
|
||||||
adaptor: this.adaptor.constructor.name || this.adaptor.name,
|
|
||||||
details: this.details
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Public: Connect the adaptor's connection
|
|
||||||
//
|
|
||||||
// callback - callback function to run when the adaptor is connected
|
|
||||||
//
|
|
||||||
// Returns nothing
|
|
||||||
Connection.prototype.connect = function(callback) {
|
|
||||||
var msg = this._logstring("Connecting to");
|
|
||||||
Logger.info(msg);
|
|
||||||
this.adaptor.connect(function() {
|
|
||||||
Utils.proxyFunctions(this.adaptor, this)
|
|
||||||
callback.apply(this, arguments);
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Public: Disconnect the adaptor's connection
|
|
||||||
//
|
|
||||||
// callback - function to be triggered then the adaptor has disconnected
|
|
||||||
//
|
|
||||||
// Returns nothing
|
|
||||||
Connection.prototype.disconnect = function(callback) {
|
|
||||||
var msg = this._logstring("Disconnecting from");
|
|
||||||
Logger.info(msg);
|
|
||||||
this.removeAllListeners();
|
|
||||||
this.adaptor.disconnect(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Public: sets up adaptor with @robot
|
|
||||||
//
|
|
||||||
// opts - options for adaptor being initialized
|
|
||||||
// adaptor - name of the adaptor
|
|
||||||
//
|
|
||||||
// Returns the set-up adaptor
|
|
||||||
Connection.prototype.initAdaptor = function(opts) {
|
|
||||||
var module;
|
var module;
|
||||||
|
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
if (opts.module) {
|
if (opts.module) {
|
||||||
module = Registry.register(opts.module);
|
module = Registry.register(opts.module);
|
||||||
} else {
|
} else {
|
||||||
module = Registry.findByAdaptor(opts.adaptor);
|
module = Registry.findByAdaptor(opts.adaptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.connection = this;
|
|
||||||
|
|
||||||
if (!module) {
|
if (!module) {
|
||||||
Registry.register('cylon-' + opts.adaptor);
|
Registry.register('cylon-' + opts.adaptor);
|
||||||
module = Registry.findByAdaptor(opts.adaptor);
|
module = Registry.findByAdaptor(opts.adaptor);
|
||||||
|
@ -110,6 +43,16 @@ Connection.prototype.initAdaptor = function(opts) {
|
||||||
|
|
||||||
var adaptor = module.adaptor(opts);
|
var adaptor = module.adaptor(opts);
|
||||||
|
|
||||||
|
for (var prop in adaptor) {
|
||||||
|
if (~['constructor'].indexOf(prop)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof adaptor[prop] === 'function') {
|
||||||
|
adaptor[prop] = adaptor[prop].bind(adaptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (testMode()) {
|
if (testMode()) {
|
||||||
var testAdaptor = Registry.findByAdaptor('test').adaptor(opts);
|
var testAdaptor = Registry.findByAdaptor('test').adaptor(opts);
|
||||||
|
|
||||||
|
@ -124,15 +67,3 @@ Connection.prototype.initAdaptor = function(opts) {
|
||||||
|
|
||||||
return adaptor;
|
return adaptor;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype._logstring = function _logstring(action) {
|
|
||||||
var msg = action + " '" + this.name + "'";
|
|
||||||
|
|
||||||
if (this.port != null) {
|
|
||||||
msg += " on port " + this.port;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg += ".";
|
|
||||||
|
|
||||||
return msg;
|
|
||||||
};
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ Cylon.toJSON = function() {
|
||||||
var robots = [];
|
var robots = [];
|
||||||
|
|
||||||
for (var bot in this.robots) {
|
for (var bot in this.robots) {
|
||||||
robots.push(this.robots[bot]);
|
robots.push(this.robots[bot].toJSON());
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -8,12 +8,8 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
|
||||||
|
|
||||||
var Registry = require('./registry'),
|
var Registry = require('./registry'),
|
||||||
Config = require('./config'),
|
Config = require('./config');
|
||||||
Logger = require('./logger'),
|
|
||||||
Utils = require('./utils');
|
|
||||||
|
|
||||||
var testMode = function() {
|
var testMode = function() {
|
||||||
return process.env.NODE_ENV === 'test' && Config.testMode;
|
return process.env.NODE_ENV === 'test' && Config.testMode;
|
||||||
|
@ -29,83 +25,7 @@ var testMode = function() {
|
||||||
// driver - string name of the module the device driver logic lives in
|
// driver - string name of the module the device driver logic lives in
|
||||||
//
|
//
|
||||||
// Returns a new Device
|
// Returns a new Device
|
||||||
var Device = module.exports = function Device(opts) {
|
module.exports = function Device(opts) {
|
||||||
if (opts == null) {
|
|
||||||
opts = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.halt = this.halt.bind(this);
|
|
||||||
this.start = this.start.bind(this);
|
|
||||||
|
|
||||||
this.robot = opts.robot;
|
|
||||||
this.name = opts.name;
|
|
||||||
this.pin = opts.pin;
|
|
||||||
this.connection = opts.connection;
|
|
||||||
this.driver = this.initDriver(opts);
|
|
||||||
|
|
||||||
this.details = {};
|
|
||||||
|
|
||||||
for (var opt in opts) {
|
|
||||||
if (['robot', 'name', 'connection', 'driver', 'device', 'adaptor'].indexOf(opt) < 0) {
|
|
||||||
this.details[opt] = opts[opt];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Utils.subclass(Device, EventEmitter);
|
|
||||||
|
|
||||||
// Public: Starts the device driver
|
|
||||||
//
|
|
||||||
// callback - callback function to be executed by the driver start
|
|
||||||
//
|
|
||||||
// Returns nothing
|
|
||||||
Device.prototype.start = function(callback) {
|
|
||||||
var msg = "Starting device '" + this.name + "'";
|
|
||||||
|
|
||||||
if (this.pin != null) {
|
|
||||||
msg += " on pin " + this.pin;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg += ".";
|
|
||||||
|
|
||||||
Logger.info(msg);
|
|
||||||
this.driver.start(function() {
|
|
||||||
Utils.proxyFunctions(this.driver, this)
|
|
||||||
callback.apply(this, arguments);
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Public: Halt the device driver
|
|
||||||
//
|
|
||||||
// callback - function to trigger when the device has been halted
|
|
||||||
//
|
|
||||||
// Returns nothing
|
|
||||||
Device.prototype.halt = function(callback) {
|
|
||||||
Logger.info("Halting device '" + this.name + "'.");
|
|
||||||
this.removeAllListeners();
|
|
||||||
this.driver.halt(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Public: Expresses the Device in JSON format
|
|
||||||
//
|
|
||||||
// Returns an Object containing Connection data
|
|
||||||
Device.prototype.toJSON = function() {
|
|
||||||
return {
|
|
||||||
name: this.name,
|
|
||||||
driver: this.driver.constructor.name || this.driver.name,
|
|
||||||
connection: this.connection.name,
|
|
||||||
commands: Object.keys(this.driver.commands),
|
|
||||||
details: this.details
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Public: sets up driver with @robot
|
|
||||||
//
|
|
||||||
// opts - object containing options when initializing driver
|
|
||||||
// driver - name of the driver to intt()
|
|
||||||
//
|
|
||||||
// Returns the set-up driver
|
|
||||||
Device.prototype.initDriver = function(opts) {
|
|
||||||
var module;
|
var module;
|
||||||
|
|
||||||
if (opts.module) {
|
if (opts.module) {
|
||||||
|
@ -123,6 +43,16 @@ Device.prototype.initDriver = function(opts) {
|
||||||
|
|
||||||
var driver = module.driver(opts);
|
var driver = module.driver(opts);
|
||||||
|
|
||||||
|
for (var prop in driver) {
|
||||||
|
if (~['constructor'].indexOf(prop)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof driver[prop] === 'function') {
|
||||||
|
driver[prop] = driver[prop].bind(driver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (testMode()) {
|
if (testMode()) {
|
||||||
var testDriver = Registry.findByDriver('test').driver(opts);
|
var testDriver = Registry.findByDriver('test').driver(opts);
|
||||||
|
|
||||||
|
|
|
@ -23,21 +23,30 @@ var Driver = module.exports = function Driver(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
|
this.robot = opts.robot
|
||||||
|
|
||||||
this.device = opts.device;
|
this.adaptor = opts.adaptor
|
||||||
this.connection = opts.device.connection;
|
|
||||||
this.adaptor = this.connection.adaptor;
|
|
||||||
|
|
||||||
this.interval = opts.interval || 10;
|
|
||||||
|
|
||||||
this.commands = {};
|
this.commands = {};
|
||||||
|
|
||||||
|
// some default options
|
||||||
|
this.pin = opts.pin;
|
||||||
|
this.interval = opts.interval || 10;
|
||||||
|
|
||||||
|
this.details = {};
|
||||||
|
|
||||||
|
for (var opt in opts) {
|
||||||
|
if (['robot', 'name', 'adaptor', 'driver'].indexOf(opt) < 0) {
|
||||||
|
this.details[opt] = opts[opt];
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.subclass(Driver, Basestar);
|
Utils.subclass(Driver, Basestar);
|
||||||
|
|
||||||
Driver.prototype.setupCommands = function(commands, proxy) {
|
Driver.prototype.setupCommands = function(commands, proxy) {
|
||||||
if (proxy == null) {
|
if (proxy == null) {
|
||||||
proxy = this.connection;
|
proxy = this.adaptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.proxyMethods(commands, proxy, this);
|
this.proxyMethods(commands, proxy, this);
|
||||||
|
@ -58,3 +67,13 @@ Driver.prototype.setupCommands = function(commands, proxy) {
|
||||||
this.commands[snake_case] = this[command];
|
this.commands[snake_case] = this[command];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Driver.prototype.toJSON = function() {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
driver: this.constructor.name || this.name,
|
||||||
|
connection: this.adaptor.name,
|
||||||
|
commands: Object.keys(this.commands),
|
||||||
|
details: this.details
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
22
lib/robot.js
22
lib/robot.js
|
@ -139,11 +139,11 @@ Robot.prototype.toJSON = function() {
|
||||||
n;
|
n;
|
||||||
|
|
||||||
for (n in this.connections) {
|
for (n in this.connections) {
|
||||||
connections.push(this.connections[n]);
|
connections.push(this.connections[n].toJSON());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (n in this.devices) {
|
for (n in this.devices) {
|
||||||
devices.push(this.devices[n]);
|
devices.push(this.devices[n].toJSON());
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -173,7 +173,7 @@ Robot.prototype.initConnections = function(opts) {
|
||||||
Logger.warn("Connection names must be unique. Renaming '" + original + "' to '" + conn.name + "'");
|
Logger.warn("Connection names must be unique. Renaming '" + original + "' to '" + conn.name + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.connections[conn.name] = new Connection(conn);
|
this.connections[conn.name] = Connection(conn);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
if (opts.connection == null && opts.connections == null) {
|
if (opts.connection == null && opts.connections == null) {
|
||||||
|
@ -229,15 +229,15 @@ Robot.prototype.initDevices = function(opts) {
|
||||||
process.emit('SIGINT');
|
process.emit('SIGINT');
|
||||||
}
|
}
|
||||||
|
|
||||||
device.connection = this.connections[device.connection];
|
device.adaptor = this.connections[device.connection];
|
||||||
} else {
|
} else {
|
||||||
for (var conn in this.connections) {
|
for (var conn in this.connections) {
|
||||||
device.connection = this.connections[conn];
|
device.adaptor = this.connections[conn];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.devices[device.name] = new Device(device);
|
this.devices[device.name] = Device(device);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
if (opts.device == null && opts.devices == null) {
|
if (opts.device == null && opts.devices == null) {
|
||||||
|
@ -334,9 +334,8 @@ Robot.prototype.startConnections = function(callback) {
|
||||||
Logger.info("Starting connections.");
|
Logger.info("Starting connections.");
|
||||||
|
|
||||||
for (var n in this.connections) {
|
for (var n in this.connections) {
|
||||||
var connection = this.connections[n];
|
this[n] = this.connections[n];
|
||||||
this[n] = connection;
|
starters[n] = this.connections[n].connect;
|
||||||
starters[n] = connection.connect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Async.parallel(starters, callback);
|
return Async.parallel(starters, callback);
|
||||||
|
@ -353,9 +352,8 @@ Robot.prototype.startDevices = function(callback) {
|
||||||
Logger.info("Starting devices.");
|
Logger.info("Starting devices.");
|
||||||
|
|
||||||
for (var n in this.devices) {
|
for (var n in this.devices) {
|
||||||
var device = this.devices[n];
|
this[n] = this.devices[n];
|
||||||
this[n] = device;
|
starters[n] = this.devices[n].start.bind(this.devices[n]);
|
||||||
starters[n] = device.start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Async.parallel(starters, callback);
|
return Async.parallel(starters, callback);
|
||||||
|
|
|
@ -22,7 +22,7 @@ var Ping = module.exports = function Ping() {
|
||||||
Utils.subclass(Ping, Driver);
|
Utils.subclass(Ping, Driver);
|
||||||
|
|
||||||
Ping.prototype.ping = function() {
|
Ping.prototype.ping = function() {
|
||||||
this.device.emit('ping', 'ping');
|
this.emit('ping', 'ping');
|
||||||
return "pong";
|
return "pong";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,15 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
|
||||||
|
|
||||||
var Adaptor = source("adaptor"),
|
var Adaptor = source("adaptor"),
|
||||||
Logger = source('logger'),
|
Logger = source('logger'),
|
||||||
Utils = source('utils');
|
Utils = source('utils');
|
||||||
|
|
||||||
describe("Adaptor", function() {
|
describe("Adaptor", function() {
|
||||||
var connection = new EventEmitter;
|
var adaptor = new Adaptor({ name: 'adaptor' });
|
||||||
var adaptor = new Adaptor({ name: 'adaptor', connection: connection });
|
|
||||||
|
|
||||||
describe("#constructor", function() {
|
describe("#constructor", function() {
|
||||||
it("sets @name to the provided name", function() {
|
it("sets @name to the provided name", function() {
|
||||||
expect(adaptor.name).to.be.eql('adaptor');
|
expect(adaptor.name).to.be.eql('adaptor');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets @connection to the provided connection", function() {
|
|
||||||
expect(adaptor.connection).to.be.eql(connection);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -107,13 +107,12 @@ describe('Basestar', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
basestar = new Basestar();
|
basestar = new Basestar();
|
||||||
basestar.connector = new EventEmitter();
|
basestar.connector = new EventEmitter();
|
||||||
basestar.connection = new EventEmitter();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("proxies events between the connector and connection", function() {
|
it("proxies events between the connector and connection", function() {
|
||||||
var eventSpy = spy();
|
var eventSpy = spy();
|
||||||
|
|
||||||
basestar.connection.on('testevent', eventSpy);
|
basestar.on('testevent', eventSpy);
|
||||||
basestar.defineAdaptorEvent({ eventName: "testevent" });
|
basestar.defineAdaptorEvent({ eventName: "testevent" });
|
||||||
|
|
||||||
basestar.connector.emit("testevent", "data");
|
basestar.connector.emit("testevent", "data");
|
||||||
|
@ -124,7 +123,7 @@ describe('Basestar', function() {
|
||||||
it("uses it as the eventName", function() {
|
it("uses it as the eventName", function() {
|
||||||
var eventSpy = spy();
|
var eventSpy = spy();
|
||||||
|
|
||||||
basestar.connection.on('testevent', eventSpy);
|
basestar.on('testevent', eventSpy);
|
||||||
basestar.defineAdaptorEvent("testevent");
|
basestar.defineAdaptorEvent("testevent");
|
||||||
|
|
||||||
basestar.connector.emit("testevent", "data");
|
basestar.connector.emit("testevent", "data");
|
||||||
|
@ -138,17 +137,16 @@ describe('Basestar', function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
basestar = new Basestar();
|
basestar = new Basestar();
|
||||||
basestar.connection = new EventEmitter();
|
basestar.adaptor = new EventEmitter();
|
||||||
basestar.device = new EventEmitter();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("proxies events between the connection and device", function() {
|
it("proxies events between the connection and device", function() {
|
||||||
var eventSpy = spy();
|
var eventSpy = spy();
|
||||||
|
|
||||||
basestar.device.on('testevent', eventSpy);
|
basestar.on('testevent', eventSpy);
|
||||||
basestar.defineDriverEvent({ eventName: "testevent" });
|
basestar.defineDriverEvent({ eventName: "testevent" });
|
||||||
|
|
||||||
basestar.connection.emit("testevent", "data");
|
basestar.adaptor.emit("testevent", "data");
|
||||||
assert(eventSpy.calledWith('data'));
|
assert(eventSpy.calledWith('data'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -156,10 +154,10 @@ describe('Basestar', function() {
|
||||||
it("uses it as the eventName", function() {
|
it("uses it as the eventName", function() {
|
||||||
var eventSpy = spy();
|
var eventSpy = spy();
|
||||||
|
|
||||||
basestar.device.on('testevent', eventSpy);
|
basestar.on('testevent', eventSpy);
|
||||||
basestar.defineDriverEvent("testevent");
|
basestar.defineDriverEvent("testevent");
|
||||||
|
|
||||||
basestar.connection.emit("testevent", "data");
|
basestar.adaptor.emit("testevent", "data");
|
||||||
assert(eventSpy.calledWith('data'));
|
assert(eventSpy.calledWith('data'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,123 +1,15 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Loopback = source('test/loopback'),
|
var Loopback = source('test/loopback'),
|
||||||
Robot = source("robot"),
|
Connection = source("connection");
|
||||||
Logger = source('logger'),
|
|
||||||
Utils = source('utils');
|
|
||||||
|
|
||||||
describe("Connection", function() {
|
describe("Connection", function() {
|
||||||
var robot, connection;
|
it("returns a Adaptor instance", function() {
|
||||||
|
var conn = Connection({
|
||||||
beforeEach(function() {
|
name: 'test',
|
||||||
robot = new Robot({
|
adaptor: 'loopback'
|
||||||
name: "Robby",
|
|
||||||
connection: { name: 'loopback', adaptor: 'loopback', port: "/dev/null" }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connection = robot.connections.loopback;
|
expect(conn).to.be.an.instanceOf(Loopback);
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe("#constructor", function() {
|
|
||||||
it("sets @robot to the passed robot", function() {
|
|
||||||
expect(connection.robot).to.be.eql(robot);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @name to the passed name", function() {
|
|
||||||
expect(connection.name).to.be.eql('loopback');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @port to the passed port", function() {
|
|
||||||
expect(connection.port.toString()).to.be.eql("/dev/null");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#toJSON", function() {
|
|
||||||
var json;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
json = connection.toJSON();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns an object", function() {
|
|
||||||
expect(json).to.be.an('object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains the connection's name", function() {
|
|
||||||
expect(json.name).to.be.eql("loopback");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains the connection's port", function() {
|
|
||||||
expect(json.details.port).to.be.eql("/dev/null");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains the connection's adaptor name", function() {
|
|
||||||
expect(json.adaptor).to.be.eql("Loopback");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#connect", function() {
|
|
||||||
var callback;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
callback = spy();
|
|
||||||
Loopback.prototype.test = function() { return "Test" };
|
|
||||||
|
|
||||||
stub(Logger, 'info').returns(true);
|
|
||||||
connection.adaptor.connect = stub();
|
|
||||||
|
|
||||||
connection.connect(callback);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
Logger.info.restore();
|
|
||||||
delete Loopback.prototype.test;
|
|
||||||
})
|
|
||||||
|
|
||||||
it("logs that it's connecting the device", function() {
|
|
||||||
var message = "Connecting to 'loopback' on port /dev/null.";
|
|
||||||
expect(Logger.info).to.be.calledWith(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("triggers the provided callback after the adaptor finishes connecting", function() {
|
|
||||||
expect(callback).to.not.be.called;
|
|
||||||
connection.adaptor.connect.yield();
|
|
||||||
expect(callback).to.be.called;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("proxies methods from the Adaptor", function() {
|
|
||||||
connection.adaptor.connect.yield();
|
|
||||||
expect(connection.test()).to.be.eql("Test");
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#disconnect", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
stub(Logger, 'info').returns(true);
|
|
||||||
stub(connection, 'removeAllListeners');
|
|
||||||
|
|
||||||
connection.adaptor.disconnect = stub().returns(true);
|
|
||||||
|
|
||||||
connection.disconnect();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
connection.removeAllListeners.restore();
|
|
||||||
Logger.info.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("logs that it's disconnecting from the device", function() {
|
|
||||||
var message = "Disconnecting from 'loopback' on port /dev/null.";
|
|
||||||
expect(Logger.info).to.be.calledWith(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("tells the adaptor to disconnect", function() {
|
|
||||||
expect(connection.adaptor.disconnect).to.be.called;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("disconnects all event listeners", function() {
|
|
||||||
expect(connection.removeAllListeners).to.be.called;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Cylon = source("cylon"),
|
var Cylon = source("cylon"),
|
||||||
|
Robot = source("robot"),
|
||||||
Utils = source('utils');
|
Utils = source('utils');
|
||||||
|
|
||||||
var API = source('api'),
|
var API = source('api'),
|
||||||
|
@ -164,8 +165,8 @@ describe("Cylon", function() {
|
||||||
var json, bot1, bot2, echo;
|
var json, bot1, bot2, echo;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
bot1 = {};
|
bot1 = new Robot();
|
||||||
bot2 = {};
|
bot2 = new Robot();
|
||||||
|
|
||||||
Cylon.robots = { 'bot1': bot1, 'bot2': bot2 };
|
Cylon.robots = { 'bot1': bot1, 'bot2': bot2 };
|
||||||
Cylon.commands.echo = echo = function(arg) { return arg; };
|
Cylon.commands.echo = echo = function(arg) { return arg; };
|
||||||
|
@ -174,7 +175,7 @@ describe("Cylon", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("contains all robots the MCP knows about", function() {
|
it("contains all robots the MCP knows about", function() {
|
||||||
expect(json.robots).to.be.eql([bot1, bot2]);
|
expect(json.robots).to.be.eql([bot1.toJSON(), bot2.toJSON()]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("contains an array of MCP commands", function() {
|
it("contains an array of MCP commands", function() {
|
||||||
|
|
|
@ -1,165 +1,15 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Ping = source('test/ping'),
|
var Ping = source('test/ping'),
|
||||||
Device = source("device"),
|
Device = source("device");
|
||||||
Robot = source("robot"),
|
|
||||||
Logger = source('logger'),
|
|
||||||
Utils = source('utils');
|
|
||||||
|
|
||||||
describe("Device", function() {
|
describe("Device", function() {
|
||||||
var robot, connection, driver, device, initDriver;
|
it("returns a Driver instance", function() {
|
||||||
|
var driver = Device({
|
||||||
beforeEach(function() {
|
name: 'test',
|
||||||
robot = new Robot({
|
driver: 'ping'
|
||||||
name: "TestingBot",
|
|
||||||
connection: { name: 'loopback', adaptor: 'loopback' }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connection = robot.connections.loopback;
|
expect(driver).to.be.an.instanceOf(Ping);
|
||||||
|
|
||||||
driver = new Ping({
|
|
||||||
name: 'driver',
|
|
||||||
device: { connection: connection, pin: 13 },
|
|
||||||
connection: connection
|
|
||||||
});
|
|
||||||
|
|
||||||
driver.cmd = spy();
|
|
||||||
driver.string = "";
|
|
||||||
driver.robot = spy();
|
|
||||||
|
|
||||||
initDriver = stub(Device.prototype, 'initDriver').returns(driver);
|
|
||||||
|
|
||||||
device = new Device({
|
|
||||||
robot: robot,
|
|
||||||
name: "ping",
|
|
||||||
pin: 13,
|
|
||||||
connection: connection
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
initDriver.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("constructor", function() {
|
|
||||||
it("sets @robot to the passed robot", function() {
|
|
||||||
expect(device.robot).to.be.eql(robot);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @name to the passed name", function() {
|
|
||||||
expect(device.name).to.be.eql('ping');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @pin to the passed pin", function() {
|
|
||||||
expect(device.pin).to.be.eql(13);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @connection to the name of the specified connection on the Robot", function() {
|
|
||||||
expect(device.connection).to.be.eql(connection);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("asks the Robot to init a driver", function() {
|
|
||||||
expect(device.driver).to.be.eql(driver);
|
|
||||||
expect(initDriver).to.be.calledOnce
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not override existing functions", function() {
|
|
||||||
expect(device.robot).to.not.be.a('function');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#start", function() {
|
|
||||||
var callback;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
callback = spy();
|
|
||||||
|
|
||||||
stub(Logger, 'info');
|
|
||||||
driver.start = stub();
|
|
||||||
|
|
||||||
device.start(callback);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
Logger.info.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("logs that it's starting the device", function() {
|
|
||||||
var message = "Starting device 'ping' on pin 13.";
|
|
||||||
expect(Logger.info).to.be.calledWith(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("triggers the provided callback after the adaptor finishes connecting", function() {
|
|
||||||
expect(callback).to.not.be.called;
|
|
||||||
driver.start.yield();
|
|
||||||
expect(callback).to.be.called;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("binds driver methods to the device", function() {
|
|
||||||
driver.start.yield();
|
|
||||||
device.cmd();
|
|
||||||
expect(driver.cmd).to.be.called;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#halt", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
stub(Logger, 'info');
|
|
||||||
|
|
||||||
driver.halt = stub().returns(true);
|
|
||||||
device.removeAllListeners = spy();
|
|
||||||
|
|
||||||
device.halt();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
Logger.info.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("halts the driver", function() {
|
|
||||||
expect(driver.halt).to.be.called;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("logs that it's halt the device", function() {
|
|
||||||
var message = "Halting device 'ping'.";
|
|
||||||
|
|
||||||
expect(Logger.info).to.be.calledWith(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("disconnects all event listeners", function() {
|
|
||||||
expect(device.removeAllListeners).to.be.called;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#toJSON", function() {
|
|
||||||
var json;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
json = device.toJSON();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns an object", function() {
|
|
||||||
expect(json).to.be.a('object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains the device's name", function() {
|
|
||||||
expect(json.name).to.be.eql(device.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains the device's pin", function() {
|
|
||||||
expect(json.details.pin).to.be.eql(device.pin);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains the device's driver name", function() {
|
|
||||||
expect(json.driver).to.be.eql('Ping');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains the device's connection name", function() {
|
|
||||||
expect(json.connection).to.be.eql('loopback');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("contains the device's driver commands", function() {
|
|
||||||
expect(json.commands).to.be.eql(Object.keys(driver.commands));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,22 +7,16 @@ var Driver = source("driver"),
|
||||||
Utils = source('utils');
|
Utils = source('utils');
|
||||||
|
|
||||||
describe("Driver", function() {
|
describe("Driver", function() {
|
||||||
var connection, device, driver;
|
var adaptor, device, driver;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
connection = {
|
adaptor = {
|
||||||
adaptor: 'adaptor'
|
adaptor: 'adaptor'
|
||||||
};
|
};
|
||||||
|
|
||||||
device = {
|
|
||||||
connection: connection,
|
|
||||||
emit: spy()
|
|
||||||
};
|
|
||||||
|
|
||||||
driver = new Driver({
|
driver = new Driver({
|
||||||
name: 'driver',
|
name: 'driver',
|
||||||
device: device,
|
adaptor: adaptor,
|
||||||
connection: connection
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,16 +25,8 @@ describe("Driver", function() {
|
||||||
expect(driver.name).to.be.eql('driver');
|
expect(driver.name).to.be.eql('driver');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets @device to the provided device", function() {
|
it("sets @adaptor to the provided adaptor", function() {
|
||||||
expect(driver.device).to.be.eql(device);
|
expect(driver.adaptor).to.be.eql(adaptor);
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @connection to the provided device's connection", function() {
|
|
||||||
expect(driver.connection).to.be.eql(device.connection);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets @connection to the device's connection adaptor", function() {
|
|
||||||
expect(driver.adaptor).to.be.eql(device.connection.adaptor);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets @commands to an empty object by default", function() {
|
it("sets @commands to an empty object by default", function() {
|
||||||
|
@ -52,9 +38,8 @@ describe("Driver", function() {
|
||||||
|
|
||||||
driver = new Driver({
|
driver = new Driver({
|
||||||
name: 'driver',
|
name: 'driver',
|
||||||
device: device,
|
adaptor: adaptor,
|
||||||
interval: 2000,
|
interval: 2000,
|
||||||
connection: { }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(driver.interval).to.be.eql(2000);
|
expect(driver.interval).to.be.eql(2000);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Device = source('device'),
|
var Driver = source('driver'),
|
||||||
Connection = source('connection'),
|
Adaptor = source('adaptor'),
|
||||||
Robot = source("robot"),
|
Robot = source("robot"),
|
||||||
Utils = source('utils');
|
Utils = source('utils');
|
||||||
|
|
||||||
|
@ -217,11 +217,11 @@ describe("Robot", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("contains the robot's devices", function() {
|
it("contains the robot's devices", function() {
|
||||||
expect(json.devices).to.eql([bot.devices.ping]);
|
expect(json.devices).to.eql([bot.devices.ping.toJSON()]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("contains the robot's connections", function() {
|
it("contains the robot's connections", function() {
|
||||||
expect(json.connections).to.eql([bot.connections.loopback]);
|
expect(json.connections).to.eql([bot.connections.loopback.toJSON()]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ describe("Robot", function() {
|
||||||
it("instantiates a new connection with the provided object", function() {
|
it("instantiates a new connection with the provided object", function() {
|
||||||
var connection = { name: 'loopback', adaptor: 'loopback' };
|
var connection = { name: 'loopback', adaptor: 'loopback' };
|
||||||
bot.initConnections({ connection: connection });
|
bot.initConnections({ connection: connection });
|
||||||
expect(bot.connections['loopback']).to.be.instanceOf(Connection);
|
expect(bot.connections['loopback']).to.be.instanceOf(Adaptor);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ describe("Robot", function() {
|
||||||
it("instantiates a new connection with each of the provided objects", function() {
|
it("instantiates a new connection with each of the provided objects", function() {
|
||||||
var connections = [{ name: 'loopback', adaptor: 'loopback' }]
|
var connections = [{ name: 'loopback', adaptor: 'loopback' }]
|
||||||
bot.initConnections({ connections: connections });
|
bot.initConnections({ connections: connections });
|
||||||
expect(bot.connections['loopback']).to.be.instanceOf(Connection);
|
expect(bot.connections['loopback']).to.be.instanceOf(Adaptor);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("avoids name collisions", function() {
|
it("avoids name collisions", function() {
|
||||||
|
@ -286,20 +286,20 @@ describe("Robot", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context("when passed a devicw object", function() {
|
context("when passed a device object", function() {
|
||||||
it("instantiates a new device with the provided object", function() {
|
it("instantiates a new driver with the provided object", function() {
|
||||||
var device = { name: 'ping', driver: 'ping' };
|
var device = { name: 'ping', driver: 'ping' };
|
||||||
bot.initDevices({ device: device });
|
bot.initDevices({ device: device });
|
||||||
expect(bot.devices['ping']).to.be.instanceOf(Device);
|
expect(bot.devices['ping']).to.be.instanceOf(Driver);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context("when passed an array of device objects", function() {
|
context("when passed an array of device objects", function() {
|
||||||
it("instantiates a new device with each of the provided objects", function() {
|
it("instantiates a new driver with each of the provided objects", function() {
|
||||||
var devices = [{ name: 'ping', driver: 'ping' }]
|
var devices = [{ name: 'ping', driver: 'ping' }]
|
||||||
bot.initDevices({ devices: devices});
|
bot.initDevices({ devices: devices});
|
||||||
|
|
||||||
expect(bot.devices['ping']).to.be.instanceOf(Device);
|
expect(bot.devices['ping']).to.be.instanceOf(Driver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("avoids name collisions collisions", function() {
|
it("avoids name collisions collisions", function() {
|
||||||
|
|
Loading…
Reference in New Issue