summaryrefslogtreecommitdiff
path: root/vendor/github.com/fluffle/goirc/client
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/fluffle/goirc/client')
-rw-r--r--vendor/github.com/fluffle/goirc/client/commands_test.go205
-rw-r--r--vendor/github.com/fluffle/goirc/client/connection_test.go585
-rw-r--r--vendor/github.com/fluffle/goirc/client/dispatch_test.go201
-rw-r--r--vendor/github.com/fluffle/goirc/client/handlers_test.go451
-rw-r--r--vendor/github.com/fluffle/goirc/client/line_test.go186
-rw-r--r--vendor/github.com/fluffle/goirc/client/mocknetconn_test.go154
6 files changed, 0 insertions, 1782 deletions
diff --git a/vendor/github.com/fluffle/goirc/client/commands_test.go b/vendor/github.com/fluffle/goirc/client/commands_test.go
deleted file mode 100644
index 15a8a05..0000000
--- a/vendor/github.com/fluffle/goirc/client/commands_test.go
+++ /dev/null
@@ -1,205 +0,0 @@
-package client
-
-import (
- "reflect"
- "testing"
-)
-
-func TestCutNewLines(t *testing.T) {
- tests := []struct{ in, out string }{
- {"", ""},
- {"foo bar", "foo bar"},
- {"foo bar\rbaz", "foo bar"},
- {"foo bar\nbaz", "foo bar"},
- {"blorp\r\n\r\nbloop", "blorp"},
- {"\n\rblaap", ""},
- {"\r\n", ""},
- {"boo\\r\\n\\n\r", "boo\\r\\n\\n"},
- }
- for i, test := range tests {
- out := cutNewLines(test.in)
- if test.out != out {
- t.Errorf("test %d: expected %q, got %q", i, test.out, out)
- }
- }
-}
-
-func TestIndexFragment(t *testing.T) {
- tests := []struct {
- in string
- out int
- }{
- {"", -1},
- {"foobarbaz", -1},
- {"foo bar baz", 8},
- {"foo. bar baz", 5},
- {"foo: bar baz", 5},
- {"foo; bar baz", 5},
- {"foo, bar baz", 5},
- {"foo! bar baz", 5},
- {"foo? bar baz", 5},
- {"foo\" bar baz", 5},
- {"foo' bar baz", 5},
- {"foo. bar. baz beep", 10},
- {"foo. bar, baz beep", 10},
- }
- for i, test := range tests {
- out := indexFragment(test.in)
- if test.out != out {
- t.Errorf("test %d: expected %d, got %d", i, test.out, out)
- }
- }
-}
-
-func TestSplitMessage(t *testing.T) {
- tests := []struct {
- in string
- sp int
- out []string
- }{
- {"", 0, []string{""}},
- {"foo", 0, []string{"foo"}},
- {"foo bar baz beep", 0, []string{"foo bar baz beep"}},
- {"foo bar baz beep", 15, []string{"foo bar baz ...", "beep"}},
- {"foo bar, baz beep", 15, []string{"foo bar, ...", "baz beep"}},
- {"0123456789012345", 0, []string{"0123456789012345"}},
- {"0123456789012345", 15, []string{"012345678901...", "2345"}},
- {"0123456789012345", 16, []string{"0123456789012345"}},
- }
- for i, test := range tests {
- out := splitMessage(test.in, test.sp)
- if !reflect.DeepEqual(test.out, out) {
- t.Errorf("test %d: expected %q, got %q", i, test.out, out)
- }
- }
-}
-
-func TestClientCommands(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Avoid having to type ridiculously long lines to test that
- // messages longer than SplitLen are correctly sent to the server.
- c.cfg.SplitLen = 23
-
- c.Pass("password")
- s.nc.Expect("PASS password")
-
- c.Nick("test")
- s.nc.Expect("NICK test")
-
- c.User("test", "Testing IRC")
- s.nc.Expect("USER test 12 * :Testing IRC")
-
- c.Raw("JUST a raw :line")
- s.nc.Expect("JUST a raw :line")
-
- c.Join("#foo")
- s.nc.Expect("JOIN #foo")
- c.Join("#foo bar")
- s.nc.Expect("JOIN #foo bar")
-
- c.Part("#foo")
- s.nc.Expect("PART #foo")
- c.Part("#foo", "Screw you guys...")
- s.nc.Expect("PART #foo :Screw you guys...")
-
- c.Quit()
- s.nc.Expect("QUIT :GoBye!")
- c.Quit("I'm going home.")
- s.nc.Expect("QUIT :I'm going home.")
-
- c.Whois("somebody")
- s.nc.Expect("WHOIS somebody")
-
- c.Who("*@some.host.com")
- s.nc.Expect("WHO *@some.host.com")
-
- c.Privmsg("#foo", "bar")
- s.nc.Expect("PRIVMSG #foo :bar")
-
- c.Privmsgln("#foo", "bar")
- s.nc.Expect("PRIVMSG #foo :bar")
-
- c.Privmsgf("#foo", "say %s", "foo")
- s.nc.Expect("PRIVMSG #foo :say foo")
-
- c.Privmsgln("#foo", "bar", 1, 3.54, []int{24, 36})
- s.nc.Expect("PRIVMSG #foo :bar 1 3.54 [24 36]")
-
- c.Privmsgf("#foo", "user %d is at %s", 2, "home")
- s.nc.Expect("PRIVMSG #foo :user 2 is at home")
-
- // 0123456789012345678901234567890123
- c.Privmsg("#foo", "foo bar baz blorp. woo woobly woo.")
- s.nc.Expect("PRIVMSG #foo :foo bar baz blorp. ...")
- s.nc.Expect("PRIVMSG #foo :woo woobly woo.")
-
- c.Privmsgln("#foo", "foo bar baz blorp. woo woobly woo.")
- s.nc.Expect("PRIVMSG #foo :foo bar baz blorp. ...")
- s.nc.Expect("PRIVMSG #foo :woo woobly woo.")
-
- c.Privmsgf("#foo", "%s %s", "foo bar baz blorp.", "woo woobly woo.")
- s.nc.Expect("PRIVMSG #foo :foo bar baz blorp. ...")
- s.nc.Expect("PRIVMSG #foo :woo woobly woo.")
-
- c.Privmsgln("#foo", "foo bar", 3.54, "blorp.", "woo", "woobly", []int{1, 2})
- s.nc.Expect("PRIVMSG #foo :foo bar 3.54 blorp. ...")
- s.nc.Expect("PRIVMSG #foo :woo woobly [1 2]")
-
- c.Privmsgf("#foo", "%s %.2f %s %s %s %v", "foo bar", 3.54, "blorp.", "woo", "woobly", []int{1, 2})
- s.nc.Expect("PRIVMSG #foo :foo bar 3.54 blorp. ...")
- s.nc.Expect("PRIVMSG #foo :woo woobly [1 2]")
-
- c.Notice("somebody", "something")
- s.nc.Expect("NOTICE somebody :something")
-
- // 01234567890123456789012345678901234567
- c.Notice("somebody", "something much much longer that splits")
- s.nc.Expect("NOTICE somebody :something much much ...")
- s.nc.Expect("NOTICE somebody :longer that splits")
-
- c.Ctcp("somebody", "ping", "123456789")
- s.nc.Expect("PRIVMSG somebody :\001PING 123456789\001")
-
- c.Ctcp("somebody", "ping", "123456789012345678901234567890")
- s.nc.Expect("PRIVMSG somebody :\001PING 12345678901234567890...\001")
- s.nc.Expect("PRIVMSG somebody :\001PING 1234567890\001")
-
- c.CtcpReply("somebody", "pong", "123456789012345678901234567890")
- s.nc.Expect("NOTICE somebody :\001PONG 12345678901234567890...\001")
- s.nc.Expect("NOTICE somebody :\001PONG 1234567890\001")
-
- c.CtcpReply("somebody", "pong", "123456789")
- s.nc.Expect("NOTICE somebody :\001PONG 123456789\001")
-
- c.Version("somebody")
- s.nc.Expect("PRIVMSG somebody :\001VERSION\001")
-
- c.Action("#foo", "pokes somebody")
- s.nc.Expect("PRIVMSG #foo :\001ACTION pokes somebody\001")
-
- c.Topic("#foo")
- s.nc.Expect("TOPIC #foo")
- c.Topic("#foo", "la la la")
- s.nc.Expect("TOPIC #foo :la la la")
-
- c.Mode("#foo")
- s.nc.Expect("MODE #foo")
- c.Mode("#foo", "+o somebody")
- s.nc.Expect("MODE #foo +o somebody")
-
- c.Away()
- s.nc.Expect("AWAY")
- c.Away("Dave's not here, man.")
- s.nc.Expect("AWAY :Dave's not here, man.")
-
- c.Invite("somebody", "#foo")
- s.nc.Expect("INVITE somebody #foo")
-
- c.Oper("user", "pass")
- s.nc.Expect("OPER user pass")
-
- c.VHost("user", "pass")
- s.nc.Expect("VHOST user pass")
-}
diff --git a/vendor/github.com/fluffle/goirc/client/connection_test.go b/vendor/github.com/fluffle/goirc/client/connection_test.go
deleted file mode 100644
index acf4713..0000000
--- a/vendor/github.com/fluffle/goirc/client/connection_test.go
+++ /dev/null
@@ -1,585 +0,0 @@
-package client
-
-import (
- "runtime"
- "strings"
- "testing"
- "time"
-
- "github.com/fluffle/goirc/state"
- "github.com/golang/mock/gomock"
-)
-
-type checker struct {
- t *testing.T
- c chan struct{}
-}
-
-func callCheck(t *testing.T) checker {
- return checker{t: t, c: make(chan struct{})}
-}
-
-func (c checker) call() {
- c.c <- struct{}{}
-}
-
-func (c checker) assertNotCalled(fmt string, args ...interface{}) {
- select {
- case <-c.c:
- c.t.Errorf(fmt, args...)
- default:
- }
-}
-
-func (c checker) assertWasCalled(fmt string, args ...interface{}) {
- select {
- case <-c.c:
- case <-time.After(time.Millisecond):
- // Usually need to wait for goroutines to settle :-/
- c.t.Errorf(fmt, args...)
- }
-}
-
-type testState struct {
- ctrl *gomock.Controller
- st *state.MockTracker
- nc *mockNetConn
- c *Conn
-}
-
-// NOTE: including a second argument at all prevents calling c.postConnect()
-func setUp(t *testing.T, start ...bool) (*Conn, *testState) {
- ctrl := gomock.NewController(t)
- st := state.NewMockTracker(ctrl)
- nc := MockNetConn(t)
- c := SimpleClient("test", "test", "Testing IRC")
- c.initialise()
-
- c.st = st
- c.sock = nc
- c.cfg.Flood = true // Tests can take a while otherwise
- c.connected = true
- // If a second argument is passed to setUp, we tell postConnect not to
- // start the various goroutines that shuttle data around.
- c.postConnect(len(start) == 0)
- // Sleep 1ms to allow background routines to start.
- <-time.After(time.Millisecond)
-
- return c, &testState{ctrl, st, nc, c}
-}
-
-func (s *testState) tearDown() {
- s.nc.ExpectNothing()
- s.c.Close()
- s.ctrl.Finish()
-}
-
-// Practically the same as the above test, but Close is called implicitly
-// by recv() getting an EOF from the mock connection.
-func TestEOF(t *testing.T) {
- c, s := setUp(t)
- // Since we're not using tearDown() here, manually call Finish()
- defer s.ctrl.Finish()
-
- // Set up a handler to detect whether disconnected handlers are called
- dcon := callCheck(t)
- c.HandleFunc(DISCONNECTED, func(conn *Conn, line *Line) {
- dcon.call()
- })
-
- // Simulate EOF from server
- s.nc.Close()
-
- // Verify that disconnected handler was called
- dcon.assertWasCalled("Conn did not call disconnected handlers.")
-
- // Verify that the connection no longer thinks it's connected
- if c.Connected() {
- t.Errorf("Conn still thinks it's connected to the server.")
- }
-}
-
-func TestClientAndStateTracking(t *testing.T) {
- ctrl := gomock.NewController(t)
- st := state.NewMockTracker(ctrl)
- c := SimpleClient("test", "test", "Testing IRC")
-
- // Assert some basic things about the initial state of the Conn struct
- me := c.cfg.Me
- if me.Nick != "test" || me.Ident != "test" ||
- me.Name != "Testing IRC" || me.Host != "" {
- t.Errorf("Conn.cfg.Me not correctly initialised.")
- }
- // Check that the internal handlers are correctly set up
- for k, _ := range intHandlers {
- if _, ok := c.intHandlers.set[strings.ToLower(k)]; !ok {
- t.Errorf("Missing internal handler for '%s'.", k)
- }
- }
-
- // Now enable the state tracking code and check its handlers
- c.EnableStateTracking()
- for k, _ := range stHandlers {
- if _, ok := c.intHandlers.set[strings.ToLower(k)]; !ok {
- t.Errorf("Missing state handler for '%s'.", k)
- }
- }
- if len(c.stRemovers) != len(stHandlers) {
- t.Errorf("Incorrect number of Removers (%d != %d) when adding state handlers.",
- len(c.stRemovers), len(stHandlers))
- }
- if neu := c.Me(); neu.Nick != me.Nick || neu.Ident != me.Ident ||
- neu.Name != me.Name || neu.Host != me.Host {
- t.Errorf("Enabling state tracking erased information about me!")
- }
-
- // We're expecting the untracked me to be replaced by a tracked one
- if c.st == nil {
- t.Errorf("State tracker not enabled correctly.")
- }
- if me = c.cfg.Me; me.Nick != "test" || me.Ident != "test" ||
- me.Name != "Testing IRC" || me.Host != "" {
- t.Errorf("Enabling state tracking did not replace Me correctly.")
- }
-
- // Now, shim in the mock state tracker and test disabling state tracking
- c.st = st
- gomock.InOrder(
- st.EXPECT().Me().Return(me),
- st.EXPECT().Wipe(),
- )
- c.DisableStateTracking()
- if c.st != nil || !c.cfg.Me.Equals(me) {
- t.Errorf("State tracker not disabled correctly.")
- }
-
- // Finally, check state tracking handlers were all removed correctly
- for k, _ := range stHandlers {
- if _, ok := c.intHandlers.set[strings.ToLower(k)]; ok && k != "NICK" {
- // A bit leaky, because intHandlers adds a NICK handler.
- t.Errorf("State handler for '%s' not removed correctly.", k)
- }
- }
- if len(c.stRemovers) != 0 {
- t.Errorf("stRemovers not zeroed correctly when removing state handlers.")
- }
- ctrl.Finish()
-}
-
-func TestSendExitsOnDie(t *testing.T) {
- // Passing a second value to setUp stops goroutines from starting
- c, s := setUp(t, false)
- defer s.tearDown()
-
- // Assert that before send is running, nothing should be sent to the socket
- // but writes to the buffered channel "out" should not block.
- c.out <- "SENT BEFORE START"
- s.nc.ExpectNothing()
-
- // We want to test that the a goroutine calling send will exit correctly.
- exited := callCheck(t)
- // send() will decrement the WaitGroup, so we must increment it.
- c.wg.Add(1)
- go func() {
- c.send()
- exited.call()
- }()
-
- // send is now running in the background as if started by postConnect.
- // This should read the line previously buffered in c.out, and write it
- // to the socket connection.
- s.nc.Expect("SENT BEFORE START")
-
- // Send another line, just to be sure :-)
- c.out <- "SENT AFTER START"
- s.nc.Expect("SENT AFTER START")
-
- // Now, use the control channel to exit send and kill the goroutine.
- // This sneakily uses the fact that the other two goroutines that would
- // normally be waiting for die to close are not running, so we only send
- // to the goroutine started above. Normally Close() closes c.die and
- // signals to all three goroutines (send, ping, runLoop) to exit.
- exited.assertNotCalled("Exited before signal sent.")
- c.die <- struct{}{}
- exited.assertWasCalled("Didn't exit after signal.")
- s.nc.ExpectNothing()
-
- // Sending more on c.out shouldn't reach the network.
- c.out <- "SENT AFTER END"
- s.nc.ExpectNothing()
-}
-
-func TestSendExitsOnWriteError(t *testing.T) {
- // Passing a second value to setUp stops goroutines from starting
- c, s := setUp(t, false)
- // We can't use tearDown here because we're testing shutdown conditions
- // (and so need to EXPECT() a call to st.Wipe() in the right place)
- defer s.ctrl.Finish()
-
- // We want to test that the a goroutine calling send will exit correctly.
- exited := callCheck(t)
- // send() will decrement the WaitGroup, so we must increment it.
- c.wg.Add(1)
- go func() {
- c.send()
- exited.call()
- }()
-
- // Send a line to be sure things are good.
- c.out <- "SENT AFTER START"
- s.nc.Expect("SENT AFTER START")
-
- // Now, close the underlying socket to cause write() to return an error.
- // This will call Close() => a call to st.Wipe() will happen.
- exited.assertNotCalled("Exited before signal sent.")
- s.nc.Close()
- // Sending more on c.out shouldn't reach the network, but we need to send
- // *something* to trigger a call to write() that will fail.
- c.out <- "SENT AFTER END"
- exited.assertWasCalled("Didn't exit after signal.")
- s.nc.ExpectNothing()
-}
-
-func TestSendDeadlockOnFullBuffer(t *testing.T) {
- // Passing a second value to setUp stops goroutines from starting
- c, s := setUp(t, false)
- // We can't use tearDown here because we're testing a deadlock condition
- // and if tearDown tries to call Close() it will deadlock some more
- // because send() is holding the conn mutex via Close() already.
- defer s.ctrl.Finish()
-
- // We want to test that the a goroutine calling send will exit correctly.
- loopExit := callCheck(t)
- sendExit := callCheck(t)
- // send() and runLoop() will decrement the WaitGroup, so we must increment it.
- c.wg.Add(2)
-
- // The deadlock arises when a handler being called from conn.dispatch() in
- // runLoop() tries to write to conn.out to send a message back to the IRC
- // server, but the buffer is full. If at the same time send() is
- // calling conn.Close() and waiting in there for runLoop() to call
- // conn.wg.Done(), it will not empty the buffer of conn.out => deadlock.
- //
- // We simulate this by artifically filling conn.out. We must use a
- // goroutine to put in one more line than the buffer can hold, because
- // send() will read a line from conn.out on its first loop iteration:
- go func() {
- for i := 0; i < 33; i++ {
- c.out <- "FILL BUFFER WITH CRAP"
- }
- }()
- // Then we add a handler that tries to write a line to conn.out:
- c.HandleFunc(PRIVMSG, func(conn *Conn, line *Line) {
- conn.Raw(line.Raw)
- })
- // And trigger it by starting runLoop and inserting a line into conn.in:
- go func() {
- c.runLoop()
- loopExit.call()
- }()
- c.in <- &Line{Cmd: PRIVMSG, Raw: "WRITE THAT CAUSES DEADLOCK"}
-
- // At this point the handler should be blocked on a write to conn.out,
- // preventing runLoop from looping and thus noticing conn.die is closed.
- //
- // The next part is to force send() to call conn.Close(), which can
- // be done by closing the fake net.Conn so that it returns an error on
- // calls to Write():
- s.nc.ExpectNothing()
- s.nc.Close()
-
- // Now when send is started it will read one line from conn.out and try
- // to write it to the socket. It should immediately receive an error and
- // call conn.Close(), triggering the deadlock as it waits forever for
- // runLoop to call conn.wg.Done.
- go func() {
- c.send()
- sendExit.call()
- }()
-
- // Make sure that things are definitely deadlocked.
- <-time.After(time.Millisecond)
-
- // Verify that the connection no longer thinks it's connected, i.e.
- // conn.Close() has definitely been called. We can't call
- // conn.Connected() here because conn.Close() holds the mutex.
- if c.connected {
- t.Errorf("Conn still thinks it's connected to the server.")
- }
-
- // We expect both loops to terminate cleanly. If either of them don't
- // then we have successfully deadlocked :-(
- loopExit.assertWasCalled("runLoop did not exit cleanly.")
- sendExit.assertWasCalled("send did not exit cleanly.")
-}
-
-func TestRecv(t *testing.T) {
- // Passing a second value to setUp stops goroutines from starting
- c, s := setUp(t, false)
- // We can't use tearDown here because we're testing shutdown conditions
- // (and so need to EXPECT() a call to st.Wipe() in the right place)
- defer s.ctrl.Finish()
-
- // Send a line before recv is started up, to verify nothing appears on c.in
- s.nc.Send(":irc.server.org 001 test :First test line.")
-
- // reader is a helper to do a "non-blocking" read of c.in
- reader := func() *Line {
- select {
- case <-time.After(time.Millisecond):
- case l := <-c.in:
- return l
- }
- return nil
- }
- if l := reader(); l != nil {
- t.Errorf("Line parsed before recv started.")
- }
-
- // We want to test that the a goroutine calling recv will exit correctly.
- exited := callCheck(t)
- // recv() will decrement the WaitGroup, so we must increment it.
- c.wg.Add(1)
- go func() {
- c.recv()
- exited.call()
- }()
-
- // Now, this should mean that we'll receive our parsed line on c.in
- if l := reader(); l == nil || l.Cmd != "001" {
- t.Errorf("Bad first line received on input channel")
- }
-
- // Send a second line, just to be sure.
- s.nc.Send(":irc.server.org 002 test :Second test line.")
- if l := reader(); l == nil || l.Cmd != "002" {
- t.Errorf("Bad second line received on input channel.")
- }
-
- // Test that recv does something useful with a line it can't parse
- // (not that there are many, ParseLine is forgiving).
- s.nc.Send(":textwithnospaces")
- if l := reader(); l != nil {
- t.Errorf("Bad line still caused receive on input channel.")
- }
-
- // The only way recv() exits is when the socket closes.
- exited.assertNotCalled("Exited before socket close.")
- s.nc.Close()
- exited.assertWasCalled("Didn't exit on socket close.")
-
- // Since s.nc is closed we can't attempt another send on it...
- if l := reader(); l != nil {
- t.Errorf("Line received on input channel after socket close.")
- }
-}
-
-func TestPing(t *testing.T) {
- // Passing a second value to setUp stops goroutines from starting
- c, s := setUp(t, false)
- defer s.tearDown()
-
- res := time.Millisecond
-
- // Windows has a timer resolution of 15.625ms by default.
- // This means the test will be slower on windows, but
- // should at least stop most of the flakiness...
- // https://github.com/fluffle/goirc/issues/88
- if runtime.GOOS == "windows" {
- res = 15625 * time.Microsecond
- }
-
- // Set a low ping frequency for testing.
- c.cfg.PingFreq = 10 * res
-
- // reader is a helper to do a "non-blocking" read of c.out
- reader := func() string {
- select {
- case <-time.After(res):
- case s := <-c.out:
- return s
- }
- return ""
- }
- if s := reader(); s != "" {
- t.Errorf("Line output before ping started.")
- }
-
- // Start ping loop.
- exited := callCheck(t)
- // ping() will decrement the WaitGroup, so we must increment it.
- c.wg.Add(1)
- go func() {
- c.ping()
- exited.call()
- }()
-
- // The first ping should be after 10*res ms,
- // so we don't expect anything now on c.in
- if s := reader(); s != "" {
- t.Errorf("Line output directly after ping started.")
- }
-
- <-time.After(c.cfg.PingFreq)
- if s := reader(); s == "" || !strings.HasPrefix(s, "PING :") {
- t.Errorf("Line not output after %s.", c.cfg.PingFreq)
- }
-
- // Reader waits for res ms and we call it a few times above.
- <-time.After(7 * res)
- if s := reader(); s != "" {
- t.Errorf("Line output <%s after last ping.", 7*res)
- }
-
- // This is a short window in which the ping should happen
- // This may result in flaky tests; sorry (and file a bug) if so.
- <-time.After(2 * res)
- if s := reader(); s == "" || !strings.HasPrefix(s, "PING :") {
- t.Errorf("Line not output after another %s.", 2*res)
- }
-
- // Now kill the ping loop.
- // This sneakily uses the fact that the other two goroutines that would
- // normally be waiting for die to close are not running, so we only send
- // to the goroutine started above. Normally Close() closes c.die and
- // signals to all three goroutines (send, ping, runLoop) to exit.
- exited.assertNotCalled("Exited before signal sent.")
- c.die <- struct{}{}
- exited.assertWasCalled("Didn't exit after signal.")
- // Make sure we're no longer pinging by waiting >2x PingFreq
- <-time.After(2*c.cfg.PingFreq + res)
- if s := reader(); s != "" {
- t.Errorf("Line output after ping stopped.")
- }
-}
-
-func TestRunLoop(t *testing.T) {
- // Passing a second value to setUp stops goroutines from starting
- c, s := setUp(t, false)
- defer s.tearDown()
-
- // Set up a handler to detect whether 001 handler is called
- h001 := callCheck(t)
- c.HandleFunc("001", func(conn *Conn, line *Line) {
- h001.call()
- })
- h002 := callCheck(t)
- // Set up a handler to detect whether 002 handler is called
- c.HandleFunc("002", func(conn *Conn, line *Line) {
- h002.call()
- })
-
- l1 := ParseLine(":irc.server.org 001 test :First test line.")
- c.in <- l1
- h001.assertNotCalled("001 handler called before runLoop started.")
-
- // We want to test that the a goroutine calling runLoop will exit correctly.
- // Now, we can expect the call to Dispatch to take place as runLoop starts.
- exited := callCheck(t)
- // runLoop() will decrement the WaitGroup, so we must increment it.
- c.wg.Add(1)
- go func() {
- c.runLoop()
- exited.call()
- }()
- h001.assertWasCalled("001 handler not called after runLoop started.")
-
- // Send another line, just to be sure :-)
- h002.assertNotCalled("002 handler called before expected.")
- l2 := ParseLine(":irc.server.org 002 test :Second test line.")
- c.in <- l2
- h002.assertWasCalled("002 handler not called while runLoop started.")
-
- // Now, use the control channel to exit send and kill the goroutine.
- // This sneakily uses the fact that the other two goroutines that would
- // normally be waiting for die to close are not running, so we only send
- // to the goroutine started above. Normally Close() closes c.die and
- // signals to all three goroutines (send, ping, runLoop) to exit.
- exited.assertNotCalled("Exited before signal sent.")
- c.die <- struct{}{}
- exited.assertWasCalled("Didn't exit after signal.")
-
- // Sending more on c.in shouldn't dispatch any further events
- c.in <- l1
- h001.assertNotCalled("001 handler called after runLoop ended.")
-}
-
-func TestWrite(t *testing.T) {
- // Passing a second value to setUp stops goroutines from starting
- c, s := setUp(t, false)
- // We can't use tearDown here because we're testing shutdown conditions
- // (and so need to EXPECT() a call to st.Wipe() in the right place)
- defer s.ctrl.Finish()
-
- // Write should just write a line to the socket.
- if err := c.write("yo momma"); err != nil {
- t.Errorf("Write returned unexpected error %v", err)
- }
- s.nc.Expect("yo momma")
-
- // Flood control is disabled -- setUp sets c.cfg.Flood = true -- so we should
- // not have set c.badness at this point.
- if c.badness != 0 {
- t.Errorf("Flood control used when Flood = true.")
- }
-
- c.cfg.Flood = false
- if err := c.write("she so useless"); err != nil {
- t.Errorf("Write returned unexpected error %v", err)
- }
- s.nc.Expect("she so useless")
-
- // The lastsent time should have been updated very recently...
- if time.Now().Sub(c.lastsent) > time.Millisecond {
- t.Errorf("Flood control not used when Flood = false.")
- }
-
- // Finally, test the error state by closing the socket then writing.
- s.nc.Close()
- if err := c.write("she can't pass unit tests"); err == nil {
- t.Errorf("Expected write to return error after socket close.")
- }
-}
-
-func TestRateLimit(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- if c.badness != 0 {
- t.Errorf("Bad initial values for rate limit variables.")
- }
-
- // We'll be needing this later...
- abs := func(i time.Duration) time.Duration {
- if i < 0 {
- return -i
- }
- return i
- }
-
- // Since the changes to the time module, c.lastsent is now a time.Time.
- // It's initialised on client creation to time.Now() which for the purposes
- // of this test was probably around 1.2 ms ago. This is inconvenient.
- // Making it >10s ago effectively clears out the inconsistency, as this
- // makes elapsed > linetime and thus zeros c.badness and resets c.lastsent.
- c.lastsent = time.Now().Add(-10 * time.Second)
- if l := c.rateLimit(60); l != 0 || c.badness != 0 {
- t.Errorf("Rate limit got non-zero badness from long-ago lastsent.")
- }
-
- // So, time at the nanosecond resolution is a bit of a bitch. Choosing 60
- // characters as the line length means we should be increasing badness by
- // 2.5 seconds minus the delta between the two ratelimit calls. This should
- // be minimal but it's guaranteed that it won't be zero. Use 20us as a fuzz.
- if l := c.rateLimit(60); l != 0 ||
- abs(c.badness-2500*time.Millisecond) > 20*time.Microsecond {
- t.Errorf("Rate limit calculating badness incorrectly.")
- }
- // At this point, we can tip over the badness scale, with a bit of help.
- // 720 chars => +8 seconds of badness => 10.5 seconds => ratelimit
- if l := c.rateLimit(720); l != 8*time.Second ||
- abs(c.badness-10500*time.Millisecond) > 20*time.Microsecond {
- t.Errorf("Rate limit failed to return correct limiting values.")
- t.Errorf("l=%d, badness=%d", l, c.badness)
- }
-}
diff --git a/vendor/github.com/fluffle/goirc/client/dispatch_test.go b/vendor/github.com/fluffle/goirc/client/dispatch_test.go
deleted file mode 100644
index b79df64..0000000
--- a/vendor/github.com/fluffle/goirc/client/dispatch_test.go
+++ /dev/null
@@ -1,201 +0,0 @@
-package client
-
-import (
- "sync/atomic"
- "testing"
- "time"
-)
-
-func TestHandlerSet(t *testing.T) {
- // A Conn is needed here because the previous behaviour of passing nil to
- // hset.dispatch causes a nil pointer dereference with panic recovery.
- c, s := setUp(t)
- defer s.tearDown()
-
- hs := handlerSet()
- if len(hs.set) != 0 {
- t.Errorf("New set contains things!")
- }
-
- callcount := new(int32)
- f := func(_ *Conn, _ *Line) {
- atomic.AddInt32(callcount, 1)
- }
-
- // Add one
- hn1 := hs.add("ONE", HandlerFunc(f)).(*hNode)
- hl, ok := hs.set["one"]
- if len(hs.set) != 1 || !ok {
- t.Errorf("Set doesn't contain 'one' list after add().")
- }
- if hn1.set != hs || hn1.event != "one" || hn1.prev != nil || hn1.next != nil {
- t.Errorf("First node for 'one' not created correctly")
- }
- if hl.start != hn1 || hl.end != hn1 {
- t.Errorf("Node not added to empty 'one' list correctly.")
- }
-
- // Add another one...
- hn2 := hs.add("one", HandlerFunc(f)).(*hNode)
- if len(hs.set) != 1 {
- t.Errorf("Set contains more than 'one' list after add().")
- }
- if hn2.set != hs || hn2.event != "one" {
- t.Errorf("Second node for 'one' not created correctly")
- }
- if hn1.prev != nil || hn1.next != hn2 || hn2.prev != hn1 || hn2.next != nil {
- t.Errorf("Nodes for 'one' not linked correctly.")
- }
- if hl.start != hn1 || hl.end != hn2 {
- t.Errorf("Node not appended to 'one' list correctly.")
- }
-
- // Add a third one!
- hn3 := hs.add("one", HandlerFunc(f)).(*hNode)
- if len(hs.set) != 1 {
- t.Errorf("Set contains more than 'one' list after add().")
- }
- if hn3.set != hs || hn3.event != "one" {
- t.Errorf("Third node for 'one' not created correctly")
- }
- if hn1.prev != nil || hn1.next != hn2 ||
- hn2.prev != hn1 || hn2.next != hn3 ||
- hn3.prev != hn2 || hn3.next != nil {
- t.Errorf("Nodes for 'one' not linked correctly.")
- }
- if hl.start != hn1 || hl.end != hn3 {
- t.Errorf("Node not appended to 'one' list correctly.")
- }
-
- // And finally a fourth one!
- hn4 := hs.add("one", HandlerFunc(f)).(*hNode)
- if len(hs.set) != 1 {
- t.Errorf("Set contains more than 'one' list after add().")
- }
- if hn4.set != hs || hn4.event != "one" {
- t.Errorf("Fourth node for 'one' not created correctly.")
- }
- if hn1.prev != nil || hn1.next != hn2 ||
- hn2.prev != hn1 || hn2.next != hn3 ||
- hn3.prev != hn2 || hn3.next != hn4 ||
- hn4.prev != hn3 || hn4.next != nil {
- t.Errorf("Nodes for 'one' not linked correctly.")
- }
- if hl.start != hn1 || hl.end != hn4 {
- t.Errorf("Node not appended to 'one' list correctly.")
- }
-
- // Dispatch should result in 4 additions.
- if atomic.LoadInt32(callcount) != 0 {
- t.Errorf("Something incremented call count before we were expecting it.")
- }
- hs.dispatch(c, &Line{Cmd: "One"})
- <-time.After(time.Millisecond)
- if atomic.LoadInt32(callcount) != 4 {
- t.Errorf("Our handler wasn't called four times :-(")
- }
-
- // Remove node 3.
- hn3.Remove()
- if len(hs.set) != 1 {
- t.Errorf("Set list count changed after remove().")
- }
- if hn3.set != nil || hn3.prev != nil || hn3.next != nil {
- t.Errorf("Third node for 'one' not removed correctly.")
- }
- if hn1.prev != nil || hn1.next != hn2 ||
- hn2.prev != hn1 || hn2.next != hn4 ||
- hn4.prev != hn2 || hn4.next != nil {
- t.Errorf("Third node for 'one' not unlinked correctly.")
- }
- if hl.start != hn1 || hl.end != hn4 {
- t.Errorf("Third node for 'one' changed list pointers.")
- }
-
- // Dispatch should result in 3 additions.
- hs.dispatch(c, &Line{Cmd: "One"})
- <-time.After(time.Millisecond)
- if atomic.LoadInt32(callcount) != 7 {
- t.Errorf("Our handler wasn't called three times :-(")
- }
-
- // Remove node 1.
- hs.remove(hn1)
- if len(hs.set) != 1 {
- t.Errorf("Set list count changed after remove().")
- }
- if hn1.set != nil || hn1.prev != nil || hn1.next != nil {
- t.Errorf("First node for 'one' not removed correctly.")
- }
- if hn2.prev != nil || hn2.next != hn4 || hn4.prev != hn2 || hn4.next != nil {
- t.Errorf("First node for 'one' not unlinked correctly.")
- }
- if hl.start != hn2 || hl.end != hn4 {
- t.Errorf("First node for 'one' didn't change list pointers.")
- }
-
- // Dispatch should result in 2 additions.
- hs.dispatch(c, &Line{Cmd: "One"})
- <-time.After(time.Millisecond)
- if atomic.LoadInt32(callcount) != 9 {
- t.Errorf("Our handler wasn't called two times :-(")
- }
-
- // Remove node 4.
- hn4.Remove()
- if len(hs.set) != 1 {
- t.Errorf("Set list count changed after remove().")
- }
- if hn4.set != nil || hn4.prev != nil || hn4.next != nil {
- t.Errorf("Fourth node for 'one' not removed correctly.")
- }
- if hn2.prev != nil || hn2.next != nil {
- t.Errorf("Fourth node for 'one' not unlinked correctly.")
- }
- if hl.start != hn2 || hl.end != hn2 {
- t.Errorf("Fourth node for 'one' didn't change list pointers.")
- }
-
- // Dispatch should result in 1 addition.
- hs.dispatch(c, &Line{Cmd: "One"})
- <-time.After(time.Millisecond)
- if atomic.LoadInt32(callcount) != 10 {
- t.Errorf("Our handler wasn't called once :-(")
- }
-
- // Remove node 2.
- hs.remove(hn2)
- if len(hs.set) != 0 {
- t.Errorf("Removing last node in 'one' didn't remove list.")
- }
- if hn2.set != nil || hn2.prev != nil || hn2.next != nil {
- t.Errorf("Second node for 'one' not removed correctly.")
- }
- if hl.start != nil || hl.end != nil {
- t.Errorf("Second node for 'one' didn't change list pointers.")
- }
-
- // Dispatch should result in NO additions.
- hs.dispatch(c, &Line{Cmd: "One"})
- <-time.After(time.Millisecond)
- if atomic.LoadInt32(callcount) != 10 {
- t.Errorf("Our handler was called?")
- }
-}
-
-func TestPanicRecovery(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- recovered := callCheck(t)
- c.cfg.Recover = func(conn *Conn, line *Line) {
- if err, ok := recover().(string); ok && err == "panic!" {
- recovered.call()
- }
- }
- c.HandleFunc(PRIVMSG, func(conn *Conn, line *Line) {
- panic("panic!")
- })
- c.in <- ParseLine(":nick!user@host.com PRIVMSG #channel :OH NO PIGEONS")
- recovered.assertWasCalled("Failed to recover panic!")
-}
diff --git a/vendor/github.com/fluffle/goirc/client/handlers_test.go b/vendor/github.com/fluffle/goirc/client/handlers_test.go
deleted file mode 100644
index 7808022..0000000
--- a/vendor/github.com/fluffle/goirc/client/handlers_test.go
+++ /dev/null
@@ -1,451 +0,0 @@
-package client
-
-import (
- "github.com/fluffle/goirc/state"
- "github.com/golang/mock/gomock"
- "testing"
- "time"
-)
-
-// This test performs a simple end-to-end verification of correct line parsing
-// and event dispatch as well as testing the PING handler. All the other tests
-// in this file will call their respective handlers synchronously, otherwise
-// testing becomes more difficult.
-func TestPING(t *testing.T) {
- _, s := setUp(t)
- defer s.tearDown()
- s.nc.Send("PING :1234567890")
- s.nc.Expect("PONG :1234567890")
-}
-
-// Test the REGISTER handler matches section 3.1 of rfc2812
-func TestREGISTER(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- c.h_REGISTER(&Line{Cmd: REGISTER})
- s.nc.Expect("NICK test")
- s.nc.Expect("USER test 12 * :Testing IRC")
- s.nc.ExpectNothing()
-
- c.cfg.Pass = "12345"
- c.cfg.Me.Ident = "idiot"
- c.cfg.Me.Name = "I've got the same combination on my luggage!"
- c.h_REGISTER(&Line{Cmd: REGISTER})
- s.nc.Expect("PASS 12345")
- s.nc.Expect("NICK test")
- s.nc.Expect("USER idiot 12 * :I've got the same combination on my luggage!")
- s.nc.ExpectNothing()
-}
-
-// Test the handler for 001 / RPL_WELCOME
-func Test001(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- l := ParseLine(":irc.server.org 001 test :Welcome to IRC test!ident@somehost.com")
- // Set up a handler to detect whether connected handler is called from 001
- hcon := false
- c.HandleFunc("connected", func(conn *Conn, line *Line) {
- hcon = true
- })
-
- // Test state tracking first.
- gomock.InOrder(
- s.st.EXPECT().Me().Return(c.cfg.Me),
- s.st.EXPECT().NickInfo("test", "test", "somehost.com", "Testing IRC"),
- )
- // Call handler with a valid 001 line
- c.h_001(l)
- <-time.After(time.Millisecond)
- if !hcon {
- t.Errorf("001 handler did not dispatch connected event.")
- }
-
- // Now without state tracking.
- c.st = nil
- c.h_001(l)
- // Check host parsed correctly
- if c.cfg.Me.Host != "somehost.com" {
- t.Errorf("Host parsing failed, host is '%s'.", c.cfg.Me.Host)
- }
- c.st = s.st
-}
-
-// Test the handler for 433 / ERR_NICKNAMEINUSE
-func Test433(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Call handler with a 433 line, not triggering c.cfg.Me.Renick()
- s.st.EXPECT().Me().Return(c.cfg.Me)
- c.h_433(ParseLine(":irc.server.org 433 test new :Nickname is already in use."))
- s.nc.Expect("NICK new_")
-
- // Send a line that will trigger a renick. This happens when our wanted
- // nick is unavailable during initial negotiation, so we must choose a
- // different one before the connection can proceed. No NICK line will be
- // sent by the server to confirm nick change in this case.
- gomock.InOrder(
- s.st.EXPECT().Me().Return(c.cfg.Me),
- s.st.EXPECT().ReNick("test", "test_").Return(c.cfg.Me),
- )
- c.h_433(ParseLine(":irc.server.org 433 test test :Nickname is already in use."))
- s.nc.Expect("NICK test_")
-
- // Test the code path that *doesn't* involve state tracking.
- c.st = nil
- c.h_433(ParseLine(":irc.server.org 433 test test :Nickname is already in use."))
- s.nc.Expect("NICK test_")
-
- if c.cfg.Me.Nick != "test_" {
- t.Errorf("My nick not updated from '%s'.", c.cfg.Me.Nick)
- }
- c.st = s.st
-}
-
-// Test the handler for NICK messages when state tracking is disabled
-func TestNICK(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // State tracking is enabled by default in setUp
- c.st = nil
-
- // Call handler with a NICK line changing "our" nick to test1.
- c.h_NICK(ParseLine(":test!test@somehost.com NICK :test1"))
-
- // Verify that our Nick has changed
- if c.cfg.Me.Nick != "test1" {
- t.Errorf("NICK did not result in changing our nick.")
- }
-
- // Send a NICK line for something that isn't us.
- c.h_NICK(ParseLine(":blah!moo@cows.com NICK :milk"))
-
- // Verify that our Nick hasn't changed
- if c.cfg.Me.Nick != "test1" {
- t.Errorf("NICK did not result in changing our nick.")
- }
-
- // Re-enable state tracking and send a line that *should* change nick.
- c.st = s.st
- c.h_NICK(ParseLine(":test1!test@somehost.com NICK :test2"))
-
- // Verify that our Nick hasn't changed (should be handled by h_STNICK).
- if c.cfg.Me.Nick != "test1" {
- t.Errorf("NICK changed our nick when state tracking enabled.")
- }
-}
-
-// Test the handler for CTCP messages
-func TestCTCP(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Call handler with CTCP VERSION
- c.h_CTCP(ParseLine(":blah!moo@cows.com PRIVMSG test :\001VERSION\001"))
-
- // Expect a version reply
- s.nc.Expect("NOTICE blah :\001VERSION Powered by GoIRC\001")
-
- // Call handler with CTCP PING
- c.h_CTCP(ParseLine(":blah!moo@cows.com PRIVMSG test :\001PING 1234567890\001"))
-
- // Expect a ping reply
- s.nc.Expect("NOTICE blah :\001PING 1234567890\001")
-
- // Call handler with CTCP UNKNOWN
- c.h_CTCP(ParseLine(":blah!moo@cows.com PRIVMSG test :\001UNKNOWN ctcp\001"))
-}
-
-// Test the handler for JOIN messages
-func TestJOIN(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // The state tracker should be creating a new channel in this first test
- chan1 := &state.Channel{Name: "#test1"}
-
- gomock.InOrder(
- s.st.EXPECT().GetChannel("#test1").Return(nil),
- s.st.EXPECT().GetNick("test").Return(c.cfg.Me),
- s.st.EXPECT().Me().Return(c.cfg.Me),
- s.st.EXPECT().NewChannel("#test1").Return(chan1),
- s.st.EXPECT().Associate("#test1", "test"),
- )
-
- // Use #test1 to test expected behaviour
- // Call handler with JOIN by test to #test1
- c.h_JOIN(ParseLine(":test!test@somehost.com JOIN :#test1"))
-
- // Verify that the MODE and WHO commands are sent correctly
- s.nc.Expect("MODE #test1")
- s.nc.Expect("WHO #test1")
-
- // In this second test, we should be creating a new nick
- nick1 := &state.Nick{Nick: "user1"}
-
- gomock.InOrder(
- s.st.EXPECT().GetChannel("#test1").Return(chan1),
- s.st.EXPECT().GetNick("user1").Return(nil),
- s.st.EXPECT().NewNick("user1").Return(nick1),
- s.st.EXPECT().NickInfo("user1", "ident1", "host1.com", "").Return(nick1),
- s.st.EXPECT().Associate("#test1", "user1"),
- )
-
- // OK, now #test1 exists, JOIN another user we don't know about
- c.h_JOIN(ParseLine(":user1!ident1@host1.com JOIN :#test1"))
-
- // Verify that the WHO command is sent correctly
- s.nc.Expect("WHO user1")
-
- // In this third test, we'll be pretending we know about the nick already.
- nick2 := &state.Nick{Nick: "user2"}
- gomock.InOrder(
- s.st.EXPECT().GetChannel("#test1").Return(chan1),
- s.st.EXPECT().GetNick("user2").Return(nick2),
- s.st.EXPECT().Associate("#test1", "user2"),
- )
- c.h_JOIN(ParseLine(":user2!ident2@host2.com JOIN :#test1"))
-
- // Test error paths
- gomock.InOrder(
- // unknown channel, unknown nick
- s.st.EXPECT().GetChannel("#test2").Return(nil),
- s.st.EXPECT().GetNick("blah").Return(nil),
- s.st.EXPECT().Me().Return(c.cfg.Me),
- // unknown channel, known nick that isn't Me.
- s.st.EXPECT().GetChannel("#test2").Return(nil),
- s.st.EXPECT().GetNick("user2").Return(nick2),
- s.st.EXPECT().Me().Return(c.cfg.Me),
- )
- c.h_JOIN(ParseLine(":blah!moo@cows.com JOIN :#test2"))
- c.h_JOIN(ParseLine(":user2!ident2@host2.com JOIN :#test2"))
-}
-
-// Test the handler for PART messages
-func TestPART(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // PART should dissociate a nick from a channel.
- s.st.EXPECT().Dissociate("#test1", "user1")
- c.h_PART(ParseLine(":user1!ident1@host1.com PART #test1 :Bye!"))
-}
-
-// Test the handler for KICK messages
-// (this is very similar to the PART message test)
-func TestKICK(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // KICK should dissociate a nick from a channel.
- s.st.EXPECT().Dissociate("#test1", "user1")
- c.h_KICK(ParseLine(":test!test@somehost.com KICK #test1 user1 :Bye!"))
-}
-
-// Test the handler for QUIT messages
-func TestQUIT(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Have user1 QUIT. All possible errors handled by state tracker \o/
- s.st.EXPECT().DelNick("user1")
- c.h_QUIT(ParseLine(":user1!ident1@host1.com QUIT :Bye!"))
-}
-
-// Test the handler for MODE messages
-func TestMODE(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Channel modes
- gomock.InOrder(
- s.st.EXPECT().GetChannel("#test1").Return(&state.Channel{Name: "#test1"}),
- s.st.EXPECT().ChannelModes("#test1", "+sk", "somekey"),
- )
- c.h_MODE(ParseLine(":user1!ident1@host1.com MODE #test1 +sk somekey"))
-
- // Nick modes for Me.
- gomock.InOrder(
- s.st.EXPECT().GetChannel("test").Return(nil),
- s.st.EXPECT().GetNick("test").Return(c.cfg.Me),
- s.st.EXPECT().Me().Return(c.cfg.Me),
- s.st.EXPECT().NickModes("test", "+i"),
- )
- c.h_MODE(ParseLine(":test!test@somehost.com MODE test +i"))
-
- // Check error paths
- gomock.InOrder(
- // send a valid user mode that's not us
- s.st.EXPECT().GetChannel("user1").Return(nil),
- s.st.EXPECT().GetNick("user1").Return(&state.Nick{Nick: "user1"}),
- s.st.EXPECT().Me().Return(c.cfg.Me),
- // Send a random mode for an unknown channel
- s.st.EXPECT().GetChannel("#test2").Return(nil),
- s.st.EXPECT().GetNick("#test2").Return(nil),
- )
- c.h_MODE(ParseLine(":user1!ident1@host1.com MODE user1 +w"))
- c.h_MODE(ParseLine(":user1!ident1@host1.com MODE #test2 +is"))
-}
-
-// Test the handler for TOPIC messages
-func TestTOPIC(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Ensure TOPIC reply calls Topic
- gomock.InOrder(
- s.st.EXPECT().GetChannel("#test1").Return(&state.Channel{Name: "#test1"}),
- s.st.EXPECT().Topic("#test1", "something something"),
- )
- c.h_TOPIC(ParseLine(":user1!ident1@host1.com TOPIC #test1 :something something"))
-
- // Check error paths -- send a topic for an unknown channel
- s.st.EXPECT().GetChannel("#test2").Return(nil)
- c.h_TOPIC(ParseLine(":user1!ident1@host1.com TOPIC #test2 :dark side"))
-}
-
-// Test the handler for 311 / RPL_WHOISUSER
-func Test311(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Ensure 311 reply calls NickInfo
- gomock.InOrder(
- s.st.EXPECT().GetNick("user1").Return(&state.Nick{Nick: "user1"}),
- s.st.EXPECT().Me().Return(c.cfg.Me),
- s.st.EXPECT().NickInfo("user1", "ident1", "host1.com", "name"),
- )
- c.h_311(ParseLine(":irc.server.org 311 test user1 ident1 host1.com * :name"))
-
- // Check error paths -- send a 311 for an unknown nick
- s.st.EXPECT().GetNick("user2").Return(nil)
- c.h_311(ParseLine(":irc.server.org 311 test user2 ident2 host2.com * :dongs"))
-}
-
-// Test the handler for 324 / RPL_CHANNELMODEIS
-func Test324(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Ensure 324 reply calls ChannelModes
- gomock.InOrder(
- s.st.EXPECT().GetChannel("#test1").Return(&state.Channel{Name: "#test1"}),
- s.st.EXPECT().ChannelModes("#test1", "+sk", "somekey"),
- )
- c.h_324(ParseLine(":irc.server.org 324 test #test1 +sk somekey"))
-
- // Check error paths -- send 324 for an unknown channel
- s.st.EXPECT().GetChannel("#test2").Return(nil)
- c.h_324(ParseLine(":irc.server.org 324 test #test2 +pmt"))
-}
-
-// Test the handler for 332 / RPL_TOPIC
-func Test332(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Ensure 332 reply calls Topic
- gomock.InOrder(
- s.st.EXPECT().GetChannel("#test1").Return(&state.Channel{Name: "#test1"}),
- s.st.EXPECT().Topic("#test1", "something something"),
- )
- c.h_332(ParseLine(":irc.server.org 332 test #test1 :something something"))
-
- // Check error paths -- send 332 for an unknown channel
- s.st.EXPECT().GetChannel("#test2").Return(nil)
- c.h_332(ParseLine(":irc.server.org 332 test #test2 :dark side"))
-}
-
-// Test the handler for 352 / RPL_WHOREPLY
-func Test352(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Ensure 352 reply calls NickInfo and NickModes
- gomock.InOrder(
- s.st.EXPECT().GetNick("user1").Return(&state.Nick{Nick: "user1"}),
- s.st.EXPECT().Me().Return(c.cfg.Me),
- s.st.EXPECT().NickInfo("user1", "ident1", "host1.com", "name"),
- )
- c.h_352(ParseLine(":irc.server.org 352 test #test1 ident1 host1.com irc.server.org user1 G :0 name"))
-
- // Check that modes are set correctly from WHOREPLY
- gomock.InOrder(
- s.st.EXPECT().GetNick("user1").Return(&state.Nick{Nick: "user1"}),
- s.st.EXPECT().Me().Return(c.cfg.Me),
- s.st.EXPECT().NickInfo("user1", "ident1", "host1.com", "name"),
- s.st.EXPECT().NickModes("user1", "+o"),
- s.st.EXPECT().NickModes("user1", "+i"),
- )
- c.h_352(ParseLine(":irc.server.org 352 test #test1 ident1 host1.com irc.server.org user1 H* :0 name"))
-
- // Check error paths -- send a 352 for an unknown nick
- s.st.EXPECT().GetNick("user2").Return(nil)
- c.h_352(ParseLine(":irc.server.org 352 test #test2 ident2 host2.com irc.server.org user2 G :0 fooo"))
-}
-
-// Test the handler for 353 / RPL_NAMREPLY
-func Test353(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // 353 handler is called twice, so GetChannel will be called twice
- s.st.EXPECT().GetChannel("#test1").Return(&state.Channel{Name: "#test1"}).Times(2)
- gomock.InOrder(
- // "test" is Me, i am known, and already on the channel
- s.st.EXPECT().GetNick("test").Return(c.cfg.Me),
- s.st.EXPECT().IsOn("#test1", "test").Return(&state.ChanPrivs{}, true),
- // user1 is known, but not on the channel, so should be associated
- s.st.EXPECT().GetNick("user1").Return(&state.Nick{Nick: "user1"}),
- s.st.EXPECT().IsOn("#test1", "user1").Return(nil, false),
- s.st.EXPECT().Associate("#test1", "user1").Return(&state.ChanPrivs{}),
- s.st.EXPECT().ChannelModes("#test1", "+o", "user1"),
- )
- for n, m := range map[string]string{
- "user2": "",
- "voice": "+v",
- "halfop": "+h",
- "op": "+o",
- "admin": "+a",
- "owner": "+q",
- } {
- calls := []*gomock.Call{
- s.st.EXPECT().GetNick(n).Return(nil),
- s.st.EXPECT().NewNick(n).Return(&state.Nick{Nick: n}),
- s.st.EXPECT().IsOn("#test1", n).Return(nil, false),
- s.st.EXPECT().Associate("#test1", n).Return(&state.ChanPrivs{}),
- }
- if m != "" {
- calls = append(calls, s.st.EXPECT().ChannelModes("#test1", m, n))
- }
- gomock.InOrder(calls...)
- }
-
- // Send a couple of names replies (complete with trailing space)
- c.h_353(ParseLine(":irc.server.org 353 test = #test1 :test @user1 user2 +voice "))
- c.h_353(ParseLine(":irc.server.org 353 test = #test1 :%halfop @op &admin ~owner "))
-
- // Check error paths -- send 353 for an unknown channel
- s.st.EXPECT().GetChannel("#test2").Return(nil)
- c.h_353(ParseLine(":irc.server.org 353 test = #test2 :test ~user3"))
-}
-
-// Test the handler for 671 (unreal specific)
-func Test671(t *testing.T) {
- c, s := setUp(t)
- defer s.tearDown()
-
- // Ensure 671 reply calls NickModes
- gomock.InOrder(
- s.st.EXPECT().GetNick("user1").Return(&state.Nick{Nick: "user1"}),
- s.st.EXPECT().NickModes("user1", "+z"),
- )
- c.h_671(ParseLine(":irc.server.org 671 test user1 :some ignored text"))
-
- // Check error paths -- send a 671 for an unknown nick
- s.st.EXPECT().GetNick("user2").Return(nil)
- c.h_671(ParseLine(":irc.server.org 671 test user2 :some ignored text"))
-}
diff --git a/vendor/github.com/fluffle/goirc/client/line_test.go b/vendor/github.com/fluffle/goirc/client/line_test.go
deleted file mode 100644
index 88b758d..0000000
--- a/vendor/github.com/fluffle/goirc/client/line_test.go
+++ /dev/null
@@ -1,186 +0,0 @@
-package client
-
-import (
- "reflect"
- "testing"
- "time"
-)
-
-func TestLineCopy(t *testing.T) {
- l1 := &Line{
- Tags: map[string]string{"foo": "bar", "fizz": "buzz"},
- Nick: "nick",
- Ident: "ident",
- Host: "host",
- Src: "src",
- Cmd: "cmd",
- Raw: "raw",
- Args: []string{"arg", "text"},
- Time: time.Now(),
- }
-
- l2 := l1.Copy()
-
- // Ugly. Couldn't be bothered to bust out reflect and actually think.
- if l2.Tags == nil || l2.Tags["foo"] != "bar" || l2.Tags["fizz"] != "buzz" ||
- l2.Nick != "nick" || l2.Ident != "ident" || l2.Host != "host" ||
- l2.Src != "src" || l2.Cmd != "cmd" || l2.Raw != "raw" ||
- l2.Args[0] != "arg" || l2.Args[1] != "text" || l2.Time != l1.Time {
- t.Errorf("Line not copied correctly")
- t.Errorf("l1: %#v\nl2: %#v", l1, l2)
- }
-
- // Now, modify l2 and verify l1 not changed
- l2.Tags["foo"] = "baz"
- l2.Nick = l2.Nick[1:]
- l2.Ident = "foo"
- l2.Host = ""
- l2.Args[0] = l2.Args[0][1:]
- l2.Args[1] = "bar"
- l2.Time = time.Now()
-
- if l2.Tags == nil || l2.Tags["foo"] != "baz" || l2.Tags["fizz"] != "buzz" ||
- l1.Nick != "nick" || l1.Ident != "ident" || l1.Host != "host" ||
- l1.Src != "src" || l1.Cmd != "cmd" || l1.Raw != "raw" ||
- l1.Args[0] != "arg" || l1.Args[1] != "text" || l1.Time == l2.Time {
- t.Errorf("Original modified when copy changed")
- t.Errorf("l1: %#v\nl2: %#v", l1, l2)
- }
-}
-
-func TestLineText(t *testing.T) {
- tests := []struct {
- in *Line
- out string
- }{
- {&Line{}, ""},
- {&Line{Args: []string{"one thing"}}, "one thing"},
- {&Line{Args: []string{"one", "two"}}, "two"},
- }
-
- for i, test := range tests {
- out := test.in.Text()
- if out != test.out {
- t.Errorf("test %d: expected: '%s', got '%s'", i, test.out, out)
- }
- }
-}
-
-func TestLineTarget(t *testing.T) {
- tests := []struct {
- in *Line
- out string
- }{
- {&Line{}, ""},
- {&Line{Cmd: JOIN, Args: []string{"#foo"}}, "#foo"},
- {&Line{Cmd: PART, Args: []string{"#foo", "bye"}}, "#foo"},
- {&Line{Cmd: PRIVMSG, Args: []string{"Me", "la"}, Nick: "Them"}, "Them"},
- {&Line{Cmd: NOTICE, Args: []string{"Me", "la"}, Nick: "Them"}, "Them"},
- {&Line{Cmd: ACTION, Args: []string{"Me", "la"}, Nick: "Them"}, "Them"},
- {&Line{Cmd: CTCP, Args: []string{"PING", "Me", "1"}, Nick: "Them"}, "Them"},
- {&Line{Cmd: CTCPREPLY, Args: []string{"PONG", "Me", "2"}, Nick: "Them"}, "Them"},
- {&Line{Cmd: PRIVMSG, Args: []string{"#foo", "la"}, Nick: "Them"}, "#foo"},
- {&Line{Cmd: NOTICE, Args: []string{"&foo", "la"}, Nick: "Them"}, "&foo"},
- {&Line{Cmd: ACTION, Args: []string{"!foo", "la"}, Nick: "Them"}, "!foo"},
- {&Line{Cmd: CTCP, Args: []string{"PING", "#foo", "1"}, Nick: "Them"}, "#foo"},
- {&Line{Cmd: CTCPREPLY, Args: []string{"PONG", "#foo", "2"}, Nick: "Them"}, "#foo"},
- }
-
- for i, test := range tests {
- out := test.in.Target()
- if out != test.out {
- t.Errorf("test %d: expected: '%s', got '%s'", i, test.out, out)
- }
- }
-}
-
-func TestLineTags(t *testing.T) {
- tests := []struct {
- in string
- out *Line
- }{
- { // Make sure ERROR lines work
- "ERROR :Closing Link: example.org (Too many user connections (global))",
- &Line{
- Nick: "",
- Ident: "",
- Host: "",
- Src: "",
- Cmd: ERROR,
- Raw: "ERROR :Closing Link: example.org (Too many user connections (global))",
- Args: []string{"Closing Link: example.org (Too many user connections (global))"},
- },
- },
- { // Make sure non-tagged lines work
- ":nick!ident@host.com PRIVMSG me :Hello",
- &Line{
- Nick: "nick",
- Ident: "ident",
- Host: "host.com",
- Src: "nick!ident@host.com",
- Cmd: PRIVMSG,
- Raw: ":nick!ident@host.com PRIVMSG me :Hello",
- Args: []string{"me", "Hello"},
- },
- },
- { // Tags example from the spec
- "@aaa=bbb;ccc;example.com/ddd=eee :nick!ident@host.com PRIVMSG me :Hello",
- &Line{
- Tags: map[string]string{"aaa": "bbb", "ccc": "", "example.com/ddd": "eee"},
- Nick: "nick",
- Ident: "ident",
- Host: "host.com",
- Src: "nick!ident@host.com",
- Cmd: PRIVMSG,
- Raw: "@aaa=bbb;ccc;example.com/ddd=eee :nick!ident@host.com PRIVMSG me :Hello",
- Args: []string{"me", "Hello"},
- },
- },
- { // Test escaped characters
- "@\\:=\\:;\\s=\\s;\\r=\\r;\\n=\\n :nick!ident@host.com PRIVMSG me :Hello",
- &Line{
- Tags: map[string]string{";": ";", " ": " ", "\r": "\r", "\n": "\n"},
- Nick: "nick",
- Ident: "ident",
- Host: "host.com",
- Src: "nick!ident@host.com",
- Cmd: PRIVMSG,
- Raw: "@\\:=\\:;\\s=\\s;\\r=\\r;\\n=\\n :nick!ident@host.com PRIVMSG me :Hello",
- Args: []string{"me", "Hello"},
- },
- },
- { // Skip empty tag
- "@a=a; :nick!ident@host.com PRIVMSG me :Hello",
- &Line{
- Tags: map[string]string{"a": "a"},
- Nick: "nick",
- Ident: "ident",
- Host: "host.com",
- Src: "nick!ident@host.com",
- Cmd: PRIVMSG,
- Raw: "@a=a; :nick!ident@host.com PRIVMSG me :Hello",
- Args: []string{"me", "Hello"},
- },
- },
- { // = in tag
- "@a=a=a; :nick!ident@host.com PRIVMSG me :Hello",
- &Line{
- Tags: map[string]string{"a": "a=a"},
- Nick: "nick",
- Ident: "ident",
- Host: "host.com",
- Src: "nick!ident@host.com",
- Cmd: PRIVMSG,
- Raw: "@a=a=a; :nick!ident@host.com PRIVMSG me :Hello",
- Args: []string{"me", "Hello"},
- },
- },
- }
-
- for i, test := range tests {
- got := ParseLine(test.in)
- if !reflect.DeepEqual(got, test.out) {
- t.Errorf("test %d:\nexpected %#v\ngot %#v", i, test.out, got)
- }
- }
-}
diff --git a/vendor/github.com/fluffle/goirc/client/mocknetconn_test.go b/vendor/github.com/fluffle/goirc/client/mocknetconn_test.go
deleted file mode 100644
index e736c88..0000000
--- a/vendor/github.com/fluffle/goirc/client/mocknetconn_test.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package client
-
-import (
- "io"
- "net"
- "os"
- "strings"
- "testing"
- "time"
-)
-
-type mockNetConn struct {
- *testing.T
-
- In, Out chan string
- in, out chan []byte
- die chan struct{}
-
- closed bool
- rt, wt time.Time
-}
-
-func MockNetConn(t *testing.T) *mockNetConn {
- // Our mock connection is a testing object
- m := &mockNetConn{T: t, die: make(chan struct{})}
-
- // buffer input
- m.In = make(chan string, 20)
- m.in = make(chan []byte)
- go func() {
- for {
- select {
- case <-m.die:
- return
- case s := <-m.In:
- m.in <- []byte(s)
- }
- }
- }()
-
- // buffer output
- m.Out = make(chan string)
- m.out = make(chan []byte, 20)
- go func() {
- for {
- select {
- case <-m.die:
- return
- case b := <-m.out:
- m.Out <- string(b)
- }
- }
- }()
-
- return m
-}
-
-// Test helpers
-func (m *mockNetConn) Send(s string) {
- m.In <- s + "\r\n"
-}
-
-func (m *mockNetConn) Expect(e string) {
- select {
- case <-time.After(time.Millisecond):
- m.Errorf("Mock connection did not receive expected output.\n\t"+
- "Expected: '%s', got nothing.", e)
- case s := <-m.Out:
- s = strings.Trim(s, "\r\n")
- if e != s {
- m.Errorf("Mock connection received unexpected value.\n\t"+
- "Expected: '%s'\n\tGot: '%s'", e, s)
- }
- }
-}
-
-func (m *mockNetConn) ExpectNothing() {
- select {
- case <-time.After(time.Millisecond):
- case s := <-m.Out:
- s = strings.Trim(s, "\r\n")
- m.Errorf("Mock connection received unexpected output.\n\t"+
- "Expected nothing, got: '%s'", s)
- }
-}
-
-// Implement net.Conn interface
-func (m *mockNetConn) Read(b []byte) (int, error) {
- if m.Closed() {
- return 0, os.ErrInvalid
- }
- l := 0
- select {
- case s := <-m.in:
- l = len(s)
- copy(b, s)
- case <-m.die:
- return 0, io.EOF
- }
- return l, nil
-}
-
-func (m *mockNetConn) Write(s []byte) (int, error) {
- if m.Closed() {
- return 0, os.ErrInvalid
- }
- b := make([]byte, len(s))
- copy(b, s)
- m.out <- b
- return len(s), nil
-}
-
-func (m *mockNetConn) Close() error {
- if m.Closed() {
- return os.ErrInvalid
- }
- // Shut down *ALL* the goroutines!
- // This will trigger an EOF event in Read() too
- close(m.die)
- return nil
-}
-
-func (m *mockNetConn) Closed() bool {
- select {
- case <-m.die:
- return true
- default:
- return false
- }
-}
-
-func (m *mockNetConn) LocalAddr() net.Addr {
- return &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}
-}
-
-func (m *mockNetConn) RemoteAddr() net.Addr {
- return &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}
-}
-
-func (m *mockNetConn) SetDeadline(t time.Time) error {
- m.rt = t
- m.wt = t
- return nil
-}
-
-func (m *mockNetConn) SetReadDeadline(t time.Time) error {
- m.rt = t
- return nil
-}
-
-func (m *mockNetConn) SetWriteDeadline(t time.Time) error {
- m.wt = t
- return nil
-}