diff --git a/state/channel.go b/state/channel.go index 5b96d14..d555b22 100644 --- a/state/channel.go +++ b/state/channel.go @@ -133,7 +133,7 @@ func (ch *Channel) delNick(nk *Nick) { } // Parses mode strings for a channel. -func (ch *Channel) ParseModes(modes string, modeargs []string) { +func (ch *Channel) ParseModes(modes string, modeargs ...string) { var modeop bool // true => add mode, false => remove mode var modestr string for i := 0; i < len(modes); i++ { @@ -167,7 +167,7 @@ func (ch *Channel) ParseModes(modes string, modeargs []string) { ch.Modes.Key = "" } else { ch.l.Warn("Channel.ParseModes(): not enough arguments to "+ - "process MODE %s %s%s", ch.Name, modestr, m) + "process MODE %s %s%c", ch.Name, modestr, m) } case 'l': if modeop && len(modeargs) != 0 { @@ -177,7 +177,7 @@ func (ch *Channel) ParseModes(modes string, modeargs []string) { ch.Modes.Limit = 0 } else { ch.l.Warn("Channel.ParseModes(): not enough arguments to "+ - "process MODE %s %s%s", ch.Name, modestr, m) + "process MODE %s %s%c", ch.Name, modestr, m) } case 'q', 'a', 'o', 'h', 'v': if len(modeargs) != 0 { @@ -198,11 +198,11 @@ func (ch *Channel) ParseModes(modes string, modeargs []string) { modeargs = modeargs[1:] } else { ch.l.Warn("Channel.ParseModes(): untracked nick %s "+ - "recieved MODE on channel %s", modeargs[0], ch.Name) + "received MODE on channel %s", modeargs[0], ch.Name) } } else { ch.l.Warn("Channel.ParseModes(): not enough arguments to "+ - "process MODE %s %s%s", ch.Name, modestr, m) + "process MODE %s %s%c", ch.Name, modestr, m) } default: ch.l.Info("Channel.ParseModes(): unknown mode char %c", m) diff --git a/state/channel_test.go b/state/channel_test.go index 9924bbf..6af5c79 100644 --- a/state/channel_test.go +++ b/state/channel_test.go @@ -64,3 +64,129 @@ func TestDelNick(t *testing.T) { t.Errorf("Nick test1 not properly removed from lookup map.") } } + +func TestChannelParseModes(t *testing.T) { + l, m := logging.NewMock() + ch := NewChannel("#test1", l) + md := ch.Modes + + // Channel modes can adjust channel privs too, so we need a Nick + nk := NewNick("test1", l) + cp := new(ChanPrivs) + ch.addNick(nk, cp) + + // Test bools first. + if md.Private || md.Secret || md.ProtectedTopic || md.NoExternalMsg || + md.Moderated || md.InviteOnly || md.OperOnly || md.SSLOnly { + t.Errorf("Modes for new channel set to true.") + } + + // Flip some bits! + md.Private = true + md.NoExternalMsg = true + md.InviteOnly = true + + // Flip some MOAR bits. + ch.ParseModes("+s-p+tm-i") + m.CheckNothingWritten(t) + + if md.Private || !md.Secret || !md.ProtectedTopic || !md.NoExternalMsg || + !md.Moderated || md.InviteOnly || md.OperOnly || md.SSLOnly { + t.Errorf("Modes not flipped correctly by ParseModes.") + } + + // Test numeric parsing (currently only channel limits) + if md.Limit != 0 { + t.Errorf("Limit for new channel not zero.") + } + + // enable limit correctly + ch.ParseModes("+l", "256") + m.CheckNothingWritten(t) + if md.Limit != 256 { + t.Errorf("Limit for channel not set correctly") + } + + // enable limit incorrectly + ch.ParseModes("+l") + m.CheckWrittenAtLevel(t, logging.Warn, + "Channel.ParseModes(): not enough arguments to process MODE #test1 +l") + if md.Limit != 256 { + t.Errorf("Bad limit value caused limit to be unset.") + } + + // disable limit correctly + ch.ParseModes("-l") + m.CheckNothingWritten(t) + if md.Limit != 0 { + t.Errorf("Limit for channel not unset correctly") + } + + // Test string parsing (currently only channel key) + if md.Key != "" { + t.Errorf("Key set for new channel.") + } + + // enable key correctly + ch.ParseModes("+k", "foobar") + m.CheckNothingWritten(t) + if md.Key != "foobar" { + t.Errorf("Key for channel not set correctly") + } + + // enable key incorrectly + ch.ParseModes("+k") + m.CheckWrittenAtLevel(t, logging.Warn, + "Channel.ParseModes(): not enough arguments to process MODE #test1 +k") + if md.Key != "foobar" { + t.Errorf("Bad key value caused key to be unset.") + } + + // disable key correctly + ch.ParseModes("-k") + m.CheckNothingWritten(t) + if md.Key != "" { + t.Errorf("Key for channel not unset correctly") + } + + // Test chan privs parsing. + cp.Op = true + cp.HalfOp = true + ch.ParseModes("+aq-o", "test1", "test1", "test1") + m.CheckNothingWritten(t) + + if !cp.Owner || !cp.Admin || cp.Op || !cp.HalfOp || cp.Voice { + t.Errorf("Channel privileges not flipped correctly by ParseModes.") + } + + ch.ParseModes("+v", "test2") + m.CheckWrittenAtLevel(t, logging.Warn, + "Channel.ParseModes(): untracked nick test2 received MODE on channel #test1") + + ch.ParseModes("-v") + m.CheckWrittenAtLevel(t, logging.Warn, + "Channel.ParseModes(): not enough arguments to process MODE #test1 -v") + + // Test a random mix of modes, just to be sure + md.Limit = 256 + ch.ParseModes("+zpt-qsl+kv-h", "test1", "foobar", "test1") + m.CheckWrittenAtLevel(t, logging.Warn, + "Channel.ParseModes(): not enough arguments to process MODE #test1 -h") + + if !md.Private || md.Secret || !md.ProtectedTopic || !md.NoExternalMsg || + !md.Moderated || md.InviteOnly || md.OperOnly || !md.SSLOnly { + t.Errorf("Modes not flipped correctly by ParseModes (2).") + } + if md.Limit != 0 || md.Key != "foobar" { + t.Errorf("Key and limit not changed correctly by ParseModes (2).") + } + if cp.Owner || !cp.Admin || cp.Op || !cp.HalfOp || !cp.Voice { + // NOTE: HalfOp not actually unset above thanks to deliberate error. + t.Errorf("Channel privileges not flipped correctly by ParseModes (2).") + } + + // Finally, check we get an info log for an unrecognised mode character + ch.ParseModes("+d") + m.CheckWrittenAtLevel(t, logging.Info, + "Channel.ParseModes(): unknown mode char d") +} diff --git a/state/nick_test.go b/state/nick_test.go index 2541662..ae6415b 100644 --- a/state/nick_test.go +++ b/state/nick_test.go @@ -65,7 +65,7 @@ func TestDelChannel(t *testing.T) { } } -func TestParseModes(t *testing.T) { +func TestNickParseModes(t *testing.T) { l, m := logging.NewMock() nk := NewNick("test1", l) md := nk.Modes