func (r *MockRequest) Headers(headers map[string]string) *MockRequest {
	for k, v := range headers {
		normalizedKey := textproto.CanonicalMIMEHeaderKey(k)
		r.headers[normalizedKey] = append(r.headers[normalizedKey], v)
	}
	return r
}
Headers configures the mock request to match the given headers
package apitest
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/textproto"
	"net/url"
	"reflect"
	"regexp"
	"sort"
	"strings"
	"sync"
	"time"
	"github.com/davecgh/go-spew/spew"
	"github.com/steinfletcher/apitest/difflib"
)
type Transport struct {
	debugEnabled             bool
	mockResponseDelayEnabled bool
	mocks                    []*Mock
	nativeTransport          http.RoundTripper
	httpClient               *http.Client
	observers                []Observe
	apiTest                  *APITest
}
func newTransport(
	mocks []*Mock,
	httpClient *http.Client,
	debugEnabled bool,
	mockResponseDelayEnabled bool,
	observers []Observe,
	apiTest *APITest) *Transport {
	t := &Transport{
		mocks:                    mocks,
		httpClient:               httpClient,
		debugEnabled:             debugEnabled,
		mockResponseDelayEnabled: mockResponseDelayEnabled,
		observers:                observers,
		apiTest:                  apiTest,
	}
	if httpClient != nil {
		t.nativeTransport = httpClient.Transport
	} else {
		t.nativeTransport = http.DefaultTransport
	}
	return t
}
type unmatchedMockError struct {
	errors map[int][]error
}
func newUnmatchedMockError() *unmatchedMockError {
	return &unmatchedMockError{
		errors: map[int][]error{},
	}
}
func (u *unmatchedMockError) addErrors(mockNumber int, errors ...error) *unmatchedMockError {
	u.errors[mockNumber] = append(u.errors[mockNumber], errors...)
	return u
}
func (u *unmatchedMockError) Error() string {
	var strBuilder strings.Builder
	strBuilder.WriteString("received request did not match any mocks\n\n")
	for _, mockNumber := range u.orderedMockKeys() {
		strBuilder.WriteString(fmt.Sprintf("Mock %d mismatches:\n", mockNumber))
		for _, err := range u.errors[mockNumber] {
			strBuilder.WriteString("• ")
			strBuilder.WriteString(err.Error())
			strBuilder.WriteString("\n")
		}
		strBuilder.WriteString("\n")
	}
	return strBuilder.String()
}
func (u *unmatchedMockError) orderedMockKeys() []int {
	var mockKeys []int
	for mockKey := range u.errors {
		mockKeys = append(mockKeys, mockKey)
	}
	sort.Ints(mockKeys)
	return mockKeys
}
func (r *Transport) RoundTrip(req *http.Request) (mockResponse *http.Response, matchErrors error) {
	if r.debugEnabled {
		defer func() {
			debugMock(mockResponse, req)
		}()
	}
	if r.observers != nil && len(r.observers) > 0 {
		defer func() {
			for _, observe := range r.observers {
				observe(mockResponse, req, r.apiTest)
			}
		}()
	}
	matchedResponse, matchErrors := matches(req, r.mocks)
	if matchErrors == nil {
		res := buildResponseFromMock(matchedResponse)
		res.Request = req
		if matchedResponse.timeout {
			return nil, timeoutError{}
		}
		if r.mockResponseDelayEnabled && matchedResponse.fixedDelayMillis > 0 {
			time.Sleep(time.Duration(matchedResponse.fixedDelayMillis) * time.Millisecond)
		}
		return res, nil
	}
	if r.debugEnabled {
		fmt.Printf("failed to match mocks. Errors: %s\n", matchErrors)
	}
	return nil, matchErrors
}
func debugMock(res *http.Response, req *http.Request) {
	requestDump, err := httputil.DumpRequestOut(req, true)
	if err == nil {
		debugLog(requestDebugPrefix, "request to mock", string(requestDump))
	}
	if res != nil {
		responseDump, err := httputil.DumpResponse(res, true)
		if err == nil {
			debugLog(responseDebugPrefix, "response from mock", string(responseDump))
		}
	} else {
		debugLog(responseDebugPrefix, "response from mock", "")
	}
}
func (r *Transport) Hijack() {
	if r.httpClient != nil {
		r.httpClient.Transport = r
		return
	}
	http.DefaultTransport = r
}
func (r *Transport) Reset() {
	if r.httpClient != nil {
		r.httpClient.Transport = r.nativeTransport
		return
	}
	http.DefaultTransport = r.nativeTransport
}
func buildResponseFromMock(mockResponse *MockResponse) *http.Response {
	if mockResponse == nil {
		return nil
	}
	contentTypeHeader := mockResponse.headers["Content-Type"]
	var contentType string
	if len(mockResponse.body) > 0 {
		if len(contentTypeHeader) == 0 {
			if json.Valid([]byte(mockResponse.body)) {
				contentType = "application/json"
			} else {
				contentType = "text/plain"
			}
		} else {
			contentType = contentTypeHeader[0]
		}
	}
	res := &http.Response{
		Body:          ioutil.NopCloser(strings.NewReader(mockResponse.body)),
		Header:        mockResponse.headers,
		StatusCode:    mockResponse.statusCode,
		ProtoMajor:    1,
		ProtoMinor:    1,
		ContentLength: int64(len(mockResponse.body)),
	}
	for _, cookie := range mockResponse.cookies {
		if v := cookie.ToHttpCookie().String(); v != "" {
			res.Header.Add("Set-Cookie", v)
		}
	}
	if contentType != "" {
		res.Header.Set("Content-Type", contentType)
	}
	return res
}
type Mock struct {
	m               *sync.Mutex
	isUsed          bool
	request         *MockRequest
	response        *MockResponse
	httpClient      *http.Client
	debugStandalone bool
	times           int
	timesSet        bool
}
func (m *Mock) Matches(req *http.Request) []error {
	var errs []error
	for _, matcher := range m.request.matchers {
		if matcherError := matcher(req, m.request); matcherError != nil {
			errs = append(errs, matcherError)
		}
	}
	return errs
}
func (m *Mock) copy() *Mock {
	newMock := *m
	newMock.m = &sync.Mutex{}
	req := *m.request
	newMock.request = &req
	res := *m.response
	newMock.response = &res
	return &newMock
}
type MockRequest struct {
	mock               *Mock
	url                *url.URL
	method             string
	headers            map[string][]string
	basicAuthUsername  string
	basicAuthPassword  string
	headerPresent      []string
	headerNotPresent   []string
	formData           map[string][]string
	formDataPresent    []string
	formDataNotPresent []string
	query              map[string][]string
	queryPresent       []string
	queryNotPresent    []string
	cookie             []Cookie
	cookiePresent      []string
	cookieNotPresent   []string
	body               string
	bodyRegexp         string
	matchers           []Matcher
}
type UnmatchedMock struct {
	URL url.URL
}
type MockResponse struct {
	mock             *Mock
	timeout          bool
	headers          map[string][]string
	cookies          []*Cookie
	body             string
	statusCode       int
	fixedDelayMillis int64
}
type StandaloneMocks struct {
	mocks      []*Mock
	httpClient *http.Client
	debug      bool
}
func NewStandaloneMocks(mocks ...*Mock) *StandaloneMocks {
	return &StandaloneMocks{
		mocks: mocks,
	}
}
func (r *StandaloneMocks) HttpClient(cli *http.Client) *StandaloneMocks {
	r.httpClient = cli
	return r
}
func (r *StandaloneMocks) Debug() *StandaloneMocks {
	r.debug = true
	return r
}
func (r *StandaloneMocks) End() func() {
	transport := newTransport(
		r.mocks,
		r.httpClient,
		r.debug,
		false,
		nil,
		nil,
	)
	resetFunc := func() { transport.Reset() }
	transport.Hijack()
	return resetFunc
}
func NewMock() *Mock {
	mock := &Mock{
		m:     &sync.Mutex{},
		times: 1,
	}
	mock.request = &MockRequest{
		mock:     mock,
		headers:  map[string][]string{},
		formData: map[string][]string{},
		query:    map[string][]string{},
		matchers: defaultMatchers,
	}
	mock.response = &MockResponse{
		mock:    mock,
		headers: map[string][]string{},
	}
	return mock
}
func (m *Mock) Debug() *Mock {
	m.debugStandalone = true
	return m
}
func (m *Mock) HttpClient(cli *http.Client) *Mock {
	m.httpClient = cli
	return m
}
func (m *Mock) Get(u string) *MockRequest {
	m.parseUrl(u)
	m.request.method = http.MethodGet
	return m.request
}
func (m *Mock) Getf(format string, args ...interface{}) *MockRequest {
	return m.Get(fmt.Sprintf(format, args...))
}
func (m *Mock) Head(u string) *MockRequest {
	m.parseUrl(u)
	m.request.method = http.MethodHead
	return m.request
}
func (m *Mock) Put(u string) *MockRequest {
	m.parseUrl(u)
	m.request.method = http.MethodPut
	return m.request
}
func (m *Mock) Putf(format string, args ...interface{}) *MockRequest {
	return m.Put(fmt.Sprintf(format, args...))
}
func (m *Mock) Post(u string) *MockRequest {
	m.parseUrl(u)
	m.request.method = http.MethodPost
	return m.request
}
func (m *Mock) Postf(format string, args ...interface{}) *MockRequest {
	return m.Post(fmt.Sprintf(format, args...))
}
func (m *Mock) Delete(u string) *MockRequest {
	m.parseUrl(u)
	m.request.method = http.MethodDelete
	return m.request
}
func (m *Mock) Deletef(format string, args ...interface{}) *MockRequest {
	return m.Delete(fmt.Sprintf(format, args...))
}
func (m *Mock) Patch(u string) *MockRequest {
	m.parseUrl(u)
	m.request.method = http.MethodPatch
	return m.request
}
func (m *Mock) Patchf(format string, args ...interface{}) *MockRequest {
	return m.Patch(fmt.Sprintf(format, args...))
}
func (m *Mock) parseUrl(u string) {
	parsed, err := url.Parse(u)
	if err != nil {
		panic(err)
	}
	m.request.url = parsed
}
func (m *Mock) Method(method string) *MockRequest {
	m.request.method = method
	return m.request
}
func matches(req *http.Request, mocks []*Mock) (*MockResponse, error) {
	mockError := newUnmatchedMockError()
	for mockNumber, mock := range mocks {
		mock.m.Lock()  
		if mock.isUsed {
			mock.m.Unlock()
			continue
		}
		errs := mock.Matches(req)
		if len(errs) == 0 {
			mock.isUsed = true
			mock.m.Unlock()
			return mock.response, nil
		}
		mockError = mockError.addErrors(mockNumber+1, errs...)
		mock.m.Unlock()
	}
	return nil, mockError
}
func (r *MockRequest) Body(b string) *MockRequest {
	r.body = b
	return r
}
func (r *MockRequest) BodyRegexp(b string) *MockRequest {
	r.body = b
	return r
}
func (r *MockRequest) Bodyf(format string, args ...interface{}) *MockRequest {
	return r.Body(fmt.Sprintf(format, args...))
}
func (r *MockRequest) BodyFromFile(f string) *MockRequest {
	b, err := ioutil.ReadFile(f)
	if err != nil {
		panic(err)
	}
	r.body = string(b)
	return r
}
func (r *MockRequest) JSON(v interface{}) *MockRequest {
	switch x := v.(type) {
	case string:
		r.body = x
	case []byte:
		r.body = string(x)
	default:
		asJSON, _ := json.Marshal(x)
		r.body = string(asJSON)
	}
	return r
}
func (r *MockRequest) Header(key, value string) *MockRequest {
	normalizedKey := textproto.CanonicalMIMEHeaderKey(key)
	r.headers[normalizedKey] = append(r.headers[normalizedKey], value)
	return r
}