Skip to content

Commit 787e2d2

Browse files
committed
chore: test coverage
1 parent 4fe6f18 commit 787e2d2

12 files changed

+1445
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.idea
22
AGENTS.md
33
SPECIFICATION.md
4+
cover.out

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ It keeps req's power and escape hatches, while making the 90% use case feel effo
1414
<a href="https://goreportcard.com/report/github.com/goforj/httpx"><img src="https://goreportcard.com/badge/github.com/goforj/httpx" alt="Go Report Card"></a>
1515
<a href="https://codecov.io/gh/goforj/httpx" ><img src="https://codecov.io/gh/goforj/httpx/graph/badge.svg?token=R5O7LYAD4B"/></a>
1616
<!-- test-count:embed:start -->
17-
<img src="https://img.shields.io/badge/tests-74-brightgreen" alt="Tests">
17+
<img src="https://img.shields.io/badge/tests-135-brightgreen" alt="Tests">
1818
<!-- test-count:embed:end -->
1919
</p>
2020

client_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package httpx
22

33
import (
4+
"context"
45
"encoding/json"
56
"errors"
67
"net/http"
78
"net/http/httptest"
9+
"os"
810
"testing"
911

1012
"github.com/imroc/req/v3"
@@ -203,3 +205,131 @@ func TestQueryOddPanics(t *testing.T) {
203205
req := req.C().R()
204206
Query("q")(req)
205207
}
208+
209+
func TestDefaultReqRaw(t *testing.T) {
210+
c1 := Default()
211+
c2 := Default()
212+
if c1 == nil || c2 == nil || c1 != c2 {
213+
t.Fatalf("expected default client singleton")
214+
}
215+
if c1.Req() == nil {
216+
t.Fatalf("expected req client")
217+
}
218+
if c1.Raw() == nil {
219+
t.Fatalf("expected raw client")
220+
}
221+
}
222+
223+
func TestRequestMethods(t *testing.T) {
224+
var gotMethod string
225+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
226+
gotMethod = r.Method
227+
_, _ = w.Write([]byte(`{"name":"ok"}`))
228+
}))
229+
t.Cleanup(server.Close)
230+
231+
client := New()
232+
res := Put[createUser, user](client, server.URL, createUser{Name: "ok"})
233+
if res.Err != nil {
234+
t.Fatalf("put error: %v", res.Err)
235+
}
236+
if gotMethod != http.MethodPut {
237+
t.Fatalf("method = %q", gotMethod)
238+
}
239+
240+
res = Patch[createUser, user](client, server.URL, createUser{Name: "ok"})
241+
if res.Err != nil {
242+
t.Fatalf("patch error: %v", res.Err)
243+
}
244+
if gotMethod != http.MethodPatch {
245+
t.Fatalf("method = %q", gotMethod)
246+
}
247+
248+
resDel := Delete[user](client, server.URL)
249+
if resDel.Err != nil {
250+
t.Fatalf("delete error: %v", resDel.Err)
251+
}
252+
if gotMethod != http.MethodDelete {
253+
t.Fatalf("method = %q", gotMethod)
254+
}
255+
}
256+
257+
func TestContextMethods(t *testing.T) {
258+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
259+
_, _ = w.Write([]byte(`{"name":"ctx"}`))
260+
}))
261+
t.Cleanup(server.Close)
262+
263+
client := New()
264+
ctx := context.Background()
265+
266+
if res := GetCtx[user](client, ctx, server.URL); res.Err != nil {
267+
t.Fatalf("getctx error: %v", res.Err)
268+
}
269+
if res := PostCtx[createUser, user](client, ctx, server.URL, createUser{Name: "ctx"}); res.Err != nil {
270+
t.Fatalf("postctx error: %v", res.Err)
271+
}
272+
if res := PutCtx[createUser, user](client, ctx, server.URL, createUser{Name: "ctx"}); res.Err != nil {
273+
t.Fatalf("putctx error: %v", res.Err)
274+
}
275+
if res := PatchCtx[createUser, user](client, ctx, server.URL, createUser{Name: "ctx"}); res.Err != nil {
276+
t.Fatalf("patchctx error: %v", res.Err)
277+
}
278+
if res := DeleteCtx[user](client, ctx, server.URL); res.Err != nil {
279+
t.Fatalf("deletectx error: %v", res.Err)
280+
}
281+
}
282+
283+
func TestSendUnknownMethod(t *testing.T) {
284+
_, err := send(req.C().R(), "TRACE-UNKNOWN", "http://example.com")
285+
if err == nil {
286+
t.Fatalf("expected error for unsupported method")
287+
}
288+
}
289+
290+
func TestNewWithHTTPTrace(t *testing.T) {
291+
if err := os.Setenv("HTTP_TRACE", "1"); err != nil {
292+
t.Fatalf("set env: %v", err)
293+
}
294+
defer os.Unsetenv("HTTP_TRACE")
295+
_ = New()
296+
}
297+
298+
func TestDumpExample(t *testing.T) {
299+
dumpExample("ok")
300+
}
301+
302+
func TestDoIgnoresAfterResponseErrorOnEmptyBody(t *testing.T) {
303+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
304+
w.WriteHeader(http.StatusOK)
305+
}))
306+
t.Cleanup(server.Close)
307+
308+
client := New()
309+
res := Get[user](client, server.URL, Before(func(r *req.Request) {
310+
r.OnAfterResponse(func(_ *req.Client, _ *req.Response) error {
311+
return errors.New("after response error")
312+
})
313+
}))
314+
if res.Err != nil {
315+
t.Fatalf("expected error to be ignored, got %v", res.Err)
316+
}
317+
if res.Response == nil {
318+
t.Fatalf("expected response")
319+
}
320+
}
321+
322+
func TestNilClientDefaults(t *testing.T) {
323+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
324+
_ = json.NewEncoder(w).Encode(user{Name: "default"})
325+
}))
326+
t.Cleanup(server.Close)
327+
328+
res := Get[user](nil, server.URL)
329+
if res.Err != nil {
330+
t.Fatalf("unexpected error: %v", res.Err)
331+
}
332+
if res.Body.Name != "default" {
333+
t.Fatalf("unexpected response: %s", res.Body.Name)
334+
}
335+
}

decode_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package httpx
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/imroc/req/v3"
9+
)
10+
11+
func TestRawKindAndDecode(t *testing.T) {
12+
if rawKindOf[string]() != rawString {
13+
t.Fatalf("expected rawString")
14+
}
15+
if rawKindOf[[]byte]() != rawBytes {
16+
t.Fatalf("expected rawBytes")
17+
}
18+
if rawKindOf[[]int]() != rawNone {
19+
t.Fatalf("expected rawNone for slice")
20+
}
21+
if rawKindOf[int]() != rawNone {
22+
t.Fatalf("expected rawNone")
23+
}
24+
25+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
26+
_, _ = w.Write([]byte("hello"))
27+
}))
28+
t.Cleanup(srv.Close)
29+
30+
resp, err := req.C().R().Get(srv.URL)
31+
if err != nil {
32+
t.Fatalf("request failed: %v", err)
33+
}
34+
if got := decodeRaw[string](resp); got != "hello" {
35+
t.Fatalf("decode string = %q", got)
36+
}
37+
if got := decodeRaw[[]byte](resp); string(got) != "hello" {
38+
t.Fatalf("decode bytes = %q", string(got))
39+
}
40+
if got := decodeRaw[int](resp); got != 0 {
41+
t.Fatalf("decode int = %d", got)
42+
}
43+
}
44+
45+
func TestEnsureNonNil(t *testing.T) {
46+
var p *int
47+
ensureNonNil(p)
48+
49+
var s []int
50+
ensureNonNil(&s)
51+
if s == nil {
52+
t.Fatalf("expected slice initialized")
53+
}
54+
55+
var m map[string]int
56+
ensureNonNil(&m)
57+
if m == nil {
58+
t.Fatalf("expected map initialized")
59+
}
60+
}
61+
62+
func TestIsEmptyBody(t *testing.T) {
63+
if isEmptyBody(nil) {
64+
t.Fatalf("expected false for nil response")
65+
}
66+
67+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
68+
w.WriteHeader(http.StatusOK)
69+
}))
70+
t.Cleanup(srv.Close)
71+
72+
resp, err := req.C().R().Get(srv.URL)
73+
if err != nil {
74+
t.Fatalf("request failed: %v", err)
75+
}
76+
if !isEmptyBody(resp) {
77+
t.Fatalf("expected empty body")
78+
}
79+
80+
srv2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
81+
_, _ = w.Write([]byte("data"))
82+
}))
83+
t.Cleanup(srv2.Close)
84+
85+
resp2, err := req.C().R().Get(srv2.URL)
86+
if err != nil {
87+
t.Fatalf("request failed: %v", err)
88+
}
89+
if isEmptyBody(resp2) {
90+
t.Fatalf("expected non-empty body")
91+
}
92+
93+
srv3 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
94+
_, _ = w.Write([]byte(" "))
95+
}))
96+
t.Cleanup(srv3.Close)
97+
98+
resp3, err := req.C().R().Get(srv3.URL)
99+
if err != nil {
100+
t.Fatalf("request failed: %v", err)
101+
}
102+
if !isEmptyBody(resp3) {
103+
t.Fatalf("expected empty body for whitespace")
104+
}
105+
}

errors_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package httpx
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/imroc/req/v3"
9+
)
10+
11+
func TestHTTPErrorString(t *testing.T) {
12+
err := (&HTTPError{StatusCode: 400, Status: "Bad Request"}).Error()
13+
if err == "" {
14+
t.Fatalf("expected error string")
15+
}
16+
}
17+
18+
func TestNewHTTPErrorNilResponse(t *testing.T) {
19+
err := newHTTPError(nil)
20+
if err.StatusCode != 0 {
21+
t.Fatalf("expected status 0")
22+
}
23+
if err.Status == "" {
24+
t.Fatalf("expected status message")
25+
}
26+
}
27+
28+
func TestNewHTTPErrorResponse(t *testing.T) {
29+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
30+
w.WriteHeader(http.StatusInternalServerError)
31+
}))
32+
t.Cleanup(srv.Close)
33+
34+
resp, reqErr := req.C().R().Get(srv.URL)
35+
if reqErr != nil {
36+
t.Fatalf("request failed: %v", reqErr)
37+
}
38+
err := newHTTPError(resp)
39+
if err.StatusCode != 500 {
40+
t.Fatalf("status code = %d", err.StatusCode)
41+
}
42+
}

options_auth_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package httpx
2+
3+
import (
4+
"encoding/base64"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
)
9+
10+
func TestAuthHeaders(t *testing.T) {
11+
var gotAuth string
12+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
13+
gotAuth = r.Header.Get("Authorization")
14+
w.WriteHeader(http.StatusOK)
15+
}))
16+
defer srv.Close()
17+
18+
c := New()
19+
res := Get[string](c, srv.URL, Auth("Token", "abc123"))
20+
if res.Err != nil {
21+
t.Fatalf("auth request failed: %v", res.Err)
22+
}
23+
if gotAuth != "Token abc123" {
24+
t.Fatalf("auth header = %q", gotAuth)
25+
}
26+
}
27+
28+
func TestBearerAndBasic(t *testing.T) {
29+
var auths []string
30+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
31+
auths = append(auths, r.Header.Get("Authorization"))
32+
w.WriteHeader(http.StatusOK)
33+
}))
34+
defer srv.Close()
35+
36+
c := New()
37+
res := Get[string](c, srv.URL, Bearer("token"))
38+
if res.Err != nil {
39+
t.Fatalf("bearer request failed: %v", res.Err)
40+
}
41+
res = Get[string](c, srv.URL, Basic("user", "pass"))
42+
if res.Err != nil {
43+
t.Fatalf("basic request failed: %v", res.Err)
44+
}
45+
if len(auths) != 2 {
46+
t.Fatalf("auths len = %d", len(auths))
47+
}
48+
if auths[0] != "Bearer token" {
49+
t.Fatalf("bearer header = %q", auths[0])
50+
}
51+
wantBasic := "Basic " + base64.StdEncoding.EncodeToString([]byte("user:pass"))
52+
if auths[1] != wantBasic {
53+
t.Fatalf("basic header = %q", auths[1])
54+
}
55+
}

0 commit comments

Comments
 (0)