package deepseek import ( "context" "io" "net/http" "strings" "testing" ) type roundTripFunc func(*http.Request) (*http.Response, error) func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) } func testAPI(handler roundTripFunc) *Client { return NewClient(). SetBaseURL("https://api.example.test"). SetHTTPClient(&http.Client{Transport: handler}) } func testHTTPResponse(body string) *http.Response { return &http.Response{ StatusCode: http.StatusOK, Status: "200 OK", Header: make(http.Header), Body: io.NopCloser(strings.NewReader(body)), } } func TestRequestUnmarshallBizResponse(t *testing.T) { tests := []struct { name string body string wantValue string wantErr string }{ {name: "success", body: `{"code":0,"data":{"biz_code":0,"biz_data":{"value":"ok"}}}`, wantValue: "ok"}, {name: "outer error", body: `{"code":401,"msg":"unauthorized"}`, wantErr: "unauthorized (401)"}, {name: "business error", body: `{"code":0,"data":{"biz_code":23,"biz_msg":"denied"}}`, wantErr: "denied (23)"}, {name: "invalid JSON", body: `{`, wantErr: "unexpected end of JSON input"}, } type result struct { Value string `json:"value"` } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req := NewRequest[result](http.MethodGet, "test", NoParams) resp := &http.Response{Body: io.NopCloser(strings.NewReader(tt.body))} got, err := req.unmarshallBizResponse(resp) if tt.wantErr != "" { if err == nil || !strings.Contains(err.Error(), tt.wantErr) { t.Fatalf("unmarshallBizResponse() error = %v, want containing %q", err, tt.wantErr) } return } if err != nil { t.Fatalf("unmarshallBizResponse() error = %v", err) } if got.Data.Data.Value != tt.wantValue { t.Fatalf("value = %q, want %q", got.Data.Data.Value, tt.wantValue) } }) } } func TestRequestDoWithContext(t *testing.T) { client := testAPI(func(r *http.Request) (*http.Response, error) { if r.Method != http.MethodPost { t.Errorf("method = %q, want POST", r.Method) } if r.URL.Path != "/items" { t.Errorf("path = %q, want /items", r.URL.Path) } if got := r.Header.Get("Authorization"); got != "Bearer test-token" { t.Errorf("Authorization = %q", got) } if got := r.Header.Get("x-ds-pow-response"); got != "pow-answer" { t.Errorf("x-ds-pow-response = %q", got) } if got := r.Header.Get("Content-Type"); got != "application/json" { t.Errorf("Content-Type = %q", got) } body, err := io.ReadAll(r.Body) if err != nil { t.Errorf("read body: %v", err) } if got := string(body); got != `{"name":"value"}` { t.Errorf("body = %s", got) } return testHTTPResponse(`{}`), nil }).SetToken("test-token") req := NewRequest[struct{}](http.MethodPost, "items", map[string]string{"name": "value"}) req.powAnswer = "pow-answer" resp, err := req.DoWithContext(context.Background(), client) if err != nil { t.Fatalf("DoWithContext() error = %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("status = %d, want 200", resp.StatusCode) } } func TestRequestDoWithCanceledContext(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() client := testAPI(func(r *http.Request) (*http.Response, error) { if err := r.Context().Err(); err != context.Canceled { t.Errorf("request context error = %v, want context canceled", err) } return nil, r.Context().Err() }) req := NewRequest[struct{}](http.MethodGet, "test", NoParams) _, err := req.DoWithContext(ctx, client) if err == nil || !strings.Contains(err.Error(), context.Canceled.Error()) { t.Fatalf("DoWithContext() error = %v, want context canceled", err) } }