mirror of
https://github.com/gin-gonic/gin.git
synced 2026-09-05 07:02:15 +08:00
H.MarshalXML returns early when the opening e.EncodeToken(start) call fails, but no test covered that error path. Because xml.Encoder buffers its output, the underlying writer is not called until the buffer flushes. The test writes an 8KB token first to push the encoder into an error state, then calls MarshalXML and asserts the write error is propagated.
196 lines
5.4 KiB
Go
196 lines
5.4 KiB
Go
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
|
// Use of this source code is governed by a MIT style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gin
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/xml"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func init() {
|
|
SetMode(TestMode)
|
|
}
|
|
|
|
func BenchmarkParseAccept(b *testing.B) {
|
|
for b.Loop() {
|
|
parseAccept("text/html , application/xhtml+xml,application/xml;q=0.9, */* ;q=0.8")
|
|
}
|
|
}
|
|
|
|
type testStruct struct {
|
|
T *testing.T
|
|
}
|
|
|
|
func (t *testStruct) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
assert.Equal(t.T, http.MethodPost, req.Method)
|
|
assert.Equal(t.T, "/path", req.URL.Path)
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
fmt.Fprint(w, "hello")
|
|
}
|
|
|
|
func TestWrap(t *testing.T) {
|
|
router := New()
|
|
router.POST("/path", WrapH(&testStruct{t}))
|
|
router.GET("/path2", WrapF(func(w http.ResponseWriter, req *http.Request) {
|
|
assert.Equal(t, http.MethodGet, req.Method)
|
|
assert.Equal(t, "/path2", req.URL.Path)
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
fmt.Fprint(w, "hola!")
|
|
}))
|
|
|
|
w := PerformRequest(router, http.MethodPost, "/path")
|
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
|
assert.Equal(t, "hello", w.Body.String())
|
|
|
|
w = PerformRequest(router, http.MethodGet, "/path2")
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
assert.Equal(t, "hola!", w.Body.String())
|
|
}
|
|
|
|
func TestLastChar(t *testing.T) {
|
|
assert.Equal(t, uint8('a'), lastChar("hola"))
|
|
assert.Equal(t, uint8('s'), lastChar("adios"))
|
|
assert.Panics(t, func() { lastChar("") })
|
|
}
|
|
|
|
func TestParseAccept(t *testing.T) {
|
|
parts := parseAccept("text/html , application/xhtml+xml,application/xml;q=0.9, */* ;q=0.8")
|
|
assert.Len(t, parts, 4)
|
|
assert.Equal(t, "text/html", parts[0])
|
|
assert.Equal(t, "application/xhtml+xml", parts[1])
|
|
assert.Equal(t, "application/xml", parts[2])
|
|
assert.Equal(t, "*/*", parts[3])
|
|
}
|
|
|
|
func TestChooseData(t *testing.T) {
|
|
A := "a"
|
|
B := "b"
|
|
assert.Equal(t, A, chooseData(A, B))
|
|
assert.Equal(t, B, chooseData(nil, B))
|
|
assert.Panics(t, func() { chooseData(nil, nil) })
|
|
}
|
|
|
|
func TestFilterFlags(t *testing.T) {
|
|
result := filterFlags("text/html ")
|
|
assert.Equal(t, "text/html", result)
|
|
|
|
result = filterFlags("text/html;")
|
|
assert.Equal(t, "text/html", result)
|
|
}
|
|
|
|
func TestFunctionName(t *testing.T) {
|
|
assert.Regexp(t, `^(.*/vendor/)?github.com/gin-gonic/gin.somefunction$`, nameOfFunction(somefunction))
|
|
}
|
|
|
|
func somefunction() {
|
|
// this empty function is used by TestFunctionName()
|
|
}
|
|
|
|
func TestJoinPaths(t *testing.T) {
|
|
assert.Empty(t, joinPaths("", ""))
|
|
assert.Equal(t, "/", joinPaths("", "/"))
|
|
assert.Equal(t, "/a", joinPaths("/a", ""))
|
|
assert.Equal(t, "/a/", joinPaths("/a/", ""))
|
|
assert.Equal(t, "/a/", joinPaths("/a/", "/"))
|
|
assert.Equal(t, "/a/", joinPaths("/a", "/"))
|
|
assert.Equal(t, "/a/hola", joinPaths("/a", "/hola"))
|
|
assert.Equal(t, "/a/hola", joinPaths("/a/", "/hola"))
|
|
assert.Equal(t, "/a/hola/", joinPaths("/a/", "/hola/"))
|
|
assert.Equal(t, "/a/hola/", joinPaths("/a/", "/hola//"))
|
|
}
|
|
|
|
type bindTestStruct struct {
|
|
Foo string `form:"foo" binding:"required"`
|
|
Bar int `form:"bar" binding:"min=4"`
|
|
}
|
|
|
|
func TestBindMiddleware(t *testing.T) {
|
|
var value *bindTestStruct
|
|
var called bool
|
|
router := New()
|
|
router.GET("/", Bind(bindTestStruct{}), func(c *Context) {
|
|
called = true
|
|
value = c.MustGet(BindKey).(*bindTestStruct)
|
|
})
|
|
PerformRequest(router, http.MethodGet, "/?foo=hola&bar=10")
|
|
assert.True(t, called)
|
|
assert.Equal(t, "hola", value.Foo)
|
|
assert.Equal(t, 10, value.Bar)
|
|
|
|
called = false
|
|
PerformRequest(router, http.MethodGet, "/?foo=hola&bar=1")
|
|
assert.False(t, called)
|
|
|
|
assert.Panics(t, func() {
|
|
Bind(&bindTestStruct{})
|
|
})
|
|
}
|
|
|
|
func TestMarshalXMLforH(t *testing.T) {
|
|
h := H{
|
|
"": "test",
|
|
}
|
|
var b bytes.Buffer
|
|
enc := xml.NewEncoder(&b)
|
|
var x xml.StartElement
|
|
e := h.MarshalXML(enc, x)
|
|
assert.Error(t, e)
|
|
}
|
|
|
|
func TestMarshalXMLforHSuccess(t *testing.T) {
|
|
h := H{
|
|
"key1": "value1",
|
|
"key2": 123,
|
|
}
|
|
data, err := xml.Marshal(h)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, string(data), "<key1>value1</key1>")
|
|
assert.Contains(t, string(data), "<key2>123</key2>")
|
|
}
|
|
|
|
// errXMLWriter always fails, to exercise encoder write-error paths.
|
|
type errXMLWriter struct{}
|
|
|
|
func (errXMLWriter) Write(_ []byte) (int, error) { return 0, errors.New("write failed") }
|
|
|
|
// TestMarshalXMLEncodeTokenError covers the branch where the opening
|
|
// EncodeToken(start) fails. xml.Encoder buffers its output, so the failing
|
|
// writer is only reached once the buffer overflows; we prime it with a large
|
|
// token first, which puts the encoder into an error state. MarshalXML's very
|
|
// first EncodeToken then returns that cached write error.
|
|
func TestMarshalXMLEncodeTokenError(t *testing.T) {
|
|
enc := xml.NewEncoder(errXMLWriter{})
|
|
|
|
// Overflow the encoder's internal buffer so it flushes to the failing
|
|
// writer and latches the error.
|
|
require.Error(t, enc.EncodeToken(xml.CharData(bytes.Repeat([]byte("a"), 8192))))
|
|
|
|
err := H{"key": "value"}.MarshalXML(enc, xml.StartElement{})
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestIsASCII(t *testing.T) {
|
|
assert.True(t, isASCII("test"))
|
|
assert.False(t, isASCII("🧡💛💚💙💜"))
|
|
}
|
|
|
|
func TestSafeInt8(t *testing.T) {
|
|
assert.Equal(t, int8(100), safeInt8(100))
|
|
assert.Equal(t, int8(math.MaxInt8), safeInt8(int(math.MaxInt8)+123))
|
|
}
|
|
|
|
func TestSafeUint16(t *testing.T) {
|
|
assert.Equal(t, uint16(100), safeUint16(100))
|
|
assert.Equal(t, uint16(math.MaxUint16), safeUint16(int(math.MaxUint16)+123))
|
|
}
|