package guilds import ( "fmt" "testing" "time" "eq2emu/internal/database" ) // TestNewGuild tests guild creation with default values func TestNewGuild(t *testing.T) { // Create a mock database (we'll use nil since these tests don't use database) var db *database.Database guild := New(db) // Test initial state if guild.GetLevel() != 1 { t.Errorf("Expected initial level 1, got %d", guild.GetLevel()) } if guild.GetEXPCurrent() != 111 { t.Errorf("Expected initial expCurrent 111, got %d", guild.GetEXPCurrent()) } if guild.GetEXPToNextLevel() != 2521 { t.Errorf("Expected initial expToNextLevel 2521, got %d", guild.GetEXPToNextLevel()) } if guild.GetRecruitingMinLevel() != 1 { t.Errorf("Expected initial recruitingMinLevel 1, got %d", guild.GetRecruitingMinLevel()) } if guild.GetRecruitingPlayStyle() != RecruitingPlayStyleNone { t.Errorf("Expected initial recruitingPlayStyle %d, got %d", RecruitingPlayStyleNone, guild.GetRecruitingPlayStyle()) } if guild.GetNextEventID() != 1 { t.Errorf("Expected initial nextEventID 1, got %d", guild.GetNextEventID()) } // Test recruiting flags are initialized if guild.GetRecruitingFlag(RecruitingFlagTraining) != 0 { t.Error("Training recruiting flag should be initialized to 0") } if guild.GetRecruitingFlag(RecruitingFlagFighters) != 0 { t.Error("Fighters recruiting flag should be initialized to 0") } // Test description tags are initialized if guild.GetRecruitingDescTag(0) != RecruitingDescTagNone { t.Error("Description tag 0 should be initialized to None") } // Test default rank names are set if guild.GetRankName(RankLeader) != "Leader" { t.Errorf("Expected leader rank name 'Leader', got '%s'", guild.GetRankName(RankLeader)) } if guild.GetRankName(RankRecruit) != "Recruit" { t.Errorf("Expected recruit rank name 'Recruit', got '%s'", guild.GetRankName(RankRecruit)) } } // TestGuildBasicOperations tests basic guild getter/setter operations func TestGuildBasicOperations(t *testing.T) { var db *database.Database guild := New(db) // Test ID operations testID := int32(12345) guild.SetID(testID) if guild.GetID() != testID { t.Errorf("Expected ID %d, got %d", testID, guild.GetID()) } // Test name operations testName := "Test Guild" guild.SetName(testName, false) if guild.GetName() != testName { t.Errorf("Expected name '%s', got '%s'", testName, guild.GetName()) } // Test level operations testLevel := int8(10) guild.SetLevel(testLevel, false) if guild.GetLevel() != testLevel { t.Errorf("Expected level %d, got %d", testLevel, guild.GetLevel()) } // Test MOTD operations testMOTD := "Welcome to our guild!" guild.SetMOTD(testMOTD, false) if guild.GetMOTD() != testMOTD { t.Errorf("Expected MOTD '%s', got '%s'", testMOTD, guild.GetMOTD()) } // Test formed date operations testDate := time.Now().Add(-24 * time.Hour) guild.SetFormedDate(testDate) if !guild.GetFormedDate().Equal(testDate) { t.Errorf("Expected formed date %v, got %v", testDate, guild.GetFormedDate()) } // Test experience operations testExpCurrent := int64(5000) testExpNext := int64(10000) guild.SetEXPCurrent(testExpCurrent, false) guild.SetEXPToNextLevel(testExpNext, false) current := guild.GetEXPCurrent() next := guild.GetEXPToNextLevel() if current != testExpCurrent { t.Errorf("Expected current exp %d, got %d", testExpCurrent, current) } if next != testExpNext { t.Errorf("Expected next level exp %d, got %d", testExpNext, next) } } // TestGuildMemberOperations tests guild member management func TestGuildMemberOperations(t *testing.T) { var db *database.Database guild := New(db) guild.SetID(1) // Test adding members using the actual method characterID1 := int32(1) characterID2 := int32(2) inviterName := "TestInviter" joinDate := time.Now() // Add first member success := guild.AddNewGuildMember(characterID1, inviterName, joinDate, RankRecruit) if !success { t.Error("Should be able to add first member") } // Add second member success = guild.AddNewGuildMember(characterID2, inviterName, joinDate, RankMember) if !success { t.Error("Should be able to add second member") } // Test getting member by ID member1 := guild.GetGuildMember(characterID1) if member1 == nil { t.Error("Should be able to retrieve member by ID") } if member1.CharacterID != characterID1 { t.Errorf("Expected member ID %d, got %d", characterID1, member1.CharacterID) } // Test getting all members allMembers := guild.GetAllMembers() if len(allMembers) != 2 { t.Errorf("Expected 2 members, got %d", len(allMembers)) } // Test removing member guild.RemoveGuildMember(characterID1, false) member1After := guild.GetGuildMember(characterID1) if member1After != nil { t.Error("Member should be nil after removal") } allMembersAfter := guild.GetAllMembers() if len(allMembersAfter) != 1 { t.Errorf("Expected 1 member after removal, got %d", len(allMembersAfter)) } } // TestGuildEventOperations tests guild event management func TestGuildEventOperations(t *testing.T) { var db *database.Database guild := New(db) // Test adding events eventType := int32(EventMemberJoins) description := "Member joined guild" eventDate := time.Now() // Add first event (should get ID 1) guild.AddNewGuildEvent(eventType, description, eventDate, false) // Add another event (should get ID 2) guild.AddNewGuildEvent(EventMemberLeaves, "Member left guild", eventDate, false) // Test getting next event ID (should be 3 now) nextID := guild.GetNextEventID() if nextID != 3 { t.Errorf("Expected next event ID 3, got %d", nextID) } // Test getting specific event (first event should have ID 1) event := guild.GetGuildEvent(1) if event == nil { t.Error("Should be able to retrieve event by ID") } if event != nil && event.Description != description { t.Errorf("Expected event description '%s', got '%s'", description, event.Description) } } // TestGuildRankOperations tests guild rank management func TestGuildRankOperations(t *testing.T) { var db *database.Database guild := New(db) // Test setting custom rank name customRankName := "Elite Member" success := guild.SetRankName(RankMember, customRankName, false) if !success { t.Error("Should be able to set rank name") } rankName := guild.GetRankName(RankMember) if rankName != customRankName { t.Errorf("Expected rank name '%s', got '%s'", customRankName, rankName) } // Test getting default rank names leaderName := guild.GetRankName(RankLeader) if leaderName != "Leader" { t.Errorf("Expected leader rank name 'Leader', got '%s'", leaderName) } } // TestGuildRecruitingOperations tests guild recruiting settings func TestGuildRecruitingOperations(t *testing.T) { var db *database.Database guild := New(db) // Test recruiting descriptions shortDesc := "Looking for members" fullDesc := "We are a friendly guild looking for active members" guild.SetRecruitingShortDesc(shortDesc, false) guild.SetRecruitingFullDesc(fullDesc, false) short := guild.GetRecruitingShortDesc() full := guild.GetRecruitingFullDesc() if short != shortDesc { t.Errorf("Expected short description '%s', got '%s'", shortDesc, short) } if full != fullDesc { t.Errorf("Expected full description '%s', got '%s'", fullDesc, full) } // Test recruiting settings minLevel := int8(20) playStyle := int8(2) guild.SetRecruitingMinLevel(minLevel, false) guild.SetRecruitingPlayStyle(playStyle, false) getMinLevel := guild.GetRecruitingMinLevel() getPlayStyle := guild.GetRecruitingPlayStyle() if getMinLevel != minLevel { t.Errorf("Expected min level %d, got %d", minLevel, getMinLevel) } if getPlayStyle != playStyle { t.Errorf("Expected play style %d, got %d", playStyle, getPlayStyle) } // Test recruiting flags success := guild.SetRecruitingFlag(RecruitingFlagFighters, 1, false) if !success { t.Error("Should be able to set recruiting flag") } flag := guild.GetRecruitingFlag(RecruitingFlagFighters) if flag != 1 { t.Errorf("Expected recruiting flag 1, got %d", flag) } // Test recruiting description tags success = guild.SetRecruitingDescTag(0, RecruitingDescTagRoleplay, false) if !success { t.Error("Should be able to set recruiting desc tag") } tag := guild.GetRecruitingDescTag(0) if tag != RecruitingDescTagRoleplay { t.Errorf("Expected description tag %d, got %d", RecruitingDescTagRoleplay, tag) } } // TestGuildPermissions tests guild permission system func TestGuildPermissions(t *testing.T) { var db *database.Database guild := New(db) // Test setting permissions rank := int8(RankMember) permission := int8(PermissionInvite) value := int8(1) success := guild.SetPermission(rank, permission, value, false, false) if !success { t.Error("Should be able to set permission") } getValue := guild.GetPermission(rank, permission) if getValue != value { t.Errorf("Expected permission value %d, got %d", value, getValue) } // Test removing permission success = guild.SetPermission(rank, permission, 0, false, false) if !success { t.Error("Should be able to remove permission") } getValue = guild.GetPermission(rank, permission) if getValue != 0 { t.Errorf("Expected permission value 0 after removal, got %d", getValue) } } // TestGuildSaveFlags tests the save flag system func TestGuildSaveFlags(t *testing.T) { var db *database.Database guild := New(db) // Test initial state if guild.GetSaveNeeded() { t.Error("Guild should not need save initially") } // Test marking save needed guild.SetSaveNeeded(true) if !guild.GetSaveNeeded() { t.Error("Guild should need save after marking") } // Test clearing save needed guild.SetSaveNeeded(false) if guild.GetSaveNeeded() { t.Error("Guild should not need save after clearing") } } // TestGuildMemberPromotionDemotion tests member rank changes func TestGuildMemberPromotionDemotion(t *testing.T) { var db *database.Database guild := New(db) guild.SetID(1) // Add a member characterID := int32(1) inviterName := "TestInviter" joinDate := time.Now() success := guild.AddNewGuildMember(characterID, inviterName, joinDate, RankRecruit) if !success { t.Error("Should be able to add member") } // Get member and check initial rank member := guild.GetGuildMember(characterID) if member == nil { t.Fatal("Member should exist") } if member.Rank != RankRecruit { t.Errorf("Expected initial rank %d, got %d", RankRecruit, member.Rank) } // Test promotion promoterName := "TestPromoter" success = guild.PromoteGuildMember(characterID, promoterName, false) if !success { t.Error("Should be able to promote member") } member = guild.GetGuildMember(characterID) if member.Rank != RankInitiate { t.Errorf("Expected rank after promotion %d, got %d", RankInitiate, member.Rank) } // Test demotion demoterName := "TestDemoter" success = guild.DemoteGuildMember(characterID, demoterName, false) if !success { t.Error("Should be able to demote member") } member = guild.GetGuildMember(characterID) if member.Rank != RankRecruit { t.Errorf("Expected rank after demotion %d, got %d", RankRecruit, member.Rank) } } // TestGuildPointsSystem tests the guild points system func TestGuildPointsSystem(t *testing.T) { var db *database.Database guild := New(db) guild.SetID(1) // Add a member characterID := int32(1) inviterName := "TestInviter" joinDate := time.Now() success := guild.AddNewGuildMember(characterID, inviterName, joinDate, RankRecruit) if !success { t.Error("Should be able to add member") } // Get initial points member := guild.GetGuildMember(characterID) if member == nil { t.Fatal("Member should exist") } initialPoints := member.Points // Add points pointsToAdd := 100.0 modifiedBy := "TestAdmin" comment := "Test point award" success = guild.AddPointsToGuildMember(characterID, pointsToAdd, modifiedBy, comment, false) if !success { t.Error("Should be able to add points to member") } // Check points were added member = guild.GetGuildMember(characterID) expectedPoints := initialPoints + pointsToAdd if member.Points != expectedPoints { t.Errorf("Expected points %f, got %f", expectedPoints, member.Points) } } // TestGuildConcurrency tests thread safety of guild operations func TestGuildConcurrency(t *testing.T) { var db *database.Database guild := New(db) guild.SetID(1) guild.SetName("Concurrent Test Guild", false) const numGoroutines = 20 done := make(chan bool, numGoroutines) // Test concurrent reads for i := 0; i < numGoroutines; i++ { go func(id int) { _ = guild.GetID() _ = guild.GetName() _ = guild.GetLevel() _ = guild.GetMOTD() _ = guild.GetEXPCurrent() _ = guild.GetRecruitingShortDesc() _ = guild.GetRankName(RankMember) _ = guild.GetPermission(RankMember, PermissionInvite) done <- true }(i) } // Wait for all read operations for i := 0; i < numGoroutines; i++ { <-done } // Test concurrent member additions (smaller number to avoid conflicts) const memberGoroutines = 10 for i := 0; i < memberGoroutines; i++ { go func(id int) { inviterName := fmt.Sprintf("Inviter%d", id) joinDate := time.Now() characterID := int32(100 + id) guild.AddNewGuildMember(characterID, inviterName, joinDate, RankRecruit) done <- true }(i) } // Wait for all member additions for i := 0; i < memberGoroutines; i++ { <-done } // Verify members were added members := guild.GetAllMembers() if len(members) != memberGoroutines { t.Logf("Expected %d members, got %d (some concurrent additions may have failed, which is acceptable)", memberGoroutines, len(members)) } } // TestGuildEventFilters tests guild event filter system func TestGuildEventFilters(t *testing.T) { var db *database.Database guild := New(db) // Test setting event filters eventID := int8(EventMemberJoins) category := int8(EventFilterCategoryBroadcast) value := int8(1) success := guild.SetEventFilter(eventID, category, value, false, false) if !success { t.Error("Should be able to set event filter") } getValue := guild.GetEventFilter(eventID, category) if getValue != value { t.Errorf("Expected event filter value %d, got %d", value, getValue) } // Test removing event filter success = guild.SetEventFilter(eventID, category, 0, false, false) if !success { t.Error("Should be able to remove event filter") } getValue = guild.GetEventFilter(eventID, category) if getValue != 0 { t.Errorf("Expected event filter value 0 after removal, got %d", getValue) } } // TestGuildInfo tests the guild info structure func TestGuildInfo(t *testing.T) { var db *database.Database guild := New(db) guild.SetID(123) guild.SetName("Test Guild Info", false) guild.SetLevel(25, false) guild.SetMOTD("Test MOTD", false) info := guild.GetGuildInfo() if info.ID != 123 { t.Errorf("Expected guild info ID 123, got %d", info.ID) } if info.Name != "Test Guild Info" { t.Errorf("Expected guild info name 'Test Guild Info', got '%s'", info.Name) } if info.Level != 25 { t.Errorf("Expected guild info level 25, got %d", info.Level) } if info.MOTD != "Test MOTD" { t.Errorf("Expected guild info MOTD 'Test MOTD', got '%s'", info.MOTD) } }