diff --git a/client_test.go b/client_test.go deleted file mode 100644 index 907b39f..0000000 --- a/client_test.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) Liam Stanley . All rights reserved. Use -// of this source code is governed by the MIT license that can be found in -// the LICENSE file. - -package girc - -import ( - "strings" - "testing" - "time" -) - -func TestDisableTracking(t *testing.T) { - client := New(Config{ - Server: "dummy.int", - Port: 6667, - Nick: "test", - User: "test", - Name: "Testing123", - }) - - if len(client.Handlers.internal) < 1 { - t.Fatal("Client.Handlers empty, though just initialized") - } - - client.DisableTracking() - if _, ok := client.Handlers.internal[CAP]; ok { - t.Fatal("Client.Handlers contains capability tracking handlers, though disabled") - } - - client.state.Lock() - defer client.state.Unlock() - - if client.state.channels != nil { - t.Fatal("Client.DisableTracking() called but channel state still exists") - } -} - -func TestConfigValid(t *testing.T) { - conf := Config{ - Server: "irc.example.com", Port: 6667, - Nick: "test", User: "test", Name: "Realname", - } - - var err error - if err = conf.isValid(); err != nil { - t.Fatalf("valid config failed Config.isValid() with: %s", err) - } - - conf.Server = "" - if err = conf.isValid(); err == nil { - t.Fatalf("invalid server passed validation check: %s", err) - } - conf.Server = "irc.example.com" - - conf.Port = 100000 - if err = conf.isValid(); err == nil { - t.Fatalf("invalid port passed validation check: %s", err) - } - conf.Port = 0 // Assumes "default". - if err = conf.isValid(); err != nil { - t.Fatalf("valid default failed validation check: %s", err) - } - if conf.Port != 6667 { - t.Fatal("irc port was not defaulted to 6667") - } - - conf.Nick = "invalid nick" - if err = conf.isValid(); err == nil { - t.Fatalf("invalid nick passed validation check: %s", err) - } - conf.User = "test" - - conf.User = "invalid user" - if err = conf.isValid(); err == nil { - t.Fatalf("invalid user passed validation check: %s", err) - } - conf.User = "test" -} - -func TestClientLifetime(t *testing.T) { - client := New(Config{ - Server: "dummy.int", - Port: 6667, - Nick: "test", - User: "test", - Name: "Testing123", - }) - - tm := client.Lifetime() - - if tm < 0 || tm > 2*time.Second { - t.Fatalf("Client.Lifetime() = %q, out of bounds", tm) - } -} - -func TestClientUptime(t *testing.T) { - c, conn, server := genMockConn() - defer conn.Close() - defer server.Close() - go mockReadBuffer(conn) - - done := make(chan struct{}, 1) - c.Handlers.Add(INITIALIZED, func(c *Client, e Event) { close(done) }) - - go c.MockConnect(server) - defer c.Close() - - select { - case <-done: - case <-time.After(2 * time.Second): - t.Fatal("Client.Uptime() timed out") - } - - uptime, err := c.Uptime() - if err != nil { - t.Fatalf("Client.Uptime() = %s, wanted time", err) - } - - since := time.Since(*uptime) - connsince, err := c.ConnSince() - if err != nil { - t.Fatalf("Client.ConnSince() = %s, wanted time", err) - } - - if since < 0 || since > 4*time.Second || *connsince < 0 || *connsince > 4*time.Second { - t.Fatalf("Client.Uptime() = %q (%q, connsince: %q), out of bounds", uptime, since, connsince) - } - - // Verify the time we got from Client.Uptime() and Client.ConnSince() are - // within reach of eachother. - - if *connsince-since > 2*time.Second { - t.Fatalf("Client.Uptime() (diff) = %q, Client.ConnSince() = %q, differ too much", since, connsince) - } - - if !c.IsConnected() { - t.Fatal("Client.IsConnected() = false, though mock should be true") - } -} - -func TestClientGet(t *testing.T) { - c, conn, server := genMockConn() - defer conn.Close() - defer server.Close() - go mockReadBuffer(conn) - - done := make(chan struct{}, 1) - c.Handlers.Add(INITIALIZED, func(c *Client, e Event) { close(done) }) - - go c.MockConnect(server) - defer c.Close() - - select { - case <-done: - case <-time.After(2 * time.Second): - t.Fatal("timed out during connect") - } - - if nick := c.GetNick(); nick != c.Config.Nick { - t.Fatalf("Client.GetNick() = %q though should be %q", nick, c.Config.Nick) - } - - if user := c.GetIdent(); user != c.Config.User { - t.Fatalf("Client.GetIdent() = %q though should be %q", user, c.Config.User) - } - - if !strings.Contains(c.String(), "connected:true") { - t.Fatalf("Client.String() == %q, doesn't contain 'connected:true'", c.String()) - } -} - -func TestClientClose(t *testing.T) { - c, conn, server := genMockConn() - defer server.Close() - defer conn.Close() - go mockReadBuffer(conn) - - errchan := make(chan error, 1) - done := make(chan struct{}, 1) - - c.Handlers.AddBg(CLOSED, func(c *Client, e Event) { close(done) }) - c.Handlers.AddBg(INITIALIZED, func(c *Client, e Event) { c.Close() }) - - go func() { errchan <- c.MockConnect(server) }() - - defer c.Close() - - select { - case err := <-errchan: - if err == nil { - break - } - - t.Fatalf("connect returned with error when close was invoked: %s", err) - case <-time.After(5 * time.Second): - t.Fatal("Client.Close() timed out") - case <-done: - } -} diff --git a/conn_test.go b/conn_test.go deleted file mode 100644 index ae7ca80..0000000 --- a/conn_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Liam Stanley . All rights reserved. Use -// of this source code is governed by the MIT license that can be found in -// the LICENSE file. - -package girc - -import ( - "bufio" - "bytes" - "net" - "testing" - "time" -) - -func mockBuffers() (in *bytes.Buffer, out *bytes.Buffer, irc *ircConn) { - in = &bytes.Buffer{} - out = &bytes.Buffer{} - irc = &ircConn{ - io: bufio.NewReadWriter(bufio.NewReader(in), bufio.NewWriter(out)), - connected: true, - } - - return in, out, irc -} - -func TestDecode(t *testing.T) { - in, _, c := mockBuffers() - - e := mockEvent() - - in.Write(e.Bytes()) - in.Write(endline) - - event, err := c.decode() - if err != nil { - t.Fatalf("received error during decode: %s", err) - } - - if event.String() != e.String() { - t.Fatalf("event returned from decode not the same as mock event. want %#v, got %#v", e, event) - } - - // Test a failure. - in.WriteString("::abcd\r\n") - event, err = c.decode() - if err == nil { - t.Fatalf("should have failed to parse decoded event. got: %#v", event) - } - - return -} - -func TestEncode(t *testing.T) { - _, out, c := mockBuffers() - - e := mockEvent() - - err := c.encode(e) - if err != nil { - t.Fatalf("received error during encode: %s", err) - } - - line, err := out.ReadString(delim) - if err != nil { - t.Fatalf("received error during check for encoded event: %s", err) - } - - want := e.String() + "\r\n" - - if want != line { - t.Fatalf("encoded line wanted: %q, got: %q", want, line) - } - - return -} - -func TestRate(t *testing.T) { - _, _, c := mockBuffers() - c.lastWrite = time.Now() - if delay := c.rate(100); delay > time.Second { - t.Fatal("first instance of rate is > second") - } - - for i := 0; i < 500; i++ { - c.rate(200) - } - - if delay := c.rate(200); delay > (3 * time.Second) { - t.Fatal("rate delay too high") - } - - return -} - -func genMockConn() (client *Client, clientConn net.Conn, serverConn net.Conn) { - client = New(Config{ - Server: "dummy.int", - Port: 6667, - Nick: "test", - User: "test", - Name: "Testing123", - }) - - conn1, conn2 := net.Pipe() - - return client, conn1, conn2 -} - -func mockReadBuffer(conn net.Conn) { - // Accept all outgoing writes from the client. - b := bufio.NewReader(conn) - for { - conn.SetReadDeadline(time.Now().Add(10 * time.Second)) - _, err := b.ReadString(byte('\n')) - if err != nil { - return - } - } -} diff --git a/state_test.go b/state_test.go deleted file mode 100644 index c856366..0000000 --- a/state_test.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) Liam Stanley . All rights reserved. Use -// of this source code is governed by the MIT license that can be found in -// the LICENSE file. - -package girc - -import ( - "reflect" - "testing" - "time" -) - -func debounce(delay time.Duration, done chan bool, f func()) { - var init bool - for { - select { - case <-done: - init = true - case <-time.After(delay): - if init { - f() - return - } - } - } -} - -const mockConnStartState = `:dummy.int NOTICE * :*** Looking up your hostname... -:dummy.int NOTICE * :*** Checking Ident -:dummy.int NOTICE * :*** Found your hostname -:dummy.int NOTICE * :*** No Ident response -:dummy.int 001 nick :Welcome to the DUMMY Internet Relay Chat Network nick -:dummy.int 005 nick NETWORK=DummyIRC NICKLEN=20 :are supported by this server -:dummy.int 375 nick :- dummy.int Message of the Day - -:dummy.int 372 nick :example motd -:dummy.int 376 nick :End of /MOTD command. -:nick!~user@local.int JOIN #channel * :realname -:dummy.int 332 nick #channel :example topic -:dummy.int 353 nick = #channel :nick!~user@local.int @nick2!nick2@other.int -:dummy.int 366 nick #channel :End of /NAMES list. -:dummy.int 354 nick 1 #channel ~user local.int nick 0 :realname -:dummy.int 354 nick 1 #channel nick2 other.int nick2 nick2 :realname2 -:dummy.int 315 nick #channel :End of /WHO list. -:nick!~user@local.int JOIN #channel2 * :realname -:dummy.int 332 nick #channel2 :example topic -:dummy.int 353 nick = #channel2 :nick!~user@local.int @nick2!nick2@other.int -:dummy.int 366 nick #channel2 :End of /NAMES list. -:dummy.int 354 nick 1 #channel2 ~user local.int nick 0 :realname -:dummy.int 354 nick 1 #channel2 nick2 other.int nick2 nick2 :realname2 -:dummy.int 315 nick #channel2 :End of /WHO list. -` - -const mockConnEndState = `:nick2!nick2@other.int QUIT :example reason -:nick!~user@local.int PART #channel2 :example reason -:nick!~user@local.int NICK newnick -` - -func TestState(t *testing.T) { - c, conn, server := genMockConn() - defer c.Close() - go mockReadBuffer(conn) - - go func() { - err := c.MockConnect(server) - if err != nil { - panic(err) - } - }() - - bounceStart := make(chan bool, 1) - finishStart := make(chan bool, 1) - go debounce(250*time.Millisecond, bounceStart, func() { - if motd := c.ServerMOTD(); motd != "example motd" { - t.Fatalf("Client.ServerMOTD() returned invalid MOTD: %q", motd) - } - - if network := c.NetworkName(); network != "DummyIRC" { - t.Fatalf("Client.NetworkName() returned invalid network name: %q", network) - } - - if caseExample, ok := c.GetServerOption("NICKLEN"); !ok || caseExample != "20" { - t.Fatalf("Client.GetServerOptions returned invalid ISUPPORT variable") - } - - users := c.UserList() - channels := c.ChannelList() - - if !reflect.DeepEqual(users, []string{"nick", "nick2"}) { - // This could fail too, if sorting isn't occurring. - t.Fatalf("got state users %#v, wanted: %#v", users, []string{"nick", "nick2"}) - } - - if !reflect.DeepEqual(channels, []string{"#channel", "#channel2"}) { - // This could fail too, if sorting isn't occurring. - t.Fatalf("got state channels %#v, wanted: %#v", channels, []string{"#channel", "#channel2"}) - } - - fullChannels := c.Channels() - for i := 0; i < len(fullChannels); i++ { - if fullChannels[i].Name != channels[i] { - t.Fatalf("fullChannels name doesn't map to same name in ChannelsList: %q :: %#v", fullChannels[i].Name, channels) - } - } - - fullUsers := c.Users() - for i := 0; i < len(fullUsers); i++ { - if fullUsers[i].Nick != users[i] { - t.Fatalf("fullUsers nick doesn't map to same nick in UsersList: %q :: %#v", fullUsers[i].Nick, users) - } - } - - ch := c.LookupChannel("#channel") - if ch == nil { - t.Fatal("Client.LookupChannel returned nil on existing channel") - } - - adm := ch.Admins(c) - admList := []string{} - for i := 0; i < len(adm); i++ { - admList = append(admList, adm[i].Nick) - } - trusted := ch.Trusted(c) - trustedList := []string{} - for i := 0; i < len(trusted); i++ { - trustedList = append(trustedList, trusted[i].Nick) - } - - if !reflect.DeepEqual(admList, []string{"nick2"}) { - t.Fatalf("got Channel.Admins() == %#v, wanted %#v", admList, []string{"nick2"}) - } - - if !reflect.DeepEqual(trustedList, []string{"nick2"}) { - t.Fatalf("got Channel.Trusted() == %#v, wanted %#v", trustedList, []string{"nick2"}) - } - - if topic := ch.Topic; topic != "example topic" { - t.Fatalf("Channel.Topic == %q, want \"example topic\"", topic) - } - - if in := ch.UserIn("nick"); !in { - t.Fatalf("Channel.UserIn == %t, want %t", in, true) - } - - if users := ch.Users(c); len(users) != 2 { - t.Fatalf("Channel.Users == %#v, wanted length of 2", users) - } - - if h := c.GetHost(); h != "local.int" { - t.Fatalf("Client.GetHost() == %q, want local.int", h) - } - - if nick := c.GetNick(); nick != "nick" { - t.Fatalf("Client.GetNick() == %q, want nick", nick) - } - - if ident := c.GetIdent(); ident != "~user" { - t.Fatalf("Client.GetIdent() == %q, want ~user", ident) - } - - user := c.LookupUser("nick") - if user == nil { - t.Fatal("Client.LookupUser() returned nil on existing user") - } - - if !reflect.DeepEqual(user.ChannelList, []string{"#channel", "#channel2"}) { - t.Fatalf("User.ChannelList == %#v, wanted %#v", user.ChannelList, []string{"#channel", "#channel2"}) - } - - if count := len(user.Channels(c)); count != 2 { - t.Fatalf("len(User.Channels) == %d, want 2", count) - } - - if user.Nick != "nick" { - t.Fatalf("User.Nick == %q, wanted \"nick\"", user.Nick) - } - - if user.Extras.Name != "realname" { - t.Fatalf("User.Extras.Name == %q, wanted \"realname\"", user.Extras.Name) - } - - if user.Host != "local.int" { - t.Fatalf("User.Host == %q, wanted \"local.int\"", user.Host) - } - - if user.Ident != "~user" { - t.Fatalf("User.Ident == %q, wanted \"~user\"", user.Ident) - } - - if !user.InChannel("#channel2") { - t.Fatal("User.InChannel() returned false for existing channel") - } - - finishStart <- true - }) - - cuid := c.Handlers.AddBg(UPDATE_STATE, func(c *Client, e Event) { - bounceStart <- true - }) - - conn.SetDeadline(time.Now().Add(5 * time.Second)) - _, err := conn.Write([]byte(mockConnStartState)) - if err != nil { - panic(err) - } - - select { - case <-finishStart: - case <-time.After(5 * time.Second): - t.Fatal("timed out while waiting for state update start") - } - c.Handlers.Remove(cuid) - - bounceEnd := make(chan bool, 1) - finishEnd := make(chan bool, 1) - go debounce(250*time.Millisecond, bounceEnd, func() { - if !reflect.DeepEqual(c.ChannelList(), []string{"#channel"}) { - t.Fatalf("Client.ChannelList() == %#v, wanted %#v", c.ChannelList(), []string{"#channel"}) - } - - if !reflect.DeepEqual(c.UserList(), []string{"newnick"}) { - t.Fatalf("Client.UserList() == %#v, wanted %#v", c.UserList(), []string{"newnick"}) - } - - user := c.LookupUser("newnick") - if user == nil { - t.Fatal("Client.LookupUser() returned nil for existing user") - } - - if !reflect.DeepEqual(user.ChannelList, []string{"#channel"}) { - t.Fatalf("user.ChannelList == %q, wanted %q", user.ChannelList, []string{"#channel"}) - } - - channel := c.LookupChannel("#channel") - if channel == nil { - t.Fatal("Client.LookupChannel() returned nil for existing channel") - } - - if !reflect.DeepEqual(channel.UserList, []string{"newnick"}) { - t.Fatalf("channel.UserList == %q, wanted %q", channel.UserList, []string{"newnick"}) - } - - finishEnd <- true - }) - - cuid = c.Handlers.AddBg(UPDATE_STATE, func(c *Client, e Event) { - bounceEnd <- true - }) - - conn.SetDeadline(time.Now().Add(5 * time.Second)) - _, err = conn.Write([]byte(mockConnEndState)) - if err != nil { - panic(err) - } - - select { - case <-finishEnd: - case <-time.After(5 * time.Second): - t.Fatal("timed out while waiting for state update end") - } - c.Handlers.Remove(cuid) -}