...

Source file src/github.com/go-openapi/runtime/middleware/string_conversion_test.go

Documentation: github.com/go-openapi/runtime/middleware

     1  // Copyright 2015 go-swagger maintainers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package middleware
    16  
    17  import (
    18  	"errors"
    19  	"reflect"
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/go-openapi/spec"
    25  	"github.com/go-openapi/strfmt"
    26  	"github.com/go-openapi/swag"
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  var evaluatesAsTrue = []string{"true", "1", "yes", "ok", "y", "on", "selected", "checked", "t", "enabled"}
    32  
    33  type unmarshallerSlice []string
    34  
    35  func (u *unmarshallerSlice) UnmarshalText(data []byte) error {
    36  	if len(data) == 0 {
    37  		return errors.New("an error")
    38  	}
    39  	*u = strings.Split(string(data), ",")
    40  	return nil
    41  }
    42  
    43  type SomeOperationParams struct {
    44  	Name        string
    45  	ID          int64
    46  	Confirmed   bool
    47  	Age         int
    48  	Visits      int32
    49  	Count       int16
    50  	Seq         int8
    51  	UID         uint64
    52  	UAge        uint
    53  	UVisits     uint32
    54  	UCount      uint16
    55  	USeq        uint8
    56  	Score       float32
    57  	Rate        float64
    58  	Timestamp   strfmt.DateTime
    59  	Birthdate   strfmt.Date
    60  	LastFailure *strfmt.DateTime
    61  	Unsupported struct{}
    62  	Tags        []string
    63  	Prefs       []int32
    64  	Categories  unmarshallerSlice
    65  }
    66  
    67  func FloatParamTest(t *testing.T, _, pName, _ string, val reflect.Value, defVal, expectedDef interface{}, actual func() interface{}) {
    68  	fld := val.FieldByName(pName)
    69  	binder := &untypedParamBinder{
    70  		parameter: spec.QueryParam(pName).Typed("number", "double").WithDefault(defVal),
    71  		Name:      pName,
    72  	}
    73  
    74  	err := binder.setFieldValue(fld, defVal, "5", true)
    75  	require.NoError(t, err)
    76  	assert.EqualValues(t, 5, actual())
    77  
    78  	err = binder.setFieldValue(fld, defVal, "", true)
    79  	require.NoError(t, err)
    80  	assert.EqualValues(t, expectedDef, actual())
    81  
    82  	err = binder.setFieldValue(fld, defVal, "yada", true)
    83  	require.Error(t, err)
    84  }
    85  
    86  func IntParamTest(t *testing.T, pName string, val reflect.Value, defVal, expectedDef interface{}, actual func() interface{}) {
    87  	fld := val.FieldByName(pName)
    88  
    89  	binder := &untypedParamBinder{
    90  		parameter: spec.QueryParam(pName).Typed("integer", "int64").WithDefault(defVal),
    91  		Name:      pName,
    92  	}
    93  	err := binder.setFieldValue(fld, defVal, "5", true)
    94  	require.NoError(t, err)
    95  	assert.EqualValues(t, 5, actual())
    96  
    97  	err = binder.setFieldValue(fld, defVal, "", true)
    98  	require.NoError(t, err)
    99  	assert.EqualValues(t, expectedDef, actual())
   100  
   101  	err = binder.setFieldValue(fld, defVal, "yada", true)
   102  	require.Error(t, err)
   103  }
   104  
   105  func TestParamBinding(t *testing.T) {
   106  	actual := new(SomeOperationParams)
   107  	val := reflect.ValueOf(actual).Elem()
   108  	pName := "Name"
   109  	fld := val.FieldByName(pName)
   110  
   111  	binder := &untypedParamBinder{
   112  		parameter: spec.QueryParam(pName).Typed(typeString, "").WithDefault("some-name"),
   113  		Name:      pName,
   114  	}
   115  
   116  	err := binder.setFieldValue(fld, "some-name", "the name value", true)
   117  	require.NoError(t, err)
   118  	assert.Equal(t, "the name value", actual.Name)
   119  
   120  	err = binder.setFieldValue(fld, "some-name", "", true)
   121  	require.NoError(t, err)
   122  	assert.Equal(t, "some-name", actual.Name)
   123  
   124  	IntParamTest(t, "ID", val, 1, 1, func() interface{} { return actual.ID })
   125  	IntParamTest(t, "ID", val, nil, 0, func() interface{} { return actual.ID })
   126  	IntParamTest(t, "Age", val, 1, 1, func() interface{} { return actual.Age })
   127  	IntParamTest(t, "Age", val, nil, 0, func() interface{} { return actual.Age })
   128  	IntParamTest(t, "Visits", val, 1, 1, func() interface{} { return actual.Visits })
   129  	IntParamTest(t, "Visits", val, nil, 0, func() interface{} { return actual.Visits })
   130  	IntParamTest(t, "Count", val, 1, 1, func() interface{} { return actual.Count })
   131  	IntParamTest(t, "Count", val, nil, 0, func() interface{} { return actual.Count })
   132  	IntParamTest(t, "Seq", val, 1, 1, func() interface{} { return actual.Seq })
   133  	IntParamTest(t, "Seq", val, nil, 0, func() interface{} { return actual.Seq })
   134  	IntParamTest(t, "UID", val, uint64(1), 1, func() interface{} { return actual.UID })
   135  	IntParamTest(t, "UID", val, uint64(0), 0, func() interface{} { return actual.UID })
   136  	IntParamTest(t, "UAge", val, uint(1), 1, func() interface{} { return actual.UAge })
   137  	IntParamTest(t, "UAge", val, nil, 0, func() interface{} { return actual.UAge })
   138  	IntParamTest(t, "UVisits", val, uint32(1), 1, func() interface{} { return actual.UVisits })
   139  	IntParamTest(t, "UVisits", val, nil, 0, func() interface{} { return actual.UVisits })
   140  	IntParamTest(t, "UCount", val, uint16(1), 1, func() interface{} { return actual.UCount })
   141  	IntParamTest(t, "UCount", val, nil, 0, func() interface{} { return actual.UCount })
   142  	IntParamTest(t, "USeq", val, uint8(1), 1, func() interface{} { return actual.USeq })
   143  	IntParamTest(t, "USeq", val, nil, 0, func() interface{} { return actual.USeq })
   144  
   145  	FloatParamTest(t, "score", "Score", "float", val, 1.0, 1, func() interface{} { return actual.Score })
   146  	FloatParamTest(t, "score", "Score", "float", val, nil, 0, func() interface{} { return actual.Score })
   147  	FloatParamTest(t, "rate", "Rate", "double", val, 1.0, 1, func() interface{} { return actual.Rate })
   148  	FloatParamTest(t, "rate", "Rate", "double", val, nil, 0, func() interface{} { return actual.Rate })
   149  
   150  	pName = "Confirmed"
   151  	confirmedField := val.FieldByName(pName)
   152  	binder = &untypedParamBinder{
   153  		parameter: spec.QueryParam(pName).Typed("boolean", "").WithDefault(true),
   154  		Name:      pName,
   155  	}
   156  
   157  	for _, tv := range evaluatesAsTrue {
   158  		err = binder.setFieldValue(confirmedField, true, tv, true)
   159  		require.NoError(t, err)
   160  		assert.True(t, actual.Confirmed)
   161  	}
   162  
   163  	err = binder.setFieldValue(confirmedField, true, "", true)
   164  	require.NoError(t, err)
   165  	assert.True(t, actual.Confirmed)
   166  
   167  	err = binder.setFieldValue(confirmedField, true, "0", true)
   168  	require.NoError(t, err)
   169  	assert.False(t, actual.Confirmed)
   170  
   171  	pName = "Timestamp"
   172  	timeField := val.FieldByName(pName)
   173  	dt := strfmt.DateTime(time.Date(2014, 3, 19, 2, 9, 0, 0, time.UTC))
   174  	binder = &untypedParamBinder{
   175  		parameter: spec.QueryParam(pName).Typed(typeString, "date-time").WithDefault(dt),
   176  		Name:      pName,
   177  	}
   178  	exp := strfmt.DateTime(time.Date(2014, 5, 14, 2, 9, 0, 0, time.UTC))
   179  
   180  	err = binder.setFieldValue(timeField, dt, exp.String(), true)
   181  	require.NoError(t, err)
   182  	assert.Equal(t, exp, actual.Timestamp)
   183  
   184  	err = binder.setFieldValue(timeField, dt, "", true)
   185  	require.NoError(t, err)
   186  	assert.Equal(t, dt, actual.Timestamp)
   187  
   188  	err = binder.setFieldValue(timeField, dt, "yada", true)
   189  	require.Error(t, err)
   190  
   191  	ddt := strfmt.Date(time.Date(2014, 3, 19, 0, 0, 0, 0, time.UTC))
   192  	pName = "Birthdate"
   193  	dateField := val.FieldByName(pName)
   194  	binder = &untypedParamBinder{
   195  		parameter: spec.QueryParam(pName).Typed(typeString, "date").WithDefault(ddt),
   196  		Name:      pName,
   197  	}
   198  	expd := strfmt.Date(time.Date(2014, 5, 14, 0, 0, 0, 0, time.UTC))
   199  
   200  	err = binder.setFieldValue(dateField, ddt, expd.String(), true)
   201  	require.NoError(t, err)
   202  	assert.Equal(t, expd, actual.Birthdate)
   203  
   204  	err = binder.setFieldValue(dateField, ddt, "", true)
   205  	require.NoError(t, err)
   206  	assert.Equal(t, ddt, actual.Birthdate)
   207  
   208  	err = binder.setFieldValue(dateField, ddt, "yada", true)
   209  	require.Error(t, err)
   210  
   211  	dt = strfmt.DateTime(time.Date(2014, 3, 19, 2, 9, 0, 0, time.UTC))
   212  	fdt := &dt
   213  	pName = "LastFailure"
   214  	ftimeField := val.FieldByName(pName)
   215  	binder = &untypedParamBinder{
   216  		parameter: spec.QueryParam(pName).Typed(typeString, "date").WithDefault(fdt),
   217  		Name:      pName,
   218  	}
   219  	exp = strfmt.DateTime(time.Date(2014, 5, 14, 2, 9, 0, 0, time.UTC))
   220  	fexp := &exp
   221  
   222  	err = binder.setFieldValue(ftimeField, fdt, fexp.String(), true)
   223  	require.NoError(t, err)
   224  	assert.Equal(t, fexp, actual.LastFailure)
   225  
   226  	err = binder.setFieldValue(ftimeField, fdt, "", true)
   227  	require.NoError(t, err)
   228  	assert.Equal(t, fdt, actual.LastFailure)
   229  
   230  	err = binder.setFieldValue(ftimeField, fdt, "", true)
   231  	require.NoError(t, err)
   232  	assert.Equal(t, fdt, actual.LastFailure)
   233  
   234  	actual.LastFailure = nil
   235  	err = binder.setFieldValue(ftimeField, fdt, "yada", true)
   236  	require.Error(t, err)
   237  	assert.Nil(t, actual.LastFailure)
   238  
   239  	pName = "Unsupported"
   240  	unsupportedField := val.FieldByName(pName)
   241  	binder = &untypedParamBinder{
   242  		parameter: spec.QueryParam(pName).Typed(typeString, ""),
   243  		Name:      pName,
   244  	}
   245  	err = binder.setFieldValue(unsupportedField, nil, "", true)
   246  	require.Error(t, err)
   247  }
   248  
   249  func TestSliceConversion(t *testing.T) {
   250  	actual := new(SomeOperationParams)
   251  	val := reflect.ValueOf(actual).Elem()
   252  
   253  	// prefsField := val.FieldByName("Prefs")
   254  	// cData := "yada,2,3"
   255  	// _, _, err := readFormattedSliceFieldValue("Prefs", prefsField, cData, "csv", nil)
   256  	// require.Error(t, err)
   257  
   258  	sliced := []string{"some", typeString, "values"}
   259  	seps := map[string]string{"ssv": " ", "tsv": "\t", "pipes": "|", "csv": ",", "": ","}
   260  
   261  	tagsField := val.FieldByName("Tags")
   262  	for k, sep := range seps {
   263  		binder := &untypedParamBinder{
   264  			Name:      "Tags",
   265  			parameter: spec.QueryParam("tags").CollectionOf(stringItems, k),
   266  		}
   267  
   268  		actual.Tags = nil
   269  		cData := strings.Join(sliced, sep)
   270  		tags, _, err := binder.readFormattedSliceFieldValue(cData, tagsField)
   271  		require.NoError(t, err)
   272  		assert.Equal(t, sliced, tags)
   273  		cData = strings.Join(sliced, " "+sep+" ")
   274  		tags, _, err = binder.readFormattedSliceFieldValue(cData, tagsField)
   275  		require.NoError(t, err)
   276  		assert.Equal(t, sliced, tags)
   277  		tags, _, err = binder.readFormattedSliceFieldValue("", tagsField)
   278  		require.NoError(t, err)
   279  		assert.Empty(t, tags)
   280  	}
   281  
   282  	assert.Nil(t, swag.SplitByFormat("yada", "multi"))
   283  	assert.Nil(t, swag.SplitByFormat("", ""))
   284  
   285  	categoriesField := val.FieldByName("Categories")
   286  	binder := &untypedParamBinder{
   287  		Name:      "Categories",
   288  		parameter: spec.QueryParam("categories").CollectionOf(stringItems, "csv"),
   289  	}
   290  	cData := strings.Join(sliced, ",")
   291  	categories, custom, err := binder.readFormattedSliceFieldValue(cData, categoriesField)
   292  	require.NoError(t, err)
   293  	assert.EqualValues(t, sliced, actual.Categories)
   294  	assert.True(t, custom)
   295  	assert.Empty(t, categories)
   296  	categories, custom, err = binder.readFormattedSliceFieldValue("", categoriesField)
   297  	require.Error(t, err)
   298  	assert.True(t, custom)
   299  	assert.Empty(t, categories)
   300  }
   301  

View as plain text