1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-10-31 20:14:21 +00:00

gateway: Fix RequestGuildMembersCommand for empty query

This commit is contained in:
diamondburned 2022-10-03 04:46:49 -07:00
parent afeacebced
commit d97492348d
No known key found for this signature in database
GPG key ID: D78C4471CE776659
2 changed files with 131 additions and 6 deletions

View file

@ -1,10 +1,13 @@
package gateway
import (
"encoding/json"
"errors"
"strconv"
"strings"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/json/option"
"github.com/diamondburned/arikawa/v3/utils/ws"
)
@ -69,19 +72,52 @@ type ResumeCommand struct {
// https://discord.com/developers/docs/topics/gateway#connecting-and-resuming
type InvalidSessionEvent bool
// RequestGuildMembersCommand is a command for Op 8.
// RequestGuildMembersCommand is a command for Op 8. Either UserIDs or (Query
// and Limit) must be filled.
type RequestGuildMembersCommand struct {
// GuildIDs contains the ids of the guilds to request data from. Multiple
// GuildIDs contains the IDs of the guilds to request data from. Multiple
// guilds can only be requested when using user accounts.
GuildIDs []discord.GuildID `json:"guild_id"`
UserIDs []discord.UserID `json:"user_ids,omitempty"`
GuildIDs []discord.GuildID `json:"guild_ids"`
// UserIDs contains the IDs of the users to request data for. If this is
// filled, then the Query field must be empty.
UserIDs []discord.UserID `json:"user_ids,omitempty"`
// Query is a string to search for matching usernames. If this is filled,
// then the UserIDs field must be empty. If Query is empty, then all members
// are filled for bots.
Query option.String `json:"query,omitempty"`
// Limit is used to specify the maximum number of members to send back when
// Query is used.
Limit uint `json:"limit,omitempty"`
Query string `json:"query,omitempty"`
Limit uint `json:"limit,omitempty"`
Presences bool `json:"presences"`
Nonce string `json:"nonce,omitempty"`
}
// MarshalJSON marshals a RequestGuildMembersCommand.
func (c *RequestGuildMembersCommand) MarshalJSON() ([]byte, error) {
type raw RequestGuildMembersCommand
if c.UserIDs != nil && c.Query != nil {
return nil, errors.New("neither UserIDs nor Query can be filled")
}
var marshaling interface{} = (*raw)(c)
if c.Query != nil {
// Force the Limit field to be present if Query is present.
marshaling = struct {
*raw
Limit uint `json:"limit"`
}{
raw: (*raw)(c),
Limit: c.Limit,
}
}
return json.Marshal(marshaling)
}
// UpdateVoiceStateCommand is a command for Op 4.
type UpdateVoiceStateCommand struct {
GuildID discord.GuildID `json:"guild_id"`

89
gateway/events_test.go Normal file
View file

@ -0,0 +1,89 @@
package gateway
import (
"context"
"encoding/json"
"reflect"
"strings"
"testing"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/json/option"
"github.com/diamondburned/arikawa/v3/utils/ws"
)
func TestRequestGuildMembersCommand(t *testing.T) {
assert := func(cmd Event, data map[string]interface{}) {
cmdBytes, err := json.Marshal(cmd)
if err != nil {
t.Fatal("failed to marshal command:", err)
}
var cmdMap map[string]interface{}
if err := json.Unmarshal(cmdBytes, &cmdMap); err != nil {
t.Fatal("failed to unmarshal command:", err)
}
if !reflect.DeepEqual(cmdMap, data) {
t.Fatalf("mismatched command, got %#v", cmdMap)
}
}
t.Run("userIDs", func(t *testing.T) {
cmd := RequestGuildMembersCommand{
GuildIDs: []discord.GuildID{123},
UserIDs: []discord.UserID{456},
}
assert(&cmd, map[string]interface{}{
"guild_ids": []interface{}{"123"},
"user_ids": []interface{}{"456"},
"presences": false,
})
})
t.Run("query_empty", func(t *testing.T) {
cmd := RequestGuildMembersCommand{
GuildIDs: []discord.GuildID{123},
Query: option.NewString(""),
}
assert(&cmd, map[string]interface{}{
"guild_ids": []interface{}{"123"},
"query": "",
"limit": float64(0),
"presences": false,
})
})
t.Run("query_nonempty", func(t *testing.T) {
cmd := RequestGuildMembersCommand{
GuildIDs: []discord.GuildID{123},
Query: option.NewString("abc"),
}
assert(&cmd, map[string]interface{}{
"guild_ids": []interface{}{"123"},
"query": "abc",
"limit": float64(0),
"presences": false,
})
})
t.Run("both", func(t *testing.T) {
cmd := RequestGuildMembersCommand{
GuildIDs: []discord.GuildID{123},
UserIDs: []discord.UserID{456},
Query: option.NewString("abc"),
}
// Gateway should never be touched when Marshal fails, so we can just
// create a zero-value.
var gateway ws.Gateway
err := gateway.Send(context.Background(), &cmd)
if err == nil || !strings.Contains(err.Error(), "neither UserIDs nor Query can be filled") {
t.Fatal("unexpected error:", err)
}
})
}