irc-go/ircevent/irc_labeledresponse_test.go
2022-05-23 14:26:13 -04:00

308 lines
8.7 KiB
Go

package ircevent
import (
"bytes"
"crypto/rand"
"encoding/hex"
"fmt"
"testing"
"github.com/ergochat/irc-go/ircmsg"
)
const (
multilineName = "draft/multiline"
chathistoryName = "draft/chathistory"
concatTag = "draft/multiline-concat"
playbackCap = "draft/event-playback"
)
func TestLabeledResponse(t *testing.T) {
irccon := connForTesting("go-eventirc", "go-eventirc", false)
irccon.Debug = true
irccon.RequestCaps = []string{"message-tags", "batch", "labeled-response"}
irccon.RealName = "ecf61da38b58"
results := make(map[string]string)
irccon.AddConnectCallback(func(e ircmsg.Message) {
irccon.SendWithLabel(func(batch *Batch) {
if batch == nil {
return
}
for _, line := range batch.Items {
results[line.Command] = line.Params[len(line.Params)-1]
}
irccon.Quit()
}, nil, "WHOIS", irccon.CurrentNick())
})
err := irccon.Connect()
if err != nil {
t.Fatalf("labeled response connection failed: %s", err)
}
irccon.Loop()
// RPL_WHOISUSER, last param is the realname
assertEqual(results["311"], "ecf61da38b58")
if _, ok := results["379"]; !ok {
t.Errorf("Expected 379 RPL_WHOISMODES in response, but not received")
}
assertEqual(len(irccon.batches), 0)
}
func TestLabeledResponseNoCaps(t *testing.T) {
irccon := connForTesting("go-eventirc", "go-eventirc", false)
irccon.Debug = true
irccon.RequestCaps = []string{"message-tags"}
irccon.RealName = "ecf61da38b58"
err := irccon.Connect()
if err != nil {
t.Fatalf("labeled response connection failed: %s", err)
}
go irccon.Loop()
results := make(map[string]string)
err = irccon.SendWithLabel(func(batch *Batch) {
if batch == nil {
return
}
for _, line := range batch.Items {
results[line.Command] = line.Params[len(line.Params)-1]
}
irccon.Quit()
}, nil, "WHOIS", irccon.CurrentNick())
if err != CapabilityNotNegotiated {
t.Errorf("expected capability negotiation error, got %v", err)
}
assertEqual(len(irccon.batches), 0)
irccon.Quit()
}
// test labeled single-line response, and labeled ACK
func TestLabeledResponseSingleResponse(t *testing.T) {
irc := connForTesting("go-eventirc", "go-eventirc", false)
irc.Debug = true
irc.RequestCaps = []string{"message-tags", "batch", "labeled-response"}
err := irc.Connect()
if err != nil {
t.Fatalf("labeled response connection failed: %s", err)
}
go irc.Loop()
channel := fmt.Sprintf("#%s", randomString())
irc.Join(channel)
event := make(chan empty)
err = irc.SendWithLabel(func(batch *Batch) {
if !(batch != nil && batch.Command == "PONG" && batch.Params[len(batch.Params)-1] == "asdf") {
t.Errorf("expected labeled PONG, got %#v", batch)
}
close(event)
}, nil, "PING", "asdf")
<-event
// no-op JOIN will send labeled ACK
event = make(chan empty)
err = irc.SendWithLabel(func(batch *Batch) {
if !(batch != nil && batch.Command == "ACK") {
t.Errorf("expected labeled ACK, got %#v", batch)
}
close(event)
}, nil, "JOIN", channel)
<-event
assertEqual(len(irc.batches), 0)
irc.Quit()
}
func randomString() string {
buf := make([]byte, 8)
rand.Read(buf)
return hex.EncodeToString(buf)
}
func TestNestedBatch(t *testing.T) {
irc := connForTesting("go-eventirc", "go-eventirc", false)
irc.Debug = true
irc.RequestCaps = []string{"message-tags", "batch", "labeled-response", "server-time", multilineName, chathistoryName, playbackCap}
channel := fmt.Sprintf("#%s", randomString())
err := irc.Connect()
if err != nil {
t.Fatalf("labeled response connection failed: %s", err)
}
go irc.Loop()
irc.Join(channel)
irc.Privmsg(channel, "hi")
irc.Send("BATCH", "+123", "draft/multiline", channel)
irc.SendWithTags(map[string]string{"batch": "123"}, "PRIVMSG", channel, "hello")
irc.SendWithTags(map[string]string{"batch": "123"}, "PRIVMSG", channel, "")
irc.SendWithTags(map[string]string{"batch": "123", concatTag: ""}, "PRIVMSG", channel, "how is ")
irc.SendWithTags(map[string]string{"batch": "123"}, "PRIVMSG", channel, "everyone?")
irc.Send("BATCH", "-123")
var historyBatch *Batch
event := make(chan empty)
irc.SendWithLabel(func(batch *Batch) {
historyBatch = batch
close(event)
}, nil, "CHATHISTORY", "LATEST", channel, "*", "10")
<-event
assertEqual(len(irc.labelCallbacks), 0)
if historyBatch == nil {
t.Errorf("received nil history batch")
}
// history should contain the JOIN, the PRIVMSG, and the multiline batch as a single item
if !(historyBatch.Command == "BATCH" && len(historyBatch.Items) == 3) {
t.Errorf("chathistory must send a real batch, got %#v", historyBatch)
}
var privmsg, multiline *Batch
for _, item := range historyBatch.Items {
switch item.Command {
case "PRIVMSG":
privmsg = item
case "BATCH":
multiline = item
}
}
if !(privmsg.Command == "PRIVMSG" && privmsg.Params[0] == channel && privmsg.Params[1] == "hi") {
t.Errorf("expected echo of individual privmsg, got %#v", privmsg)
}
if !(multiline.Command == "BATCH" && len(multiline.Items) == 4 && multiline.Items[3].Command == "PRIVMSG" && multiline.Items[3].Params[1] == "everyone?") {
t.Errorf("expected multiline in history, got %#v\n", multiline)
}
assertEqual(len(irc.batches), 0)
irc.Quit()
}
func TestBatchHandlers(t *testing.T) {
alice := connForTesting("alice", "go-eventirc", false)
alice.Debug = true
alice.RequestCaps = []string{"message-tags", "batch", "labeled-response", "server-time", "echo-message", multilineName, chathistoryName, playbackCap}
channel := fmt.Sprintf("#%s", randomString())
aliceUnderstandsBatches := true
var aliceBatchCount, alicePrivmsgCount int
alice.AddBatchCallback(func(batch *Batch) bool {
if aliceUnderstandsBatches {
aliceBatchCount++
return true
}
return false
})
alice.AddCallback("PRIVMSG", func(e ircmsg.Message) {
alicePrivmsgCount++
})
err := alice.Connect()
if err != nil {
t.Fatalf("labeled response connection failed: %s", err)
}
go alice.Loop()
alice.Join(channel)
synchronize(alice)
bob := connForTesting("bob", "go-eventirc", false)
bob.Debug = true
bob.RequestCaps = []string{"message-tags", "batch", "labeled-response", "server-time", "echo-message", multilineName, chathistoryName, playbackCap}
var buf bytes.Buffer
bob.AddBatchCallback(func(b *Batch) bool {
if !(len(b.Params) >= 3 && b.Params[1] == multilineName) {
return false
}
for i, item := range b.Items {
if item.Command == "PRIVMSG" {
buf.WriteString(item.Params[1])
if !(item.HasTag(concatTag) || i == len(b.Items)-1) {
buf.WriteByte('\n')
}
}
}
return true
})
err = bob.Connect()
if err != nil {
t.Fatalf("labeled response connection failed: %s", err)
}
go bob.Loop()
bob.Join(channel)
synchronize(bob)
sendMultiline := func() {
alice.Send("BATCH", "+123", "draft/multiline", channel)
alice.SendWithTags(map[string]string{"batch": "123"}, "PRIVMSG", channel, "hello")
alice.SendWithTags(map[string]string{"batch": "123"}, "PRIVMSG", channel, "")
alice.SendWithTags(map[string]string{"batch": "123", concatTag: ""}, "PRIVMSG", channel, "how is ")
alice.SendWithTags(map[string]string{"batch": "123"}, "PRIVMSG", channel, "everyone?")
alice.Send("BATCH", "-123")
synchronize(alice)
synchronize(bob)
}
multilineMessageValue := "hello\n\nhow is everyone?"
sendMultiline()
assertEqual(alicePrivmsgCount, 0)
alicePrivmsgCount = 0
assertEqual(aliceBatchCount, 1)
aliceBatchCount = 0
assertEqual(buf.String(), multilineMessageValue)
buf.Reset()
aliceUnderstandsBatches = false
sendMultiline()
// disabled alice's batch handler, she should see a flattened batch
assertEqual(alicePrivmsgCount, 4)
assertEqual(aliceBatchCount, 0)
assertEqual(buf.String(), multilineMessageValue)
assertEqual(len(alice.batches), 0)
assertEqual(len(bob.batches), 0)
alice.Quit()
bob.Quit()
}
func synchronize(irc *Connection) {
event := make(chan empty)
irc.SendWithLabel(func(b *Batch) {
close(event)
}, nil, "PING", "!")
<-event
}
func TestSynchronousLabeledResponse(t *testing.T) {
irccon := connForTesting("go-eventirc", "go-eventirc", false)
irccon.Debug = true
irccon.RequestCaps = []string{"message-tags", "batch", "labeled-response"}
irccon.RealName = "Al_b6AHLrxh8TZb5kNO1gw"
err := irccon.Connect()
if err != nil {
t.Fatalf("labeled response connection failed: %s", err)
}
go irccon.Loop()
batch, err := irccon.GetLabeledResponse(nil, "WHOIS", irccon.CurrentNick())
if err != nil {
t.Fatalf("labeled response failed: %v", err)
}
assertEqual(batch.Command, "BATCH")
results := make(map[string]string)
for _, line := range batch.Items {
results[line.Command] = line.Params[len(line.Params)-1]
}
// RPL_WHOISUSER, last param is the realname
assertEqual(results["311"], "Al_b6AHLrxh8TZb5kNO1gw")
if _, ok := results["379"]; !ok {
t.Errorf("Expected 379 RPL_WHOISMODES in response, but not received")
}
assertEqual(len(irccon.batches), 0)
}