...
Run Format

Source file src/net/http/httptest/recorder_test.go

Documentation: net/http/httptest

  // Copyright 2012 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 httptest
  
  import (
  	"fmt"
  	"io"
  	"net/http"
  	"testing"
  )
  
  func TestRecorder(t *testing.T) {
  	type checkFunc func(*ResponseRecorder) error
  	check := func(fns ...checkFunc) []checkFunc { return fns }
  
  	hasStatus := func(wantCode int) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if rec.Code != wantCode {
  				return fmt.Errorf("Status = %d; want %d", rec.Code, wantCode)
  			}
  			return nil
  		}
  	}
  	hasResultStatus := func(want string) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if rec.Result().Status != want {
  				return fmt.Errorf("Result().Status = %q; want %q", rec.Result().Status, want)
  			}
  			return nil
  		}
  	}
  	hasResultStatusCode := func(wantCode int) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if rec.Result().StatusCode != wantCode {
  				return fmt.Errorf("Result().StatusCode = %d; want %d", rec.Result().StatusCode, wantCode)
  			}
  			return nil
  		}
  	}
  	hasContents := func(want string) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if rec.Body.String() != want {
  				return fmt.Errorf("wrote = %q; want %q", rec.Body.String(), want)
  			}
  			return nil
  		}
  	}
  	hasFlush := func(want bool) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if rec.Flushed != want {
  				return fmt.Errorf("Flushed = %v; want %v", rec.Flushed, want)
  			}
  			return nil
  		}
  	}
  	hasOldHeader := func(key, want string) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if got := rec.HeaderMap.Get(key); got != want {
  				return fmt.Errorf("HeaderMap header %s = %q; want %q", key, got, want)
  			}
  			return nil
  		}
  	}
  	hasHeader := func(key, want string) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if got := rec.Result().Header.Get(key); got != want {
  				return fmt.Errorf("final header %s = %q; want %q", key, got, want)
  			}
  			return nil
  		}
  	}
  	hasNotHeaders := func(keys ...string) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			for _, k := range keys {
  				v, ok := rec.Result().Header[http.CanonicalHeaderKey(k)]
  				if ok {
  					return fmt.Errorf("unexpected header %s with value %q", k, v)
  				}
  			}
  			return nil
  		}
  	}
  	hasTrailer := func(key, want string) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if got := rec.Result().Trailer.Get(key); got != want {
  				return fmt.Errorf("trailer %s = %q; want %q", key, got, want)
  			}
  			return nil
  		}
  	}
  	hasNotTrailers := func(keys ...string) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			trailers := rec.Result().Trailer
  			for _, k := range keys {
  				_, ok := trailers[http.CanonicalHeaderKey(k)]
  				if ok {
  					return fmt.Errorf("unexpected trailer %s", k)
  				}
  			}
  			return nil
  		}
  	}
  	hasContentLength := func(length int64) checkFunc {
  		return func(rec *ResponseRecorder) error {
  			if got := rec.Result().ContentLength; got != length {
  				return fmt.Errorf("ContentLength = %d; want %d", got, length)
  			}
  			return nil
  		}
  	}
  
  	tests := []struct {
  		name   string
  		h      func(w http.ResponseWriter, r *http.Request)
  		checks []checkFunc
  	}{
  		{
  			"200 default",
  			func(w http.ResponseWriter, r *http.Request) {},
  			check(hasStatus(200), hasContents("")),
  		},
  		{
  			"first code only",
  			func(w http.ResponseWriter, r *http.Request) {
  				w.WriteHeader(201)
  				w.WriteHeader(202)
  				w.Write([]byte("hi"))
  			},
  			check(hasStatus(201), hasContents("hi")),
  		},
  		{
  			"write sends 200",
  			func(w http.ResponseWriter, r *http.Request) {
  				w.Write([]byte("hi first"))
  				w.WriteHeader(201)
  				w.WriteHeader(202)
  			},
  			check(hasStatus(200), hasContents("hi first"), hasFlush(false)),
  		},
  		{
  			"write string",
  			func(w http.ResponseWriter, r *http.Request) {
  				io.WriteString(w, "hi first")
  			},
  			check(
  				hasStatus(200),
  				hasContents("hi first"),
  				hasFlush(false),
  				hasHeader("Content-Type", "text/plain; charset=utf-8"),
  			),
  		},
  		{
  			"flush",
  			func(w http.ResponseWriter, r *http.Request) {
  				w.(http.Flusher).Flush() // also sends a 200
  				w.WriteHeader(201)
  			},
  			check(hasStatus(200), hasFlush(true), hasContentLength(-1)),
  		},
  		{
  			"Content-Type detection",
  			func(w http.ResponseWriter, r *http.Request) {
  				io.WriteString(w, "<html>")
  			},
  			check(hasHeader("Content-Type", "text/html; charset=utf-8")),
  		},
  		{
  			"no Content-Type detection with Transfer-Encoding",
  			func(w http.ResponseWriter, r *http.Request) {
  				w.Header().Set("Transfer-Encoding", "some encoding")
  				io.WriteString(w, "<html>")
  			},
  			check(hasHeader("Content-Type", "")), // no header
  		},
  		{
  			"no Content-Type detection if set explicitly",
  			func(w http.ResponseWriter, r *http.Request) {
  				w.Header().Set("Content-Type", "some/type")
  				io.WriteString(w, "<html>")
  			},
  			check(hasHeader("Content-Type", "some/type")),
  		},
  		{
  			"Content-Type detection doesn't crash if HeaderMap is nil",
  			func(w http.ResponseWriter, r *http.Request) {
  				// Act as if the user wrote new(httptest.ResponseRecorder)
  				// rather than using NewRecorder (which initializes
  				// HeaderMap)
  				w.(*ResponseRecorder).HeaderMap = nil
  				io.WriteString(w, "<html>")
  			},
  			check(hasHeader("Content-Type", "text/html; charset=utf-8")),
  		},
  		{
  			"Header is not changed after write",
  			func(w http.ResponseWriter, r *http.Request) {
  				hdr := w.Header()
  				hdr.Set("Key", "correct")
  				w.WriteHeader(200)
  				hdr.Set("Key", "incorrect")
  			},
  			check(hasHeader("Key", "correct")),
  		},
  		{
  			"Trailer headers are correctly recorded",
  			func(w http.ResponseWriter, r *http.Request) {
  				w.Header().Set("Non-Trailer", "correct")
  				w.Header().Set("Trailer", "Trailer-A")
  				w.Header().Add("Trailer", "Trailer-B")
  				w.Header().Add("Trailer", "Trailer-C")
  				io.WriteString(w, "<html>")
  				w.Header().Set("Non-Trailer", "incorrect")
  				w.Header().Set("Trailer-A", "valuea")
  				w.Header().Set("Trailer-C", "valuec")
  				w.Header().Set("Trailer-NotDeclared", "should be omitted")
  				w.Header().Set("Trailer:Trailer-D", "with prefix")
  			},
  			check(
  				hasStatus(200),
  				hasHeader("Content-Type", "text/html; charset=utf-8"),
  				hasHeader("Non-Trailer", "correct"),
  				hasNotHeaders("Trailer-A", "Trailer-B", "Trailer-C", "Trailer-NotDeclared"),
  				hasTrailer("Trailer-A", "valuea"),
  				hasTrailer("Trailer-C", "valuec"),
  				hasNotTrailers("Non-Trailer", "Trailer-B", "Trailer-NotDeclared"),
  				hasTrailer("Trailer-D", "with prefix"),
  			),
  		},
  		{
  			"Header set without any write", // Issue 15560
  			func(w http.ResponseWriter, r *http.Request) {
  				w.Header().Set("X-Foo", "1")
  
  				// Simulate somebody using
  				// new(ResponseRecorder) instead of
  				// using the constructor which sets
  				// this to 200
  				w.(*ResponseRecorder).Code = 0
  			},
  			check(
  				hasOldHeader("X-Foo", "1"),
  				hasStatus(0),
  				hasHeader("X-Foo", "1"),
  				hasResultStatus("200 OK"),
  				hasResultStatusCode(200),
  			),
  		},
  		{
  			"HeaderMap vs FinalHeaders", // more for Issue 15560
  			func(w http.ResponseWriter, r *http.Request) {
  				h := w.Header()
  				h.Set("X-Foo", "1")
  				w.Write([]byte("hi"))
  				h.Set("X-Foo", "2")
  				h.Set("X-Bar", "2")
  			},
  			check(
  				hasOldHeader("X-Foo", "2"),
  				hasOldHeader("X-Bar", "2"),
  				hasHeader("X-Foo", "1"),
  				hasNotHeaders("X-Bar"),
  			),
  		},
  		{
  			"setting Content-Length header",
  			func(w http.ResponseWriter, r *http.Request) {
  				body := "Some body"
  				contentLength := fmt.Sprintf("%d", len(body))
  				w.Header().Set("Content-Length", contentLength)
  				io.WriteString(w, body)
  			},
  			check(hasStatus(200), hasContents("Some body"), hasContentLength(9)),
  		},
  	}
  	r, _ := http.NewRequest("GET", "http://foo.com/", nil)
  	for _, tt := range tests {
  		h := http.HandlerFunc(tt.h)
  		rec := NewRecorder()
  		h.ServeHTTP(rec, r)
  		for _, check := range tt.checks {
  			if err := check(rec); err != nil {
  				t.Errorf("%s: %v", tt.name, err)
  			}
  		}
  	}
  }
  

View as plain text