From 473acc61c8392dc7ae303d91568e179c4f105a76 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 2 Jul 2019 12:12:53 +0200 Subject: add black list --- .../fluffle/goirc/client/commands_test.go | 205 -------- .../fluffle/goirc/client/connection_test.go | 585 --------------------- .../fluffle/goirc/client/dispatch_test.go | 201 ------- .../fluffle/goirc/client/handlers_test.go | 451 ---------------- .../github.com/fluffle/goirc/client/line_test.go | 186 ------- .../fluffle/goirc/client/mocknetconn_test.go | 154 ------ 6 files changed, 1782 deletions(-) delete mode 100644 vendor/github.com/fluffle/goirc/client/commands_test.go delete mode 100644 vendor/github.com/fluffle/goirc/client/connection_test.go delete mode 100644 vendor/github.com/fluffle/goirc/client/dispatch_test.go delete mode 100644 vendor/github.com/fluffle/goirc/client/handlers_test.go delete mode 100644 vendor/github.com/fluffle/goirc/client/line_test.go delete mode 100644 vendor/github.com/fluffle/goirc/client/mocknetconn_test.go (limited to 'vendor/github.com/fluffle/goirc/client') 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 -} -- cgit v1.2.3