tests: extra tests for Dicord bit and nullcomp.

This commit is contained in:
Houmgaor
2025-10-27 12:33:33 +01:00
parent 127d3af167
commit d3fd0c72b0
2 changed files with 826 additions and 0 deletions

View File

@@ -0,0 +1,419 @@
package discordbot
import (
"regexp"
"testing"
)
func TestReplaceTextAll(t *testing.T) {
tests := []struct {
name string
text string
regex *regexp.Regexp
handler func(string) string
expected string
}{
{
name: "replace single match",
text: "Hello @123456789012345678",
regex: regexp.MustCompile(`@(\d+)`),
handler: func(id string) string {
return "@user_" + id
},
expected: "Hello @user_123456789012345678",
},
{
name: "replace multiple matches",
text: "Users @111111111111111111 and @222222222222222222",
regex: regexp.MustCompile(`@(\d+)`),
handler: func(id string) string {
return "@user_" + id
},
expected: "Users @user_111111111111111111 and @user_222222222222222222",
},
{
name: "no matches",
text: "Hello World",
regex: regexp.MustCompile(`@(\d+)`),
handler: func(id string) string {
return "@user_" + id
},
expected: "Hello World",
},
{
name: "replace with empty string",
text: "Remove @123456789012345678 this",
regex: regexp.MustCompile(`@(\d+)`),
handler: func(id string) string {
return ""
},
expected: "Remove this",
},
{
name: "replace emoji syntax",
text: "Hello :smile: and :wave:",
regex: regexp.MustCompile(`:(\w+):`),
handler: func(emoji string) string {
return "[" + emoji + "]"
},
expected: "Hello [smile] and [wave]",
},
{
name: "complex replacement",
text: "Text with <@!123456789012345678> mention",
regex: regexp.MustCompile(`<@!?(\d+)>`),
handler: func(id string) string {
return "@user_" + id
},
expected: "Text with @user_123456789012345678 mention",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ReplaceTextAll(tt.text, tt.regex, tt.handler)
if result != tt.expected {
t.Errorf("ReplaceTextAll() = %q, want %q", result, tt.expected)
}
})
}
}
func TestReplaceTextAll_UserMentionPattern(t *testing.T) {
// Test the actual user mention regex used in NormalizeDiscordMessage
userRegex := regexp.MustCompile(`<@!?(\d{17,19})>`)
tests := []struct {
name string
text string
expected []string // Expected captured IDs
}{
{
name: "standard mention",
text: "<@123456789012345678>",
expected: []string{"123456789012345678"},
},
{
name: "nickname mention",
text: "<@!123456789012345678>",
expected: []string{"123456789012345678"},
},
{
name: "multiple mentions",
text: "<@123456789012345678> and <@!987654321098765432>",
expected: []string{"123456789012345678", "987654321098765432"},
},
{
name: "17 digit ID",
text: "<@12345678901234567>",
expected: []string{"12345678901234567"},
},
{
name: "19 digit ID",
text: "<@1234567890123456789>",
expected: []string{"1234567890123456789"},
},
{
name: "invalid - too short",
text: "<@1234567890123456>",
expected: []string{},
},
{
name: "invalid - too long",
text: "<@12345678901234567890>",
expected: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
matches := userRegex.FindAllStringSubmatch(tt.text, -1)
if len(matches) != len(tt.expected) {
t.Fatalf("Expected %d matches, got %d", len(tt.expected), len(matches))
}
for i, match := range matches {
if len(match) < 2 {
t.Fatalf("Match %d: expected capture group", i)
}
if match[1] != tt.expected[i] {
t.Errorf("Match %d: got ID %q, want %q", i, match[1], tt.expected[i])
}
}
})
}
}
func TestReplaceTextAll_EmojiPattern(t *testing.T) {
// Test the actual emoji regex used in NormalizeDiscordMessage
emojiRegex := regexp.MustCompile(`(?:<a?)?:(\w+):(?:\d{18}>)?`)
tests := []struct {
name string
text string
expectedName []string // Expected emoji names
}{
{
name: "simple emoji",
text: ":smile:",
expectedName: []string{"smile"},
},
{
name: "custom emoji",
text: "<:customemoji:123456789012345678>",
expectedName: []string{"customemoji"},
},
{
name: "animated emoji",
text: "<a:animated:123456789012345678>",
expectedName: []string{"animated"},
},
{
name: "multiple emojis",
text: ":wave: <:custom:123456789012345678> :smile:",
expectedName: []string{"wave", "custom", "smile"},
},
{
name: "emoji with underscores",
text: ":thumbs_up:",
expectedName: []string{"thumbs_up"},
},
{
name: "emoji with numbers",
text: ":emoji123:",
expectedName: []string{"emoji123"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
matches := emojiRegex.FindAllStringSubmatch(tt.text, -1)
if len(matches) != len(tt.expectedName) {
t.Fatalf("Expected %d matches, got %d", len(tt.expectedName), len(matches))
}
for i, match := range matches {
if len(match) < 2 {
t.Fatalf("Match %d: expected capture group", i)
}
if match[1] != tt.expectedName[i] {
t.Errorf("Match %d: got name %q, want %q", i, match[1], tt.expectedName[i])
}
}
})
}
}
func TestNormalizeDiscordMessage_Integration(t *testing.T) {
// Create a mock bot for testing the normalization logic
// Note: We can't fully test this without a real Discord session,
// but we can test the regex patterns and structure
tests := []struct {
name string
input string
contains []string // Strings that should be in the output
}{
{
name: "plain text unchanged",
input: "Hello World",
contains: []string{"Hello World"},
},
{
name: "user mention format",
input: "Hello <@123456789012345678>",
// We can't test the actual replacement without a real Discord session
// but we can verify the pattern is matched
contains: []string{"Hello"},
},
{
name: "emoji format preserved",
input: "Hello :smile:",
contains: []string{"Hello", ":smile:"},
},
{
name: "mixed content",
input: "<@123456789012345678> sent :wave:",
contains: []string{"sent"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test that the message contains expected parts
for _, expected := range tt.contains {
if len(expected) > 0 && !contains(tt.input, expected) {
t.Errorf("Input %q should contain %q", tt.input, expected)
}
}
})
}
}
func TestCommands_Structure(t *testing.T) {
// Test that the Commands slice is properly structured
if len(Commands) == 0 {
t.Error("Commands slice should not be empty")
}
expectedCommands := map[string]bool{
"link": false,
"password": false,
}
for _, cmd := range Commands {
if cmd.Name == "" {
t.Error("Command should have a name")
}
if cmd.Description == "" {
t.Errorf("Command %q should have a description", cmd.Name)
}
if _, exists := expectedCommands[cmd.Name]; exists {
expectedCommands[cmd.Name] = true
}
}
// Verify expected commands exist
for name, found := range expectedCommands {
if !found {
t.Errorf("Expected command %q not found in Commands", name)
}
}
}
func TestCommands_LinkCommand(t *testing.T) {
var linkCmd *struct {
Name string
Description string
Options []struct {
Type int
Name string
Description string
Required bool
}
}
// Find the link command
for _, cmd := range Commands {
if cmd.Name == "link" {
// Verify structure
if cmd.Description == "" {
t.Error("Link command should have a description")
}
if len(cmd.Options) == 0 {
t.Error("Link command should have options")
}
// Verify token option
for _, opt := range cmd.Options {
if opt.Name == "token" {
if !opt.Required {
t.Error("Token option should be required")
}
if opt.Description == "" {
t.Error("Token option should have a description")
}
return
}
}
t.Error("Link command should have a 'token' option")
}
}
if linkCmd == nil {
t.Error("Link command not found")
}
}
func TestCommands_PasswordCommand(t *testing.T) {
// Find the password command
for _, cmd := range Commands {
if cmd.Name == "password" {
// Verify structure
if cmd.Description == "" {
t.Error("Password command should have a description")
}
if len(cmd.Options) == 0 {
t.Error("Password command should have options")
}
// Verify password option
for _, opt := range cmd.Options {
if opt.Name == "password" {
if !opt.Required {
t.Error("Password option should be required")
}
if opt.Description == "" {
t.Error("Password option should have a description")
}
return
}
}
t.Error("Password command should have a 'password' option")
}
}
t.Error("Password command not found")
}
func TestDiscordBotStruct(t *testing.T) {
// Test that the DiscordBot struct can be initialized
bot := &DiscordBot{
Session: nil, // Can't create real session in tests
MainGuild: nil,
RelayChannel: nil,
}
if bot == nil {
t.Error("Failed to create DiscordBot struct")
}
}
func TestOptionsStruct(t *testing.T) {
// Test that the Options struct can be initialized
opts := Options{
Config: nil,
Logger: nil,
}
// Just verify we can create the struct
_ = opts
}
// Helper function
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr || len(s) > len(substr) && containsHelper(s, substr))
}
func containsHelper(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}
func BenchmarkReplaceTextAll(b *testing.B) {
text := "Message with <@123456789012345678> and <@!987654321098765432> mentions and :smile: :wave: emojis"
userRegex := regexp.MustCompile(`<@!?(\d{17,19})>`)
handler := func(id string) string {
return "@user_" + id
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = ReplaceTextAll(text, userRegex, handler)
}
}
func BenchmarkReplaceTextAll_NoMatches(b *testing.B) {
text := "Message with no mentions or special syntax at all, just plain text"
userRegex := regexp.MustCompile(`<@!?(\d{17,19})>`)
handler := func(id string) string {
return "@user_" + id
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = ReplaceTextAll(text, userRegex, handler)
}
}