Skip to content
This repository has been archived by the owner on Sep 10, 2024. It is now read-only.

Commit

Permalink
Allow .part to use a comma-separated list per IRC spec
Browse files Browse the repository at this point in the history
  • Loading branch information
Throne3d committed Sep 26, 2017
1 parent 6ff1349 commit f6f3294
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 14 deletions.
8 changes: 5 additions & 3 deletions docs/API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ Client
Joins the specified channel.

:param string channelList: the channel(s) to join
:param function callback: a callback to automatically attach to `join#channelname` for each channel
:param function callback: an optional callback to automatically attach to ``join#channelname`` for each channel

``channelList`` supports multiple channels in a comma-separated string (`as in the IRC protocol <https://tools.ietf.org/html/rfc2812#page-16>`_).
The callback is called for each channel, but does not include the ``channel`` parameter (see the ``join#channel`` event).
Expand All @@ -156,9 +156,11 @@ Client

Parts the specified channel.

:param string channel: the channel to part
:param string channelList: the channel(s) to part
:param string message: an optional message to send upon leaving the channel
:param function callback: a callback to run once the bot has parted the channel
:param function callback: a optional callback to automatically attach to ``part#channelname`` for each channel

As with ``Client.join``, the ``channelList`` parameter supports multiple channels in a comma-separated string, for each of which the callback will be called.

.. js:function:: Client.say(target, message)

Expand Down
26 changes: 15 additions & 11 deletions lib/irc.js
Original file line number Diff line number Diff line change
Expand Up @@ -1059,24 +1059,28 @@ Client.prototype.join = function(channelList, callback) {
self.send('JOIN', channelList);
};

Client.prototype.part = function(channel, message, callback) {
Client.prototype.part = function(channelList, message, callback) {
if (typeof (message) === 'function') {
callback = message;
message = undefined;
}
if (typeof callback === 'function') {
this.once('part' + channel, callback);
}

// remove this channel from this.opt.channels so we won't rejoin upon reconnect
if (this.opt.channels.indexOf(channel) !== -1) {
this.opt.channels.splice(this.opt.channels.indexOf(channel), 1);
}
var self = this;
var channels = channelList.split(',');
channels.forEach(function(channelName) {
if (typeof callback === 'function') {
self.once('part' + channelName.toLowerCase(), callback);
}

// remove this channel from this.opt.channels so we won't rejoin upon reconnect
if (self.opt.channels.indexOf(channelName) !== -1) {
self.opt.channels.splice(self.opt.channels.indexOf(channelName), 1);
}
});

if (message) {
this.send('PART', channel, message);
this.send('PART', channelList, message);
} else {
this.send('PART', channel);
this.send('PART', channelList);
}
};

Expand Down
136 changes: 136 additions & 0 deletions test/test-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,140 @@ describe('Client', function() {
});
});
});

describe('#part', function() {
testHelpers.hookMockSetup(beforeEach, afterEach);

function downcaseChannels(chans) {
return chans.map(function(x) { return x.toLowerCase(); });
}

beforeEach(function(done) {
var self = this;
setTimeout(function() {
self.debugSpy = sinon.spy();
self.sendSpy = sinon.spy();
self.client.out.debug = self.debugSpy;
self.client.send = self.sendSpy;
done();
}, 10);
});

function sharedExamplesFor(channels, remoteChannels) {
joinChannelsBefore(beforeEach, channels, remoteChannels);

it('works with no message or callback', function() {
var self = this;
function wrap() {
self.client.part(channels.join(','));
}
expect(wrap).not.to.throw();
expect(this.sendSpy.args).to.deep.equal([
['PART', channels.join(',')]
]);
});

it('sends with message and no callback', function() {
var self = this;
function wrap() {
self.client.part(channels.join(','), 'test message');
}
expect(wrap).not.to.throw();
expect(this.sendSpy.args).to.deep.equal([
['PART', channels.join(','), 'test message']
]);
});

it('sends with callback and no message', function() {
var self = this;
function wrap() {
self.client.part(channels.join(','), function() {});
}
expect(wrap).not.to.throw();
expect(this.sendSpy.args).to.deep.equal([
['PART', channels.join(',')]
]);
});

it('sends with message and callback', function() {
var self = this;
function wrap() {
self.client.part(channels.join(','), 'test message', function() {});
}
expect(wrap).not.to.throw();
expect(this.sendSpy.args).to.deep.equal([
['PART', channels.join(','), 'test message']
]);
});

it('removes from opt.channels', function(done) {
var self = this;
var i = 0;
self.client.on('part', function() {
i++;
if (i === channels.length) setTimeout(check, 10);
});
expect(downcaseChannels(self.client.opt.channels)).to.deep.equal(downcaseChannels(remoteChannels));
self.client.part(channels.join(','), 'test message');
remoteChannels.forEach(function(remoteChan) {
self.mock.send(':testbot!~testbot@EXAMPLE.HOST PART ' + remoteChan + ' :test message\r\n');
});

function check() {
expect(self.client.opt.channels).to.empty;
done();
}
});

it('calls given callback', function(done) {
var self = this;
expect(downcaseChannels(self.client.opt.channels)).to.deep.equal(downcaseChannels(remoteChannels));
self.client.part(channels.join(','), check);
remoteChannels.forEach(function(remoteChan) {
self.mock.send(':testbot!~testbot@EXAMPLE.HOST PART ' + remoteChan + ' :test message\r\n');
});

var i = 0;
function check(nick, reason, message) {
expect(nick).to.equal('testbot');
expect(reason).to.equal('test message');
expect(message).to.deep.equal({
prefix: 'testbot!~testbot@EXAMPLE.HOST',
nick: 'testbot',
user: '~testbot',
host: 'EXAMPLE.HOST',
commandType: 'normal',
command: 'PART',
rawCommand: 'PART',
args: [remoteChannels[i], 'test message']
});
i++;
if (i === channels.length) done();
}
});
}

context('with same lowercase local and remote channel', function() {
sharedExamplesFor(['#channel'], ['#channel']);
});

context('with same mixed-case local and remote channel', function() {
sharedExamplesFor(['#Channel'], ['#Channel']);
});

context('with mixed-case local channel differing from lowercase remote channel', function() {
sharedExamplesFor(['#Channel'], ['#channel']);
});

context('with lowercase local channel differing from mixed-case remote channel', function() {
sharedExamplesFor(['#channel'], ['#Channel']);
});

context('with multiple channels', function() {
var localChannels = ['#channel', '#channel2', '#Test', '#Test2'];
var remoteChannels = ['#channel', '#Channel2', '#test', '#Test2'];

sharedExamplesFor(localChannels, remoteChannels);
});
});
});

0 comments on commit f6f3294

Please sign in to comment.