mirror of
https://github.com/diamondburned/arikawa.git
synced 2024-11-27 09:12:53 +00:00
efde3f4ea6
This commit refactors a lot of packages. It refactors the handler package, removing the Synchronous field and replacing it the AddSyncHandler API, which allows each handler to control whether or not it should be ran synchronously independent of other handlers. This is useful for libraries that need to guarantee the incoming order of events. It also refactors the store interfaces to accept more interfaces. This is to make the API more consistent as well as reducing potential useless copies. The public-facing state API should still be the same, so this change will mostly concern users with their own store implementations. Several miscellaneous functions (such as a few in package gateway) were modified to be more suitable to other packages, but those functions should rarely ever be used, anyway. Several tests are also fixed within this commit, namely fixing state's intents bug.
300 lines
5.4 KiB
Go
300 lines
5.4 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/diamondburned/arikawa/v3/discord"
|
|
"github.com/diamondburned/arikawa/v3/gateway"
|
|
)
|
|
|
|
func newMessage(content string) *gateway.MessageCreateEvent {
|
|
return &gateway.MessageCreateEvent{
|
|
Message: discord.Message{Content: content},
|
|
}
|
|
}
|
|
|
|
func TestCall(t *testing.T) {
|
|
var results = make(chan string)
|
|
|
|
h := &Handler{}
|
|
|
|
// Add handler test
|
|
rm := h.AddHandler(func(m *gateway.MessageCreateEvent) {
|
|
results <- m.Content
|
|
})
|
|
|
|
go h.Call(newMessage("hime arikawa"))
|
|
|
|
if r := <-results; r != "hime arikawa" {
|
|
t.Fatal("Returned results is wrong:", r)
|
|
}
|
|
|
|
// Delete handler test
|
|
rm()
|
|
|
|
go h.Call(newMessage("astolfo"))
|
|
|
|
select {
|
|
case <-results:
|
|
t.Fatal("Unexpected results")
|
|
case <-time.After(5 * time.Millisecond):
|
|
break
|
|
}
|
|
|
|
// Invalid type test
|
|
_, err := h.AddHandlerCheck("this should panic")
|
|
if err == nil {
|
|
t.Fatal("No errors found")
|
|
}
|
|
|
|
// We don't do anything with the returned callback, as there's none.
|
|
|
|
if !strings.Contains(err.Error(), "given interface is not a function") {
|
|
t.Fatal("Unexpected error:", err)
|
|
}
|
|
}
|
|
|
|
func TestHandler(t *testing.T) {
|
|
var results = make(chan string)
|
|
|
|
h, err := newHandler(func(m *gateway.MessageCreateEvent) {
|
|
results <- m.Content
|
|
}, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
const result = "Hime Arikawa"
|
|
var msg = newMessage(result)
|
|
|
|
var msgV = reflect.ValueOf(msg)
|
|
var msgT = msgV.Type()
|
|
|
|
if h.not(msgT) {
|
|
t.Fatal("Event type mismatch")
|
|
}
|
|
|
|
go h.call(msgV)
|
|
|
|
if results := <-results; results != result {
|
|
t.Fatal("Unexpected results:", results)
|
|
}
|
|
}
|
|
|
|
func TestHandlerChan(t *testing.T) {
|
|
var results = make(chan *gateway.MessageCreateEvent)
|
|
|
|
h, err := newHandler(results, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
const result = "Hime Arikawa"
|
|
var msg = newMessage(result)
|
|
|
|
var msgV = reflect.ValueOf(msg)
|
|
var msgT = msgV.Type()
|
|
|
|
if h.not(msgT) {
|
|
t.Fatal("Event type mismatch")
|
|
}
|
|
|
|
go h.call(msgV)
|
|
|
|
if results := <-results; results.Content != result {
|
|
t.Fatal("Unexpected results:", results)
|
|
}
|
|
}
|
|
|
|
func TestHandlerChanCancel(t *testing.T) {
|
|
// Never receive from this channel. It is important that this channel is
|
|
// unbuffered.
|
|
var results = make(chan *gateway.MessageCreateEvent)
|
|
|
|
h, err := newHandler(results, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
const result = "Hime Arikawa"
|
|
var msg = newMessage(result)
|
|
|
|
var msgV = reflect.ValueOf(msg)
|
|
var msgT = msgV.Type()
|
|
|
|
if h.not(msgT) {
|
|
t.Fatal("Event type mismatch")
|
|
}
|
|
|
|
// Channel that waits for call() to die.
|
|
die := make(chan struct{})
|
|
|
|
// Call in a goroutine, which would trigger a close.
|
|
go func() { h.call(msgV); die <- struct{}{} }()
|
|
|
|
// Call the cleanup function, which should stop the send.
|
|
h.cleanup()
|
|
|
|
// Check if we still have things being sent.
|
|
select {
|
|
case <-die:
|
|
// pass
|
|
case <-time.After(200 * time.Millisecond):
|
|
t.Fatal("Timed out waiting for call routine to die.")
|
|
}
|
|
|
|
// Check if we still receive something.
|
|
select {
|
|
case <-results:
|
|
t.Fatal("Unexpected results received.")
|
|
default:
|
|
// pass
|
|
}
|
|
}
|
|
|
|
func TestHandlerInterface(t *testing.T) {
|
|
var results = make(chan interface{})
|
|
|
|
h, err := newHandler(func(m interface{}) {
|
|
results <- m
|
|
}, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
const result = "Hime Arikawa"
|
|
var msg = newMessage(result)
|
|
|
|
var msgV = reflect.ValueOf(msg)
|
|
var msgT = msgV.Type()
|
|
|
|
if h.not(msgT) {
|
|
t.Fatal("Event type mismatch")
|
|
}
|
|
|
|
go h.call(msgV)
|
|
recv := <-results
|
|
|
|
if msg, ok := recv.(*gateway.MessageCreateEvent); ok {
|
|
if msg.Content == result {
|
|
return
|
|
}
|
|
|
|
t.Fatal("Content mismatch:", msg.Content)
|
|
}
|
|
|
|
t.Fatal("Assertion failed:", recv)
|
|
}
|
|
|
|
func TestHandlerWaitFor(t *testing.T) {
|
|
inc := make(chan interface{}, 1)
|
|
|
|
h := New()
|
|
|
|
wanted := &gateway.TypingStartEvent{
|
|
ChannelID: 123456,
|
|
}
|
|
|
|
evs := []interface{}{
|
|
&gateway.TypingStartEvent{},
|
|
&gateway.MessageCreateEvent{},
|
|
&gateway.ChannelDeleteEvent{},
|
|
wanted,
|
|
}
|
|
|
|
go func() {
|
|
inc <- h.WaitFor(context.Background(), func(v interface{}) bool {
|
|
tp, ok := v.(*gateway.TypingStartEvent)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return tp.ChannelID == wanted.ChannelID
|
|
})
|
|
}()
|
|
|
|
// Wait for WaitFor to add its handler:
|
|
time.Sleep(time.Millisecond)
|
|
|
|
for _, ev := range evs {
|
|
h.Call(ev)
|
|
}
|
|
|
|
recv := <-inc
|
|
if recv != wanted {
|
|
t.Fatal("Unexpected receive:", recv)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
|
|
defer cancel()
|
|
|
|
// Test timeout
|
|
v := h.WaitFor(ctx, func(v interface{}) bool {
|
|
return false
|
|
})
|
|
|
|
if v != nil {
|
|
t.Fatal("Unexpected value:", v)
|
|
}
|
|
}
|
|
|
|
func TestHandlerChanFor(t *testing.T) {
|
|
h := New()
|
|
|
|
wanted := &gateway.TypingStartEvent{
|
|
ChannelID: 123456,
|
|
}
|
|
|
|
evs := []interface{}{
|
|
&gateway.TypingStartEvent{},
|
|
&gateway.MessageCreateEvent{},
|
|
&gateway.ChannelDeleteEvent{},
|
|
wanted,
|
|
}
|
|
|
|
inc, cancel := h.ChanFor(func(v interface{}) bool {
|
|
tp, ok := v.(*gateway.TypingStartEvent)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return tp.ChannelID == wanted.ChannelID
|
|
})
|
|
defer cancel()
|
|
|
|
for _, ev := range evs {
|
|
h.Call(ev)
|
|
}
|
|
|
|
recv := <-inc
|
|
if recv != wanted {
|
|
t.Fatal("Unexpected receive:", recv)
|
|
}
|
|
}
|
|
|
|
func BenchmarkReflect(b *testing.B) {
|
|
h, err := newHandler(func(m *gateway.MessageCreateEvent) {}, false)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
var msg = &gateway.MessageCreateEvent{}
|
|
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
var msgV = reflect.ValueOf(msg)
|
|
var msgT = msgV.Type()
|
|
|
|
if h.not(msgT) {
|
|
b.Fatal("Event type mismatch")
|
|
}
|
|
|
|
h.call(msgV)
|
|
}
|
|
}
|