gin/codec/binding/encoding_test.go

153 lines
3.7 KiB
Go

//go:build gin_bind_encoding
package bindingcodec
import (
"encoding"
"errors"
"reflect"
"testing"
"time"
"github.com/stretchr/testify/require"
)
// mockBindUnmarshaler implements the bindUnmarshaler interface for testing
type mockBindUnmarshaler struct {
receivedParam string
returnError error
}
func (m *mockBindUnmarshaler) UnmarshalParam(param string) error {
m.receivedParam = param
return m.returnError
}
// mockTextUnmarshaler implements encoding.TextUnmarshaler for testing
type mockTextUnmarshaler struct {
receivedText []byte
returnError error
}
func (m *mockTextUnmarshaler) UnmarshalText(text []byte) error {
m.receivedText = text
return m.returnError
}
func TestTrySetByInterface_WithBindUnmarshaler(t *testing.T) {
api := bindingApi{}
mock := &mockBindUnmarshaler{}
value := reflect.ValueOf(mock).Elem()
inputVal := "test-value"
isSet, err := api.TrySetByInterface(inputVal, value)
require.True(t, isSet)
require.NoError(t, err)
require.Equal(t, inputVal, mock.receivedParam)
}
func TestTrySetByInterface_WithBindUnmarshalerError(t *testing.T) {
api := bindingApi{}
expectedErr := errors.New("unmarshal error")
mock := &mockBindUnmarshaler{returnError: expectedErr}
value := reflect.ValueOf(mock).Elem()
inputVal := "test-value"
isSet, err := api.TrySetByInterface(inputVal, value)
require.True(t, isSet)
require.Error(t, err)
}
func TestTrySetByInterface_WithTextUnmarshaler(t *testing.T) {
api := bindingApi{}
mock := &mockTextUnmarshaler{}
value := reflect.ValueOf(mock).Elem()
inputVal := "text-value"
isSet, err := api.TrySetByInterface(inputVal, value)
require.True(t, isSet)
require.NoError(t, err)
require.Equal(t, []byte(inputVal), mock.receivedText)
}
func TestTrySetByInterface_WithTextUnmarshalerError(t *testing.T) {
api := bindingApi{}
expectedErr := errors.New("text unmarshal error")
mock := &mockTextUnmarshaler{returnError: expectedErr}
value := reflect.ValueOf(mock).Elem()
inputVal := "text-value"
isSet, err := api.TrySetByInterface(inputVal, value)
require.True(t, isSet)
require.Error(t, err)
}
func TestTrySetByInterface_WithTimeTime(t *testing.T) {
api := bindingApi{}
now := time.Now()
value := reflect.ValueOf(&now).Elem()
inputVal := "2023-01-01T00:00:00Z"
isSet, err := api.TrySetByInterface(inputVal, value)
require.False(t, isSet)
require.NoError(t, err)
}
// TestTrySetByInterface_WithoutInterface tests behavior with regular types
func TestTrySetByInterface_WithoutInterface(t *testing.T) {
api := bindingApi{}
testCases := []struct {
name string
value any
}{
{"string", "test"},
{"int", 42},
{"bool", true},
{"struct", struct{ Field string }{"value"}},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
ptr := reflect.New(reflect.TypeOf(tc.value))
ptr.Elem().Set(reflect.ValueOf(tc.value))
value := ptr.Elem()
isSet, err := api.TrySetByInterface("input", value)
require.False(t, isSet)
require.NoError(t, err)
})
}
}
// mockBothInterfaces implements both bindUnmarshaler and encoding.TextUnmarshaler
type mockBothInterfaces struct {
bindCalled bool
textCalled bool
}
func (m *mockBothInterfaces) UnmarshalParam(param string) error {
m.bindCalled = true
return nil
}
func (m *mockBothInterfaces) UnmarshalText(text []byte) error {
m.textCalled = true
return nil
}
var _ encoding.TextUnmarshaler = (*mockBothInterfaces)(nil)
func TestTrySetByInterface_PriorityBindUnmarshaler(t *testing.T) {
api := bindingApi{}
mock := &mockBothInterfaces{}
value := reflect.ValueOf(mock).Elem()
inputVal := "test"
isSet, err := api.TrySetByInterface(inputVal, value)
require.True(t, isSet)
require.NoError(t, err)
require.True(t, mock.bindCalled)
require.False(t, mock.textCalled)
}