2022-05-28 05:42:28 +03:00
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
2014-08-29 21:49:50 +04:00
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
2014-08-08 15:48:15 +04:00
package gin
import (
2014-08-11 14:25:52 +04:00
"bytes"
2019-06-03 17:52:33 +03:00
"context"
2014-08-08 15:48:15 +04:00
"errors"
2017-01-09 18:24:48 +03:00
"fmt"
2014-08-08 15:48:15 +04:00
"html/template"
2018-08-14 04:51:56 +03:00
"io"
2015-05-26 15:21:35 +03:00
"mime/multipart"
2021-12-03 09:49:16 +03:00
"net"
2014-08-08 15:48:15 +04:00
"net/http"
"net/http/httptest"
2022-03-17 06:56:16 +03:00
"net/url"
2019-05-27 09:04:30 +03:00
"os"
2017-06-02 11:00:55 +03:00
"reflect"
2015-09-25 13:04:55 +03:00
"strings"
2019-05-27 09:04:30 +03:00
"sync"
2014-08-08 15:48:15 +04:00
"testing"
2015-05-19 03:29:32 +03:00
"time"
2014-08-08 15:48:15 +04:00
2017-06-28 00:17:02 +03:00
"github.com/gin-contrib/sse"
2018-05-11 05:33:33 +03:00
"github.com/gin-gonic/gin/binding"
2021-09-21 10:22:21 +03:00
testdata "github.com/gin-gonic/gin/testdata/protoexample"
2015-04-08 03:58:35 +03:00
"github.com/stretchr/testify/assert"
2021-08-19 10:46:31 +03:00
"google.golang.org/protobuf/proto"
2015-04-08 03:58:35 +03:00
)
2014-08-08 15:48:15 +04:00
2016-10-19 17:13:38 +03:00
var _ context . Context = & Context { }
2015-05-07 17:00:37 +03:00
// Unit tests TODO
2015-04-09 13:15:02 +03:00
// func (c *Context) File(filepath string) {
// func (c *Context) Negotiate(code int, config Negotiate) {
// BAD case: func (c *Context) Render(code int, render render.Render, obj ...interface{}) {
2015-05-07 17:00:37 +03:00
// test that information is not leaked when reusing Contexts (using the Pool)
2015-04-09 13:15:02 +03:00
2015-05-26 18:22:39 +03:00
func createMultipartRequest ( ) * http . Request {
2015-05-26 15:21:35 +03:00
boundary := "--testboundary"
2015-05-26 18:22:39 +03:00
body := new ( bytes . Buffer )
2015-05-26 15:21:35 +03:00
mw := multipart . NewWriter ( body )
defer mw . Close ( )
2015-05-26 18:22:39 +03:00
must ( mw . SetBoundary ( boundary ) )
must ( mw . WriteField ( "foo" , "bar" ) )
2016-01-29 04:07:44 +03:00
must ( mw . WriteField ( "bar" , "10" ) )
2015-07-08 05:26:37 +03:00
must ( mw . WriteField ( "bar" , "foo2" ) )
must ( mw . WriteField ( "array" , "first" ) )
must ( mw . WriteField ( "array" , "second" ) )
2016-01-29 04:07:44 +03:00
must ( mw . WriteField ( "id" , "" ) )
2017-02-17 16:32:36 +03:00
must ( mw . WriteField ( "time_local" , "31/12/2016 14:55" ) )
must ( mw . WriteField ( "time_utc" , "31/12/2016 14:55" ) )
2017-09-28 17:23:18 +03:00
must ( mw . WriteField ( "time_location" , "31/12/2016 14:55" ) )
2018-08-06 07:07:11 +03:00
must ( mw . WriteField ( "names[a]" , "thinkerou" ) )
must ( mw . WriteField ( "names[b]" , "tianou" ) )
2015-05-26 18:22:39 +03:00
req , err := http . NewRequest ( "POST" , "/" , body )
must ( err )
req . Header . Set ( "Content-Type" , MIMEMultipartPOSTForm + "; boundary=" + boundary )
return req
}
func must ( err error ) {
if err != nil {
panic ( err . Error ( ) )
2015-05-26 15:21:35 +03:00
}
}
2016-12-24 07:25:01 +03:00
func TestContextFormFile ( t * testing . T ) {
buf := new ( bytes . Buffer )
mw := multipart . NewWriter ( buf )
w , err := mw . CreateFormFile ( "file" , "test" )
if assert . NoError ( t , err ) {
2019-01-18 04:32:53 +03:00
_ , err = w . Write ( [ ] byte ( "test" ) )
assert . NoError ( t , err )
2016-12-24 07:25:01 +03:00
}
mw . Close ( )
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "POST" , "/" , buf )
c . Request . Header . Set ( "Content-Type" , mw . FormDataContentType ( ) )
f , err := c . FormFile ( "file" )
if assert . NoError ( t , err ) {
assert . Equal ( t , "test" , f . Filename )
}
2017-07-16 06:42:08 +03:00
assert . NoError ( t , c . SaveUploadedFile ( f , "test" ) )
2016-12-24 07:25:01 +03:00
}
func TestContextMultipartForm ( t * testing . T ) {
buf := new ( bytes . Buffer )
mw := multipart . NewWriter ( buf )
2019-01-18 04:32:53 +03:00
assert . NoError ( t , mw . WriteField ( "foo" , "bar" ) )
2017-07-16 06:42:08 +03:00
w , err := mw . CreateFormFile ( "file" , "test" )
if assert . NoError ( t , err ) {
2019-01-18 04:32:53 +03:00
_ , err = w . Write ( [ ] byte ( "test" ) )
assert . NoError ( t , err )
2017-07-16 06:42:08 +03:00
}
2016-12-24 07:25:01 +03:00
mw . Close ( )
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "POST" , "/" , buf )
c . Request . Header . Set ( "Content-Type" , mw . FormDataContentType ( ) )
f , err := c . MultipartForm ( )
if assert . NoError ( t , err ) {
assert . NotNil ( t , f )
}
2017-07-16 06:42:08 +03:00
assert . NoError ( t , c . SaveUploadedFile ( f . File [ "file" ] [ 0 ] , "test" ) )
}
func TestSaveUploadedOpenFailed ( t * testing . T ) {
buf := new ( bytes . Buffer )
mw := multipart . NewWriter ( buf )
mw . Close ( )
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "POST" , "/" , buf )
c . Request . Header . Set ( "Content-Type" , mw . FormDataContentType ( ) )
f := & multipart . FileHeader {
Filename : "file" ,
}
assert . Error ( t , c . SaveUploadedFile ( f , "test" ) )
}
func TestSaveUploadedCreateFailed ( t * testing . T ) {
buf := new ( bytes . Buffer )
mw := multipart . NewWriter ( buf )
w , err := mw . CreateFormFile ( "file" , "test" )
if assert . NoError ( t , err ) {
2019-01-18 04:32:53 +03:00
_ , err = w . Write ( [ ] byte ( "test" ) )
assert . NoError ( t , err )
2017-07-16 06:42:08 +03:00
}
mw . Close ( )
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "POST" , "/" , buf )
c . Request . Header . Set ( "Content-Type" , mw . FormDataContentType ( ) )
f , err := c . FormFile ( "file" )
if assert . NoError ( t , err ) {
assert . Equal ( t , "test" , f . Filename )
}
assert . Error ( t , c . SaveUploadedFile ( f , "/" ) )
2016-12-24 07:25:01 +03:00
}
2015-04-08 03:58:35 +03:00
func TestContextReset ( t * testing . T ) {
router := New ( )
c := router . allocateContext ( )
2015-05-22 03:24:13 +03:00
assert . Equal ( t , c . engine , router )
2015-04-08 03:58:35 +03:00
c . index = 2
c . Writer = & responseWriter { ResponseWriter : httptest . NewRecorder ( ) }
2015-04-08 15:24:49 +03:00
c . Params = Params { Param { } }
2022-08-15 16:38:20 +03:00
c . Error ( errors . New ( "test" ) ) //nolint: errcheck
2015-04-08 03:58:35 +03:00
c . Set ( "foo" , "bar" )
c . reset ( )
assert . False ( t , c . IsAborted ( ) )
assert . Nil ( t , c . Keys )
assert . Nil ( t , c . Accepted )
assert . Len ( t , c . Errors , 0 )
2015-05-19 01:49:01 +03:00
assert . Empty ( t , c . Errors . Errors ( ) )
assert . Empty ( t , c . Errors . ByType ( ErrorTypeAny ) )
2015-04-08 03:58:35 +03:00
assert . Len ( t , c . Params , 0 )
2015-05-31 23:35:49 +03:00
assert . EqualValues ( t , c . index , - 1 )
2015-04-08 03:58:35 +03:00
assert . Equal ( t , c . Writer . ( * responseWriter ) , & c . writermem )
2014-08-08 15:48:15 +04:00
}
2015-07-03 05:20:18 +03:00
func TestContextHandlers ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-07-03 05:20:18 +03:00
assert . Nil ( t , c . handlers )
assert . Nil ( t , c . handlers . Last ( ) )
c . handlers = HandlersChain { }
assert . NotNil ( t , c . handlers )
assert . Nil ( t , c . handlers . Last ( ) )
f := func ( c * Context ) { }
g := func ( c * Context ) { }
c . handlers = HandlersChain { f }
compareFunc ( t , f , c . handlers . Last ( ) )
c . handlers = HandlersChain { f , g }
compareFunc ( t , g , c . handlers . Last ( ) )
}
2014-08-08 15:48:15 +04:00
// TestContextSetGet tests that a parameter is set correctly on the
// current context and can be retrieved using Get.
func TestContextSetGet ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-04-08 03:58:35 +03:00
c . Set ( "foo" , "bar" )
2014-08-08 15:48:15 +04:00
2015-04-08 03:58:35 +03:00
value , err := c . Get ( "foo" )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "bar" , value )
2015-04-08 03:58:35 +03:00
assert . True ( t , err )
2014-08-08 15:48:15 +04:00
2015-04-08 03:58:35 +03:00
value , err = c . Get ( "foo2" )
assert . Nil ( t , value )
assert . False ( t , err )
2014-08-08 15:48:15 +04:00
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "bar" , c . MustGet ( "foo" ) )
2015-04-08 03:58:35 +03:00
assert . Panics ( t , func ( ) { c . MustGet ( "no_exist" ) } )
}
2014-08-08 15:48:15 +04:00
2015-05-07 17:00:37 +03:00
func TestContextSetGetValues ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-07 17:00:37 +03:00
c . Set ( "string" , "this is a string" )
c . Set ( "int32" , int32 ( - 42 ) )
c . Set ( "int64" , int64 ( 42424242424242 ) )
c . Set ( "uint64" , uint64 ( 42 ) )
c . Set ( "float32" , float32 ( 4.2 ) )
c . Set ( "float64" , 4.2 )
2022-03-21 04:43:17 +03:00
var a any = 1
2015-05-11 02:04:08 +03:00
c . Set ( "intInterface" , a )
2015-05-07 17:00:37 +03:00
assert . Exactly ( t , c . MustGet ( "string" ) . ( string ) , "this is a string" )
assert . Exactly ( t , c . MustGet ( "int32" ) . ( int32 ) , int32 ( - 42 ) )
assert . Exactly ( t , c . MustGet ( "int64" ) . ( int64 ) , int64 ( 42424242424242 ) )
assert . Exactly ( t , c . MustGet ( "uint64" ) . ( uint64 ) , uint64 ( 42 ) )
assert . Exactly ( t , c . MustGet ( "float32" ) . ( float32 ) , float32 ( 4.2 ) )
assert . Exactly ( t , c . MustGet ( "float64" ) . ( float64 ) , 4.2 )
2015-05-11 02:04:08 +03:00
assert . Exactly ( t , c . MustGet ( "intInterface" ) . ( int ) , 1 )
2015-05-07 17:00:37 +03:00
}
2017-06-02 04:00:04 +03:00
func TestContextGetString ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "string" , "this is a string" )
assert . Equal ( t , "this is a string" , c . GetString ( "string" ) )
}
func TestContextSetGetBool ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "bool" , true )
2017-11-21 16:18:45 +03:00
assert . True ( t , c . GetBool ( "bool" ) )
2017-06-02 04:00:04 +03:00
}
func TestContextGetInt ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "int" , 1 )
assert . Equal ( t , 1 , c . GetInt ( "int" ) )
}
func TestContextGetInt64 ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "int64" , int64 ( 42424242424242 ) )
assert . Equal ( t , int64 ( 42424242424242 ) , c . GetInt64 ( "int64" ) )
}
2020-09-01 04:33:54 +03:00
func TestContextGetUint ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "uint" , uint ( 1 ) )
assert . Equal ( t , uint ( 1 ) , c . GetUint ( "uint" ) )
}
func TestContextGetUint64 ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "uint64" , uint64 ( 18446744073709551615 ) )
assert . Equal ( t , uint64 ( 18446744073709551615 ) , c . GetUint64 ( "uint64" ) )
}
2017-06-02 04:00:04 +03:00
func TestContextGetFloat64 ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "float64" , 4.2 )
assert . Equal ( t , 4.2 , c . GetFloat64 ( "float64" ) )
}
func TestContextGetTime ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
t1 , _ := time . Parse ( "1/2/2006 15:04:05" , "01/01/2017 12:00:00" )
c . Set ( "time" , t1 )
assert . Equal ( t , t1 , c . GetTime ( "time" ) )
}
func TestContextGetDuration ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "duration" , time . Second )
assert . Equal ( t , time . Second , c . GetDuration ( "duration" ) )
}
func TestContextGetStringSlice ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Set ( "slice" , [ ] string { "foo" } )
assert . Equal ( t , [ ] string { "foo" } , c . GetStringSlice ( "slice" ) )
}
func TestContextGetStringMap ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2022-03-21 04:43:17 +03:00
m := make ( map [ string ] any )
2017-06-02 04:00:04 +03:00
m [ "foo" ] = 1
c . Set ( "map" , m )
assert . Equal ( t , m , c . GetStringMap ( "map" ) )
assert . Equal ( t , 1 , c . GetStringMap ( "map" ) [ "foo" ] )
}
func TestContextGetStringMapString ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2021-08-19 10:46:31 +03:00
m := make ( map [ string ] string )
2017-06-02 04:00:04 +03:00
m [ "foo" ] = "bar"
c . Set ( "map" , m )
assert . Equal ( t , m , c . GetStringMapString ( "map" ) )
assert . Equal ( t , "bar" , c . GetStringMapString ( "map" ) [ "foo" ] )
}
func TestContextGetStringMapStringSlice ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2021-08-19 10:46:31 +03:00
m := make ( map [ string ] [ ] string )
2017-06-02 04:00:04 +03:00
m [ "foo" ] = [ ] string { "foo" }
c . Set ( "map" , m )
assert . Equal ( t , m , c . GetStringMapStringSlice ( "map" ) )
assert . Equal ( t , [ ] string { "foo" } , c . GetStringMapStringSlice ( "map" ) [ "foo" ] )
}
2015-04-09 13:15:02 +03:00
func TestContextCopy ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-04-09 13:15:02 +03:00
c . index = 2
c . Request , _ = http . NewRequest ( "POST" , "/hola" , nil )
2015-05-07 12:30:01 +03:00
c . handlers = HandlersChain { func ( c * Context ) { } }
2015-04-09 13:15:02 +03:00
c . Params = Params { Param { Key : "foo" , Value : "bar" } }
c . Set ( "foo" , "bar" )
cp := c . Copy ( )
assert . Nil ( t , cp . handlers )
2015-05-05 16:06:38 +03:00
assert . Nil ( t , cp . writermem . ResponseWriter )
assert . Equal ( t , & cp . writermem , cp . Writer . ( * responseWriter ) )
2015-04-09 13:15:02 +03:00
assert . Equal ( t , cp . Request , c . Request )
2015-07-02 21:24:54 +03:00
assert . Equal ( t , cp . index , abortIndex )
2015-04-09 13:15:02 +03:00
assert . Equal ( t , cp . Keys , c . Keys )
2015-05-22 03:24:13 +03:00
assert . Equal ( t , cp . engine , c . engine )
2015-04-09 13:15:02 +03:00
assert . Equal ( t , cp . Params , c . Params )
2019-02-26 10:10:16 +03:00
cp . Set ( "foo" , "notBar" )
assert . False ( t , cp . Keys [ "foo" ] == c . Keys [ "foo" ] )
2015-04-09 13:15:02 +03:00
}
2015-06-25 20:44:52 +03:00
func TestContextHandlerName ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-06-25 20:44:52 +03:00
c . handlers = HandlersChain { func ( c * Context ) { } , handlerNameTest }
2015-08-21 21:57:53 +03:00
assert . Regexp ( t , "^(.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest$" , c . HandlerName ( ) )
2015-06-25 20:44:52 +03:00
}
2019-02-26 07:15:40 +03:00
func TestContextHandlerNames ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . handlers = HandlersChain { func ( c * Context ) { } , handlerNameTest , func ( c * Context ) { } , handlerNameTest2 }
names := c . HandlerNames ( )
assert . True ( t , len ( names ) == 4 )
for _ , name := range names {
assert . Regexp ( t , ` ^(.*/vendor/)?(github\.com/gin-gonic/gin\.) { 1}(TestContextHandlerNames\.func.*) { 0,1}(handlerNameTest.*) { 0,1} ` , name )
}
}
2015-06-25 20:44:52 +03:00
func handlerNameTest ( c * Context ) {
}
2019-02-26 07:15:40 +03:00
func handlerNameTest2 ( c * Context ) {
}
2017-06-02 11:00:55 +03:00
var handlerTest HandlerFunc = func ( c * Context ) {
}
func TestContextHandler ( t * testing . T ) {
2017-06-13 05:50:42 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . handlers = HandlersChain { func ( c * Context ) { } , handlerTest }
2017-06-02 11:00:55 +03:00
2017-06-13 05:50:42 +03:00
assert . Equal ( t , reflect . ValueOf ( handlerTest ) . Pointer ( ) , reflect . ValueOf ( c . Handler ( ) ) . Pointer ( ) )
2017-06-02 11:00:55 +03:00
}
2015-05-26 18:22:39 +03:00
func TestContextQuery ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2016-01-29 04:07:44 +03:00
c . Request , _ = http . NewRequest ( "GET" , "http://example.com/?foo=bar&page=10&id=" , nil )
2015-05-05 16:06:38 +03:00
2016-01-29 04:07:44 +03:00
value , ok := c . GetQuery ( "foo" )
assert . True ( t , ok )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "bar" , value )
assert . Equal ( t , "bar" , c . DefaultQuery ( "foo" , "none" ) )
assert . Equal ( t , "bar" , c . Query ( "foo" ) )
2015-05-05 16:06:38 +03:00
2016-01-29 04:07:44 +03:00
value , ok = c . GetQuery ( "page" )
assert . True ( t , ok )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "10" , value )
assert . Equal ( t , "10" , c . DefaultQuery ( "page" , "0" ) )
assert . Equal ( t , "10" , c . Query ( "page" ) )
2015-05-05 16:06:38 +03:00
2016-01-29 04:07:44 +03:00
value , ok = c . GetQuery ( "id" )
assert . True ( t , ok )
assert . Empty ( t , value )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , c . DefaultQuery ( "id" , "nada" ) )
2016-01-29 04:07:44 +03:00
assert . Empty ( t , c . Query ( "id" ) )
value , ok = c . GetQuery ( "NoKey" )
assert . False ( t , ok )
assert . Empty ( t , value )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "nada" , c . DefaultQuery ( "NoKey" , "nada" ) )
2015-05-26 13:11:59 +03:00
assert . Empty ( t , c . Query ( "NoKey" ) )
2016-01-29 04:07:44 +03:00
// postform should not mess
value , ok = c . GetPostForm ( "page" )
assert . False ( t , ok )
assert . Empty ( t , value )
assert . Empty ( t , c . PostForm ( "foo" ) )
2015-05-05 16:06:38 +03:00
}
2020-08-08 15:32:19 +03:00
func TestContextDefaultQueryOnEmptyRequest ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) ) // here c.Request == nil
assert . NotPanics ( t , func ( ) {
value , ok := c . GetQuery ( "NoKey" )
assert . False ( t , ok )
assert . Empty ( t , value )
} )
assert . NotPanics ( t , func ( ) {
assert . Equal ( t , "nada" , c . DefaultQuery ( "NoKey" , "nada" ) )
} )
assert . NotPanics ( t , func ( ) {
assert . Empty ( t , c . Query ( "NoKey" ) )
} )
}
2015-05-26 18:22:39 +03:00
func TestContextQueryAndPostForm ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2016-01-29 04:07:44 +03:00
body := bytes . NewBufferString ( "foo=bar&page=11&both=&foo=second" )
2018-08-06 07:07:11 +03:00
c . Request , _ = http . NewRequest ( "POST" ,
"/?both=GET&id=main&id=omit&array[]=first&array[]=second&ids[a]=hi&ids[b]=3.14" , body )
2015-05-05 16:06:38 +03:00
c . Request . Header . Add ( "Content-Type" , MIMEPOSTForm )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "bar" , c . DefaultPostForm ( "foo" , "none" ) )
assert . Equal ( t , "bar" , c . PostForm ( "foo" ) )
2015-05-26 13:11:59 +03:00
assert . Empty ( t , c . Query ( "foo" ) )
2015-05-05 16:06:38 +03:00
2016-01-29 04:07:44 +03:00
value , ok := c . GetPostForm ( "page" )
assert . True ( t , ok )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "11" , value )
assert . Equal ( t , "11" , c . DefaultPostForm ( "page" , "0" ) )
assert . Equal ( t , "11" , c . PostForm ( "page" ) )
assert . Empty ( t , c . Query ( "page" ) )
2015-05-05 16:06:38 +03:00
2016-01-29 04:07:44 +03:00
value , ok = c . GetPostForm ( "both" )
assert . True ( t , ok )
assert . Empty ( t , value )
assert . Empty ( t , c . PostForm ( "both" ) )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , c . DefaultPostForm ( "both" , "nothing" ) )
assert . Equal ( t , "GET" , c . Query ( "both" ) , "GET" )
2015-05-05 16:06:38 +03:00
2016-01-29 04:07:44 +03:00
value , ok = c . GetQuery ( "id" )
assert . True ( t , ok )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "main" , value )
assert . Equal ( t , "000" , c . DefaultPostForm ( "id" , "000" ) )
assert . Equal ( t , "main" , c . Query ( "id" ) )
2015-05-26 13:11:59 +03:00
assert . Empty ( t , c . PostForm ( "id" ) )
2015-05-05 16:06:38 +03:00
2016-01-29 04:07:44 +03:00
value , ok = c . GetQuery ( "NoKey" )
assert . False ( t , ok )
assert . Empty ( t , value )
value , ok = c . GetPostForm ( "NoKey" )
assert . False ( t , ok )
assert . Empty ( t , value )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "nada" , c . DefaultPostForm ( "NoKey" , "nada" ) )
assert . Equal ( t , "nothing" , c . DefaultQuery ( "NoKey" , "nothing" ) )
2015-05-26 13:11:59 +03:00
assert . Empty ( t , c . PostForm ( "NoKey" ) )
assert . Empty ( t , c . Query ( "NoKey" ) )
2015-05-26 13:08:33 +03:00
2015-05-26 18:22:39 +03:00
var obj struct {
2015-07-08 05:26:37 +03:00
Foo string ` form:"foo" `
ID string ` form:"id" `
2016-01-29 04:07:44 +03:00
Page int ` form:"page" `
2015-07-08 05:26:37 +03:00
Both string ` form:"both" `
Array [ ] string ` form:"array[]" `
2015-05-26 18:22:39 +03:00
}
assert . NoError ( t , c . Bind ( & obj ) )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "bar" , obj . Foo , "bar" )
assert . Equal ( t , "main" , obj . ID , "main" )
assert . Equal ( t , 11 , obj . Page , 11 )
assert . Empty ( t , obj . Both )
assert . Equal ( t , [ ] string { "first" , "second" } , obj . Array )
2016-03-29 19:05:13 +03:00
values , ok := c . GetQueryArray ( "array[]" )
assert . True ( t , ok )
assert . Equal ( t , "first" , values [ 0 ] )
assert . Equal ( t , "second" , values [ 1 ] )
values = c . QueryArray ( "array[]" )
assert . Equal ( t , "first" , values [ 0 ] )
assert . Equal ( t , "second" , values [ 1 ] )
values = c . QueryArray ( "nokey" )
assert . Equal ( t , 0 , len ( values ) )
values = c . QueryArray ( "both" )
assert . Equal ( t , 1 , len ( values ) )
assert . Equal ( t , "GET" , values [ 0 ] )
2018-08-06 07:07:11 +03:00
dicts , ok := c . GetQueryMap ( "ids" )
assert . True ( t , ok )
assert . Equal ( t , "hi" , dicts [ "a" ] )
assert . Equal ( t , "3.14" , dicts [ "b" ] )
dicts , ok = c . GetQueryMap ( "nokey" )
assert . False ( t , ok )
assert . Equal ( t , 0 , len ( dicts ) )
dicts , ok = c . GetQueryMap ( "both" )
assert . False ( t , ok )
assert . Equal ( t , 0 , len ( dicts ) )
dicts , ok = c . GetQueryMap ( "array" )
assert . False ( t , ok )
assert . Equal ( t , 0 , len ( dicts ) )
dicts = c . QueryMap ( "ids" )
assert . Equal ( t , "hi" , dicts [ "a" ] )
assert . Equal ( t , "3.14" , dicts [ "b" ] )
dicts = c . QueryMap ( "nokey" )
assert . Equal ( t , 0 , len ( dicts ) )
2015-05-26 18:22:39 +03:00
}
func TestContextPostFormMultipart ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-26 18:22:39 +03:00
c . Request = createMultipartRequest ( )
var obj struct {
2017-09-28 17:23:18 +03:00
Foo string ` form:"foo" `
Bar string ` form:"bar" `
BarAsInt int ` form:"bar" `
Array [ ] string ` form:"array" `
ID string ` form:"id" `
TimeLocal time . Time ` form:"time_local" time_format:"02/01/2006 15:04" `
TimeUTC time . Time ` form:"time_utc" time_format:"02/01/2006 15:04" time_utc:"1" `
TimeLocation time . Time ` form:"time_location" time_format:"02/01/2006 15:04" time_location:"Asia/Tokyo" `
BlankTime time . Time ` form:"blank_time" time_format:"02/01/2006 15:04" `
2015-05-26 18:22:39 +03:00
}
assert . NoError ( t , c . Bind ( & obj ) )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "bar" , obj . Foo )
assert . Equal ( t , "10" , obj . Bar )
assert . Equal ( t , 10 , obj . BarAsInt )
assert . Equal ( t , [ ] string { "first" , "second" } , obj . Array )
assert . Empty ( t , obj . ID )
assert . Equal ( t , "31/12/2016 14:55" , obj . TimeLocal . Format ( "02/01/2006 15:04" ) )
assert . Equal ( t , time . Local , obj . TimeLocal . Location ( ) )
assert . Equal ( t , "31/12/2016 14:55" , obj . TimeUTC . Format ( "02/01/2006 15:04" ) )
assert . Equal ( t , time . UTC , obj . TimeUTC . Location ( ) )
2017-09-28 17:23:18 +03:00
loc , _ := time . LoadLocation ( "Asia/Tokyo" )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "31/12/2016 14:55" , obj . TimeLocation . Format ( "02/01/2006 15:04" ) )
assert . Equal ( t , loc , obj . TimeLocation . Location ( ) )
2017-02-17 16:32:36 +03:00
assert . True ( t , obj . BlankTime . IsZero ( ) )
2015-05-26 13:08:33 +03:00
2016-01-29 04:07:44 +03:00
value , ok := c . GetQuery ( "foo" )
assert . False ( t , ok )
assert . Empty ( t , value )
2015-05-26 18:22:39 +03:00
assert . Empty ( t , c . Query ( "bar" ) )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "nothing" , c . DefaultQuery ( "id" , "nothing" ) )
2016-01-29 04:07:44 +03:00
value , ok = c . GetPostForm ( "foo" )
assert . True ( t , ok )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "bar" , value )
assert . Equal ( t , "bar" , c . PostForm ( "foo" ) )
2016-01-29 04:07:44 +03:00
value , ok = c . GetPostForm ( "array" )
assert . True ( t , ok )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "first" , value )
assert . Equal ( t , "first" , c . PostForm ( "array" ) )
2016-01-29 04:07:44 +03:00
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "10" , c . DefaultPostForm ( "bar" , "nothing" ) )
2016-01-29 04:07:44 +03:00
value , ok = c . GetPostForm ( "id" )
assert . True ( t , ok )
assert . Empty ( t , value )
assert . Empty ( t , c . PostForm ( "id" ) )
assert . Empty ( t , c . DefaultPostForm ( "id" , "nothing" ) )
value , ok = c . GetPostForm ( "nokey" )
assert . False ( t , ok )
assert . Empty ( t , value )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "nothing" , c . DefaultPostForm ( "nokey" , "nothing" ) )
2016-03-29 19:05:13 +03:00
values , ok := c . GetPostFormArray ( "array" )
assert . True ( t , ok )
assert . Equal ( t , "first" , values [ 0 ] )
assert . Equal ( t , "second" , values [ 1 ] )
values = c . PostFormArray ( "array" )
assert . Equal ( t , "first" , values [ 0 ] )
assert . Equal ( t , "second" , values [ 1 ] )
values = c . PostFormArray ( "nokey" )
assert . Equal ( t , 0 , len ( values ) )
values = c . PostFormArray ( "foo" )
assert . Equal ( t , 1 , len ( values ) )
assert . Equal ( t , "bar" , values [ 0 ] )
2018-08-06 07:07:11 +03:00
dicts , ok := c . GetPostFormMap ( "names" )
assert . True ( t , ok )
assert . Equal ( t , "thinkerou" , dicts [ "a" ] )
assert . Equal ( t , "tianou" , dicts [ "b" ] )
dicts , ok = c . GetPostFormMap ( "nokey" )
assert . False ( t , ok )
assert . Equal ( t , 0 , len ( dicts ) )
dicts = c . PostFormMap ( "names" )
assert . Equal ( t , "thinkerou" , dicts [ "a" ] )
assert . Equal ( t , "tianou" , dicts [ "b" ] )
dicts = c . PostFormMap ( "nokey" )
assert . Equal ( t , 0 , len ( dicts ) )
2015-05-05 16:06:38 +03:00
}
2015-08-27 11:04:50 +03:00
func TestContextSetCookie ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2020-03-27 05:47:22 +03:00
c . SetSameSite ( http . SameSiteLaxMode )
c . SetCookie ( "user" , "gin" , 1 , "/" , "localhost" , true , true )
2020-01-20 10:12:44 +03:00
assert . Equal ( t , "user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax" , c . Writer . Header ( ) . Get ( "Set-Cookie" ) )
2015-08-27 11:04:50 +03:00
}
2017-05-24 12:39:05 +03:00
func TestContextSetCookiePathEmpty ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2020-03-27 05:47:22 +03:00
c . SetSameSite ( http . SameSiteLaxMode )
c . SetCookie ( "user" , "gin" , 1 , "" , "localhost" , true , true )
2020-01-20 10:12:44 +03:00
assert . Equal ( t , "user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax" , c . Writer . Header ( ) . Get ( "Set-Cookie" ) )
2017-05-24 12:39:05 +03:00
}
2015-08-27 11:04:50 +03:00
func TestContextGetCookie ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-08-27 11:04:50 +03:00
c . Request , _ = http . NewRequest ( "GET" , "/get" , nil )
c . Request . Header . Set ( "Cookie" , "user=gin" )
2016-01-28 02:35:09 +03:00
cookie , _ := c . Cookie ( "user" )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "gin" , cookie )
2017-05-24 12:39:05 +03:00
_ , err := c . Cookie ( "nokey" )
assert . Error ( t , err )
2015-08-27 11:04:50 +03:00
}
2017-01-09 18:24:48 +03:00
func TestContextBodyAllowedForStatus ( t * testing . T ) {
2019-05-07 13:32:32 +03:00
assert . False ( t , false , bodyAllowedForStatus ( http . StatusProcessing ) )
2018-08-14 04:51:56 +03:00
assert . False ( t , false , bodyAllowedForStatus ( http . StatusNoContent ) )
assert . False ( t , false , bodyAllowedForStatus ( http . StatusNotModified ) )
assert . True ( t , true , bodyAllowedForStatus ( http . StatusInternalServerError ) )
2017-01-09 18:24:48 +03:00
}
2021-08-19 10:46:31 +03:00
type TestPanicRender struct { }
2017-01-09 18:24:48 +03:00
func ( * TestPanicRender ) Render ( http . ResponseWriter ) error {
return errors . New ( "TestPanicRender" )
}
func ( * TestPanicRender ) WriteContentType ( http . ResponseWriter ) { }
func TestContextRenderPanicIfErr ( t * testing . T ) {
defer func ( ) {
r := recover ( )
assert . Equal ( t , "TestPanicRender" , fmt . Sprint ( r ) )
} ( )
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Render ( http . StatusOK , & TestPanicRender { } )
assert . Fail ( t , "Panic not detected" )
}
2015-04-08 03:58:35 +03:00
// Tests that the response is serialized as JSON
// and Content-Type is set to application/json
2018-08-20 10:15:31 +03:00
// and special HTML characters are escaped
2015-04-08 03:58:35 +03:00
func TestContextRenderJSON ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-20 10:15:31 +03:00
c . JSON ( http . StatusCreated , H { "foo" : "bar" , "html" : "<b>" } )
2014-08-08 15:48:15 +04:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2020-02-21 12:15:17 +03:00
assert . Equal ( t , "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2014-08-08 15:48:15 +04:00
}
2018-04-26 06:52:19 +03:00
// Tests that the response is serialized as JSONP
// and Content-Type is set to application/javascript
func TestContextRenderJSONP ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "GET" , "http://example.com/?callback=x" , nil )
2018-08-14 04:51:56 +03:00
c . JSONP ( http . StatusCreated , H { "foo" : "bar" } )
2018-04-26 06:52:19 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2019-09-02 15:18:08 +03:00
assert . Equal ( t , "x({\"foo\":\"bar\"});" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/javascript; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2018-04-26 06:52:19 +03:00
}
2018-07-20 19:52:55 +03:00
// Tests that the response is serialized as JSONP
// and Content-Type is set to application/json
func TestContextRenderJSONPWithoutCallback ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "GET" , "http://example.com" , nil )
2018-08-14 04:51:56 +03:00
c . JSONP ( http . StatusCreated , H { "foo" : "bar" } )
2018-07-20 19:52:55 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2020-02-21 12:15:17 +03:00
assert . Equal ( t , "{\"foo\":\"bar\"}" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2018-07-20 19:52:55 +03:00
}
2017-01-09 18:24:48 +03:00
// Tests that no JSON is rendered if code is 204
func TestContextRenderNoContentJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . JSON ( http . StatusNoContent , H { "foo" : "bar" } )
2017-01-09 18:24:48 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-01-09 18:24:48 +03:00
}
2015-06-13 05:29:10 +03:00
// Tests that the response is serialized as JSON
// we change the content-type before
func TestContextRenderAPIJSON ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-06-13 05:29:10 +03:00
c . Header ( "Content-Type" , "application/vnd.api+json" )
2018-08-14 04:51:56 +03:00
c . JSON ( http . StatusCreated , H { "foo" : "bar" } )
2015-06-13 05:29:10 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2020-02-21 12:15:17 +03:00
assert . Equal ( t , "{\"foo\":\"bar\"}" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/vnd.api+json" , w . Header ( ) . Get ( "Content-Type" ) )
2015-06-13 05:29:10 +03:00
}
2017-01-09 18:24:48 +03:00
// Tests that no Custom JSON is rendered if code is 204
func TestContextRenderNoContentAPIJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Header ( "Content-Type" , "application/vnd.api+json" )
2018-08-14 04:51:56 +03:00
c . JSON ( http . StatusNoContent , H { "foo" : "bar" } )
2017-01-09 18:24:48 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , w . Header ( ) . Get ( "Content-Type" ) , "application/vnd.api+json" )
2017-01-09 18:24:48 +03:00
}
2015-05-11 02:04:08 +03:00
// Tests that the response is serialized as JSON
// and Content-Type is set to application/json
func TestContextRenderIndentedJSON ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . IndentedJSON ( http . StatusCreated , H { "foo" : "bar" , "bar" : "foo" , "nested" : H { "foo" : "bar" } } )
2015-05-11 02:04:08 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-07-11 08:59:03 +03:00
assert . Equal ( t , "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2015-05-11 02:04:08 +03:00
}
2017-01-09 18:24:48 +03:00
// Tests that no Custom JSON is rendered if code is 204
func TestContextRenderNoContentIndentedJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . IndentedJSON ( http . StatusNoContent , H { "foo" : "bar" , "bar" : "foo" , "nested" : H { "foo" : "bar" } } )
2017-01-09 18:24:48 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-07-07 20:21:30 +03:00
}
// Tests that the response is serialized as Secure JSON
// and Content-Type is set to application/json
func TestContextRenderSecureJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , router := CreateTestContext ( w )
router . SecureJsonPrefix ( "&&&START&&&" )
2018-08-14 04:51:56 +03:00
c . SecureJSON ( http . StatusCreated , [ ] string { "foo" , "bar" } )
2017-07-07 20:21:30 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "&&&START&&&[\"foo\",\"bar\"]" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-07-07 20:21:30 +03:00
}
// Tests that no Custom JSON is rendered if code is 204
func TestContextRenderNoContentSecureJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . SecureJSON ( http . StatusNoContent , [ ] string { "foo" , "bar" } )
2017-07-07 20:21:30 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-01-09 18:24:48 +03:00
}
2018-07-03 12:17:08 +03:00
func TestContextRenderNoContentAsciiJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . AsciiJSON ( http . StatusNoContent , [ ] string { "lang" , "Go语言" } )
assert . Equal ( t , http . StatusNoContent , w . Code )
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json" , w . Header ( ) . Get ( "Content-Type" ) )
2018-07-03 12:17:08 +03:00
}
2019-05-07 13:32:32 +03:00
// Tests that the response is serialized as JSON
// and Content-Type is set to application/json
// and special HTML characters are preserved
func TestContextRenderPureJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . PureJSON ( http . StatusCreated , H { "foo" : "bar" , "html" : "<b>" } )
assert . Equal ( t , http . StatusCreated , w . Code )
assert . Equal ( t , "{\"foo\":\"bar\",\"html\":\"<b>\"}\n" , w . Body . String ( ) )
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
}
2015-04-08 03:58:35 +03:00
// Tests that the response executes the templates
2014-08-08 15:48:15 +04:00
// and responds with Content-Type set to text/html
2015-04-08 03:58:35 +03:00
func TestContextRenderHTML ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , router := CreateTestContext ( w )
2017-11-29 11:42:51 +03:00
2015-04-09 13:15:02 +03:00
templ := template . Must ( template . New ( "t" ) . Parse ( ` Hello {{ .name }} ` ) )
2015-04-08 03:58:35 +03:00
router . SetHTMLTemplate ( templ )
2014-08-08 15:48:15 +04:00
2018-08-14 04:51:56 +03:00
c . HTML ( http . StatusCreated , "t" , H { "name" : "alexandernyquist" } )
2014-08-08 15:48:15 +04:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "Hello alexandernyquist" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/html; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2015-04-08 03:58:35 +03:00
}
2014-08-08 15:48:15 +04:00
2017-11-29 11:42:51 +03:00
func TestContextRenderHTML2 ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , router := CreateTestContext ( w )
// print debug warning log when Engine.trees > 0
router . addRoute ( "GET" , "/" , HandlersChain { func ( _ * Context ) { } } )
assert . Len ( t , router . trees , 1 )
templ := template . Must ( template . New ( "t" ) . Parse ( ` Hello {{ .name }} ` ) )
2019-01-18 04:32:53 +03:00
re := captureOutput ( t , func ( ) {
2018-09-19 08:57:00 +03:00
SetMode ( DebugMode )
router . SetHTMLTemplate ( templ )
SetMode ( TestMode )
} )
2017-11-29 11:42:51 +03:00
2018-09-19 08:57:00 +03:00
assert . Equal ( t , "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n" , re )
2017-11-29 11:42:51 +03:00
2018-08-14 04:51:56 +03:00
c . HTML ( http . StatusCreated , "t" , H { "name" : "alexandernyquist" } )
2017-11-29 11:42:51 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-29 11:42:51 +03:00
assert . Equal ( t , "Hello alexandernyquist" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/html; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-11-29 11:42:51 +03:00
}
2017-01-09 18:24:48 +03:00
// Tests that no HTML is rendered if code is 204
func TestContextRenderNoContentHTML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , router := CreateTestContext ( w )
templ := template . Must ( template . New ( "t" ) . Parse ( ` Hello {{ .name }} ` ) )
router . SetHTMLTemplate ( templ )
2018-08-14 04:51:56 +03:00
c . HTML ( http . StatusNoContent , "t" , H { "name" : "alexandernyquist" } )
2017-01-09 18:24:48 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/html; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-01-09 18:24:48 +03:00
}
2015-04-08 03:58:35 +03:00
// TestContextXML tests that the response is serialized as XML
// and Content-Type is set to application/xml
func TestContextRenderXML ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . XML ( http . StatusCreated , H { "foo" : "bar" } )
2014-08-08 15:48:15 +04:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "<map><foo>bar</foo></map>" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/xml; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2014-08-08 15:48:15 +04:00
}
2017-01-09 18:24:48 +03:00
// Tests that no XML is rendered if code is 204
func TestContextRenderNoContentXML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . XML ( http . StatusNoContent , H { "foo" : "bar" } )
2017-01-09 18:24:48 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/xml; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-01-09 18:24:48 +03:00
}
2014-08-08 15:48:15 +04:00
// TestContextString tests that the response is returned
// with Content-Type set to text/plain
2015-04-08 03:58:35 +03:00
func TestContextRenderString ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . String ( http . StatusCreated , "test %s %d" , "string" , 2 )
2014-08-08 15:48:15 +04:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "test string 2" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/plain; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2014-08-08 15:48:15 +04:00
}
2017-01-09 18:24:48 +03:00
// Tests that no String is rendered if code is 204
func TestContextRenderNoContentString ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . String ( http . StatusNoContent , "test %s %d" , "string" , 2 )
2017-01-09 18:24:48 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/plain; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-01-09 18:24:48 +03:00
}
2015-04-08 03:58:35 +03:00
// TestContextString tests that the response is returned
// with Content-Type set to text/html
func TestContextRenderHTMLString ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-05-18 16:45:24 +03:00
c . Header ( "Content-Type" , "text/html; charset=utf-8" )
2018-08-14 04:51:56 +03:00
c . String ( http . StatusCreated , "<html>%s %d</html>" , "string" , 3 )
2015-04-08 03:58:35 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "<html>string 3</html>" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/html; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2014-08-08 17:31:01 +04:00
}
2017-01-09 18:24:48 +03:00
// Tests that no HTML String is rendered if code is 204
func TestContextRenderNoContentHTMLString ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Header ( "Content-Type" , "text/html; charset=utf-8" )
2018-08-14 04:51:56 +03:00
c . String ( http . StatusNoContent , "<html>%s %d</html>" , "string" , 3 )
2017-01-09 18:24:48 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/html; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-01-09 18:24:48 +03:00
}
2020-08-04 02:04:06 +03:00
// TestContextData tests that the response can be written from `bytestring`
2014-08-08 17:31:01 +04:00
// with specified MIME type
2015-04-08 03:58:35 +03:00
func TestContextRenderData ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . Data ( http . StatusCreated , "text/csv" , [ ] byte ( ` foo,bar ` ) )
2014-08-08 17:31:01 +04:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "foo,bar" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/csv" , w . Header ( ) . Get ( "Content-Type" ) )
2014-08-08 17:31:01 +04:00
}
2017-01-09 18:24:48 +03:00
// Tests that no Custom Data is rendered if code is 204
func TestContextRenderNoContentData ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . Data ( http . StatusNoContent , "text/csv" , [ ] byte ( ` foo,bar ` ) )
2017-01-09 18:24:48 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNoContent , w . Code )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/csv" , w . Header ( ) . Get ( "Content-Type" ) )
2017-01-09 18:24:48 +03:00
}
2015-05-19 03:29:32 +03:00
func TestContextRenderSSE ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-05-19 03:29:32 +03:00
c . SSEvent ( "float" , 1.5 )
c . Render ( - 1 , sse . Event {
Id : "123" ,
Data : "text" ,
} )
c . SSEvent ( "chat" , H {
"foo" : "bar" ,
"bar" : "foo" ,
} )
2015-09-25 13:04:55 +03:00
assert . Equal ( t , strings . Replace ( w . Body . String ( ) , " " , "" , - 1 ) , strings . Replace ( "event:float\ndata:1.5\n\nid:123\ndata:text\n\nevent:chat\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\n" , " " , "" , - 1 ) )
2015-05-19 03:29:32 +03:00
}
func TestContextRenderFile ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-05-19 03:29:32 +03:00
c . Request , _ = http . NewRequest ( "GET" , "/" , nil )
c . File ( "./gin.go" )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusOK , w . Code )
2015-05-19 03:29:32 +03:00
assert . Contains ( t , w . Body . String ( ) , "func New() *Engine {" )
2021-04-21 02:38:54 +03:00
// Content-Type='text/plain; charset=utf-8' when go version <= 1.16,
// else, Content-Type='text/x-go; charset=utf-8'
assert . NotEqual ( t , "" , w . Header ( ) . Get ( "Content-Type" ) )
2019-03-01 05:17:47 +03:00
}
2020-03-07 05:23:33 +03:00
func TestContextRenderFileFromFS ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "GET" , "/some/path" , nil )
c . FileFromFS ( "./gin.go" , Dir ( "." , false ) )
assert . Equal ( t , http . StatusOK , w . Code )
assert . Contains ( t , w . Body . String ( ) , "func New() *Engine {" )
2021-04-21 02:38:54 +03:00
// Content-Type='text/plain; charset=utf-8' when go version <= 1.16,
// else, Content-Type='text/x-go; charset=utf-8'
assert . NotEqual ( t , "" , w . Header ( ) . Get ( "Content-Type" ) )
2020-03-07 05:23:33 +03:00
assert . Equal ( t , "/some/path" , c . Request . URL . Path )
}
2019-03-01 05:17:47 +03:00
func TestContextRenderAttachment ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
newFilename := "new_filename.go"
c . Request , _ = http . NewRequest ( "GET" , "/" , nil )
c . FileAttachment ( "./gin.go" , newFilename )
assert . Equal ( t , 200 , w . Code )
assert . Contains ( t , w . Body . String ( ) , "func New() *Engine {" )
2021-04-21 02:55:08 +03:00
assert . Equal ( t , fmt . Sprintf ( "attachment; filename=\"%s\"" , newFilename ) , w . Header ( ) . Get ( "Content-Disposition" ) )
2022-03-17 06:56:16 +03:00
}
func TestContextRenderUTF8Attachment ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
newFilename := "new🧡_filename.go"
c . Request , _ = http . NewRequest ( "GET" , "/" , nil )
c . FileAttachment ( "./gin.go" , newFilename )
assert . Equal ( t , 200 , w . Code )
assert . Contains ( t , w . Body . String ( ) , "func New() *Engine {" )
assert . Equal ( t , ` attachment; filename*=UTF-8'' ` + url . QueryEscape ( newFilename ) , w . Header ( ) . Get ( "Content-Disposition" ) )
2015-05-19 03:29:32 +03:00
}
2016-04-15 00:47:49 +03:00
// TestContextRenderYAML tests that the response is serialized as YAML
// and Content-Type is set to application/x-yaml
func TestContextRenderYAML ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-08-14 04:51:56 +03:00
c . YAML ( http . StatusCreated , H { "foo" : "bar" } )
2016-04-15 00:47:49 +03:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "foo: bar\n" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/x-yaml; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2016-04-15 00:47:49 +03:00
}
2022-07-01 12:38:32 +03:00
// TestContextRenderTOML tests that the response is serialized as TOML
// and Content-Type is set to application/toml
func TestContextRenderTOML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . TOML ( http . StatusCreated , H { "foo" : "bar" } )
assert . Equal ( t , http . StatusCreated , w . Code )
assert . Equal ( t , "foo = 'bar'\n" , w . Body . String ( ) )
assert . Equal ( t , "application/toml; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
}
2018-08-19 05:45:56 +03:00
// TestContextRenderProtoBuf tests that the response is serialized as ProtoBuf
// and Content-Type is set to application/x-protobuf
// and we just use the example protobuf to check if the response is correct
func TestContextRenderProtoBuf ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
reps := [ ] int64 { int64 ( 1 ) , int64 ( 2 ) }
label := "test"
data := & testdata . Test {
Label : & label ,
Reps : reps ,
}
c . ProtoBuf ( http . StatusCreated , data )
protoData , err := proto . Marshal ( data )
assert . NoError ( t , err )
assert . Equal ( t , http . StatusCreated , w . Code )
2018-09-12 16:21:26 +03:00
assert . Equal ( t , string ( protoData ) , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/x-protobuf" , w . Header ( ) . Get ( "Content-Type" ) )
2018-08-19 05:45:56 +03:00
}
2015-05-18 16:45:24 +03:00
func TestContextHeaders ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-18 16:45:24 +03:00
c . Header ( "Content-Type" , "text/plain" )
c . Header ( "X-Custom" , "value" )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "text/plain" , c . Writer . Header ( ) . Get ( "Content-Type" ) )
assert . Equal ( t , "value" , c . Writer . Header ( ) . Get ( "X-Custom" ) )
2015-05-18 16:45:24 +03:00
c . Header ( "Content-Type" , "text/html" )
c . Header ( "X-Custom" , "" )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "text/html" , c . Writer . Header ( ) . Get ( "Content-Type" ) )
2015-05-18 16:45:24 +03:00
_ , exist := c . Writer . Header ( ) [ "X-Custom" ]
assert . False ( t , exist )
}
2015-04-08 03:58:35 +03:00
// TODO
func TestContextRenderRedirectWithRelativePath ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-04-08 03:58:35 +03:00
c . Request , _ = http . NewRequest ( "POST" , "http://example.com" , nil )
assert . Panics ( t , func ( ) { c . Redirect ( 299 , "/new_path" ) } )
assert . Panics ( t , func ( ) { c . Redirect ( 309 , "/new_path" ) } )
2018-08-14 04:51:56 +03:00
c . Redirect ( http . StatusMovedPermanently , "/path" )
2015-04-08 03:58:35 +03:00
c . Writer . WriteHeaderNow ( )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusMovedPermanently , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "/path" , w . Header ( ) . Get ( "Location" ) )
2014-08-08 17:31:01 +04:00
}
2015-04-08 03:58:35 +03:00
func TestContextRenderRedirectWithAbsolutePath ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-04-08 03:58:35 +03:00
c . Request , _ = http . NewRequest ( "POST" , "http://example.com" , nil )
2018-08-14 04:51:56 +03:00
c . Redirect ( http . StatusFound , "http://google.com" )
2015-04-08 03:58:35 +03:00
c . Writer . WriteHeaderNow ( )
2014-08-08 15:48:15 +04:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusFound , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "http://google.com" , w . Header ( ) . Get ( "Location" ) )
2014-08-08 15:48:15 +04:00
}
2016-01-28 02:34:05 +03:00
func TestContextRenderRedirectWith201 ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2016-01-28 02:34:05 +03:00
c . Request , _ = http . NewRequest ( "POST" , "http://example.com" , nil )
2018-08-14 04:51:56 +03:00
c . Redirect ( http . StatusCreated , "/resource" )
2016-01-28 02:34:05 +03:00
c . Writer . WriteHeaderNow ( )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusCreated , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "/resource" , w . Header ( ) . Get ( "Location" ) )
2016-01-28 02:34:05 +03:00
}
func TestContextRenderRedirectAll ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2016-01-28 02:34:05 +03:00
c . Request , _ = http . NewRequest ( "POST" , "http://example.com" , nil )
2018-08-14 04:51:56 +03:00
assert . Panics ( t , func ( ) { c . Redirect ( http . StatusOK , "/resource" ) } )
assert . Panics ( t , func ( ) { c . Redirect ( http . StatusAccepted , "/resource" ) } )
2016-01-28 02:34:05 +03:00
assert . Panics ( t , func ( ) { c . Redirect ( 299 , "/resource" ) } )
assert . Panics ( t , func ( ) { c . Redirect ( 309 , "/resource" ) } )
2018-08-14 04:51:56 +03:00
assert . NotPanics ( t , func ( ) { c . Redirect ( http . StatusMultipleChoices , "/resource" ) } )
2019-05-07 13:32:32 +03:00
assert . NotPanics ( t , func ( ) { c . Redirect ( http . StatusPermanentRedirect , "/resource" ) } )
2016-01-28 02:34:05 +03:00
}
2017-05-29 09:28:38 +03:00
func TestContextNegotiationWithJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "" , nil )
2018-08-14 04:51:56 +03:00
c . Negotiate ( http . StatusOK , Negotiate {
2020-02-06 09:50:21 +03:00
Offered : [ ] string { MIMEJSON , MIMEXML , MIMEYAML } ,
2017-05-29 09:28:38 +03:00
Data : H { "foo" : "bar" } ,
} )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusOK , w . Code )
2020-02-21 12:15:17 +03:00
assert . Equal ( t , "{\"foo\":\"bar\"}" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-05-29 09:28:38 +03:00
}
func TestContextNegotiationWithXML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "" , nil )
2018-08-14 04:51:56 +03:00
c . Negotiate ( http . StatusOK , Negotiate {
2020-02-06 09:50:21 +03:00
Offered : [ ] string { MIMEXML , MIMEJSON , MIMEYAML } ,
2017-05-29 09:28:38 +03:00
Data : H { "foo" : "bar" } ,
} )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusOK , w . Code )
2017-05-29 09:28:38 +03:00
assert . Equal ( t , "<map><foo>bar</foo></map>" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "application/xml; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-05-29 09:28:38 +03:00
}
2022-07-01 12:38:32 +03:00
func TestContextNegotiationWithYAML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "" , nil )
c . Negotiate ( http . StatusOK , Negotiate {
Offered : [ ] string { MIMEYAML , MIMEXML , MIMEJSON , MIMETOML } ,
Data : H { "foo" : "bar" } ,
} )
assert . Equal ( t , http . StatusOK , w . Code )
assert . Equal ( t , "foo: bar\n" , w . Body . String ( ) )
assert . Equal ( t , "application/x-yaml; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
}
func TestContextNegotiationWithTOML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "" , nil )
c . Negotiate ( http . StatusOK , Negotiate {
Offered : [ ] string { MIMETOML , MIMEXML , MIMEJSON , MIMEYAML } ,
Data : H { "foo" : "bar" } ,
} )
assert . Equal ( t , http . StatusOK , w . Code )
assert . Equal ( t , "foo = 'bar'\n" , w . Body . String ( ) )
assert . Equal ( t , "application/toml; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
}
2017-05-29 09:28:38 +03:00
func TestContextNegotiationWithHTML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , router := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "" , nil )
templ := template . Must ( template . New ( "t" ) . Parse ( ` Hello {{ .name }} ` ) )
router . SetHTMLTemplate ( templ )
2018-08-14 04:51:56 +03:00
c . Negotiate ( http . StatusOK , Negotiate {
2017-05-29 09:28:38 +03:00
Offered : [ ] string { MIMEHTML } ,
Data : H { "name" : "gin" } ,
HTMLName : "t" ,
} )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusOK , w . Code )
2017-05-29 09:28:38 +03:00
assert . Equal ( t , "Hello gin" , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , "text/html; charset=utf-8" , w . Header ( ) . Get ( "Content-Type" ) )
2017-05-29 09:28:38 +03:00
}
func TestContextNegotiationNotSupport ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "" , nil )
2018-08-14 04:51:56 +03:00
c . Negotiate ( http . StatusOK , Negotiate {
2017-05-29 09:28:38 +03:00
Offered : [ ] string { MIMEPOSTForm } ,
} )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusNotAcceptable , w . Code )
2017-05-29 09:28:38 +03:00
assert . Equal ( t , c . index , abortIndex )
assert . True ( t , c . IsAborted ( ) )
}
2015-04-08 03:58:35 +03:00
func TestContextNegotiationFormat ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-04-08 03:58:35 +03:00
c . Request , _ = http . NewRequest ( "POST" , "" , nil )
2014-08-08 15:48:15 +04:00
2015-04-09 13:15:02 +03:00
assert . Panics ( t , func ( ) { c . NegotiateFormat ( ) } )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , MIMEJSON , c . NegotiateFormat ( MIMEJSON , MIMEXML ) )
assert . Equal ( t , MIMEHTML , c . NegotiateFormat ( MIMEHTML , MIMEJSON ) )
2014-08-08 15:48:15 +04:00
}
2015-04-08 03:58:35 +03:00
func TestContextNegotiationFormatWithAccept ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-19 03:29:32 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
2019-03-01 05:03:14 +03:00
c . Request . Header . Add ( "Accept" , "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8" )
2014-08-11 14:25:52 +04:00
2017-11-21 16:18:45 +03:00
assert . Equal ( t , MIMEXML , c . NegotiateFormat ( MIMEJSON , MIMEXML ) )
assert . Equal ( t , MIMEHTML , c . NegotiateFormat ( MIMEXML , MIMEHTML ) )
assert . Empty ( t , c . NegotiateFormat ( MIMEJSON ) )
2015-04-08 03:58:35 +03:00
}
2014-08-11 14:25:52 +04:00
2019-03-01 05:03:14 +03:00
func TestContextNegotiationFormatWithWildcardAccept ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
c . Request . Header . Add ( "Accept" , "*/*" )
assert . Equal ( t , c . NegotiateFormat ( "*/*" ) , "*/*" )
assert . Equal ( t , c . NegotiateFormat ( "text/*" ) , "text/*" )
assert . Equal ( t , c . NegotiateFormat ( "application/*" ) , "application/*" )
assert . Equal ( t , c . NegotiateFormat ( MIMEJSON ) , MIMEJSON )
assert . Equal ( t , c . NegotiateFormat ( MIMEXML ) , MIMEXML )
assert . Equal ( t , c . NegotiateFormat ( MIMEHTML ) , MIMEHTML )
c , _ = CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
c . Request . Header . Add ( "Accept" , "text/*" )
assert . Equal ( t , c . NegotiateFormat ( "*/*" ) , "*/*" )
assert . Equal ( t , c . NegotiateFormat ( "text/*" ) , "text/*" )
assert . Equal ( t , c . NegotiateFormat ( "application/*" ) , "" )
assert . Equal ( t , c . NegotiateFormat ( MIMEJSON ) , "" )
assert . Equal ( t , c . NegotiateFormat ( MIMEXML ) , "" )
assert . Equal ( t , c . NegotiateFormat ( MIMEHTML ) , MIMEHTML )
}
2018-10-12 02:31:31 +03:00
func TestContextNegotiationFormatCustom ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-19 03:29:32 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
2019-03-01 05:03:14 +03:00
c . Request . Header . Add ( "Accept" , "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8" )
2014-08-11 14:25:52 +04:00
2015-04-08 03:58:35 +03:00
c . Accepted = nil
c . SetAccepted ( MIMEJSON , MIMEXML )
2014-08-11 14:25:52 +04:00
2017-11-21 16:18:45 +03:00
assert . Equal ( t , MIMEJSON , c . NegotiateFormat ( MIMEJSON , MIMEXML ) )
assert . Equal ( t , MIMEXML , c . NegotiateFormat ( MIMEXML , MIMEHTML ) )
assert . Equal ( t , MIMEJSON , c . NegotiateFormat ( MIMEJSON ) )
2014-08-11 14:25:52 +04:00
}
2015-07-02 14:27:22 +03:00
func TestContextIsAborted ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-07-02 14:27:22 +03:00
assert . False ( t , c . IsAborted ( ) )
c . Abort ( )
assert . True ( t , c . IsAborted ( ) )
2015-07-02 17:37:35 +03:00
c . Next ( )
2015-07-02 19:45:09 +03:00
assert . True ( t , c . IsAborted ( ) )
2015-07-02 14:27:22 +03:00
2015-07-02 21:24:54 +03:00
c . index ++
2015-07-02 14:27:22 +03:00
assert . True ( t , c . IsAborted ( ) )
}
2020-09-14 05:40:20 +03:00
// TestContextData tests that the response can be written from `bytestring`
2015-04-08 03:58:35 +03:00
// with specified MIME type
func TestContextAbortWithStatus ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-04-08 03:58:35 +03:00
c . index = 4
2018-08-14 04:51:56 +03:00
c . AbortWithStatus ( http . StatusUnauthorized )
2015-04-08 03:58:35 +03:00
2017-11-21 16:18:45 +03:00
assert . Equal ( t , abortIndex , c . index )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusUnauthorized , c . Writer . Status ( ) )
assert . Equal ( t , http . StatusUnauthorized , w . Code )
2015-04-08 03:58:35 +03:00
assert . True ( t , c . IsAborted ( ) )
}
2014-08-11 14:25:52 +04:00
2017-02-14 04:11:01 +03:00
type testJSONAbortMsg struct {
Foo string ` json:"foo" `
Bar string ` json:"bar" `
}
func TestContextAbortWithStatusJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . index = 4
in := new ( testJSONAbortMsg )
in . Bar = "barValue"
in . Foo = "fooValue"
2018-08-14 04:51:56 +03:00
c . AbortWithStatusJSON ( http . StatusUnsupportedMediaType , in )
2017-02-14 04:11:01 +03:00
2017-11-21 16:18:45 +03:00
assert . Equal ( t , abortIndex , c . index )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusUnsupportedMediaType , c . Writer . Status ( ) )
assert . Equal ( t , http . StatusUnsupportedMediaType , w . Code )
2017-02-14 04:11:01 +03:00
assert . True ( t , c . IsAborted ( ) )
contentType := w . Header ( ) . Get ( "Content-Type" )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "application/json; charset=utf-8" , contentType )
2017-02-14 04:11:01 +03:00
buf := new ( bytes . Buffer )
2019-01-18 04:32:53 +03:00
_ , err := buf . ReadFrom ( w . Body )
assert . NoError ( t , err )
2017-02-14 04:11:01 +03:00
jsonStringBody := buf . String ( )
2021-08-19 10:46:31 +03:00
assert . Equal ( t , "{\"foo\":\"fooValue\",\"bar\":\"barValue\"}" , jsonStringBody )
2017-02-14 04:11:01 +03:00
}
2015-04-08 03:58:35 +03:00
func TestContextError ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-22 17:39:15 +03:00
assert . Empty ( t , c . Errors )
2015-04-09 13:15:02 +03:00
2019-02-28 17:43:27 +03:00
firstErr := errors . New ( "first error" )
2022-08-15 16:38:20 +03:00
c . Error ( firstErr ) //nolint: errcheck
2015-04-08 03:58:35 +03:00
assert . Len ( t , c . Errors , 1 )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "Error #01: first error\n" , c . Errors . String ( ) )
2014-08-11 14:25:52 +04:00
2019-02-28 17:43:27 +03:00
secondErr := errors . New ( "second error" )
2022-08-15 16:38:20 +03:00
c . Error ( & Error { //nolint: errcheck
2019-02-28 17:43:27 +03:00
Err : secondErr ,
2015-05-22 17:39:15 +03:00
Meta : "some data 2" ,
Type : ErrorTypePublic ,
} )
2015-04-08 03:58:35 +03:00
assert . Len ( t , c . Errors , 2 )
2014-08-11 14:25:52 +04:00
2019-02-28 17:43:27 +03:00
assert . Equal ( t , firstErr , c . Errors [ 0 ] . Err )
2015-05-22 17:39:15 +03:00
assert . Nil ( t , c . Errors [ 0 ] . Meta )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , ErrorTypePrivate , c . Errors [ 0 ] . Type )
2014-08-11 14:25:52 +04:00
2019-02-28 17:43:27 +03:00
assert . Equal ( t , secondErr , c . Errors [ 1 ] . Err )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "some data 2" , c . Errors [ 1 ] . Meta )
assert . Equal ( t , ErrorTypePublic , c . Errors [ 1 ] . Type )
2015-05-22 17:39:15 +03:00
assert . Equal ( t , c . Errors . Last ( ) , c . Errors [ 1 ] )
2017-05-09 03:04:22 +03:00
defer func ( ) {
if recover ( ) == nil {
t . Error ( "didn't panic" )
}
} ( )
2022-08-15 16:38:20 +03:00
c . Error ( nil ) //nolint: errcheck
2015-04-08 03:58:35 +03:00
}
2014-08-11 14:25:52 +04:00
2015-04-08 03:58:35 +03:00
func TestContextTypedError ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2022-08-15 16:38:20 +03:00
c . Error ( errors . New ( "externo 0" ) ) . SetType ( ErrorTypePublic ) //nolint: errcheck
c . Error ( errors . New ( "interno 0" ) ) . SetType ( ErrorTypePrivate ) //nolint: errcheck
2015-05-22 04:25:21 +03:00
for _ , err := range c . Errors . ByType ( ErrorTypePublic ) {
2017-11-21 16:18:45 +03:00
assert . Equal ( t , ErrorTypePublic , err . Type )
2014-08-11 14:25:52 +04:00
}
2015-05-22 04:25:21 +03:00
for _ , err := range c . Errors . ByType ( ErrorTypePrivate ) {
2017-11-21 16:18:45 +03:00
assert . Equal ( t , ErrorTypePrivate , err . Type )
2014-08-11 14:25:52 +04:00
}
2017-11-21 16:18:45 +03:00
assert . Equal ( t , [ ] string { "externo 0" , "interno 0" } , c . Errors . Errors ( ) )
2014-08-11 14:25:52 +04:00
}
2015-05-22 17:39:15 +03:00
func TestContextAbortWithError ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2022-08-15 16:38:20 +03:00
c . AbortWithError ( http . StatusUnauthorized , errors . New ( "bad input" ) ) . SetMeta ( "some input" ) //nolint: errcheck
2014-08-11 14:25:52 +04:00
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusUnauthorized , w . Code )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , abortIndex , c . index )
2015-04-08 03:58:35 +03:00
assert . True ( t , c . IsAborted ( ) )
}
2014-08-11 14:25:52 +04:00
2015-04-08 03:58:35 +03:00
func TestContextClientIP ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-19 03:29:32 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
2021-05-25 08:47:35 +03:00
c . engine . trustedCIDRs , _ = c . engine . prepareTrustedCIDRs ( )
2021-04-06 06:37:25 +03:00
resetContextForClientIPTests ( c )
2014-08-11 14:25:52 +04:00
2022-10-08 09:21:43 +03:00
// unix address
addr := & net . UnixAddr { Net : "unix" , Name : "@" }
c . Request = c . Request . WithContext ( context . WithValue ( c . Request . Context ( ) , http . LocalAddrContextKey , addr ) )
c . Request . RemoteAddr = addr . String ( )
assert . Equal ( t , "20.20.20.20" , c . ClientIP ( ) )
// reset
c . Request = c . Request . WithContext ( context . Background ( ) )
resetContextForClientIPTests ( c )
2021-04-06 06:37:25 +03:00
// Legacy tests (validating that the defaults don't break the
// (insecure!) old behaviour)
2017-01-03 18:42:21 +03:00
assert . Equal ( t , "20.20.20.20" , c . ClientIP ( ) )
2015-05-24 16:35:08 +03:00
2017-01-03 18:42:21 +03:00
c . Request . Header . Del ( "X-Forwarded-For" )
assert . Equal ( t , "10.10.10.10" , c . ClientIP ( ) )
2015-05-24 16:35:08 +03:00
2015-06-04 14:15:22 +03:00
c . Request . Header . Set ( "X-Forwarded-For" , "30.30.30.30 " )
2017-01-03 18:42:21 +03:00
assert . Equal ( t , "30.30.30.30" , c . ClientIP ( ) )
2015-05-24 16:35:08 +03:00
2015-04-08 03:58:35 +03:00
c . Request . Header . Del ( "X-Forwarded-For" )
2017-01-03 18:42:21 +03:00
c . Request . Header . Del ( "X-Real-IP" )
2021-06-24 03:58:10 +03:00
c . engine . TrustedPlatform = PlatformGoogleAppEngine
2017-01-03 18:42:21 +03:00
assert . Equal ( t , "50.50.50.50" , c . ClientIP ( ) )
2016-12-05 13:21:59 +03:00
c . Request . Header . Del ( "X-Appengine-Remote-Addr" )
2017-01-03 18:42:21 +03:00
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
2016-12-05 13:21:59 +03:00
// no port
c . Request . RemoteAddr = "50.50.50.50"
2017-11-21 16:18:45 +03:00
assert . Empty ( t , c . ClientIP ( ) )
2021-04-06 06:37:25 +03:00
// Tests exercising the TrustedProxies functionality
resetContextForClientIPTests ( c )
2021-12-03 09:49:16 +03:00
// IPv6 support
c . Request . RemoteAddr = "[::1]:12345"
assert . Equal ( t , "20.20.20.20" , c . ClientIP ( ) )
resetContextForClientIPTests ( c )
2021-04-06 06:37:25 +03:00
// No trusted proxies
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { } )
2021-04-06 06:37:25 +03:00
c . engine . RemoteIPHeaders = [ ] string { "X-Forwarded-For" }
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
2021-10-06 04:37:25 +03:00
// Disabled TrustedProxies feature
_ = c . engine . SetTrustedProxies ( nil )
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
2021-04-06 06:37:25 +03:00
// Last proxy is trusted, but the RemoteAddr is not
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "30.30.30.30" } )
2021-04-06 06:37:25 +03:00
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
// Only trust RemoteAddr
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "40.40.40.40" } )
2021-10-09 03:38:51 +03:00
assert . Equal ( t , "30.30.30.30" , c . ClientIP ( ) )
2021-04-06 06:37:25 +03:00
// All steps are trusted
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "40.40.40.40" , "30.30.30.30" , "20.20.20.20" } )
2021-04-06 06:37:25 +03:00
assert . Equal ( t , "20.20.20.20" , c . ClientIP ( ) )
// Use CIDR
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "40.40.25.25/16" , "30.30.30.30" } )
2021-04-06 06:37:25 +03:00
assert . Equal ( t , "20.20.20.20" , c . ClientIP ( ) )
// Use hostname that resolves to all the proxies
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "foo" } )
2021-04-06 06:37:25 +03:00
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
// Use hostname that returns an error
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "bar" } )
2021-04-06 06:37:25 +03:00
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
// X-Forwarded-For has a non-IP element
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "40.40.40.40" } )
2021-04-06 06:37:25 +03:00
c . Request . Header . Set ( "X-Forwarded-For" , " blah " )
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
// Result from LookupHost has non-IP element. This should never
// happen, but we should test it to make sure we handle it
// gracefully.
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "baz" } )
2021-04-06 06:37:25 +03:00
c . Request . Header . Set ( "X-Forwarded-For" , " 30.30.30.30 " )
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
2021-05-25 08:47:35 +03:00
_ = c . engine . SetTrustedProxies ( [ ] string { "40.40.40.40" } )
2021-04-06 06:37:25 +03:00
c . Request . Header . Del ( "X-Forwarded-For" )
c . engine . RemoteIPHeaders = [ ] string { "X-Forwarded-For" , "X-Real-IP" }
assert . Equal ( t , "10.10.10.10" , c . ClientIP ( ) )
c . engine . RemoteIPHeaders = [ ] string { }
2021-06-24 03:58:10 +03:00
c . engine . TrustedPlatform = PlatformGoogleAppEngine
assert . Equal ( t , "50.50.50.50" , c . ClientIP ( ) )
2021-10-24 03:34:03 +03:00
// Use custom TrustedPlatform header
c . engine . TrustedPlatform = "X-CDN-IP"
c . Request . Header . Set ( "X-CDN-IP" , "80.80.80.80" )
assert . Equal ( t , "80.80.80.80" , c . ClientIP ( ) )
// wrong header
c . engine . TrustedPlatform = "X-Wrong-Header"
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
c . Request . Header . Del ( "X-CDN-IP" )
// TrustedPlatform is empty
2021-06-24 03:58:10 +03:00
c . engine . TrustedPlatform = ""
2021-10-24 03:34:03 +03:00
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
// Test the legacy flag
2021-04-06 06:37:25 +03:00
c . engine . AppEngine = true
assert . Equal ( t , "50.50.50.50" , c . ClientIP ( ) )
2021-06-24 03:58:10 +03:00
c . engine . AppEngine = false
c . engine . TrustedPlatform = PlatformGoogleAppEngine
2021-04-06 06:37:25 +03:00
c . Request . Header . Del ( "X-Appengine-Remote-Addr" )
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
2021-06-24 03:58:10 +03:00
c . engine . TrustedPlatform = PlatformCloudflare
2021-05-28 05:03:59 +03:00
assert . Equal ( t , "60.60.60.60" , c . ClientIP ( ) )
c . Request . Header . Del ( "CF-Connecting-IP" )
assert . Equal ( t , "40.40.40.40" , c . ClientIP ( ) )
2021-06-24 03:58:10 +03:00
c . engine . TrustedPlatform = ""
2021-04-06 06:37:25 +03:00
// no port
c . Request . RemoteAddr = "50.50.50.50"
assert . Empty ( t , c . ClientIP ( ) )
}
func resetContextForClientIPTests ( c * Context ) {
c . Request . Header . Set ( "X-Real-IP" , " 10.10.10.10 " )
c . Request . Header . Set ( "X-Forwarded-For" , " 20.20.20.20, 30.30.30.30" )
c . Request . Header . Set ( "X-Appengine-Remote-Addr" , "50.50.50.50" )
2021-05-28 05:03:59 +03:00
c . Request . Header . Set ( "CF-Connecting-IP" , "60.60.60.60" )
2021-04-06 06:37:25 +03:00
c . Request . RemoteAddr = " 40.40.40.40:42123 "
2021-06-24 03:58:10 +03:00
c . engine . TrustedPlatform = ""
2021-12-03 09:49:16 +03:00
c . engine . trustedCIDRs = defaultTrustedCIDRs
2021-04-06 06:37:25 +03:00
c . engine . AppEngine = false
2015-02-10 02:13:05 +03:00
}
2015-04-08 03:58:35 +03:00
func TestContextContentType ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-19 03:29:32 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
2015-04-08 03:58:35 +03:00
c . Request . Header . Set ( "Content-Type" , "application/json; charset=utf-8" )
2015-02-10 02:13:05 +03:00
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "application/json" , c . ContentType ( ) )
2015-04-08 03:58:35 +03:00
}
2015-02-10 02:13:05 +03:00
2015-05-26 18:22:39 +03:00
func TestContextAutoBindJSON ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-19 03:29:32 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "{\"foo\":\"bar\", \"bar\":\"foo\"}" ) )
2015-04-08 03:58:35 +03:00
c . Request . Header . Add ( "Content-Type" , MIMEJSON )
2015-05-26 18:22:39 +03:00
2015-04-08 03:58:35 +03:00
var obj struct {
Foo string ` json:"foo" `
Bar string ` json:"bar" `
}
2015-05-22 04:25:21 +03:00
assert . NoError ( t , c . Bind ( & obj ) )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
2015-05-26 18:22:39 +03:00
assert . Empty ( t , c . Errors )
2015-04-08 03:58:35 +03:00
}
2015-02-10 02:13:05 +03:00
2015-05-26 18:22:39 +03:00
func TestContextBindWithJSON ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-05-26 18:22:39 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "{\"foo\":\"bar\", \"bar\":\"foo\"}" ) )
c . Request . Header . Add ( "Content-Type" , MIMEXML ) // set fake content-type
2015-05-26 15:21:35 +03:00
var obj struct {
2015-05-26 18:22:39 +03:00
Foo string ` json:"foo" `
Bar string ` json:"bar" `
2015-05-26 15:21:35 +03:00
}
2015-05-26 18:22:39 +03:00
assert . NoError ( t , c . BindJSON ( & obj ) )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
assert . Equal ( t , 0 , w . Body . Len ( ) )
2015-05-26 15:21:35 +03:00
}
2021-08-19 10:46:31 +03:00
2018-08-17 04:12:15 +03:00
func TestContextBindWithXML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( ` < ? xml version = "1.0" encoding = "UTF-8" ? >
< root >
< foo > FOO < / foo >
< bar > BAR < / bar >
< / root > ` ) )
c . Request . Header . Add ( "Content-Type" , MIMEXML ) // set fake content-type
var obj struct {
Foo string ` xml:"foo" `
Bar string ` xml:"bar" `
}
assert . NoError ( t , c . BindXML ( & obj ) )
assert . Equal ( t , "FOO" , obj . Foo )
assert . Equal ( t , "BAR" , obj . Bar )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2015-05-26 15:21:35 +03:00
2019-06-27 07:47:45 +03:00
func TestContextBindHeader ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
c . Request . Header . Add ( "rate" , "8000" )
c . Request . Header . Add ( "domain" , "music" )
c . Request . Header . Add ( "limit" , "1000" )
var testHeader struct {
Rate int ` header:"Rate" `
Domain string ` header:"Domain" `
Limit int ` header:"limit" `
}
assert . NoError ( t , c . BindHeader ( & testHeader ) )
assert . Equal ( t , 8000 , testHeader . Rate )
assert . Equal ( t , "music" , testHeader . Domain )
assert . Equal ( t , 1000 , testHeader . Limit )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2017-07-19 10:50:05 +03:00
func TestContextBindWithQuery ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/?foo=bar&bar=foo" , bytes . NewBufferString ( "foo=unused" ) )
var obj struct {
Foo string ` form:"foo" `
Bar string ` form:"bar" `
}
assert . NoError ( t , c . BindQuery ( & obj ) )
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2018-11-06 04:49:45 +03:00
func TestContextBindWithYAML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "foo: bar\nbar: foo" ) )
c . Request . Header . Add ( "Content-Type" , MIMEXML ) // set fake content-type
var obj struct {
Foo string ` yaml:"foo" `
Bar string ` yaml:"bar" `
}
assert . NoError ( t , c . BindYAML ( & obj ) )
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2022-07-01 12:38:32 +03:00
func TestContextBindWithTOML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "foo = 'bar'\nbar = 'foo'" ) )
c . Request . Header . Add ( "Content-Type" , MIMEXML ) // set fake content-type
var obj struct {
Foo string ` toml:"foo" `
Bar string ` toml:"bar" `
}
assert . NoError ( t , c . BindTOML ( & obj ) )
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2015-04-08 03:58:35 +03:00
func TestContextBadAutoBind ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2015-04-08 03:58:35 +03:00
c . Request , _ = http . NewRequest ( "POST" , "http://example.com" , bytes . NewBufferString ( "\"foo\":\"bar\", \"bar\":\"foo\"}" ) )
c . Request . Header . Add ( "Content-Type" , MIMEJSON )
var obj struct {
Foo string ` json:"foo" `
Bar string ` json:"bar" `
2015-02-10 02:13:05 +03:00
}
2015-04-08 03:58:35 +03:00
assert . False ( t , c . IsAborted ( ) )
2015-05-22 04:25:21 +03:00
assert . Error ( t , c . Bind ( & obj ) )
2015-04-08 03:58:35 +03:00
c . Writer . WriteHeaderNow ( )
2015-02-10 02:13:05 +03:00
2015-04-08 03:58:35 +03:00
assert . Empty ( t , obj . Bar )
assert . Empty ( t , obj . Foo )
2018-08-14 04:51:56 +03:00
assert . Equal ( t , http . StatusBadRequest , w . Code )
2015-04-08 03:58:35 +03:00
assert . True ( t , c . IsAborted ( ) )
2014-08-11 14:25:52 +04:00
}
2014-12-21 15:42:48 +03:00
2017-10-23 12:14:09 +03:00
func TestContextAutoShouldBindJSON ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "{\"foo\":\"bar\", \"bar\":\"foo\"}" ) )
c . Request . Header . Add ( "Content-Type" , MIMEJSON )
var obj struct {
Foo string ` json:"foo" `
Bar string ` json:"bar" `
}
assert . NoError ( t , c . ShouldBind ( & obj ) )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
2017-10-23 12:14:09 +03:00
assert . Empty ( t , c . Errors )
}
func TestContextShouldBindWithJSON ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "{\"foo\":\"bar\", \"bar\":\"foo\"}" ) )
c . Request . Header . Add ( "Content-Type" , MIMEXML ) // set fake content-type
var obj struct {
Foo string ` json:"foo" `
Bar string ` json:"bar" `
}
assert . NoError ( t , c . ShouldBindJSON ( & obj ) )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
assert . Equal ( t , 0 , w . Body . Len ( ) )
2017-10-23 12:14:09 +03:00
}
2018-08-17 04:12:15 +03:00
func TestContextShouldBindWithXML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( ` < ? xml version = "1.0" encoding = "UTF-8" ? >
< root >
< foo > FOO < / foo >
2018-12-29 06:46:26 +03:00
< bar > BAR < / bar >
2018-08-17 04:12:15 +03:00
< / root > ` ) )
c . Request . Header . Add ( "Content-Type" , MIMEXML ) // set fake content-type
var obj struct {
Foo string ` xml:"foo" `
Bar string ` xml:"bar" `
}
assert . NoError ( t , c . ShouldBindXML ( & obj ) )
assert . Equal ( t , "FOO" , obj . Foo )
assert . Equal ( t , "BAR" , obj . Bar )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2019-06-27 07:47:45 +03:00
func TestContextShouldBindHeader ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
c . Request . Header . Add ( "rate" , "8000" )
c . Request . Header . Add ( "domain" , "music" )
c . Request . Header . Add ( "limit" , "1000" )
var testHeader struct {
Rate int ` header:"Rate" `
Domain string ` header:"Domain" `
Limit int ` header:"limit" `
}
assert . NoError ( t , c . ShouldBindHeader ( & testHeader ) )
assert . Equal ( t , 8000 , testHeader . Rate )
assert . Equal ( t , "music" , testHeader . Domain )
assert . Equal ( t , 1000 , testHeader . Limit )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2017-10-23 12:14:09 +03:00
func TestContextShouldBindWithQuery ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
2018-12-29 06:46:26 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/?foo=bar&bar=foo&Foo=bar1&Bar=foo1" , bytes . NewBufferString ( "foo=unused" ) )
2017-10-23 12:14:09 +03:00
var obj struct {
2018-12-29 06:46:26 +03:00
Foo string ` form:"foo" `
Bar string ` form:"bar" `
Foo1 string ` form:"Foo" `
Bar1 string ` form:"Bar" `
2017-10-23 12:14:09 +03:00
}
assert . NoError ( t , c . ShouldBindQuery ( & obj ) )
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
2018-12-29 06:46:26 +03:00
assert . Equal ( t , "foo1" , obj . Bar1 )
assert . Equal ( t , "bar1" , obj . Foo1 )
2017-10-23 12:14:09 +03:00
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2018-11-06 04:49:45 +03:00
func TestContextShouldBindWithYAML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "foo: bar\nbar: foo" ) )
c . Request . Header . Add ( "Content-Type" , MIMEXML ) // set fake content-type
var obj struct {
Foo string ` yaml:"foo" `
Bar string ` yaml:"bar" `
}
assert . NoError ( t , c . ShouldBindYAML ( & obj ) )
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2022-05-28 03:34:43 +03:00
func TestContextShouldBindWithTOML ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "foo='bar'\nbar= 'foo'" ) )
c . Request . Header . Add ( "Content-Type" , MIMETOML ) // set fake content-type
var obj struct {
Foo string ` toml:"foo" `
Bar string ` toml:"bar" `
}
assert . NoError ( t , c . ShouldBindTOML ( & obj ) )
assert . Equal ( t , "foo" , obj . Bar )
assert . Equal ( t , "bar" , obj . Foo )
assert . Equal ( t , 0 , w . Body . Len ( ) )
}
2017-10-23 12:14:09 +03:00
func TestContextBadAutoShouldBind ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest ( "POST" , "http://example.com" , bytes . NewBufferString ( "\"foo\":\"bar\", \"bar\":\"foo\"}" ) )
c . Request . Header . Add ( "Content-Type" , MIMEJSON )
var obj struct {
Foo string ` json:"foo" `
Bar string ` json:"bar" `
}
assert . False ( t , c . IsAborted ( ) )
assert . Error ( t , c . ShouldBind ( & obj ) )
assert . Empty ( t , obj . Bar )
assert . Empty ( t , obj . Foo )
assert . False ( t , c . IsAborted ( ) )
}
2018-05-11 05:33:33 +03:00
func TestContextShouldBindBodyWith ( t * testing . T ) {
type typeA struct {
Foo string ` json:"foo" xml:"foo" binding:"required" `
}
type typeB struct {
Bar string ` json:"bar" xml:"bar" binding:"required" `
}
for _ , tt := range [ ] struct {
name string
bindingA , bindingB binding . BindingBody
bodyA , bodyB string
} {
{
name : "JSON & JSON" ,
bindingA : binding . JSON ,
bindingB : binding . JSON ,
bodyA : ` { "foo":"FOO"} ` ,
bodyB : ` { "bar":"BAR"} ` ,
} ,
{
name : "JSON & XML" ,
bindingA : binding . JSON ,
bindingB : binding . XML ,
bodyA : ` { "foo":"FOO"} ` ,
bodyB : ` < ? xml version = "1.0" encoding = "UTF-8" ? >
< root >
< bar > BAR < / bar >
< / root > ` ,
} ,
{
name : "XML & XML" ,
bindingA : binding . XML ,
bindingB : binding . XML ,
bodyA : ` < ? xml version = "1.0" encoding = "UTF-8" ? >
< root >
< foo > FOO < / foo >
< / root > ` ,
bodyB : ` < ? xml version = "1.0" encoding = "UTF-8" ? >
< root >
< bar > BAR < / bar >
< / root > ` ,
} ,
} {
t . Logf ( "testing: %s" , tt . name )
// bodyA to typeA and typeB
{
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest (
"POST" , "http://example.com" , bytes . NewBufferString ( tt . bodyA ) ,
)
// When it binds to typeA and typeB, it finds the body is
// not typeB but typeA.
objA := typeA { }
assert . NoError ( t , c . ShouldBindBodyWith ( & objA , tt . bindingA ) )
assert . Equal ( t , typeA { "FOO" } , objA )
objB := typeB { }
assert . Error ( t , c . ShouldBindBodyWith ( & objB , tt . bindingB ) )
assert . NotEqual ( t , typeB { "BAR" } , objB )
}
// bodyB to typeA and typeB
{
// When it binds to typeA and typeB, it finds the body is
// not typeA but typeB.
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
c . Request , _ = http . NewRequest (
"POST" , "http://example.com" , bytes . NewBufferString ( tt . bodyB ) ,
)
objA := typeA { }
assert . Error ( t , c . ShouldBindBodyWith ( & objA , tt . bindingA ) )
assert . NotEqual ( t , typeA { "FOO" } , objA )
objB := typeB { }
assert . NoError ( t , c . ShouldBindBodyWith ( & objB , tt . bindingB ) )
assert . Equal ( t , typeB { "BAR" } , objB )
}
}
}
2015-05-19 03:29:32 +03:00
func TestContextGolangContext ( t * testing . T ) {
2016-09-21 05:16:51 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
2015-05-19 03:29:32 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , bytes . NewBufferString ( "{\"foo\":\"bar\", \"bar\":\"foo\"}" ) )
assert . NoError ( t , c . Err ( ) )
assert . Nil ( t , c . Done ( ) )
ti , ok := c . Deadline ( )
assert . Equal ( t , ti , time . Time { } )
assert . False ( t , ok )
assert . Equal ( t , c . Value ( 0 ) , c . Request )
2022-04-23 13:02:54 +03:00
assert . Equal ( t , c . Value ( ContextKey ) , c )
2015-05-19 03:29:32 +03:00
assert . Nil ( t , c . Value ( "foo" ) )
c . Set ( "foo" , "bar" )
2017-11-21 16:18:45 +03:00
assert . Equal ( t , "bar" , c . Value ( "foo" ) )
2015-05-19 03:29:32 +03:00
assert . Nil ( t , c . Value ( 1 ) )
}
2017-01-02 11:05:30 +03:00
func TestWebsocketsRequired ( t * testing . T ) {
// Example request from spec: https://tools.ietf.org/html/rfc6455#section-1.2
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "GET" , "/chat" , nil )
c . Request . Header . Set ( "Host" , "server.example.com" )
c . Request . Header . Set ( "Upgrade" , "websocket" )
c . Request . Header . Set ( "Connection" , "Upgrade" )
c . Request . Header . Set ( "Sec-WebSocket-Key" , "dGhlIHNhbXBsZSBub25jZQ==" )
c . Request . Header . Set ( "Origin" , "http://example.com" )
c . Request . Header . Set ( "Sec-WebSocket-Protocol" , "chat, superchat" )
c . Request . Header . Set ( "Sec-WebSocket-Version" , "13" )
assert . True ( t , c . IsWebsocket ( ) )
// Normal request, no websocket required.
c , _ = CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "GET" , "/chat" , nil )
c . Request . Header . Set ( "Host" , "server.example.com" )
assert . False ( t , c . IsWebsocket ( ) )
}
2017-03-24 15:43:23 +03:00
func TestGetRequestHeaderValue ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "GET" , "/chat" , nil )
c . Request . Header . Set ( "Gin-Version" , "1.0.0" )
assert . Equal ( t , "1.0.0" , c . GetHeader ( "Gin-Version" ) )
2017-11-21 16:18:45 +03:00
assert . Empty ( t , c . GetHeader ( "Connection" ) )
2017-03-24 15:43:23 +03:00
}
2017-03-31 03:45:56 +03:00
func TestContextGetRawData ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
body := bytes . NewBufferString ( "Fetch binary post data" )
c . Request , _ = http . NewRequest ( "POST" , "/" , body )
c . Request . Header . Add ( "Content-Type" , MIMEPOSTForm )
data , err := c . GetRawData ( )
assert . Nil ( t , err )
assert . Equal ( t , "Fetch binary post data" , string ( data ) )
}
2018-05-12 06:00:42 +03:00
func TestContextRenderDataFromReader ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
body := "#!PNG some raw data"
reader := strings . NewReader ( body )
contentLength := int64 ( len ( body ) )
contentType := "image/png"
extraHeaders := map [ string ] string { "Content-Disposition" : ` attachment; filename="gopher.png" ` }
c . DataFromReader ( http . StatusOK , contentLength , contentType , reader , extraHeaders )
assert . Equal ( t , http . StatusOK , w . Code )
assert . Equal ( t , body , w . Body . String ( ) )
2018-10-12 02:31:31 +03:00
assert . Equal ( t , contentType , w . Header ( ) . Get ( "Content-Type" ) )
assert . Equal ( t , fmt . Sprintf ( "%d" , contentLength ) , w . Header ( ) . Get ( "Content-Length" ) )
assert . Equal ( t , extraHeaders [ "Content-Disposition" ] , w . Header ( ) . Get ( "Content-Disposition" ) )
2018-05-12 06:00:42 +03:00
}
2018-08-07 01:44:32 +03:00
2019-11-25 05:45:53 +03:00
func TestContextRenderDataFromReaderNoHeaders ( t * testing . T ) {
w := httptest . NewRecorder ( )
c , _ := CreateTestContext ( w )
body := "#!PNG some raw data"
reader := strings . NewReader ( body )
contentLength := int64 ( len ( body ) )
contentType := "image/png"
c . DataFromReader ( http . StatusOK , contentLength , contentType , reader , nil )
assert . Equal ( t , http . StatusOK , w . Code )
assert . Equal ( t , body , w . Body . String ( ) )
assert . Equal ( t , contentType , w . Header ( ) . Get ( "Content-Type" ) )
assert . Equal ( t , fmt . Sprintf ( "%d" , contentLength ) , w . Header ( ) . Get ( "Content-Length" ) )
}
2018-08-12 05:12:33 +03:00
type TestResponseRecorder struct {
* httptest . ResponseRecorder
closeChannel chan bool
}
func ( r * TestResponseRecorder ) CloseNotify ( ) <- chan bool {
return r . closeChannel
}
func ( r * TestResponseRecorder ) closeClient ( ) {
r . closeChannel <- true
}
func CreateTestResponseRecorder ( ) * TestResponseRecorder {
return & TestResponseRecorder {
httptest . NewRecorder ( ) ,
make ( chan bool , 1 ) ,
}
}
2018-08-07 01:44:32 +03:00
func TestContextStream ( t * testing . T ) {
w := CreateTestResponseRecorder ( )
c , _ := CreateTestContext ( w )
stopStream := true
c . Stream ( func ( w io . Writer ) bool {
defer func ( ) {
stopStream = false
} ( )
2019-01-18 04:32:53 +03:00
_ , err := w . Write ( [ ] byte ( "test" ) )
assert . NoError ( t , err )
2018-08-07 01:44:32 +03:00
return stopStream
} )
assert . Equal ( t , "testtest" , w . Body . String ( ) )
}
func TestContextStreamWithClientGone ( t * testing . T ) {
w := CreateTestResponseRecorder ( )
c , _ := CreateTestContext ( w )
c . Stream ( func ( writer io . Writer ) bool {
defer func ( ) {
w . closeClient ( )
} ( )
2019-01-18 04:32:53 +03:00
_ , err := writer . Write ( [ ] byte ( "test" ) )
assert . NoError ( t , err )
2018-08-07 01:44:32 +03:00
return true
} )
assert . Equal ( t , "test" , w . Body . String ( ) )
}
2019-01-18 04:57:06 +03:00
func TestContextResetInHandler ( t * testing . T ) {
w := CreateTestResponseRecorder ( )
c , _ := CreateTestContext ( w )
c . handlers = [ ] HandlerFunc {
func ( c * Context ) { c . reset ( ) } ,
}
assert . NotPanics ( t , func ( ) {
c . Next ( )
} )
}
2019-05-27 09:04:30 +03:00
func TestRaceParamsContextCopy ( t * testing . T ) {
DefaultWriter = os . Stdout
router := Default ( )
nameGroup := router . Group ( "/:name" )
var wg sync . WaitGroup
wg . Add ( 2 )
{
nameGroup . GET ( "/api" , func ( c * Context ) {
go func ( c * Context , param string ) {
defer wg . Done ( )
// First assert must be executed after the second request
time . Sleep ( 50 * time . Millisecond )
assert . Equal ( t , c . Param ( "name" ) , param )
} ( c . Copy ( ) , c . Param ( "name" ) )
} )
}
2022-01-02 14:07:44 +03:00
PerformRequest ( router , "GET" , "/name1/api" )
PerformRequest ( router , "GET" , "/name2/api" )
2019-05-27 09:04:30 +03:00
wg . Wait ( )
}
2020-03-27 05:57:36 +03:00
func TestContextWithKeysMutex ( t * testing . T ) {
c := & Context { }
c . Set ( "foo" , "bar" )
value , err := c . Get ( "foo" )
assert . Equal ( t , "bar" , value )
assert . True ( t , err )
value , err = c . Get ( "foo2" )
assert . Nil ( t , value )
assert . False ( t , err )
}
2021-04-06 06:37:25 +03:00
func TestRemoteIPFail ( t * testing . T ) {
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
c . Request . RemoteAddr = "[:::]:80"
2021-12-03 09:49:16 +03:00
ip := net . ParseIP ( c . RemoteIP ( ) )
trust := c . engine . isTrustedProxy ( ip )
2021-04-06 06:37:25 +03:00
assert . Nil ( t , ip )
assert . False ( t , trust )
}
2021-06-24 11:33:14 +03:00
2021-07-31 19:46:53 +03:00
func TestContextWithFallbackDeadlineFromRequestContext ( t * testing . T ) {
2022-06-06 13:43:53 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c . engine . ContextWithFallback = true
2021-07-31 19:46:53 +03:00
deadline , ok := c . Deadline ( )
assert . Zero ( t , deadline )
assert . False ( t , ok )
2022-06-06 13:43:53 +03:00
c2 , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c2 . engine . ContextWithFallback = true
2021-07-31 19:46:53 +03:00
c2 . Request , _ = http . NewRequest ( http . MethodGet , "/" , nil )
d := time . Now ( ) . Add ( time . Second )
ctx , cancel := context . WithDeadline ( context . Background ( ) , d )
defer cancel ( )
c2 . Request = c2 . Request . WithContext ( ctx )
deadline , ok = c2 . Deadline ( )
assert . Equal ( t , d , deadline )
assert . True ( t , ok )
}
func TestContextWithFallbackDoneFromRequestContext ( t * testing . T ) {
2022-06-06 13:43:53 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c . engine . ContextWithFallback = true
2021-07-31 19:46:53 +03:00
assert . Nil ( t , c . Done ( ) )
2022-06-06 13:43:53 +03:00
c2 , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c2 . engine . ContextWithFallback = true
2021-07-31 19:46:53 +03:00
c2 . Request , _ = http . NewRequest ( http . MethodGet , "/" , nil )
ctx , cancel := context . WithCancel ( context . Background ( ) )
c2 . Request = c2 . Request . WithContext ( ctx )
cancel ( )
assert . NotNil ( t , <- c2 . Done ( ) )
}
func TestContextWithFallbackErrFromRequestContext ( t * testing . T ) {
2022-06-06 13:43:53 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c . engine . ContextWithFallback = true
2021-07-31 19:46:53 +03:00
assert . Nil ( t , c . Err ( ) )
2022-06-06 13:43:53 +03:00
c2 , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c2 . engine . ContextWithFallback = true
2021-07-31 19:46:53 +03:00
c2 . Request , _ = http . NewRequest ( http . MethodGet , "/" , nil )
ctx , cancel := context . WithCancel ( context . Background ( ) )
c2 . Request = c2 . Request . WithContext ( ctx )
cancel ( )
assert . EqualError ( t , c2 . Err ( ) , context . Canceled . Error ( ) )
}
2021-06-24 11:33:14 +03:00
func TestContextWithFallbackValueFromRequestContext ( t * testing . T ) {
2022-06-06 13:43:53 +03:00
type contextKey string
2021-06-24 11:33:14 +03:00
tests := [ ] struct {
name string
2022-03-21 04:43:17 +03:00
getContextAndKey func ( ) ( * Context , any )
value any
2021-06-24 11:33:14 +03:00
} {
{
name : "c with struct context key" ,
2022-03-21 04:43:17 +03:00
getContextAndKey : func ( ) ( * Context , any ) {
2021-06-24 11:33:14 +03:00
var key struct { }
2022-06-06 13:43:53 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c . engine . ContextWithFallback = true
2021-06-24 11:33:14 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
c . Request = c . Request . WithContext ( context . WithValue ( context . TODO ( ) , key , "value" ) )
return c , key
} ,
value : "value" ,
} ,
{
name : "c with string context key" ,
2022-03-21 04:43:17 +03:00
getContextAndKey : func ( ) ( * Context , any ) {
2022-06-06 13:43:53 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c . engine . ContextWithFallback = true
2021-06-24 11:33:14 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
2021-08-19 10:46:31 +03:00
c . Request = c . Request . WithContext ( context . WithValue ( context . TODO ( ) , contextKey ( "key" ) , "value" ) )
return c , contextKey ( "key" )
2021-06-24 11:33:14 +03:00
} ,
value : "value" ,
} ,
{
name : "c with nil http.Request" ,
2022-03-21 04:43:17 +03:00
getContextAndKey : func ( ) ( * Context , any ) {
2022-06-06 13:43:53 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c . engine . ContextWithFallback = true
c . Request = nil
2021-06-24 11:33:14 +03:00
return c , "key"
} ,
value : nil ,
} ,
{
name : "c with nil http.Request.Context()" ,
2022-03-21 04:43:17 +03:00
getContextAndKey : func ( ) ( * Context , any ) {
2022-06-06 13:43:53 +03:00
c , _ := CreateTestContext ( httptest . NewRecorder ( ) )
// enable ContextWithFallback feature flag
c . engine . ContextWithFallback = true
2021-06-24 11:33:14 +03:00
c . Request , _ = http . NewRequest ( "POST" , "/" , nil )
return c , "key"
} ,
value : nil ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
c , key := tt . getContextAndKey ( )
assert . Equal ( t , tt . value , c . Value ( key ) )
} )
}
}
2021-09-07 05:08:45 +03:00
2022-06-06 13:43:53 +03:00
func TestContextCopyShouldNotCancel ( t * testing . T ) {
srv := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , _ * http . Request ) {
w . WriteHeader ( http . StatusOK )
} ) )
defer srv . Close ( )
ensureRequestIsOver := make ( chan struct { } )
wg := & sync . WaitGroup { }
r := New ( )
r . GET ( "/" , func ( ginctx * Context ) {
wg . Add ( 1 )
ginctx = ginctx . Copy ( )
// start async goroutine for calling srv
go func ( ) {
defer wg . Done ( )
<- ensureRequestIsOver // ensure request is done
req , err := http . NewRequestWithContext ( ginctx , http . MethodGet , srv . URL , nil )
must ( err )
res , err := http . DefaultClient . Do ( req )
if err != nil {
t . Error ( fmt . Errorf ( "request error: %w" , err ) )
return
}
if res . StatusCode != http . StatusOK {
t . Error ( fmt . Errorf ( "unexpected status code: %s" , res . Status ) )
}
} ( )
} )
l , err := net . Listen ( "tcp" , ":0" )
must ( err )
go func ( ) {
s := & http . Server {
Handler : r ,
}
must ( s . Serve ( l ) )
} ( )
addr := strings . Split ( l . Addr ( ) . String ( ) , ":" )
res , err := http . Get ( fmt . Sprintf ( "http://127.0.0.1:%s/" , addr [ len ( addr ) - 1 ] ) )
if err != nil {
t . Error ( fmt . Errorf ( "request error: %w" , err ) )
return
}
close ( ensureRequestIsOver )
if res . StatusCode != http . StatusOK {
t . Error ( fmt . Errorf ( "unexpected status code: %s" , res . Status ) )
return
}
wg . Wait ( )
}
2021-09-07 05:08:45 +03:00
func TestContextAddParam ( t * testing . T ) {
c := & Context { }
id := "id"
value := "1"
c . AddParam ( id , value )
v , ok := c . Params . Get ( id )
assert . Equal ( t , ok , true )
assert . Equal ( t , value , v )
}