package client import ( "testing" "forge.redroom.link/yves/meowlib" "github.com/stretchr/testify/assert" ) // Helper function to create a test server list with sample servers func createTestServerList(t *testing.T) *ServerList { sl := &ServerList{ Name: "TestServerList", Servers: []*Server{}, } // Create servers with different public keys for i := 0; i < 5; i++ { srv, err := CreateServerFromUrl("https://server" + string(rune('0'+i)) + ".example.com/meow") if err != nil { t.Fatalf("Failed to create server: %v", err) } // Generate unique public keys for testing kp, err := meowlib.NewKeyPair() if err != nil { t.Fatalf("Failed to create keypair: %v", err) } srv.PublicKey = kp.Public srv.Name = "Server" + string(rune('0'+i)) sl.Servers = append(sl.Servers, srv) } return sl } func TestServerList_FilterByIdxs(t *testing.T) { sl := createTestServerList(t) t.Run("Filter with valid indices", func(t *testing.T) { indices := []int{0, 2, 4} filtered, err := sl.FilterByIdxs(indices) assert.NoError(t, err, "FilterByIdxs should not return error for valid indices") assert.NotNil(t, filtered, "Filtered list should not be nil") assert.Equal(t, 3, len(filtered.Servers), "Should have 3 servers after filtering") // Verify the filtered servers are correct assert.Equal(t, sl.Servers[0], filtered.Servers[0]) assert.Equal(t, sl.Servers[2], filtered.Servers[1]) assert.Equal(t, sl.Servers[4], filtered.Servers[2]) }) t.Run("Filter with single index", func(t *testing.T) { indices := []int{1} filtered, err := sl.FilterByIdxs(indices) assert.NoError(t, err, "FilterByIdxs should not return error for valid single index") assert.NotNil(t, filtered, "Filtered list should not be nil") assert.Equal(t, 1, len(filtered.Servers), "Should have 1 server after filtering") assert.Equal(t, sl.Servers[1], filtered.Servers[0]) }) t.Run("Filter with empty indices", func(t *testing.T) { indices := []int{} filtered, err := sl.FilterByIdxs(indices) assert.NoError(t, err, "FilterByIdxs should not return error for empty indices") assert.NotNil(t, filtered, "Filtered list should not be nil") assert.Equal(t, 0, len(filtered.Servers), "Should have 0 servers after filtering with empty indices") }) t.Run("Filter with out of range index", func(t *testing.T) { indices := []int{0, 10} filtered, err := sl.FilterByIdxs(indices) assert.Error(t, err, "FilterByIdxs should return error for out of range index") assert.Nil(t, filtered, "Filtered list should be nil on error") assert.Contains(t, err.Error(), "out of range", "Error message should mention out of range") }) t.Run("Filter with negative index", func(t *testing.T) { indices := []int{-1} filtered, err := sl.FilterByIdxs(indices) assert.Error(t, err, "FilterByIdxs should return error for negative index") assert.Nil(t, filtered, "Filtered list should be nil on error") }) t.Run("Filter with duplicate indices", func(t *testing.T) { indices := []int{1, 1, 2} filtered, err := sl.FilterByIdxs(indices) assert.NoError(t, err, "FilterByIdxs should not return error for duplicate indices") assert.NotNil(t, filtered, "Filtered list should not be nil") // Note: duplicates will result in duplicate servers in the list assert.Equal(t, 3, len(filtered.Servers), "Should have 3 servers (including duplicate)") }) } func TestServerList_FilterByIdxs_EmptyList(t *testing.T) { sl := &ServerList{ Name: "EmptyList", Servers: []*Server{}, } t.Run("Filter empty list with indices", func(t *testing.T) { indices := []int{0} filtered, err := sl.FilterByIdxs(indices) assert.Error(t, err, "FilterByIdxs should return error when trying to filter empty list") assert.Nil(t, filtered, "Filtered list should be nil on error") }) t.Run("Filter empty list with empty indices", func(t *testing.T) { indices := []int{} filtered, err := sl.FilterByIdxs(indices) assert.NoError(t, err, "FilterByIdxs should not return error for empty indices on empty list") assert.NotNil(t, filtered, "Filtered list should not be nil") assert.Equal(t, 0, len(filtered.Servers), "Should have 0 servers") }) } func TestServerList_GetServerByIdx(t *testing.T) { sl := createTestServerList(t) t.Run("Get server with valid index", func(t *testing.T) { server, err := sl.GetServerByIdx(2) assert.NoError(t, err, "GetServerByIdx should not return error for valid index") assert.NotNil(t, server, "Server should not be nil") assert.Equal(t, sl.Servers[2], server, "Should return the correct server") }) t.Run("Get first server", func(t *testing.T) { server, err := sl.GetServerByIdx(0) assert.NoError(t, err, "GetServerByIdx should not return error for index 0") assert.NotNil(t, server, "Server should not be nil") assert.Equal(t, sl.Servers[0], server, "Should return the first server") }) t.Run("Get last server", func(t *testing.T) { lastIdx := len(sl.Servers) - 1 server, err := sl.GetServerByIdx(lastIdx) assert.NoError(t, err, "GetServerByIdx should not return error for last index") assert.NotNil(t, server, "Server should not be nil") assert.Equal(t, sl.Servers[lastIdx], server, "Should return the last server") }) t.Run("Get server with out of range index", func(t *testing.T) { server, err := sl.GetServerByIdx(100) assert.Error(t, err, "GetServerByIdx should return error for out of range index") assert.Nil(t, server, "Server should be nil on error") assert.Contains(t, err.Error(), "out of range", "Error message should mention out of range") }) t.Run("Get server with negative index", func(t *testing.T) { server, err := sl.GetServerByIdx(-1) assert.Error(t, err, "GetServerByIdx should return error for negative index") assert.Nil(t, server, "Server should be nil on error") }) } func TestServerList_GetServerByIdx_EmptyList(t *testing.T) { sl := &ServerList{ Name: "EmptyList", Servers: []*Server{}, } t.Run("Get server from empty list", func(t *testing.T) { server, err := sl.GetServerByIdx(0) assert.Error(t, err, "GetServerByIdx should return error on empty list") assert.Nil(t, server, "Server should be nil on error") }) } func TestServerList_GetServerByPubkey(t *testing.T) { sl := createTestServerList(t) t.Run("Get server with existing public key", func(t *testing.T) { // Use the public key from the second server targetPubkey := sl.Servers[1].PublicKey server := sl.GetServerByPubkey(targetPubkey) assert.NotNil(t, server, "Server should not be nil when public key exists") assert.Equal(t, targetPubkey, server.PublicKey, "Should return server with matching public key") assert.Equal(t, sl.Servers[1], server, "Should return the correct server") }) t.Run("Get server with non-existent public key", func(t *testing.T) { server := sl.GetServerByPubkey("nonexistent-pubkey-12345") assert.Nil(t, server, "Server should be nil when public key doesn't exist") }) t.Run("Get server with empty public key", func(t *testing.T) { server := sl.GetServerByPubkey("") assert.Nil(t, server, "Server should be nil when searching for empty public key") }) t.Run("Get first matching server", func(t *testing.T) { // Add a duplicate public key duplicatePubkey := sl.Servers[0].PublicKey newServer, err := CreateServerFromUrl("https://duplicate.example.com/meow") if err != nil { t.Fatalf("Failed to create server: %v", err) } newServer.PublicKey = duplicatePubkey sl.Servers = append(sl.Servers, newServer) server := sl.GetServerByPubkey(duplicatePubkey) assert.NotNil(t, server, "Server should not be nil") assert.Equal(t, duplicatePubkey, server.PublicKey) // Should return the first match assert.Equal(t, sl.Servers[0], server, "Should return the first matching server") }) } func TestServerList_GetServerByPubkey_EmptyList(t *testing.T) { sl := &ServerList{ Name: "EmptyList", Servers: []*Server{}, } t.Run("Get server from empty list", func(t *testing.T) { server := sl.GetServerByPubkey("any-pubkey") assert.Nil(t, server, "Server should be nil when searching in empty list") }) } func TestServerList_AddUrls(t *testing.T) { t.Run("Add valid URLs", func(t *testing.T) { sl := &ServerList{ Name: "TestList", Servers: []*Server{}, } urls := []string{ "https://server1.example.com/meow", "https://server2.example.com/meow", "https://server3.example.com/meow", } err := sl.AddUrls(urls) assert.NoError(t, err, "AddUrls should not return error for valid URLs") assert.Equal(t, 3, len(sl.Servers), "Should have 3 servers after adding URLs") // Verify each server was created correctly for i, url := range urls { assert.Equal(t, url, sl.Servers[i].Url, "Server URL should match") assert.NotNil(t, sl.Servers[i].UserKp, "Server should have UserKp") } }) t.Run("Add empty URLs list", func(t *testing.T) { sl := &ServerList{ Name: "TestList", Servers: []*Server{}, } urls := []string{} err := sl.AddUrls(urls) assert.NoError(t, err, "AddUrls should not return error for empty list") assert.Equal(t, 0, len(sl.Servers), "Should have 0 servers after adding empty list") }) t.Run("Add URLs to existing list", func(t *testing.T) { sl := createTestServerList(t) initialCount := len(sl.Servers) urls := []string{ "https://newserver1.example.com/meow", "https://newserver2.example.com/meow", } err := sl.AddUrls(urls) assert.NoError(t, err, "AddUrls should not return error") assert.Equal(t, initialCount+2, len(sl.Servers), "Should have added 2 servers to existing list") }) t.Run("Add single URL", func(t *testing.T) { sl := &ServerList{ Name: "TestList", Servers: []*Server{}, } urls := []string{"https://single.example.com/meow"} err := sl.AddUrls(urls) assert.NoError(t, err, "AddUrls should not return error for single URL") assert.Equal(t, 1, len(sl.Servers), "Should have 1 server after adding single URL") }) } func TestServerList_AddUrls_NilList(t *testing.T) { t.Run("Add URLs to nil server list", func(t *testing.T) { sl := &ServerList{ Name: "TestList", Servers: nil, // Explicitly nil } urls := []string{"https://server.example.com/meow"} err := sl.AddUrls(urls) assert.NoError(t, err, "AddUrls should not return error even with nil Servers slice") assert.NotNil(t, sl.Servers, "Servers slice should be initialized") assert.Equal(t, 1, len(sl.Servers), "Should have 1 server after adding URL") }) } // Test the ServerList struct itself func TestServerList_Structure(t *testing.T) { t.Run("Create empty server list", func(t *testing.T) { sl := &ServerList{ Name: "TestList", Servers: []*Server{}, } assert.NotNil(t, sl, "ServerList should not be nil") assert.Equal(t, "TestList", sl.Name, "Name should be set correctly") assert.NotNil(t, sl.Servers, "Servers slice should not be nil") assert.Equal(t, 0, len(sl.Servers), "Servers slice should be empty") }) t.Run("Create server list with name", func(t *testing.T) { sl := &ServerList{ Name: "MyMessageServers", } assert.Equal(t, "MyMessageServers", sl.Name) }) }