package starnet import ( "net/http" "net/http/httptest" "testing" "time" ) func TestNewClient(t *testing.T) { client, err := NewClient() if err != nil { t.Fatalf("NewClient() error: %v", err) } if client == nil { t.Fatal("NewClient() returned nil") } } func TestNewClientNoErr(t *testing.T) { client := NewClientNoErr() if client == nil { t.Fatal("NewClientNoErr() returned nil") } } func TestNewClientFromHTTP(t *testing.T) { httpClient := &http.Client{ Timeout: 10 * time.Second, } client, err := NewClientFromHTTP(httpClient) if err != nil { t.Fatalf("NewClientFromHTTP() error: %v", err) } if client == nil { t.Fatal("NewClientFromHTTP() returned nil") } // Test with nil client _, err = NewClientFromHTTP(nil) if err == nil { t.Error("NewClientFromHTTP(nil) should return error") } } func TestClientOptions(t *testing.T) { client := NewClientNoErr() // Set options client.SetOptions(WithTimeout(5 * time.Second)) opts := client.RequestOptions() if len(opts) != 1 { t.Errorf("RequestOptions() length = %v; want 1", len(opts)) } // Add options client.AddOptions(WithUserAgent("TestAgent")) opts = client.RequestOptions() if len(opts) != 2 { t.Errorf("RequestOptions() length = %v; want 2", len(opts)) } } func TestClientClone(t *testing.T) { client := NewClientNoErr(WithTimeout(5 * time.Second)) cloned := client.Clone() if cloned == nil { t.Fatal("Clone() returned nil") } // 修改克隆的 client cloned.SetOptions(WithTimeout(10 * time.Second)) origOpts := client.RequestOptions() clonedOpts := cloned.RequestOptions() // 原 client 应该还是 1 个选项 if len(origOpts) != 1 { t.Errorf("Original client options = %v; want 1", len(origOpts)) } // 克隆的 client 应该是 1 个选项(被 SetOptions 覆盖) if len(clonedOpts) != 1 { t.Errorf("Cloned client options = %v; want 1", len(clonedOpts)) } } func TestClientHTTPMethods(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte(r.Method)) })) defer server.Close() client := NewClientNoErr() tests := []struct { name string method func(string, ...RequestOpt) (*Response, error) want string }{ {"GET", client.Get, "GET"}, {"POST", client.Post, "POST"}, {"PUT", client.Put, "PUT"}, {"DELETE", client.Delete, "DELETE"}, {"PATCH", client.Patch, "PATCH"}, {"HEAD", client.Head, "HEAD"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, err := tt.method(server.URL) if err != nil { t.Fatalf("%s() error: %v", tt.name, err) } defer resp.Close() if tt.want != "HEAD" { body, _ := resp.Body().String() if body != tt.want { t.Errorf("Body = %v; want %v", body, tt.want) } } }) } } func TestClientRedirect(t *testing.T) { redirectCount := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if redirectCount < 2 { redirectCount++ http.Redirect(w, r, "/redirected", http.StatusFound) return } w.WriteHeader(http.StatusOK) w.Write([]byte("final")) })) defer server.Close() // Test with redirect enabled (default) client := NewClientNoErr() resp, err := client.Get(server.URL) if err != nil { t.Fatalf("Get() error: %v", err) } resp.Close() if redirectCount != 2 { t.Errorf("Redirect count = %v; want 2", redirectCount) } // Test with redirect disabled redirectCount = 0 client.DisableRedirect() resp2, err := client.Get(server.URL) if err != nil { t.Fatalf("Get() error: %v", err) } defer resp2.Close() if resp2.StatusCode != http.StatusFound { t.Errorf("StatusCode = %v; want %v", resp2.StatusCode, http.StatusFound) } } func TestClientTLSConfig(t *testing.T) { server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("OK")) })) defer server.Close() // Without skip verify (should fail with self-signed cert) client := NewClientNoErr() _, err := client.Get(server.URL) if err == nil { t.Error("Expected TLS error with self-signed cert, got nil") } // With skip verify client.SetDefaultSkipTLSVerify(true) resp, err := client.Get(server.URL) if err != nil { t.Fatalf("Get() with skip verify error: %v", err) } defer resp.Close() if resp.StatusCode != http.StatusOK { t.Errorf("StatusCode = %v; want %v", resp.StatusCode, http.StatusOK) } } func TestClientNewSimpleRequest(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("OK")) })) defer server.Close() client := NewClientNoErr() req := client.NewSimpleRequest(server.URL, "GET", WithHeader("X-Test", "v")) if req == nil { t.Fatal("NewSimpleRequest returned nil") } if req.Err() != nil { t.Fatalf("NewSimpleRequest err: %v", req.Err()) } resp, err := req.Do() if err != nil { t.Fatalf("Do() error: %v", err) } defer resp.Close() body, _ := resp.Body().String() if body != "OK" { t.Errorf("Body = %v; want OK", body) } }