package chat import ( "testing" "eq2emu/internal/database" ) func TestNew(t *testing.T) { db, err := database.NewSQLite("file::memory:?mode=memory&cache=shared") if err != nil { t.Fatalf("Failed to create test database: %v", err) } defer db.Close() // Test creating a new channel channel := New(db) if channel == nil { t.Fatal("New returned nil") } if !channel.IsNew() { t.Error("New channel should be marked as new") } // Test setting values channel.ID = 1001 channel.Name = "Test Channel" channel.ChannelType = ChannelTypeCustom if channel.GetID() != 1001 { t.Errorf("Expected GetID() to return 1001, got %d", channel.GetID()) } if channel.GetName() != "Test Channel" { t.Errorf("Expected GetName() to return 'Test Channel', got %s", channel.GetName()) } if channel.GetType() != ChannelTypeCustom { t.Errorf("Expected GetType() to return %d, got %d", ChannelTypeCustom, channel.GetType()) } } func TestNewWithData(t *testing.T) { db, err := database.NewSQLite("file::memory:?mode=memory&cache=shared") if err != nil { t.Fatalf("Failed to create test database: %v", err) } defer db.Close() channel := NewWithData(100, "Auction", ChannelTypeWorld, db) if channel == nil { t.Fatal("NewWithData returned nil") } if channel.GetID() != 100 { t.Errorf("Expected ID 100, got %d", channel.GetID()) } if channel.GetName() != "Auction" { t.Errorf("Expected name 'Auction', got '%s'", channel.GetName()) } if channel.GetType() != ChannelTypeWorld { t.Errorf("Expected type %d, got %d", ChannelTypeWorld, channel.GetType()) } if !channel.IsNew() { t.Error("NewWithData should create new channel") } } func TestChannelGettersAndSetters(t *testing.T) { db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared") defer db.Close() channel := NewWithData(123, "Test Channel", ChannelTypeCustom, db) // Test getters if id := channel.GetID(); id != 123 { t.Errorf("GetID() = %v, want 123", id) } if name := channel.GetName(); name != "Test Channel" { t.Errorf("GetName() = %v, want Test Channel", name) } if channelType := channel.GetType(); channelType != ChannelTypeCustom { t.Errorf("GetType() = %v, want %d", channelType, ChannelTypeCustom) } // Test setters channel.SetName("Modified Channel") if channel.GetName() != "Modified Channel" { t.Errorf("SetName failed: got %v, want Modified Channel", channel.GetName()) } channel.SetType(ChannelTypeWorld) if channel.GetType() != ChannelTypeWorld { t.Errorf("SetType failed: got %v, want %d", channel.GetType(), ChannelTypeWorld) } channel.SetLevelRestriction(10) if channel.LevelRestriction != 10 { t.Errorf("SetLevelRestriction failed: got %v, want 10", channel.LevelRestriction) } channel.SetPassword("secret") if !channel.HasPassword() { t.Error("HasPassword should return true after setting password") } if !channel.PasswordMatches("secret") { t.Error("PasswordMatches should return true for correct password") } if channel.PasswordMatches("wrong") { t.Error("PasswordMatches should return false for incorrect password") } } func TestChannelMembership(t *testing.T) { db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared") defer db.Close() channel := NewWithData(100, "Test", ChannelTypeCustom, db) // Test empty channel if !channel.IsEmpty() { t.Error("New channel should be empty") } if channel.GetNumClients() != 0 { t.Errorf("GetNumClients() = %v, want 0", channel.GetNumClients()) } // Test joining channel err := channel.JoinChannel(1001) if err != nil { t.Errorf("JoinChannel failed: %v", err) } if !channel.IsInChannel(1001) { t.Error("IsInChannel should return true after joining") } if channel.IsEmpty() { t.Error("Channel should not be empty after member joins") } if channel.GetNumClients() != 1 { t.Errorf("GetNumClients() = %v, want 1", channel.GetNumClients()) } // Test duplicate join err = channel.JoinChannel(1001) if err == nil { t.Error("JoinChannel should fail for duplicate member") } // Test adding another member err = channel.JoinChannel(1002) if err != nil { t.Errorf("JoinChannel failed: %v", err) } if channel.GetNumClients() != 2 { t.Errorf("GetNumClients() = %v, want 2", channel.GetNumClients()) } // Test getting members members := channel.GetMembers() if len(members) != 2 { t.Errorf("GetMembers() returned %d members, want 2", len(members)) } // Test leaving channel err = channel.LeaveChannel(1001) if err != nil { t.Errorf("LeaveChannel failed: %v", err) } if channel.IsInChannel(1001) { t.Error("IsInChannel should return false after leaving") } if channel.GetNumClients() != 1 { t.Errorf("GetNumClients() = %v, want 1", channel.GetNumClients()) } // Test leaving non-member err = channel.LeaveChannel(9999) if err == nil { t.Error("LeaveChannel should fail for non-member") } } func TestChannelRestrictions(t *testing.T) { db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared") defer db.Close() channel := NewWithData(100, "Restricted", ChannelTypeWorld, db) // Test level restrictions channel.SetLevelRestriction(10) if !channel.CanJoinChannelByLevel(10) { t.Error("CanJoinChannelByLevel should return true for exact minimum") } if !channel.CanJoinChannelByLevel(15) { t.Error("CanJoinChannelByLevel should return true for above minimum") } if channel.CanJoinChannelByLevel(5) { t.Error("CanJoinChannelByLevel should return false for below minimum") } // Test race restrictions (bitmask) channel.SetRacesAllowed(1 << 1) // Only race ID 1 allowed if !channel.CanJoinChannelByRace(1) { t.Error("CanJoinChannelByRace should return true for allowed race") } if channel.CanJoinChannelByRace(2) { t.Error("CanJoinChannelByRace should return false for disallowed race") } // Test class restrictions (bitmask) channel.SetClassesAllowed(1 << 5) // Only class ID 5 allowed if !channel.CanJoinChannelByClass(5) { t.Error("CanJoinChannelByClass should return true for allowed class") } if channel.CanJoinChannelByClass(1) { t.Error("CanJoinChannelByClass should return false for disallowed class") } // Test ValidateJoin err := channel.ValidateJoin(15, 1, 5, "") if err != nil { t.Errorf("ValidateJoin should succeed for valid player: %v", err) } err = channel.ValidateJoin(5, 1, 5, "") if err == nil { t.Error("ValidateJoin should fail for insufficient level") } err = channel.ValidateJoin(15, 2, 5, "") if err == nil { t.Error("ValidateJoin should fail for disallowed race") } err = channel.ValidateJoin(15, 1, 1, "") if err == nil { t.Error("ValidateJoin should fail for disallowed class") } // Test password validation channel.SetPassword("secret") err = channel.ValidateJoin(15, 1, 5, "secret") if err != nil { t.Errorf("ValidateJoin should succeed with correct password: %v", err) } err = channel.ValidateJoin(15, 1, 5, "wrong") if err == nil { t.Error("ValidateJoin should fail with incorrect password") } } func TestChannelInfo(t *testing.T) { db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared") defer db.Close() channel := NewWithData(100, "Info Test", ChannelTypeWorld, db) channel.SetPassword("secret") channel.SetLevelRestriction(10) channel.JoinChannel(1001) channel.JoinChannel(1002) info := channel.GetChannelInfo() if info.Name != "Info Test" { t.Errorf("ChannelInfo.Name = %v, want Info Test", info.Name) } if !info.HasPassword { t.Error("ChannelInfo.HasPassword should be true") } if info.MemberCount != 2 { t.Errorf("ChannelInfo.MemberCount = %v, want 2", info.MemberCount) } if info.LevelRestriction != 10 { t.Errorf("ChannelInfo.LevelRestriction = %v, want 10", info.LevelRestriction) } if info.ChannelType != ChannelTypeWorld { t.Errorf("ChannelInfo.ChannelType = %v, want %d", info.ChannelType, ChannelTypeWorld) } } func TestChannelCopy(t *testing.T) { db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared") defer db.Close() original := NewWithData(500, "Original Channel", ChannelTypeWorld, db) original.SetPassword("secret") original.SetLevelRestriction(15) original.JoinChannel(1001) copy := original.Copy() if copy == nil { t.Fatal("Copy returned nil") } if copy == original { t.Error("Copy returned same pointer as original") } if copy.GetID() != original.GetID() { t.Errorf("Copy ID = %v, want %v", copy.GetID(), original.GetID()) } if copy.GetName() != original.GetName() { t.Errorf("Copy Name = %v, want %v", copy.GetName(), original.GetName()) } if copy.Password != original.Password { t.Errorf("Copy Password = %v, want %v", copy.Password, original.Password) } if !copy.IsNew() { t.Error("Copy should always be marked as new") } // Verify modification independence copy.SetName("Modified Copy") if original.GetName() == "Modified Copy" { t.Error("Modifying copy affected original") } }