go.sdls.io/sin@v0.0.9/pkg/sin/context_test.go (about)

     1  // Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
     2  // Use of this source code is governed by a MIT style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sin
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"errors"
    11  	"fmt"
    12  	"mime/multipart"
    13  	"net/http"
    14  	"net/http/httptest"
    15  	"reflect"
    16  	"strings"
    17  	"sync"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  )
    23  
    24  var _ context.Context = &Context{}
    25  
    26  var errTestPanicRender = errors.New("TestPanicRender")
    27  
    28  // Unit tests TODO
    29  // func (c *Context) File(filepath string) {
    30  // func (c *Context) Negotiate(code int, config Negotiate) {
    31  // BAD case: func (c *Context) Render(code int, render render.Render, obj ...interface{}) {
    32  // test that information is not leaked when reusing Contexts (using the Pool)
    33  
    34  func TestContextFormFileFailed(t *testing.T) {
    35  	buf := new(bytes.Buffer)
    36  	mw := multipart.NewWriter(buf)
    37  	_ = mw.Close()
    38  	c, _ := CreateTestContext(httptest.NewRecorder())
    39  	c.Request, _ = http.NewRequest("POST", "/", nil)
    40  	c.Request.Header.Set("Content-Type", mw.FormDataContentType())
    41  	c.engine.MaxMultipartMemory = 8 << 20
    42  	f, err := c.FormFile("file")
    43  	assert.Error(t, err)
    44  	assert.Nil(t, f)
    45  }
    46  
    47  func TestContextReset(t *testing.T) {
    48  	router := New()
    49  	c := router.allocateContext()
    50  	assert.Equal(t, c.engine, router)
    51  
    52  	c.index = 2
    53  	c.Writer = &responseWriter{ResponseWriter: httptest.NewRecorder()}
    54  	c.Params = Params{Param{}}
    55  	c.Error(errors.New("test")) // nolint: errcheck
    56  	c.Set("foo", "bar")
    57  	c.reset()
    58  
    59  	assert.False(t, c.IsAborted())
    60  	assert.Nil(t, c.Keys)
    61  	assert.Len(t, c.Errors, 0)
    62  	assert.Empty(t, c.Errors.Errors())
    63  	assert.Empty(t, c.Errors.ByType(ErrorTypeAny))
    64  	assert.Len(t, c.Params, 0)
    65  	assert.EqualValues(t, c.index, -1)
    66  	assert.Equal(t, c.Writer.(*responseWriter), &c.writermem)
    67  }
    68  
    69  func TestContextHandlers(t *testing.T) {
    70  	c, _ := CreateTestContext(httptest.NewRecorder())
    71  	assert.Nil(t, c.handlers)
    72  	assert.Nil(t, c.handlers.Last())
    73  
    74  	c.handlers = HandlersChain{}
    75  	assert.NotNil(t, c.handlers)
    76  	assert.Nil(t, c.handlers.Last())
    77  
    78  	f := func(c *Context) {}
    79  	g := func(c *Context) {}
    80  
    81  	c.handlers = HandlersChain{f}
    82  	compareFunc(t, f, c.handlers.Last())
    83  
    84  	c.handlers = HandlersChain{f, g}
    85  	compareFunc(t, g, c.handlers.Last())
    86  }
    87  
    88  // TestContextSetGet tests that a parameter is set correctly on the
    89  // current context and can be retrieved using Get.
    90  func TestContextSetGet(t *testing.T) {
    91  	c, _ := CreateTestContext(httptest.NewRecorder())
    92  	c.Set("foo", "bar")
    93  
    94  	value, err := c.Get("foo")
    95  	assert.Equal(t, "bar", value)
    96  	assert.True(t, err)
    97  
    98  	value, err = c.Get("foo2")
    99  	assert.Nil(t, value)
   100  	assert.False(t, err)
   101  
   102  	assert.Equal(t, "bar", c.MustGet("foo"))
   103  	assert.Panics(t, func() { c.MustGet("no_exist") })
   104  }
   105  
   106  func TestContextSetGetValues(t *testing.T) {
   107  	c, _ := CreateTestContext(httptest.NewRecorder())
   108  	c.Set("string", "this is a string")
   109  	c.Set("int32", int32(-42))
   110  	c.Set("int64", int64(42424242424242))
   111  	c.Set("uint64", uint64(42))
   112  	c.Set("float32", float32(4.2))
   113  	c.Set("float64", 4.2)
   114  	var a interface{} = 1
   115  	c.Set("intInterface", a)
   116  
   117  	assert.Exactly(t, c.MustGet("string").(string), "this is a string")
   118  	assert.Exactly(t, c.MustGet("int32").(int32), int32(-42))
   119  	assert.Exactly(t, c.MustGet("int64").(int64), int64(42424242424242))
   120  	assert.Exactly(t, c.MustGet("uint64").(uint64), uint64(42))
   121  	assert.Exactly(t, c.MustGet("float32").(float32), float32(4.2))
   122  	assert.Exactly(t, c.MustGet("float64").(float64), 4.2)
   123  	assert.Exactly(t, c.MustGet("intInterface").(int), 1)
   124  }
   125  
   126  func TestContextGetString(t *testing.T) {
   127  	c, _ := CreateTestContext(httptest.NewRecorder())
   128  	c.Set("string", "this is a string")
   129  	assert.Equal(t, "this is a string", c.GetString("string"))
   130  }
   131  
   132  func TestContextSetGetBool(t *testing.T) {
   133  	c, _ := CreateTestContext(httptest.NewRecorder())
   134  	c.Set("bool", true)
   135  	assert.True(t, c.GetBool("bool"))
   136  }
   137  
   138  func TestContextGetInt(t *testing.T) {
   139  	c, _ := CreateTestContext(httptest.NewRecorder())
   140  	c.Set("int", 1)
   141  	assert.Equal(t, 1, c.GetInt("int"))
   142  }
   143  
   144  func TestContextGetInt64(t *testing.T) {
   145  	c, _ := CreateTestContext(httptest.NewRecorder())
   146  	c.Set("int64", int64(42424242424242))
   147  	assert.Equal(t, int64(42424242424242), c.GetInt64("int64"))
   148  }
   149  
   150  func TestContextGetUint(t *testing.T) {
   151  	c, _ := CreateTestContext(httptest.NewRecorder())
   152  	c.Set("uint", uint(1))
   153  	assert.Equal(t, uint(1), c.GetUint("uint"))
   154  }
   155  
   156  func TestContextGetUint64(t *testing.T) {
   157  	c, _ := CreateTestContext(httptest.NewRecorder())
   158  	c.Set("uint64", uint64(18446744073709551615))
   159  	assert.Equal(t, uint64(18446744073709551615), c.GetUint64("uint64"))
   160  }
   161  
   162  func TestContextGetFloat64(t *testing.T) {
   163  	c, _ := CreateTestContext(httptest.NewRecorder())
   164  	c.Set("float64", 4.2)
   165  	assert.Equal(t, 4.2, c.GetFloat64("float64"))
   166  }
   167  
   168  func TestContextGetTime(t *testing.T) {
   169  	c, _ := CreateTestContext(httptest.NewRecorder())
   170  	t1, _ := time.Parse("1/2/2006 15:04:05", "01/01/2017 12:00:00")
   171  	c.Set("time", t1)
   172  	assert.Equal(t, t1, c.GetTime("time"))
   173  }
   174  
   175  func TestContextGetDuration(t *testing.T) {
   176  	c, _ := CreateTestContext(httptest.NewRecorder())
   177  	c.Set("duration", time.Second)
   178  	assert.Equal(t, time.Second, c.GetDuration("duration"))
   179  }
   180  
   181  func TestContextGetStringSlice(t *testing.T) {
   182  	c, _ := CreateTestContext(httptest.NewRecorder())
   183  	c.Set("slice", []string{"foo"})
   184  	assert.Equal(t, []string{"foo"}, c.GetStringSlice("slice"))
   185  }
   186  
   187  func TestContextGetStringMap(t *testing.T) {
   188  	c, _ := CreateTestContext(httptest.NewRecorder())
   189  	m := make(map[string]interface{})
   190  	m["foo"] = 1
   191  	c.Set("map", m)
   192  
   193  	assert.Equal(t, m, c.GetStringMap("map"))
   194  	assert.Equal(t, 1, c.GetStringMap("map")["foo"])
   195  }
   196  
   197  func TestContextGetStringMapString(t *testing.T) {
   198  	c, _ := CreateTestContext(httptest.NewRecorder())
   199  	m := make(map[string]string)
   200  	m["foo"] = "bar"
   201  	c.Set("map", m)
   202  
   203  	assert.Equal(t, m, c.GetStringMapString("map"))
   204  	assert.Equal(t, "bar", c.GetStringMapString("map")["foo"])
   205  }
   206  
   207  func TestContextGetStringMapStringSlice(t *testing.T) {
   208  	c, _ := CreateTestContext(httptest.NewRecorder())
   209  	m := make(map[string][]string)
   210  	m["foo"] = []string{"foo"}
   211  	c.Set("map", m)
   212  
   213  	assert.Equal(t, m, c.GetStringMapStringSlice("map"))
   214  	assert.Equal(t, []string{"foo"}, c.GetStringMapStringSlice("map")["foo"])
   215  }
   216  
   217  func TestContextCopy(t *testing.T) {
   218  	c, _ := CreateTestContext(httptest.NewRecorder())
   219  	c.index = 2
   220  	c.Request, _ = http.NewRequest("POST", "/hola", nil)
   221  	c.handlers = HandlersChain{func(c *Context) {}}
   222  	c.Params = Params{Param{Key: "foo", Value: "bar"}}
   223  	c.Set("foo", "bar")
   224  
   225  	cp := c.Copy()
   226  	assert.Nil(t, cp.handlers)
   227  	assert.Nil(t, cp.writermem.ResponseWriter)
   228  	assert.Equal(t, &cp.writermem, cp.Writer.(*responseWriter))
   229  	assert.Equal(t, cp.Request, c.Request)
   230  	assert.Equal(t, cp.index, abortIndex)
   231  	assert.Equal(t, cp.Keys, c.Keys)
   232  	assert.Equal(t, cp.engine, c.engine)
   233  	assert.Equal(t, cp.Params, c.Params)
   234  	cp.Set("foo", "notBar")
   235  	assert.False(t, cp.Keys["foo"] == c.Keys["foo"])
   236  }
   237  
   238  func TestContextHandlerName(t *testing.T) {
   239  	c, _ := CreateTestContext(httptest.NewRecorder())
   240  	c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest}
   241  
   242  	assert.Regexp(t, "^(.*/vendor/)?go.sdls.io/sin/pkg/sin.handlerNameTest$", c.HandlerName())
   243  }
   244  
   245  func TestContextHandlerNames(t *testing.T) {
   246  	c, _ := CreateTestContext(httptest.NewRecorder())
   247  	c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest, func(c *Context) {}, handlerNameTest2}
   248  
   249  	names := c.HandlerNames()
   250  
   251  	assert.True(t, len(names) == 4)
   252  	for _, name := range names {
   253  		assert.Regexp(t, `^(.*/vendor/)?(go\.sdls\.io/sin/pkg/sin\.){1}(TestContextHandlerNames\.func.*){0,1}(handlerNameTest.*){0,1}`, name)
   254  	}
   255  }
   256  
   257  func handlerNameTest(_ *Context) {
   258  }
   259  
   260  func handlerNameTest2(_ *Context) {
   261  }
   262  
   263  var handlerTest HandlerFunc = func(c *Context) {
   264  }
   265  
   266  func TestContextHandler(t *testing.T) {
   267  	c, _ := CreateTestContext(httptest.NewRecorder())
   268  	c.handlers = HandlersChain{func(c *Context) {}, handlerTest}
   269  
   270  	assert.Equal(t, reflect.ValueOf(handlerTest).Pointer(), reflect.ValueOf(c.Handler()).Pointer())
   271  }
   272  
   273  func TestContextQuery(t *testing.T) {
   274  	c, _ := CreateTestContext(httptest.NewRecorder())
   275  	c.Request, _ = http.NewRequest("GET", "http://example.com/?foo=bar&page=10&id=", nil)
   276  
   277  	value, ok := c.GetQuery("foo")
   278  	assert.True(t, ok)
   279  	assert.Equal(t, "bar", value)
   280  	assert.Equal(t, "bar", c.DefaultQuery("foo", "none"))
   281  	assert.Equal(t, "bar", c.Query("foo"))
   282  
   283  	value, ok = c.GetQuery("page")
   284  	assert.True(t, ok)
   285  	assert.Equal(t, "10", value)
   286  	assert.Equal(t, "10", c.DefaultQuery("page", "0"))
   287  	assert.Equal(t, "10", c.Query("page"))
   288  
   289  	value, ok = c.GetQuery("id")
   290  	assert.True(t, ok)
   291  	assert.Empty(t, value)
   292  	assert.Empty(t, c.DefaultQuery("id", "nada"))
   293  	assert.Empty(t, c.Query("id"))
   294  
   295  	value, ok = c.GetQuery("NoKey")
   296  	assert.False(t, ok)
   297  	assert.Empty(t, value)
   298  	assert.Equal(t, "nada", c.DefaultQuery("NoKey", "nada"))
   299  	assert.Empty(t, c.Query("NoKey"))
   300  }
   301  
   302  func TestContextDefaultQueryOnEmptyRequest(t *testing.T) {
   303  	c, _ := CreateTestContext(httptest.NewRecorder()) // here c.Request == nil
   304  	assert.NotPanics(t, func() {
   305  		value, ok := c.GetQuery("NoKey")
   306  		assert.False(t, ok)
   307  		assert.Empty(t, value)
   308  	})
   309  	assert.NotPanics(t, func() {
   310  		assert.Equal(t, "nada", c.DefaultQuery("NoKey", "nada"))
   311  	})
   312  	assert.NotPanics(t, func() {
   313  		assert.Empty(t, c.Query("NoKey"))
   314  	})
   315  }
   316  
   317  func TestContextSetCookie(t *testing.T) {
   318  	c, _ := CreateTestContext(httptest.NewRecorder())
   319  	c.SetSameSite(http.SameSiteLaxMode)
   320  	c.SetCookie("user", "gin", 1, "/", "localhost", true, true)
   321  	assert.Equal(t, "user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax", c.Writer.Header().Get("Set-Cookie"))
   322  }
   323  
   324  func TestContextSetCookiePathEmpty(t *testing.T) {
   325  	c, _ := CreateTestContext(httptest.NewRecorder())
   326  	c.SetSameSite(http.SameSiteLaxMode)
   327  	c.SetCookie("user", "gin", 1, "", "localhost", true, true)
   328  	assert.Equal(t, "user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax", c.Writer.Header().Get("Set-Cookie"))
   329  }
   330  
   331  func TestContextGetCookie(t *testing.T) {
   332  	c, _ := CreateTestContext(httptest.NewRecorder())
   333  	c.Request, _ = http.NewRequest("GET", "/get", nil)
   334  	c.Request.Header.Set("Cookie", "user=gin")
   335  	cookie, _ := c.Cookie("user")
   336  	assert.Equal(t, "gin", cookie)
   337  
   338  	_, err := c.Cookie("nokey")
   339  	assert.Error(t, err)
   340  }
   341  
   342  func TestContextBodyAllowedForStatus(t *testing.T) {
   343  	assert.False(t, false, bodyAllowedForStatus(http.StatusProcessing))
   344  	assert.False(t, false, bodyAllowedForStatus(http.StatusNoContent))
   345  	assert.False(t, false, bodyAllowedForStatus(http.StatusNotModified))
   346  	assert.True(t, true, bodyAllowedForStatus(http.StatusInternalServerError))
   347  }
   348  
   349  type TestPanicRender struct{}
   350  
   351  func (*TestPanicRender) Render(http.ResponseWriter) error {
   352  	return errTestPanicRender
   353  }
   354  
   355  func (*TestPanicRender) WriteContentType(http.ResponseWriter) {}
   356  
   357  func TestContextRenderIfErr(t *testing.T) {
   358  	w := httptest.NewRecorder()
   359  	c, _ := CreateTestContext(w)
   360  
   361  	c.Render(http.StatusOK, &TestPanicRender{})
   362  
   363  	assert.Equal(t, errorMsgs{&Error{Err: errTestPanicRender, Type: 1}}, c.Errors)
   364  }
   365  
   366  // Tests that the response is serialized as JSON
   367  // and Content-Type is set to application/json
   368  // and special HTML characters are escaped
   369  func TestContextRenderJSON(t *testing.T) {
   370  	w := httptest.NewRecorder()
   371  	c, _ := CreateTestContext(w)
   372  
   373  	c.JSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"})
   374  
   375  	assert.Equal(t, http.StatusCreated, w.Code)
   376  	assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
   377  	assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
   378  }
   379  
   380  // Tests that no JSON is rendered if code is 204
   381  func TestContextRenderNoContentJSON(t *testing.T) {
   382  	w := httptest.NewRecorder()
   383  	c, _ := CreateTestContext(w)
   384  
   385  	c.JSON(http.StatusNoContent, H{"foo": "bar"})
   386  
   387  	assert.Equal(t, http.StatusNoContent, w.Code)
   388  	assert.Empty(t, w.Body.String())
   389  	assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
   390  }
   391  
   392  // Tests that the response is serialized as JSON
   393  // we change the content-type before
   394  func TestContextRenderAPIJSON(t *testing.T) {
   395  	w := httptest.NewRecorder()
   396  	c, _ := CreateTestContext(w)
   397  
   398  	c.Header("Content-Type", "application/vnd.api+json")
   399  	c.JSON(http.StatusCreated, H{"foo": "bar"})
   400  
   401  	assert.Equal(t, http.StatusCreated, w.Code)
   402  	assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
   403  	assert.Equal(t, "application/vnd.api+json", w.Header().Get("Content-Type"))
   404  }
   405  
   406  // Tests that no Custom JSON is rendered if code is 204
   407  func TestContextRenderNoContentAPIJSON(t *testing.T) {
   408  	w := httptest.NewRecorder()
   409  	c, _ := CreateTestContext(w)
   410  
   411  	c.Header("Content-Type", "application/vnd.api+json")
   412  	c.JSON(http.StatusNoContent, H{"foo": "bar"})
   413  
   414  	assert.Equal(t, http.StatusNoContent, w.Code)
   415  	assert.Empty(t, w.Body.String())
   416  	assert.Equal(t, w.Header().Get("Content-Type"), "application/vnd.api+json")
   417  }
   418  
   419  // Tests that the response is serialized as JSON
   420  // and Content-Type is set to application/json
   421  func TestContextRenderIndentedJSON(t *testing.T) {
   422  	w := httptest.NewRecorder()
   423  	c, _ := CreateTestContext(w)
   424  
   425  	c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})
   426  
   427  	assert.Equal(t, http.StatusCreated, w.Code)
   428  	assert.Equal(t, "{\n    \"bar\": \"foo\",\n    \"foo\": \"bar\",\n    \"nested\": {\n        \"foo\": \"bar\"\n    }\n}", w.Body.String())
   429  	assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
   430  }
   431  
   432  // Tests that no Custom JSON is rendered if code is 204
   433  func TestContextRenderNoContentIndentedJSON(t *testing.T) {
   434  	w := httptest.NewRecorder()
   435  	c, _ := CreateTestContext(w)
   436  
   437  	c.IndentedJSON(http.StatusNoContent, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})
   438  
   439  	assert.Equal(t, http.StatusNoContent, w.Code)
   440  	assert.Empty(t, w.Body.String())
   441  	assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
   442  }
   443  
   444  // TestContextXML tests that the response is serialized as XML
   445  // and Content-Type is set to application/xml
   446  func TestContextRenderXML(t *testing.T) {
   447  	w := httptest.NewRecorder()
   448  	c, _ := CreateTestContext(w)
   449  
   450  	c.XML(http.StatusCreated, H{"foo": "bar"})
   451  
   452  	assert.Equal(t, http.StatusCreated, w.Code)
   453  	assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
   454  	assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type"))
   455  }
   456  
   457  // Tests that no XML is rendered if code is 204
   458  func TestContextRenderNoContentXML(t *testing.T) {
   459  	w := httptest.NewRecorder()
   460  	c, _ := CreateTestContext(w)
   461  
   462  	c.XML(http.StatusNoContent, H{"foo": "bar"})
   463  
   464  	assert.Equal(t, http.StatusNoContent, w.Code)
   465  	assert.Empty(t, w.Body.String())
   466  	assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type"))
   467  }
   468  
   469  // TestContextString tests that the response is returned
   470  // with Content-Type set to text/plain
   471  func TestContextRenderString(t *testing.T) {
   472  	w := httptest.NewRecorder()
   473  	c, _ := CreateTestContext(w)
   474  
   475  	c.String(http.StatusCreated, "test %s %d", "string", 2)
   476  
   477  	assert.Equal(t, http.StatusCreated, w.Code)
   478  	assert.Equal(t, "test string 2", w.Body.String())
   479  	assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
   480  }
   481  
   482  // Tests that no String is rendered if code is 204
   483  func TestContextRenderNoContentString(t *testing.T) {
   484  	w := httptest.NewRecorder()
   485  	c, _ := CreateTestContext(w)
   486  
   487  	c.String(http.StatusNoContent, "test %s %d", "string", 2)
   488  
   489  	assert.Equal(t, http.StatusNoContent, w.Code)
   490  	assert.Empty(t, w.Body.String())
   491  	assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
   492  }
   493  
   494  // TestContextString tests that the response is returned
   495  // with Content-Type set to text/html
   496  func TestContextRenderHTMLString(t *testing.T) {
   497  	w := httptest.NewRecorder()
   498  	c, _ := CreateTestContext(w)
   499  
   500  	c.Header("Content-Type", "text/html; charset=utf-8")
   501  	c.String(http.StatusCreated, "<html>%s %d</html>", "string", 3)
   502  
   503  	assert.Equal(t, http.StatusCreated, w.Code)
   504  	assert.Equal(t, "<html>string 3</html>", w.Body.String())
   505  	assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
   506  }
   507  
   508  // Tests that no HTML String is rendered if code is 204
   509  func TestContextRenderNoContentHTMLString(t *testing.T) {
   510  	w := httptest.NewRecorder()
   511  	c, _ := CreateTestContext(w)
   512  
   513  	c.Header("Content-Type", "text/html; charset=utf-8")
   514  	c.String(http.StatusNoContent, "<html>%s %d</html>", "string", 3)
   515  
   516  	assert.Equal(t, http.StatusNoContent, w.Code)
   517  	assert.Empty(t, w.Body.String())
   518  	assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
   519  }
   520  
   521  // TestContextData tests that the response can be written from `bytestring`
   522  // with specified MIME type
   523  func TestContextRenderData(t *testing.T) {
   524  	w := httptest.NewRecorder()
   525  	c, _ := CreateTestContext(w)
   526  
   527  	c.Data(http.StatusCreated, "text/csv", []byte(`foo,bar`))
   528  
   529  	assert.Equal(t, http.StatusCreated, w.Code)
   530  	assert.Equal(t, "foo,bar", w.Body.String())
   531  	assert.Equal(t, "text/csv", w.Header().Get("Content-Type"))
   532  }
   533  
   534  // Tests that no Custom Data is rendered if code is 204
   535  func TestContextRenderNoContentData(t *testing.T) {
   536  	w := httptest.NewRecorder()
   537  	c, _ := CreateTestContext(w)
   538  
   539  	c.Data(http.StatusNoContent, "text/csv", []byte(`foo,bar`))
   540  
   541  	assert.Equal(t, http.StatusNoContent, w.Code)
   542  	assert.Empty(t, w.Body.String())
   543  	assert.Equal(t, "text/csv", w.Header().Get("Content-Type"))
   544  }
   545  
   546  func TestContextHeaders(t *testing.T) {
   547  	c, _ := CreateTestContext(httptest.NewRecorder())
   548  	c.Header("Content-Type", "text/plain")
   549  	c.Header("X-Custom", "value")
   550  
   551  	assert.Equal(t, "text/plain", c.Writer.Header().Get("Content-Type"))
   552  	assert.Equal(t, "value", c.Writer.Header().Get("X-Custom"))
   553  
   554  	c.Header("Content-Type", "text/html")
   555  	c.Header("X-Custom", "")
   556  
   557  	assert.Equal(t, "text/html", c.Writer.Header().Get("Content-Type"))
   558  	_, exist := c.Writer.Header()["X-Custom"]
   559  	assert.False(t, exist)
   560  }
   561  
   562  // TODO
   563  func TestContextRenderRedirectWithRelativePath(t *testing.T) {
   564  	w := httptest.NewRecorder()
   565  	c, _ := CreateTestContext(w)
   566  
   567  	c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
   568  	assert.Panics(t, func() { c.Redirect(299, "/new_path") })
   569  	assert.Panics(t, func() { c.Redirect(309, "/new_path") })
   570  
   571  	c.Redirect(http.StatusMovedPermanently, "/path")
   572  	c.Writer.WriteHeaderNow()
   573  	assert.Equal(t, http.StatusMovedPermanently, w.Code)
   574  	assert.Equal(t, "/path", w.Header().Get("Location"))
   575  }
   576  
   577  func TestContextRenderRedirectWithAbsolutePath(t *testing.T) {
   578  	w := httptest.NewRecorder()
   579  	c, _ := CreateTestContext(w)
   580  
   581  	c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
   582  	c.Redirect(http.StatusFound, "http://google.com")
   583  	c.Writer.WriteHeaderNow()
   584  
   585  	assert.Equal(t, http.StatusFound, w.Code)
   586  	assert.Equal(t, "http://google.com", w.Header().Get("Location"))
   587  }
   588  
   589  func TestContextRenderRedirectWith201(t *testing.T) {
   590  	w := httptest.NewRecorder()
   591  	c, _ := CreateTestContext(w)
   592  
   593  	c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
   594  	c.Redirect(http.StatusCreated, "/resource")
   595  	c.Writer.WriteHeaderNow()
   596  
   597  	assert.Equal(t, http.StatusCreated, w.Code)
   598  	assert.Equal(t, "/resource", w.Header().Get("Location"))
   599  }
   600  
   601  func TestContextRenderRedirectAll(t *testing.T) {
   602  	c, _ := CreateTestContext(httptest.NewRecorder())
   603  	c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
   604  	assert.Panics(t, func() { c.Redirect(http.StatusOK, "/resource") })
   605  	assert.Panics(t, func() { c.Redirect(http.StatusAccepted, "/resource") })
   606  	assert.Panics(t, func() { c.Redirect(299, "/resource") })
   607  	assert.Panics(t, func() { c.Redirect(309, "/resource") })
   608  	assert.NotPanics(t, func() { c.Redirect(http.StatusMultipleChoices, "/resource") })
   609  	assert.NotPanics(t, func() { c.Redirect(http.StatusPermanentRedirect, "/resource") })
   610  }
   611  
   612  func TestContextIsAborted(t *testing.T) {
   613  	c, _ := CreateTestContext(httptest.NewRecorder())
   614  	assert.False(t, c.IsAborted())
   615  
   616  	c.Abort()
   617  	assert.True(t, c.IsAborted())
   618  
   619  	c.Next()
   620  	assert.True(t, c.IsAborted())
   621  
   622  	c.index++
   623  	assert.True(t, c.IsAborted())
   624  }
   625  
   626  // TestContextData tests that the response can be written from `bytestring`
   627  // with specified MIME type
   628  func TestContextAbortWithStatus(t *testing.T) {
   629  	w := httptest.NewRecorder()
   630  	c, _ := CreateTestContext(w)
   631  
   632  	c.index = 4
   633  	c.AbortWithStatus(http.StatusUnauthorized)
   634  
   635  	assert.Equal(t, abortIndex, c.index)
   636  	assert.Equal(t, http.StatusUnauthorized, c.Writer.Status())
   637  	assert.Equal(t, http.StatusUnauthorized, w.Code)
   638  	assert.True(t, c.IsAborted())
   639  }
   640  
   641  type testJSONAbortMsg struct {
   642  	Foo string `json:"foo"`
   643  	Bar string `json:"bar"`
   644  }
   645  
   646  func TestContextAbortWithStatusJSON(t *testing.T) {
   647  	w := httptest.NewRecorder()
   648  	c, _ := CreateTestContext(w)
   649  	c.index = 4
   650  
   651  	in := new(testJSONAbortMsg)
   652  	in.Bar = "barValue"
   653  	in.Foo = "fooValue"
   654  
   655  	c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in)
   656  
   657  	assert.Equal(t, abortIndex, c.index)
   658  	assert.Equal(t, http.StatusUnsupportedMediaType, c.Writer.Status())
   659  	assert.Equal(t, http.StatusUnsupportedMediaType, w.Code)
   660  	assert.True(t, c.IsAborted())
   661  
   662  	contentType := w.Header().Get("Content-Type")
   663  	assert.Equal(t, "application/json; charset=utf-8", contentType)
   664  
   665  	buf := new(bytes.Buffer)
   666  	_, err := buf.ReadFrom(w.Body)
   667  	assert.NoError(t, err)
   668  	jsonStringBody := buf.String()
   669  	assert.Equal(t, "{\"foo\":\"fooValue\",\"bar\":\"barValue\"}", jsonStringBody)
   670  }
   671  
   672  func TestContextError(t *testing.T) {
   673  	c, _ := CreateTestContext(httptest.NewRecorder())
   674  	assert.Empty(t, c.Errors)
   675  
   676  	firstErr := errors.New("first error")
   677  	c.Error(firstErr) // nolint: errcheck
   678  	assert.Len(t, c.Errors, 1)
   679  	assert.Equal(t, "Error #01: first error\n", c.Errors.String())
   680  
   681  	secondErr := errors.New("second error")
   682  	c.Error(&Error{ // nolint: errcheck
   683  		Err:  secondErr,
   684  		Meta: "some data 2",
   685  		Type: ErrorTypePublic,
   686  	})
   687  	assert.Len(t, c.Errors, 2)
   688  
   689  	assert.Equal(t, firstErr, c.Errors[0].Err)
   690  	assert.Nil(t, c.Errors[0].Meta)
   691  	assert.Equal(t, ErrorTypePrivate, c.Errors[0].Type)
   692  
   693  	assert.Equal(t, secondErr, c.Errors[1].Err)
   694  	assert.Equal(t, "some data 2", c.Errors[1].Meta)
   695  	assert.Equal(t, ErrorTypePublic, c.Errors[1].Type)
   696  
   697  	assert.Equal(t, c.Errors.Last(), c.Errors[1])
   698  
   699  	defer func() {
   700  		if recover() == nil {
   701  			t.Error("didn't panic")
   702  		}
   703  	}()
   704  	c.Error(nil) // nolint: errcheck
   705  }
   706  
   707  func TestContextTypedError(t *testing.T) {
   708  	c, _ := CreateTestContext(httptest.NewRecorder())
   709  	c.Error(errors.New("externo 0")).SetType(ErrorTypePublic)  // nolint: errcheck
   710  	c.Error(errors.New("interno 0")).SetType(ErrorTypePrivate) // nolint: errcheck
   711  
   712  	for _, err := range c.Errors.ByType(ErrorTypePublic) {
   713  		assert.Equal(t, ErrorTypePublic, err.Type)
   714  	}
   715  	for _, err := range c.Errors.ByType(ErrorTypePrivate) {
   716  		assert.Equal(t, ErrorTypePrivate, err.Type)
   717  	}
   718  	assert.Equal(t, []string{"externo 0", "interno 0"}, c.Errors.Errors())
   719  }
   720  
   721  func TestContextAbortWithError(t *testing.T) {
   722  	w := httptest.NewRecorder()
   723  	c, _ := CreateTestContext(w)
   724  
   725  	c.AbortWithError(http.StatusUnauthorized, errors.New("bad input")).SetMeta("some input") // nolint: errcheck
   726  
   727  	assert.Equal(t, http.StatusUnauthorized, w.Code)
   728  	assert.Equal(t, abortIndex, c.index)
   729  	assert.True(t, c.IsAborted())
   730  }
   731  
   732  func TestContextContentType(t *testing.T) {
   733  	c, _ := CreateTestContext(httptest.NewRecorder())
   734  	c.Request, _ = http.NewRequest("POST", "/", nil)
   735  	c.Request.Header.Set("Content-Type", "application/json; charset=utf-8")
   736  
   737  	assert.Equal(t, "application/json", c.ContentType())
   738  }
   739  
   740  func TestContextGolangContext(t *testing.T) {
   741  	c, _ := CreateTestContext(httptest.NewRecorder())
   742  	c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
   743  	assert.NoError(t, c.Err())
   744  	assert.Nil(t, c.Done())
   745  	ti, ok := c.Deadline()
   746  	assert.Equal(t, ti, time.Time{})
   747  	assert.False(t, ok)
   748  	assert.Equal(t, c.Value(0), c.Request)
   749  	assert.Nil(t, c.Value("foo"))
   750  
   751  	c.Set("foo", "bar")
   752  	assert.Equal(t, "bar", c.Value("foo"))
   753  	assert.Nil(t, c.Value(1))
   754  }
   755  
   756  func TestWebsocketsRequired(t *testing.T) {
   757  	// Example request from spec: https://tools.ietf.org/html/rfc6455#section-1.2
   758  	c, _ := CreateTestContext(httptest.NewRecorder())
   759  	c.Request, _ = http.NewRequest("GET", "/chat", nil)
   760  	c.Request.Header.Set("Host", "server.example.com")
   761  	c.Request.Header.Set("Upgrade", "websocket")
   762  	c.Request.Header.Set("Connection", "Upgrade")
   763  	c.Request.Header.Set("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==")
   764  	c.Request.Header.Set("Origin", "http://example.com")
   765  	c.Request.Header.Set("Sec-WebSocket-Protocol", "chat, superchat")
   766  	c.Request.Header.Set("Sec-WebSocket-Version", "13")
   767  
   768  	assert.True(t, c.IsWebsocket())
   769  
   770  	// Normal request, no websocket required.
   771  	c, _ = CreateTestContext(httptest.NewRecorder())
   772  	c.Request, _ = http.NewRequest("GET", "/chat", nil)
   773  	c.Request.Header.Set("Host", "server.example.com")
   774  
   775  	assert.False(t, c.IsWebsocket())
   776  }
   777  
   778  func TestGetRequestHeaderValue(t *testing.T) {
   779  	c, _ := CreateTestContext(httptest.NewRecorder())
   780  	c.Request, _ = http.NewRequest("GET", "/chat", nil)
   781  	c.Request.Header.Set("Gin-Version", "1.0.0")
   782  
   783  	assert.Equal(t, "1.0.0", c.GetHeader("Gin-Version"))
   784  	assert.Empty(t, c.GetHeader("Connection"))
   785  }
   786  
   787  func TestContextRenderDataFromReader(t *testing.T) {
   788  	w := httptest.NewRecorder()
   789  	c, _ := CreateTestContext(w)
   790  
   791  	body := "#!PNG some raw data"
   792  	reader := strings.NewReader(body)
   793  	contentLength := int64(len(body))
   794  	contentType := "image/png"
   795  	extraHeaders := map[string]string{"Content-Disposition": `attachment; filename="gopher.png"`}
   796  
   797  	c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
   798  
   799  	assert.Equal(t, http.StatusOK, w.Code)
   800  	assert.Equal(t, body, w.Body.String())
   801  	assert.Equal(t, contentType, w.Header().Get("Content-Type"))
   802  	assert.Equal(t, fmt.Sprintf("%d", contentLength), w.Header().Get("Content-Length"))
   803  	assert.Equal(t, extraHeaders["Content-Disposition"], w.Header().Get("Content-Disposition"))
   804  }
   805  
   806  func TestContextRenderDataFromReaderNoHeaders(t *testing.T) {
   807  	w := httptest.NewRecorder()
   808  	c, _ := CreateTestContext(w)
   809  
   810  	body := "#!PNG some raw data"
   811  	reader := strings.NewReader(body)
   812  	contentLength := int64(len(body))
   813  	contentType := "image/png"
   814  
   815  	c.DataFromReader(http.StatusOK, contentLength, contentType, reader, nil)
   816  
   817  	assert.Equal(t, http.StatusOK, w.Code)
   818  	assert.Equal(t, body, w.Body.String())
   819  	assert.Equal(t, contentType, w.Header().Get("Content-Type"))
   820  	assert.Equal(t, fmt.Sprintf("%d", contentLength), w.Header().Get("Content-Length"))
   821  }
   822  
   823  type TestResponseRecorder struct {
   824  	*httptest.ResponseRecorder
   825  	closeChannel chan bool
   826  }
   827  
   828  func (r *TestResponseRecorder) CloseNotify() <-chan bool {
   829  	return r.closeChannel
   830  }
   831  
   832  func CreateTestResponseRecorder() *TestResponseRecorder {
   833  	return &TestResponseRecorder{
   834  		httptest.NewRecorder(),
   835  		make(chan bool, 1),
   836  	}
   837  }
   838  
   839  func TestContextResetInHandler(t *testing.T) {
   840  	w := CreateTestResponseRecorder()
   841  	c, _ := CreateTestContext(w)
   842  
   843  	c.handlers = []HandlerFunc{
   844  		func(c *Context) { c.reset() },
   845  	}
   846  	assert.NotPanics(t, func() {
   847  		c.Next()
   848  	})
   849  }
   850  
   851  func TestRaceParamsContextCopy(t *testing.T) {
   852  	router := New()
   853  	nameGroup := router.Group("/:name")
   854  	var wg sync.WaitGroup
   855  	wg.Add(2)
   856  	{
   857  		nameGroup.GET("/api", func(c *Context) {
   858  			go func(c *Context, param string) {
   859  				defer wg.Done()
   860  				// First assert must be executed after the second request
   861  				time.Sleep(50 * time.Millisecond)
   862  				assert.Equal(t, c.Param("name"), param)
   863  			}(c.Copy(), c.Param("name"))
   864  		})
   865  	}
   866  	performRequest(router, "GET", "/name1/api")
   867  	performRequest(router, "GET", "/name2/api")
   868  	wg.Wait()
   869  }
   870  
   871  func TestContextWithKeysMutex(t *testing.T) {
   872  	c := &Context{}
   873  	c.Set("foo", "bar")
   874  
   875  	value, err := c.Get("foo")
   876  	assert.Equal(t, "bar", value)
   877  	assert.True(t, err)
   878  
   879  	value, err = c.Get("foo2")
   880  	assert.Nil(t, value)
   881  	assert.False(t, err)
   882  }
   883  
   884  func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
   885  	var key struct{}
   886  	c := &Context{}
   887  	c.Request, _ = http.NewRequest("POST", "/", nil)
   888  	c.Request = c.Request.WithContext(context.WithValue(context.TODO(), key, "value"))
   889  
   890  	assert.Equal(t, "value", c.Value(key))
   891  
   892  	c2 := &Context{}
   893  	c2.Request, _ = http.NewRequest("POST", "/", nil)
   894  	// nolint:staticcheck
   895  	c2.Request = c2.Request.WithContext(context.WithValue(context.TODO(), "key", "value2"))
   896  	assert.Equal(t, "value2", c2.Value("key"))
   897  }
   898  
   899  func TestContextWithFallbackDeadlineFromRequestContext(t *testing.T) {
   900  	c := &Context{}
   901  	deadline, ok := c.Deadline()
   902  	assert.Zero(t, deadline)
   903  	assert.False(t, ok)
   904  
   905  	c2 := &Context{}
   906  	c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
   907  	d := time.Now().Add(time.Second)
   908  	ctx, cancel := context.WithDeadline(context.Background(), d)
   909  	defer cancel()
   910  	c2.Request = c2.Request.WithContext(ctx)
   911  	deadline, ok = c2.Deadline()
   912  	assert.Equal(t, d, deadline)
   913  	assert.True(t, ok)
   914  }
   915  
   916  func TestContextWithFallbackDoneFromRequestContext(t *testing.T) {
   917  	c := &Context{}
   918  	assert.Nil(t, c.Done())
   919  
   920  	c2 := &Context{}
   921  	c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
   922  	ctx, cancel := context.WithCancel(context.Background())
   923  	c2.Request = c2.Request.WithContext(ctx)
   924  	cancel()
   925  	assert.NotNil(t, <-c2.Done())
   926  }
   927  
   928  func TestContextWithFallbackErrFromRequestContext(t *testing.T) {
   929  	c := &Context{}
   930  	assert.Nil(t, c.Err())
   931  
   932  	c2 := &Context{}
   933  	c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
   934  	ctx, cancel := context.WithCancel(context.Background())
   935  	c2.Request = c2.Request.WithContext(ctx)
   936  	cancel()
   937  
   938  	assert.EqualError(t, c2.Err(), context.Canceled.Error())
   939  }