package client import ( "net/http" "net/http/httptest" "testing" "github.com/gesellix/bose-soundtouch/pkg/models" ) func TestClient_GetClockTime(t *testing.T) { tests := []struct { name string serverResponse string statusCode int expectError bool expectedUTC int64 expectedZone string }{ { name: "Successful clock time retrieval", serverResponse: `2021-01-01 00:00:00`, statusCode: http.StatusOK, expectError: false, expectedUTC: 1609459200, expectedZone: "UTC", }, { name: "Clock time with timezone", serverResponse: `2021-01-01 00:00:00`, statusCode: http.StatusOK, expectError: false, expectedUTC: 1609459200, expectedZone: "America/New_York", }, { name: "Server error", serverResponse: `Internal server error`, statusCode: http.StatusInternalServerError, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/clockTime" { t.Errorf("Expected path '/clockTime', got '%s'", r.URL.Path) } if r.Method != "GET" { t.Errorf("Expected GET method, got '%s'", r.Method) } w.WriteHeader(tt.statusCode) _, _ = w.Write([]byte(tt.serverResponse)) })) defer server.Close() client := createTestClient(server.URL) clockTime, err := client.GetClockTime() if tt.expectError { if err == nil { t.Error("Expected error, got none") } return } if err != nil { t.Errorf("Unexpected error: %v", err) return } if clockTime.GetUTC() != tt.expectedUTC { t.Errorf("Expected UTC %d, got %d", tt.expectedUTC, clockTime.GetUTC()) } if clockTime.GetZone() != tt.expectedZone { t.Errorf("Expected Zone %q, got %q", tt.expectedZone, clockTime.GetZone()) } }) } } func TestClient_SetClockTime(t *testing.T) { tests := []struct { name string request *models.ClockTimeRequest statusCode int expectError bool }{ { name: "Successful clock time set", request: &models.ClockTimeRequest{ UTCTime: 1609459200, }, statusCode: http.StatusOK, expectError: false, }, { name: "Invalid request", request: &models.ClockTimeRequest{ // Empty request - should fail validation }, expectError: true, }, { name: "Server error", request: &models.ClockTimeRequest{ UTCTime: 1609459200, }, statusCode: http.StatusInternalServerError, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/clockTime" { t.Errorf("Expected path '/clockTime', got '%s'", r.URL.Path) } if r.Method != "POST" { t.Errorf("Expected POST method, got '%s'", r.Method) } w.WriteHeader(tt.statusCode) })) defer server.Close() client := createTestClient(server.URL) err := client.SetClockTime(tt.request) if tt.expectError { if err == nil { t.Error("Expected error, got none") } return } if err != nil { t.Errorf("Unexpected error: %v", err) } }) } } func TestClient_SetClockTimeNow(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/clockTime" { t.Errorf("Expected path '/clockTime', got '%s'", r.URL.Path) } if r.Method != "POST" { t.Errorf("Expected POST method, got '%s'", r.Method) } w.WriteHeader(http.StatusOK) })) defer server.Close() client := createTestClient(server.URL) err := client.SetClockTimeNow() if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestClient_GetClockDisplay(t *testing.T) { tests := []struct { name string serverResponse string statusCode int expectError bool expectedEnabled bool expectedFormat string expectedBrightness int }{ { name: "Successful clock display retrieval", serverResponse: ``, statusCode: http.StatusOK, expectError: false, expectedEnabled: true, expectedFormat: "24", expectedBrightness: 75, }, { name: "Disabled clock display", serverResponse: ``, statusCode: http.StatusOK, expectError: false, expectedEnabled: false, expectedFormat: "12", expectedBrightness: 0, }, { name: "Server error", serverResponse: `Internal server error`, statusCode: http.StatusInternalServerError, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/clockDisplay" { t.Errorf("Expected path '/clockDisplay', got '%s'", r.URL.Path) } if r.Method != "GET" { t.Errorf("Expected GET method, got '%s'", r.Method) } w.WriteHeader(tt.statusCode) _, _ = w.Write([]byte(tt.serverResponse)) })) defer server.Close() client := createTestClient(server.URL) clockDisplay, err := client.GetClockDisplay() if tt.expectError { if err == nil { t.Error("Expected error, got none") } return } if err != nil { t.Errorf("Unexpected error: %v", err) return } if clockDisplay.IsEnabled() != tt.expectedEnabled { t.Errorf("Expected Enabled %v, got %v", tt.expectedEnabled, clockDisplay.IsEnabled()) } if clockDisplay.GetFormat() != tt.expectedFormat { t.Errorf("Expected Format %q, got %q", tt.expectedFormat, clockDisplay.GetFormat()) } if clockDisplay.GetBrightness() != tt.expectedBrightness { t.Errorf("Expected Brightness %d, got %d", tt.expectedBrightness, clockDisplay.GetBrightness()) } }) } } func TestClient_SetClockDisplay(t *testing.T) { tests := []struct { name string request *models.ClockDisplayRequest statusCode int expectError bool }{ { name: "Successful clock display set", request: models.NewClockDisplayRequest(). SetEnabled(true). SetFormat(models.ClockFormat24Hour). SetBrightness(75), statusCode: http.StatusOK, expectError: false, }, { name: "Invalid brightness", request: models.NewClockDisplayRequest(). SetBrightness(150), // Invalid brightness > 100 expectError: true, }, { name: "No changes", request: models.NewClockDisplayRequest(), expectError: true, }, { name: "Server error", request: models.NewClockDisplayRequest(). SetEnabled(true), statusCode: http.StatusInternalServerError, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.expectError && tt.statusCode == 0 { // For client-side validation errors, we don't need a server client := createTestClient("http://localhost:8080") err := client.SetClockDisplay(tt.request) if err == nil { t.Error("Expected error, got none") } return } server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/clockDisplay" { t.Errorf("Expected path '/clockDisplay', got '%s'", r.URL.Path) } if r.Method != "POST" { t.Errorf("Expected POST method, got '%s'", r.Method) } if tt.statusCode != 0 { w.WriteHeader(tt.statusCode) } else { w.WriteHeader(http.StatusOK) } })) defer server.Close() client := createTestClient(server.URL) err := client.SetClockDisplay(tt.request) if tt.expectError { if err == nil { t.Error("Expected error, got none") } return } if err != nil { t.Errorf("Unexpected error: %v", err) } }) } } func TestClient_EnableDisableClockDisplay(t *testing.T) { tests := []struct { name string method func(*Client) error expectError bool }{ { name: "Enable clock display", method: func(c *Client) error { return c.EnableClockDisplay() }, expectError: false, }, { name: "Disable clock display", method: func(c *Client) error { return c.DisableClockDisplay() }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })) defer server.Close() client := createTestClient(server.URL) err := tt.method(client) if tt.expectError { if err == nil { t.Error("Expected error, got none") } } else { if err != nil { t.Errorf("Unexpected error: %v", err) } } }) } } func TestClient_SetClockDisplayBrightness(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/clockDisplay" { t.Errorf("Expected path '/clockDisplay', got '%s'", r.URL.Path) } if r.Method != "POST" { t.Errorf("Expected POST method, got '%s'", r.Method) } w.WriteHeader(http.StatusOK) })) defer server.Close() client := createTestClient(server.URL) err := client.SetClockDisplayBrightness(75) if err != nil { t.Errorf("Unexpected error: %v", err) } } func TestClient_SetClockDisplayFormat(t *testing.T) { tests := []struct { name string format models.ClockFormat }{ { name: "12-hour format", format: models.ClockFormat12Hour, }, { name: "24-hour format", format: models.ClockFormat24Hour, }, { name: "Auto format", format: models.ClockFormatAuto, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/clockDisplay" { t.Errorf("Expected path '/clockDisplay', got '%s'", r.URL.Path) } if r.Method != "POST" { t.Errorf("Expected POST method, got '%s'", r.Method) } w.WriteHeader(http.StatusOK) })) defer server.Close() client := createTestClient(server.URL) err := client.SetClockDisplayFormat(tt.format) if err != nil { t.Errorf("Unexpected error: %v", err) } }) } } func TestClient_GetNetworkInfo(t *testing.T) { tests := []struct { name string serverResponse string statusCode int expectError bool expectedDeviceID string expectedInterfaceCount int }{ { name: "Successful network info retrieval - WiFi device", serverResponse: ` `, statusCode: http.StatusOK, expectError: false, expectedDeviceID: "", expectedInterfaceCount: 2, }, { name: "Ethernet device", serverResponse: ` `, statusCode: http.StatusOK, expectError: false, expectedDeviceID: "", expectedInterfaceCount: 1, }, { name: "Server error", serverResponse: `Internal server error`, statusCode: http.StatusInternalServerError, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/networkInfo" { t.Errorf("Expected path '/networkInfo', got '%s'", r.URL.Path) } if r.Method != "GET" { t.Errorf("Expected GET method, got '%s'", r.Method) } w.WriteHeader(tt.statusCode) _, _ = w.Write([]byte(tt.serverResponse)) })) defer server.Close() client := createTestClient(server.URL) networkInfo, err := client.GetNetworkInfo() if tt.expectError { if err == nil { t.Error("Expected error, got none") } return } if err != nil { t.Errorf("Unexpected error: %v", err) return } if tt.expectedDeviceID != "" && networkInfo.GetWifiProfileCount() == 0 { t.Errorf("Expected non-zero wifi profile count for test %q", tt.name) } if len(networkInfo.GetInterfaces()) != tt.expectedInterfaceCount { t.Errorf("Expected %d interfaces, got %d", tt.expectedInterfaceCount, len(networkInfo.GetInterfaces())) } }) } } func TestClient_SystemEndpoints_Integration(t *testing.T) { // This test ensures all system endpoints work together server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/clockTime": switch r.Method { case "GET": _, _ = w.Write([]byte(`2021-01-01 00:00:00`)) case "POST": w.WriteHeader(http.StatusOK) } case "/clockDisplay": switch r.Method { case "GET": _, _ = w.Write([]byte(``)) case "POST": w.WriteHeader(http.StatusOK) } case "/networkInfo": _, _ = w.Write([]byte(` `)) default: w.WriteHeader(http.StatusNotFound) } })) defer server.Close() client := createTestClient(server.URL) // Test clock time operations clockTime, err := client.GetClockTime() if err != nil { t.Errorf("GetClockTime failed: %v", err) } else if clockTime.GetUTC() != 1609459200 { t.Errorf("Expected UTC 1609459200, got %d", clockTime.GetUTC()) } // Test setting clock time to now err = client.SetClockTimeNow() if err != nil { t.Errorf("SetClockTimeNow failed: %v", err) } // Test clock display operations clockDisplay, err := client.GetClockDisplay() if err != nil { t.Errorf("GetClockDisplay failed: %v", err) } else if !clockDisplay.IsEnabled() { t.Error("Expected clock display to be enabled") } // Test enabling/disabling clock display err = client.EnableClockDisplay() if err != nil { t.Errorf("EnableClockDisplay failed: %v", err) } err = client.DisableClockDisplay() if err != nil { t.Errorf("DisableClockDisplay failed: %v", err) } // Test network info networkInfo, err := client.GetNetworkInfo() if err != nil { t.Errorf("GetNetworkInfo failed: %v", err) } else if networkInfo.GetWifiProfileCount() != 2 { t.Errorf("Expected wifi profile count 2, got %d", networkInfo.GetWifiProfileCount()) } }