| // Copyright 2010 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package http | |
| import ( | |
| "bufio" | |
| "bytes" | |
| "fmt" | |
| "io" | |
| "reflect" | |
| "testing" | |
| ) | |
| type respTest struct { | |
| Raw string | |
| Resp Response | |
| Body string | |
| } | |
| var respTests = []respTest{ | |
| // Unchunked response without Content-Length. | |
| respTest{ | |
| "HTTP/1.0 200 OK\r\n" + | |
| "Connection: close\r\n" + | |
| "\r\n" + | |
| "Body here\n", | |
| Response{ | |
| Status: "200 OK", | |
| StatusCode: 200, | |
| Proto: "HTTP/1.0", | |
| ProtoMajor: 1, | |
| ProtoMinor: 0, | |
| RequestMethod: "GET", | |
| Header: map[string]string{ | |
| "Connection": "close", // TODO(rsc): Delete? | |
| }, | |
| Close: true, | |
| ContentLength: -1, | |
| }, | |
| "Body here\n", | |
| }, | |
| // Unchunked response with Content-Length. | |
| respTest{ | |
| "HTTP/1.0 200 OK\r\n" + | |
| "Content-Length: 10\r\n" + | |
| "Connection: close\r\n" + | |
| "\r\n" + | |
| "Body here\n", | |
| Response{ | |
| Status: "200 OK", | |
| StatusCode: 200, | |
| Proto: "HTTP/1.0", | |
| ProtoMajor: 1, | |
| ProtoMinor: 0, | |
| RequestMethod: "GET", | |
| Header: map[string]string{ | |
| "Connection": "close", // TODO(rsc): Delete? | |
| "Content-Length": "10", // TODO(rsc): Delete? | |
| }, | |
| Close: true, | |
| ContentLength: 10, | |
| }, | |
| "Body here\n", | |
| }, | |
| // Chunked response without Content-Length. | |
| respTest{ | |
| "HTTP/1.0 200 OK\r\n" + | |
| "Transfer-Encoding: chunked\r\n" + | |
| "\r\n" + | |
| "0a\r\n" + | |
| "Body here\n" + | |
| "0\r\n" + | |
| "\r\n", | |
| Response{ | |
| Status: "200 OK", | |
| StatusCode: 200, | |
| Proto: "HTTP/1.0", | |
| ProtoMajor: 1, | |
| ProtoMinor: 0, | |
| RequestMethod: "GET", | |
| Header: map[string]string{}, | |
| Close: true, | |
| ContentLength: -1, | |
| TransferEncoding: []string{"chunked"}, | |
| }, | |
| "Body here\n", | |
| }, | |
| // Chunked response with Content-Length. | |
| respTest{ | |
| "HTTP/1.0 200 OK\r\n" + | |
| "Transfer-Encoding: chunked\r\n" + | |
| "Content-Length: 10\r\n" + | |
| "\r\n" + | |
| "0a\r\n" + | |
| "Body here\n" + | |
| "0\r\n" + | |
| "\r\n", | |
| Response{ | |
| Status: "200 OK", | |
| StatusCode: 200, | |
| Proto: "HTTP/1.0", | |
| ProtoMajor: 1, | |
| ProtoMinor: 0, | |
| RequestMethod: "GET", | |
| Header: map[string]string{}, | |
| Close: true, | |
| ContentLength: -1, // TODO(rsc): Fix? | |
| TransferEncoding: []string{"chunked"}, | |
| }, | |
| "Body here\n", | |
| }, | |
| } | |
| func TestReadResponse(t *testing.T) { | |
| for i := range respTests { | |
| tt := &respTests[i] | |
| var braw bytes.Buffer | |
| braw.WriteString(tt.Raw) | |
| resp, err := ReadResponse(bufio.NewReader(&braw), tt.Resp.RequestMethod) | |
| if err != nil { | |
| t.Errorf("#%d: %s", i, err) | |
| continue | |
| } | |
| rbody := resp.Body | |
| resp.Body = nil | |
| diff(t, fmt.Sprintf("#%d Response", i), resp, &tt.Resp) | |
| var bout bytes.Buffer | |
| if rbody != nil { | |
| io.Copy(&bout, rbody) | |
| rbody.Close() | |
| } | |
| body := bout.String() | |
| if body != tt.Body { | |
| t.Errorf("#%d: Body = %q want %q", i, body, tt.Body) | |
| } | |
| } | |
| } | |
| func diff(t *testing.T, prefix string, have, want interface{}) { | |
| hv := reflect.NewValue(have).(*reflect.PtrValue).Elem().(*reflect.StructValue) | |
| wv := reflect.NewValue(want).(*reflect.PtrValue).Elem().(*reflect.StructValue) | |
| if hv.Type() != wv.Type() { | |
| t.Errorf("%s: type mismatch %v vs %v", prefix, hv.Type(), wv.Type()) | |
| } | |
| for i := 0; i < hv.NumField(); i++ { | |
| hf := hv.Field(i).Interface() | |
| wf := wv.Field(i).Interface() | |
| if !reflect.DeepEqual(hf, wf) { | |
| t.Errorf("%s: %s = %v want %v", prefix, hv.Type().(*reflect.StructType).Field(i).Name, hf, wf) | |
| } | |
| } | |
| } |