k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/validation/validate/values_test.go (about)

     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 validate
    16  
    17  import (
    18  	"math"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  	"k8s.io/kube-openapi/pkg/validation/errors"
    23  	"k8s.io/kube-openapi/pkg/validation/strfmt"
    24  )
    25  
    26  func TestValues_ValidateIntEnum(t *testing.T) {
    27  	enumValues := []interface{}{1, 2, 3}
    28  
    29  	err := Enum("test", "body", int64(5), enumValues)
    30  	assert.NotNil(t, err)
    31  	err2 := Enum("test", "body", int64(1), enumValues)
    32  	assert.Nil(t, err2)
    33  }
    34  
    35  func TestValues_ValidateEnum(t *testing.T) {
    36  	enumValues := []string{"aa", "bb", "cc"}
    37  
    38  	err := Enum("test", "body", "a", enumValues)
    39  	assert.Error(t, err)
    40  	err = Enum("test", "body", "bb", enumValues)
    41  	assert.Nil(t, err)
    42  }
    43  
    44  // Check edge cases in Enum
    45  func TestValues_Enum_EdgeCases(t *testing.T) {
    46  	enumValues := "aa, bb, cc"
    47  
    48  	err := Enum("test", "body", int64(1), enumValues)
    49  	// No validation occurs: enumValues is not a slice
    50  	assert.Nil(t, err)
    51  
    52  	// TODO(TEST): edge case: value is not a concrete type
    53  	// It's really a go internals challenge
    54  	// to figure a test case to demonstrate
    55  	// this case must be checked (!!)
    56  }
    57  
    58  func TestValues_ValidateUniqueItems(t *testing.T) {
    59  	var err error
    60  
    61  	itemsNonUnique := []interface{}{
    62  		[]int32{1, 2, 3, 4, 4, 5},
    63  		[]string{"aa", "bb", "cc", "cc", "dd"},
    64  	}
    65  	for _, v := range itemsNonUnique {
    66  		err = UniqueItems("test", "body", v)
    67  		assert.Error(t, err)
    68  	}
    69  
    70  	itemsUnique := []interface{}{
    71  		[]int32{1, 2, 3},
    72  		"I'm a string",
    73  		map[string]int{
    74  			"aaa": 1111,
    75  			"b":   2,
    76  			"ccc": 333,
    77  		},
    78  		nil,
    79  	}
    80  	for _, v := range itemsUnique {
    81  		err = UniqueItems("test", "body", v)
    82  		assert.Nil(t, err)
    83  	}
    84  }
    85  
    86  func TestValues_ValidateMinLength(t *testing.T) {
    87  	var minLength int64 = 5
    88  	err := MinLength("test", "body", "aa", minLength)
    89  	assert.Error(t, err)
    90  	err = MinLength("test", "body", "aaaaa", minLength)
    91  	assert.Nil(t, err)
    92  }
    93  
    94  func TestValues_ValidateMaxLength(t *testing.T) {
    95  	var maxLength int64 = 5
    96  	err := MaxLength("test", "body", "bbbbbb", maxLength)
    97  	assert.Error(t, err)
    98  	err = MaxLength("test", "body", "aa", maxLength)
    99  	assert.Nil(t, err)
   100  }
   101  
   102  func TestValues_ValidateRequired(t *testing.T) {
   103  	var err error
   104  	path := "test"
   105  	in := "body"
   106  
   107  	RequiredFail := []interface{}{
   108  		"",
   109  		0,
   110  		nil,
   111  	}
   112  
   113  	for _, v := range RequiredFail {
   114  		err = Required(path, in, v)
   115  		assert.Error(t, err)
   116  	}
   117  
   118  	RequiredSuccess := []interface{}{
   119  		" ",
   120  		"bla-bla-bla",
   121  		2,
   122  		[]interface{}{21, []int{}, "testString"},
   123  	}
   124  
   125  	for _, v := range RequiredSuccess {
   126  		err = Required(path, in, v)
   127  		assert.Nil(t, err)
   128  	}
   129  
   130  }
   131  
   132  func TestValuMultipleOf(t *testing.T) {
   133  
   134  	// positive
   135  
   136  	err := MultipleOf("test", "body", 9, 3)
   137  	assert.Nil(t, err)
   138  
   139  	err = MultipleOf("test", "body", 9.3, 3.1)
   140  	assert.Nil(t, err)
   141  
   142  	err = MultipleOf("test", "body", 9.1, 0.1)
   143  	assert.Nil(t, err)
   144  
   145  	err = MultipleOf("test", "body", 3, 0.3)
   146  	assert.Nil(t, err)
   147  
   148  	err = MultipleOf("test", "body", 6, 0.3)
   149  	assert.Nil(t, err)
   150  
   151  	err = MultipleOf("test", "body", 1, 0.25)
   152  	assert.Nil(t, err)
   153  
   154  	err = MultipleOf("test", "body", 8, 0.2)
   155  	assert.Nil(t, err)
   156  
   157  	// zero
   158  	err = MultipleOf("test", "body", 9, 0)
   159  	assert.Error(t, err)
   160  
   161  	err = MultipleOf("test", "body", 9.1, 0)
   162  	assert.Error(t, err)
   163  
   164  	// negative
   165  
   166  	err = MultipleOf("test", "body", 3, 0.4)
   167  	assert.Error(t, err)
   168  
   169  	err = MultipleOf("test", "body", 9.1, 0.2)
   170  	assert.Error(t, err)
   171  
   172  	err = MultipleOf("test", "body", 9.34, 0.1)
   173  	assert.Error(t, err)
   174  
   175  	// error on negative factor
   176  	err = MultipleOf("test", "body", 9.34, -0.1)
   177  	assert.Error(t, err)
   178  }
   179  
   180  // Test edge case for Pattern (in regular spec, no invalid regexp should reach there)
   181  func TestValues_Pattern_Edgecases(t *testing.T) {
   182  	var err *errors.Validation
   183  	err = Pattern("path", "in", "pick-a-boo", `.*-[a-z]-.*`)
   184  	assert.Nil(t, err)
   185  
   186  	// Invalid regexp
   187  	err = Pattern("path", "in", "pick-a-boo", `.*-[a(-z]-^).*`)
   188  	if assert.NotNil(t, err) {
   189  		assert.Equal(t, int(err.Code()), int(errors.PatternFailCode))
   190  		assert.Contains(t, err.Error(), "pattern is invalid")
   191  	}
   192  
   193  	// Valid regexp, invalid pattern
   194  	err = Pattern("path", "in", "pick-8-boo", `.*-[a-z]-.*`)
   195  	if assert.NotNil(t, err) {
   196  		assert.Equal(t, int(err.Code()), int(errors.PatternFailCode))
   197  		assert.NotContains(t, err.Error(), "pattern is invalid")
   198  		assert.Contains(t, err.Error(), "should match")
   199  	}
   200  }
   201  
   202  // Test edge cases in FormatOf
   203  // not easily tested with full specs
   204  func TestValues_FormatOf_EdgeCases(t *testing.T) {
   205  	var err *errors.Validation
   206  
   207  	err = FormatOf("path", "in", "bugz", "", nil)
   208  	if assert.NotNil(t, err) {
   209  		assert.Equal(t, int(err.Code()), int(errors.InvalidTypeCode))
   210  		assert.Contains(t, err.Error(), "bugz is an invalid type name")
   211  	}
   212  
   213  	err = FormatOf("path", "in", "bugz", "", strfmt.Default)
   214  	if assert.NotNil(t, err) {
   215  		assert.Equal(t, int(err.Code()), int(errors.InvalidTypeCode))
   216  		assert.Contains(t, err.Error(), "bugz is an invalid type name")
   217  	}
   218  }
   219  
   220  // Test edge cases in MaximumNativeType
   221  // not easily exercised with full specs
   222  func TestValues_MaximumNative(t *testing.T) {
   223  	assert.Nil(t, MaximumNativeType("path", "in", int(5), 10, false))
   224  	assert.Nil(t, MaximumNativeType("path", "in", uint(5), 10, true))
   225  	assert.Nil(t, MaximumNativeType("path", "in", int8(5), 10, true))
   226  	assert.Nil(t, MaximumNativeType("path", "in", uint8(5), 10, true))
   227  	assert.Nil(t, MaximumNativeType("path", "in", int16(5), 10, true))
   228  	assert.Nil(t, MaximumNativeType("path", "in", uint16(5), 10, true))
   229  	assert.Nil(t, MaximumNativeType("path", "in", int32(5), 10, true))
   230  	assert.Nil(t, MaximumNativeType("path", "in", uint32(5), 10, true))
   231  	assert.Nil(t, MaximumNativeType("path", "in", int64(5), 10, true))
   232  	assert.Nil(t, MaximumNativeType("path", "in", uint64(5), 10, true))
   233  	assert.Nil(t, MaximumNativeType("path", "in", float32(5.5), 10, true))
   234  	assert.Nil(t, MaximumNativeType("path", "in", float64(5.5), 10, true))
   235  
   236  	var err *errors.Validation
   237  
   238  	err = MaximumNativeType("path", "in", int32(10), 10, true)
   239  	if assert.NotNil(t, err) {
   240  		code := int(err.Code())
   241  		assert.Equal(t, code, errors.MaxFailCode)
   242  	}
   243  
   244  	err = MaximumNativeType("path", "in", uint(10), 10, true)
   245  	if assert.NotNil(t, err) {
   246  		code := int(err.Code())
   247  		assert.Equal(t, code, errors.MaxFailCode)
   248  	}
   249  
   250  	err = MaximumNativeType("path", "in", int64(12), 10, false)
   251  	if assert.NotNil(t, err) {
   252  		code := int(err.Code())
   253  		assert.Equal(t, code, errors.MaxFailCode)
   254  	}
   255  
   256  	err = MaximumNativeType("path", "in", float32(12.6), 10, false)
   257  	if assert.NotNil(t, err) {
   258  		code := int(err.Code())
   259  		assert.Equal(t, code, int(errors.MaxFailCode))
   260  	}
   261  
   262  	err = MaximumNativeType("path", "in", float64(12.6), 10, false)
   263  	if assert.NotNil(t, err) {
   264  		code := int(err.Code())
   265  		assert.Equal(t, code, int(errors.MaxFailCode))
   266  	}
   267  
   268  	err = MaximumNativeType("path", "in", uint(5), -10, true)
   269  	if assert.NotNil(t, err) {
   270  		code := int(err.Code())
   271  		assert.Equal(t, code, int(errors.MaxFailCode))
   272  	}
   273  }
   274  
   275  // Test edge cases in MinimumNativeType
   276  // not easily exercised with full specs
   277  func TestValues_MinimumNative(t *testing.T) {
   278  	assert.Nil(t, MinimumNativeType("path", "in", int(5), 0, false))
   279  	assert.Nil(t, MinimumNativeType("path", "in", uint(5), 0, true))
   280  	assert.Nil(t, MinimumNativeType("path", "in", int8(5), 0, true))
   281  	assert.Nil(t, MinimumNativeType("path", "in", uint8(5), 0, true))
   282  	assert.Nil(t, MinimumNativeType("path", "in", int16(5), 0, true))
   283  	assert.Nil(t, MinimumNativeType("path", "in", uint16(5), 0, true))
   284  	assert.Nil(t, MinimumNativeType("path", "in", int32(5), 0, true))
   285  	assert.Nil(t, MinimumNativeType("path", "in", uint32(5), 0, true))
   286  	assert.Nil(t, MinimumNativeType("path", "in", int64(5), 0, true))
   287  	assert.Nil(t, MinimumNativeType("path", "in", uint64(5), 0, true))
   288  	assert.Nil(t, MinimumNativeType("path", "in", float32(5.5), 0, true))
   289  	assert.Nil(t, MinimumNativeType("path", "in", float64(5.5), 0, true))
   290  
   291  	var err *errors.Validation
   292  
   293  	err = MinimumNativeType("path", "in", uint(10), 10, true)
   294  	if assert.NotNil(t, err) {
   295  		code := int(err.Code())
   296  		assert.Equal(t, code, int(errors.MinFailCode))
   297  	}
   298  
   299  	err = MinimumNativeType("path", "in", uint(10), 10, true)
   300  	if assert.NotNil(t, err) {
   301  		code := int(err.Code())
   302  		assert.Equal(t, code, int(errors.MinFailCode))
   303  	}
   304  
   305  	err = MinimumNativeType("path", "in", int64(8), 10, false)
   306  	if assert.NotNil(t, err) {
   307  		code := int(err.Code())
   308  		assert.Equal(t, code, int(errors.MinFailCode))
   309  	}
   310  
   311  	err = MinimumNativeType("path", "in", float32(12.6), 20, false)
   312  	if assert.NotNil(t, err) {
   313  		code := int(err.Code())
   314  		assert.Equal(t, code, int(errors.MinFailCode))
   315  	}
   316  
   317  	err = MinimumNativeType("path", "in", float64(12.6), 20, false)
   318  	if assert.NotNil(t, err) {
   319  		code := int(err.Code())
   320  		assert.Equal(t, code, int(errors.MinFailCode))
   321  	}
   322  
   323  	err = MinimumNativeType("path", "in", uint(5), -10, true)
   324  	assert.Nil(t, err)
   325  }
   326  
   327  // Test edge cases in MaximumNativeType
   328  // not easily exercised with full specs
   329  func TestValues_MultipleOfNative(t *testing.T) {
   330  	assert.Nil(t, MultipleOfNativeType("path", "in", int(5), 1))
   331  	assert.Nil(t, MultipleOfNativeType("path", "in", uint(5), 1))
   332  	assert.Nil(t, MultipleOfNativeType("path", "in", int8(5), 1))
   333  	assert.Nil(t, MultipleOfNativeType("path", "in", uint8(5), 1))
   334  	assert.Nil(t, MultipleOfNativeType("path", "in", int16(5), 1))
   335  	assert.Nil(t, MultipleOfNativeType("path", "in", uint16(5), 1))
   336  	assert.Nil(t, MultipleOfNativeType("path", "in", int32(5), 1))
   337  	assert.Nil(t, MultipleOfNativeType("path", "in", uint32(5), 1))
   338  	assert.Nil(t, MultipleOfNativeType("path", "in", int64(5), 1))
   339  	assert.Nil(t, MultipleOfNativeType("path", "in", uint64(5), 1))
   340  
   341  	var err *errors.Validation
   342  
   343  	err = MultipleOfNativeType("path", "in", int64(5), 0)
   344  	if assert.NotNil(t, err) {
   345  		code := int(err.Code())
   346  		assert.Equal(t, code, int(errors.MultipleOfMustBePositiveCode))
   347  	}
   348  
   349  	err = MultipleOfNativeType("path", "in", uint64(5), 0)
   350  	if assert.NotNil(t, err) {
   351  		code := int(err.Code())
   352  		assert.Equal(t, code, int(errors.MultipleOfMustBePositiveCode))
   353  	}
   354  
   355  	err = MultipleOfNativeType("path", "in", int64(5), -1)
   356  	if assert.NotNil(t, err) {
   357  		code := int(err.Code())
   358  		assert.Equal(t, code, int(errors.MultipleOfMustBePositiveCode))
   359  	}
   360  
   361  	err = MultipleOfNativeType("path", "in", int64(11), 5)
   362  	if assert.NotNil(t, err) {
   363  		code := int(err.Code())
   364  		assert.Equal(t, code, int(errors.MultipleOfFailCode))
   365  	}
   366  
   367  	err = MultipleOfNativeType("path", "in", uint64(11), 5)
   368  	if assert.NotNil(t, err) {
   369  		code := int(err.Code())
   370  		assert.Equal(t, code, int(errors.MultipleOfFailCode))
   371  	}
   372  }
   373  
   374  // Test edge cases in IsValueValidAgainstRange
   375  // not easily exercised with full specs
   376  func TestValues_IsValueValidAgainstRange(t *testing.T) {
   377  	var err error
   378  
   379  	// We did not simulate these formats in full specs
   380  	err = IsValueValidAgainstRange(float32(123.45), "number", "float32", "prefix", "path")
   381  	assert.NoError(t, err)
   382  
   383  	err = IsValueValidAgainstRange(float64(123.45), "number", "float32", "prefix", "path")
   384  	assert.NoError(t, err)
   385  
   386  	err = IsValueValidAgainstRange(int64(123), "number", "float", "prefix", "path")
   387  	assert.NoError(t, err)
   388  
   389  	err = IsValueValidAgainstRange(int64(123), "integer", "", "prefix", "path")
   390  	assert.NoError(t, err)
   391  
   392  	err = IsValueValidAgainstRange(int64(123), "integer", "int64", "prefix", "path")
   393  	assert.NoError(t, err)
   394  
   395  	err = IsValueValidAgainstRange(int64(123), "integer", "uint64", "prefix", "path")
   396  	assert.NoError(t, err)
   397  
   398  	// Error case (do not occur in normal course of a validation)
   399  	err = IsValueValidAgainstRange(float64(math.MaxFloat64), "integer", "", "prefix", "path")
   400  	if assert.Error(t, err) {
   401  		assert.Contains(t, err.Error(), "must be of type integer (default format)")
   402  	}
   403  
   404  	// Checking a few limits
   405  	err = IsValueValidAgainstRange("123", "number", "", "prefix", "path")
   406  	if assert.Error(t, err) {
   407  		assert.Contains(t, err.Error(), "called with invalid (non numeric) val type")
   408  	}
   409  
   410  	err = IsValueValidAgainstRange(int64(2147483647), "integer", "int32", "prefix", "path")
   411  	assert.NoError(t, err)
   412  
   413  	err = IsValueValidAgainstRange(int64(2147483647), "integer", "uint32", "prefix", "path")
   414  	assert.NoError(t, err)
   415  }