1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-15 19:33:17 +00:00
arikawa/bot/ctx_test.go

343 lines
7.3 KiB
Go
Raw Normal View History

2020-01-19 06:06:00 +00:00
package bot
import (
"errors"
"fmt"
2020-01-19 06:06:00 +00:00
"reflect"
"strconv"
2020-01-19 06:06:00 +00:00
"strings"
"testing"
"time"
2020-01-19 06:06:00 +00:00
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/state"
)
type testc struct {
Ctx *Context
Return chan interface{}
Counter uint64
Typed bool
}
2020-05-10 08:45:00 +00:00
func (t *testc) Setup(sub *Subcommand) {
sub.AddMiddleware("*,GetCounter", func(v interface{}) {
t.Counter++
})
sub.AddMiddleware("*", func(*gateway.MessageCreateEvent) {
t.Counter++
})
}
2020-05-10 08:45:00 +00:00
func (t *testc) Noop(*gateway.MessageCreateEvent) {}
func (t *testc) GetCounter(*gateway.MessageCreateEvent) {
t.Return <- strconv.FormatUint(t.Counter, 10)
2020-01-19 06:06:00 +00:00
}
func (t *testc) Send(_ *gateway.MessageCreateEvent, args ...string) error {
2020-05-03 22:59:10 +00:00
t.Return <- args
2020-01-19 06:06:00 +00:00
return errors.New("oh no")
}
func (t *testc) Custom(_ *gateway.MessageCreateEvent, c *customManualParsed) {
2020-01-19 06:06:00 +00:00
t.Return <- c.args
}
func (t *testc) Variadic(_ *gateway.MessageCreateEvent, c ...*customParsed) {
2020-05-03 22:59:10 +00:00
t.Return <- c[len(c)-1]
}
func (t *testc) TrailCustom(_ *gateway.MessageCreateEvent, s string, c *customManualParsed) {
t.Return <- c.args
}
func (t *testc) Content(_ *gateway.MessageCreateEvent, c RawArguments) {
t.Return <- c
}
2020-05-10 08:45:00 +00:00
func (t *testc) NoArgs(*gateway.MessageCreateEvent) error {
2020-01-19 06:06:00 +00:00
return errors.New("passed")
}
2020-05-10 08:45:00 +00:00
func (t *testc) OnTyping(*gateway.TypingStartEvent) {
t.Typed = true
}
2020-01-19 06:06:00 +00:00
func TestNewContext(t *testing.T) {
var state = &state.State{
Store: state.NewDefaultStore(nil),
}
c, err := New(state, &testc{})
2020-01-19 06:06:00 +00:00
if err != nil {
t.Fatal("Failed to create new context:", err)
}
2020-02-05 04:29:45 +00:00
if !reflect.DeepEqual(c.Subcommands(), c.subcommands) {
t.Fatal("Subcommands mismatch.")
}
2020-01-19 06:06:00 +00:00
}
func TestContext(t *testing.T) {
var given = &testc{}
2020-01-19 06:06:00 +00:00
var state = &state.State{
Store: state.NewDefaultStore(nil),
}
s, err := NewSubcommand(given)
if err != nil {
t.Fatal("Failed to create subcommand:", err)
}
var ctx = &Context{
Subcommand: s,
State: state,
ParseArgs: DefaultArgsParser(),
2020-01-19 06:06:00 +00:00
}
t.Run("init commands", func(t *testing.T) {
if err := ctx.Subcommand.InitCommands(ctx); err != nil {
t.Fatal("Failed to init commands:", err)
}
if given.Ctx == nil {
t.Fatal("given's Context field is nil")
}
if given.Ctx.State.Store == nil {
2020-01-19 06:06:00 +00:00
t.Fatal("given's State is nil")
}
})
2020-02-05 04:29:45 +00:00
t.Run("find commands", func(t *testing.T) {
2020-05-10 08:45:00 +00:00
cmd := ctx.FindMethod("", "NoArgs")
2020-02-05 04:29:45 +00:00
if cmd == nil {
t.Fatal("Failed to find NoArgs")
}
})
2020-05-10 08:45:00 +00:00
// t.Run("help", func(t *testing.T) {
// if h := ctx.Help(); h == "" {
// t.Fatal("Empty help?")
// }
// if h := ctx.HelpAdmin(); h == "" {
// t.Fatal("Empty admin help?")
// }
// })
2020-02-05 04:29:45 +00:00
t.Run("middleware", func(t *testing.T) {
ctx.HasPrefix = NewPrefix("pls do ")
// This should trigger the middleware first.
2020-05-10 08:45:00 +00:00
if err := expect(ctx, given, "3", "pls do getCounter"); err != nil {
t.Fatal("Unexpected error:", err)
}
})
t.Run("typing event", func(t *testing.T) {
typing := &gateway.TypingStartEvent{}
if err := ctx.callCmd(typing); err != nil {
t.Fatal("Failed to call with TypingStart:", err)
}
if !given.Typed {
t.Fatal("Typed bool is false")
}
})
2020-01-19 06:06:00 +00:00
t.Run("call command", func(t *testing.T) {
// Set a custom prefix
ctx.HasPrefix = NewPrefix("~")
2020-01-19 06:06:00 +00:00
2020-05-03 22:59:10 +00:00
var (
strings = "hacka doll no. 3"
expects = []string{"hacka", "doll", "no.", "3"}
)
if err := expect(ctx, given, expects, "~send "+strings); err.Error() != "oh no" {
t.Fatal("Unexpected error:", err)
2020-01-19 06:06:00 +00:00
}
})
t.Run("call command rawarguments", func(t *testing.T) {
ctx.HasPrefix = NewPrefix("!")
expects := RawArguments("just things")
if err := expect(ctx, given, expects, "!content just things"); err != nil {
t.Fatal("Unexpected call error:", err)
}
})
2020-05-03 22:59:10 +00:00
t.Run("call command custom manual parser", func(t *testing.T) {
ctx.HasPrefix = NewPrefix("!")
expects := []string{"arg1", ":)"}
2020-01-19 06:06:00 +00:00
if err := expect(ctx, given, expects, "!custom arg1 :)"); err != nil {
2020-01-19 06:06:00 +00:00
t.Fatal("Unexpected call error:", err)
}
})
2020-05-03 22:59:10 +00:00
t.Run("call command custom variadic parser", func(t *testing.T) {
ctx.HasPrefix = NewPrefix("!")
expects := &customParsed{true}
if err := expect(ctx, given, expects, "!variadic bruh moment"); err != nil {
2020-05-03 22:59:10 +00:00
t.Fatal("Unexpected call error:", err)
}
})
t.Run("call command custom trailing manual parser", func(t *testing.T) {
ctx.HasPrefix = NewPrefix("!")
expects := []string{}
if err := expect(ctx, given, expects, "!trailCustom hime_arikawa"); err != nil {
t.Fatal("Unexpected call error:", err)
}
})
2020-01-19 06:06:00 +00:00
testMessage := func(content string) error {
// Mock a messageCreate event
m := &gateway.MessageCreateEvent{
Message: discord.Message{
Content: content,
},
2020-01-19 06:06:00 +00:00
}
return ctx.callCmd(m)
}
t.Run("call command without args", func(t *testing.T) {
ctx.HasPrefix = NewPrefix("")
2020-01-19 06:06:00 +00:00
if err := testMessage("noArgs"); err.Error() != "passed" {
2020-01-19 06:06:00 +00:00
t.Fatal("unexpected error:", err)
}
})
// Test error cases
t.Run("call unknown command", func(t *testing.T) {
ctx.HasPrefix = NewPrefix("joe pls ")
2020-01-19 06:06:00 +00:00
err := testMessage("joe pls no")
if err == nil || !strings.HasPrefix(err.Error(), "Unknown command:") {
t.Fatal("unexpected error:", err)
}
})
// Test subcommands
t.Run("register subcommand", func(t *testing.T) {
ctx.HasPrefix = NewPrefix("run ")
2020-01-19 06:06:00 +00:00
sub := &testc{}
_, err := ctx.RegisterSubcommand(sub)
2020-01-19 06:06:00 +00:00
if err != nil {
t.Fatal("Failed to register subcommand:", err)
}
if err := testMessage("run testc noop"); err != nil {
2020-02-05 04:29:45 +00:00
t.Fatal("Unexpected error:", err)
}
expects := RawArguments("hackadoll no. 3")
if err := expect(ctx, sub, expects, "run testc content hackadoll no. 3"); err != nil {
t.Fatal("Unexpected call error:", err)
}
2020-05-10 08:45:00 +00:00
if cmd := ctx.FindMethod("testc", "Noop"); cmd == nil {
2020-02-05 04:29:45 +00:00
t.Fatal("Failed to find subcommand Noop")
2020-01-19 06:06:00 +00:00
}
})
}
func expect(ctx *Context, given *testc, expects interface{}, content string) (call error) {
// Return channel for testing
ret := make(chan interface{})
given.Return = ret
// Mock a messageCreate event
m := &gateway.MessageCreateEvent{
Message: discord.Message{
Content: content,
},
}
var callCh = make(chan error)
go func() {
callCh <- ctx.callCmd(m)
}()
select {
case arg := <-ret:
if !reflect.DeepEqual(arg, expects) {
return fmt.Errorf("returned argument is invalid: %v", arg)
}
call = <-callCh
return
case call = <-callCh:
return fmt.Errorf("expected return before error: %w", call)
case <-time.After(time.Second):
return errors.New("Timed out while waiting")
}
}
2020-01-19 06:06:00 +00:00
func BenchmarkConstructor(b *testing.B) {
var state = &state.State{
Store: state.NewDefaultStore(nil),
}
for i := 0; i < b.N; i++ {
_, _ = New(state, &testc{})
2020-01-19 06:06:00 +00:00
}
}
func BenchmarkCall(b *testing.B) {
var given = &testc{}
2020-01-19 06:06:00 +00:00
var state = &state.State{
Store: state.NewDefaultStore(nil),
}
s, _ := NewSubcommand(given)
var ctx = &Context{
Subcommand: s,
State: state,
HasPrefix: NewPrefix("~"),
2020-05-10 08:45:00 +00:00
ParseArgs: DefaultArgsParser(),
2020-01-19 06:06:00 +00:00
}
m := &gateway.MessageCreateEvent{
Message: discord.Message{
Content: "~noop",
},
2020-01-19 06:06:00 +00:00
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
ctx.callCmd(m)
}
}
func BenchmarkHelp(b *testing.B) {
var given = &testc{}
2020-01-19 06:06:00 +00:00
var state = &state.State{
Store: state.NewDefaultStore(nil),
}
s, _ := NewSubcommand(given)
var ctx = &Context{
Subcommand: s,
State: state,
HasPrefix: NewPrefix("~"),
2020-05-10 08:45:00 +00:00
ParseArgs: DefaultArgsParser(),
2020-01-19 06:06:00 +00:00
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = ctx.Help()
}
}