github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/params/validator_test.go (about)

     1  // Copyright 2022-2023 The Inspektor Gadget authors
     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 params
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"strconv"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestValidateIntUint(t *testing.T) {
    27  	type test struct {
    28  		name          string
    29  		bitSize       int
    30  		value         string
    31  		expectedError bool
    32  		validateFn    func(bitsize int) func(string) error
    33  	}
    34  
    35  	tests := []test{}
    36  
    37  	bitSizes := []int{8, 16, 32, 64}
    38  
    39  	// ValidateInt
    40  	for _, bitSize := range bitSizes {
    41  		// test max and min numbers allowed
    42  		tests = append(tests, test{
    43  			name:          fmt.Sprintf("int%d_max", bitSize),
    44  			bitSize:       bitSize,
    45  			value:         strconv.FormatInt(1<<(bitSize-1)-1, 10),
    46  			expectedError: false,
    47  			validateFn:    ValidateInt,
    48  		})
    49  
    50  		tests = append(tests, test{
    51  			name:          fmt.Sprintf("int%d_min", bitSize),
    52  			bitSize:       bitSize,
    53  			value:         strconv.FormatInt(-(1 << (bitSize - 1)), 10),
    54  			expectedError: false,
    55  			validateFn:    ValidateInt,
    56  		})
    57  
    58  		// test offset by one numbers
    59  		if bitSize == 64 {
    60  			tests = append(tests, test{
    61  				name:          fmt.Sprintf("int%d_max+1", bitSize),
    62  				bitSize:       bitSize,
    63  				value:         "9223372036854775808", // 2^63
    64  				expectedError: true,
    65  				validateFn:    ValidateInt,
    66  			})
    67  
    68  			tests = append(tests, test{
    69  				name:          fmt.Sprintf("int%d_min-1", bitSize),
    70  				bitSize:       bitSize,
    71  				value:         "-9223372036854775809", // -2^63 - 1
    72  				expectedError: true,
    73  				validateFn:    ValidateInt,
    74  			})
    75  			break
    76  		}
    77  
    78  		tests = append(tests, test{
    79  			name:          fmt.Sprintf("int%d_max+1", bitSize),
    80  			bitSize:       bitSize,
    81  			value:         strconv.FormatInt(1<<(bitSize-1), 10),
    82  			expectedError: true,
    83  			validateFn:    ValidateInt,
    84  		})
    85  
    86  		tests = append(tests, test{
    87  			name:          fmt.Sprintf("int%d_min-1", bitSize),
    88  			bitSize:       bitSize,
    89  			value:         strconv.FormatInt(-(1<<(bitSize-1))-1, 10),
    90  			expectedError: true,
    91  			validateFn:    ValidateInt,
    92  		})
    93  	}
    94  
    95  	// ValidateUint
    96  	for _, bitSize := range bitSizes {
    97  		// test max numbers allowed
    98  		tests = append(tests, test{
    99  			name:          fmt.Sprintf("uint%d_max", bitSize),
   100  			bitSize:       bitSize,
   101  			value:         strconv.FormatUint(1<<(bitSize)-1, 10),
   102  			expectedError: false,
   103  			validateFn:    ValidateUint,
   104  		})
   105  
   106  		// test offset by one numbers
   107  		if bitSize == 64 {
   108  			// we need to hardcode this one, otherwise it'll overflow
   109  			tests = append(tests, test{
   110  				name:          fmt.Sprintf("uint%d_max+1", bitSize),
   111  				bitSize:       bitSize,
   112  				value:         "18446744073709551616", // 2^64 + 1
   113  				expectedError: true,
   114  				validateFn:    ValidateUint,
   115  			})
   116  			break
   117  		}
   118  
   119  		tests = append(tests, test{
   120  			name:          fmt.Sprintf("uint%d_max+1", bitSize),
   121  			bitSize:       bitSize,
   122  			value:         strconv.FormatUint(1<<(bitSize), 10),
   123  			expectedError: true,
   124  			validateFn:    ValidateUint,
   125  		})
   126  	}
   127  
   128  	for _, test := range tests {
   129  		test := test
   130  		t.Run(test.name, func(t *testing.T) {
   131  			fmt.Printf("set value: %s\n", test.value)
   132  
   133  			err := test.validateFn(test.bitSize)(test.value)
   134  			if test.expectedError {
   135  				require.Error(t, err)
   136  			} else {
   137  				require.Nil(t, err)
   138  			}
   139  		})
   140  	}
   141  }
   142  
   143  func TestValidateFloat(t *testing.T) {
   144  	type test struct {
   145  		name          string
   146  		bitSize       int
   147  		value         string
   148  		expectedError bool
   149  	}
   150  
   151  	tests := []test{
   152  		{
   153  			name:          "no_float",
   154  			bitSize:       32,
   155  			value:         "no_a_float",
   156  			expectedError: true,
   157  		},
   158  		{
   159  			name:          "float32",
   160  			bitSize:       32,
   161  			value:         "1.23456789",
   162  			expectedError: false,
   163  		},
   164  		{
   165  			name:          "float64",
   166  			bitSize:       64,
   167  			value:         "1.234567890123456789",
   168  			expectedError: false,
   169  		},
   170  		{
   171  			name:          "float32_overflow",
   172  			bitSize:       32,
   173  			value:         "3.4E+39", // math.MaxFloat32 * 10
   174  			expectedError: true,
   175  		},
   176  		{
   177  			name:          "float64_overflow",
   178  			bitSize:       64,
   179  			value:         "1.8E+309", // math.MaxFloat64 * 10
   180  			expectedError: true,
   181  		},
   182  	}
   183  
   184  	for _, test := range tests {
   185  		test := test
   186  		t.Run(test.name, func(t *testing.T) {
   187  			err := ValidateFloat(test.bitSize)(test.value)
   188  			if test.expectedError {
   189  				require.Error(t, err)
   190  			} else {
   191  				require.Nil(t, err)
   192  			}
   193  		})
   194  	}
   195  }
   196  
   197  func TestValidateBool(t *testing.T) {
   198  	type test struct {
   199  		name          string
   200  		value         string
   201  		expectedError bool
   202  	}
   203  
   204  	tests := []test{
   205  		{
   206  			name:          "true_no_error",
   207  			value:         "true",
   208  			expectedError: false,
   209  		},
   210  		{
   211  			name:          "false_no_error",
   212  			value:         "false",
   213  			expectedError: false,
   214  		},
   215  		{
   216  			name:          "bad_input_foo",
   217  			value:         "foo",
   218  			expectedError: true,
   219  		},
   220  		{
   221  			name:          "bad_input_0",
   222  			value:         "0",
   223  			expectedError: true,
   224  		},
   225  		{
   226  			name:          "bad_input_1",
   227  			value:         "1",
   228  			expectedError: true,
   229  		},
   230  		{
   231  			name:          "bad_input_empty",
   232  			value:         "",
   233  			expectedError: true,
   234  		},
   235  	}
   236  
   237  	for _, test := range tests {
   238  		test := test
   239  		t.Run(test.name, func(t *testing.T) {
   240  			err := ValidateBool(test.value)
   241  			if test.expectedError {
   242  				require.Error(t, err)
   243  			} else {
   244  				require.Nil(t, err)
   245  			}
   246  		})
   247  	}
   248  }
   249  
   250  func TestValidateIntRange(t *testing.T) {
   251  	type test struct {
   252  		min           int64
   253  		max           int64
   254  		value         string
   255  		expectedError bool
   256  	}
   257  
   258  	tests := []test{
   259  		{
   260  			min:           -10,
   261  			max:           10,
   262  			value:         "10",
   263  			expectedError: false,
   264  		},
   265  		{
   266  			min:           -10,
   267  			max:           10,
   268  			value:         "11",
   269  			expectedError: true,
   270  		},
   271  		{
   272  			min:           -10,
   273  			max:           10,
   274  			value:         "-10",
   275  			expectedError: false,
   276  		},
   277  		{
   278  			min:           -10,
   279  			max:           10,
   280  			value:         "-11",
   281  			expectedError: true,
   282  		},
   283  		{
   284  			min:           -10,
   285  			max:           10,
   286  			value:         "foo",
   287  			expectedError: true,
   288  		},
   289  		{
   290  			min:           int64(-9223372036854775808),
   291  			max:           int64(9223372036854775808 - 1),
   292  			value:         "9223372036854775808", // 2^63
   293  			expectedError: true,
   294  		},
   295  	}
   296  
   297  	for _, test := range tests {
   298  		test := test
   299  		t.Run(fmt.Sprintf("min%d_max%d_error_%t", test.min, test.max, test.expectedError), func(t *testing.T) {
   300  			err := ValidateIntRange(test.min, test.max)(test.value)
   301  			if test.expectedError {
   302  				require.Error(t, err)
   303  			} else {
   304  				require.Nil(t, err)
   305  			}
   306  		})
   307  	}
   308  }
   309  
   310  func TestValidateUintRange(t *testing.T) {
   311  	type test struct {
   312  		min           uint64
   313  		max           uint64
   314  		value         string
   315  		expectedError bool
   316  	}
   317  
   318  	tests := []test{
   319  		{
   320  			min:           10,
   321  			max:           20,
   322  			value:         "20",
   323  			expectedError: false,
   324  		},
   325  		{
   326  			min:           10,
   327  			max:           20,
   328  			value:         "21",
   329  			expectedError: true,
   330  		},
   331  		{
   332  			min:           10,
   333  			max:           20,
   334  			value:         "10",
   335  			expectedError: false,
   336  		},
   337  		{
   338  			min:           10,
   339  			max:           20,
   340  			value:         "9",
   341  			expectedError: true,
   342  		},
   343  		{
   344  			min:           10,
   345  			max:           20,
   346  			value:         "foo",
   347  			expectedError: true,
   348  		},
   349  		{
   350  			min:           0,
   351  			max:           uint64(18446744073709551616 - 1),
   352  			value:         "18446744073709551616", // 2^64
   353  			expectedError: true,
   354  		},
   355  	}
   356  
   357  	for _, test := range tests {
   358  		test := test
   359  		name := fmt.Sprintf("min%d_max%d_error_%t", test.min, test.max, test.expectedError)
   360  		t.Run(name, func(t *testing.T) {
   361  			err := ValidateUintRange(test.min, test.max)(test.value)
   362  			if test.expectedError {
   363  				require.Error(t, err)
   364  			} else {
   365  				require.Nil(t, err)
   366  			}
   367  		})
   368  	}
   369  }
   370  
   371  func TestValidateSlice(t *testing.T) {
   372  	type test struct {
   373  		name          string
   374  		value         string
   375  		validator     func(string) error
   376  		expectedError bool
   377  	}
   378  
   379  	noErrFn := func(string) error { return nil }
   380  	errFn := func(string) error { return errors.New("error") }
   381  
   382  	tests := []test{
   383  		{
   384  			name:          "empty_slice_no_error",
   385  			value:         "",
   386  			validator:     noErrFn,
   387  			expectedError: false,
   388  		},
   389  		{
   390  			name:          "slice_with_2_elements_no_error",
   391  			value:         "foo,bar",
   392  			validator:     noErrFn,
   393  			expectedError: false,
   394  		},
   395  		{
   396  			name:          "slice_with_2_elements_no_error",
   397  			value:         "foo,bar",
   398  			validator:     errFn,
   399  			expectedError: true,
   400  		},
   401  		{
   402  			name:  "slice_with_2_elements_custom_err_func",
   403  			value: "foo,bar",
   404  			validator: func(s string) error {
   405  				if s == "bar" {
   406  					return errors.New("error")
   407  				}
   408  
   409  				return nil
   410  			},
   411  			expectedError: true,
   412  		},
   413  		{
   414  			name:          "empty_slice_with_ValidateUintRange_no_error",
   415  			value:         "",
   416  			validator:     ValidateUintRange(1, 10),
   417  			expectedError: false,
   418  		},
   419  		{
   420  			name:          "slice_with_1_element_with_ValidateUintRange_no_error",
   421  			value:         "4",
   422  			validator:     ValidateUintRange(1, 10),
   423  			expectedError: false,
   424  		},
   425  		{
   426  			name:          "slice_with_2_elements_with_ValidateUintRange_no_error",
   427  			value:         "5,2",
   428  			validator:     ValidateUintRange(1, 10),
   429  			expectedError: false,
   430  		},
   431  		{
   432  			name:          "slice_with_3_elements_with_ValidateUintRange_error",
   433  			value:         "5,2,11",
   434  			validator:     ValidateUintRange(1, 10),
   435  			expectedError: true,
   436  		},
   437  	}
   438  
   439  	for _, test := range tests {
   440  		test := test
   441  		t.Run(test.name, func(t *testing.T) {
   442  			err := ValidateSlice(test.validator)(test.value)
   443  			if test.expectedError {
   444  				require.Error(t, err)
   445  			} else {
   446  				require.Nil(t, err)
   447  			}
   448  		})
   449  	}
   450  }
   451  
   452  type validateTest struct {
   453  	name          string
   454  	value         string
   455  	expectedError bool
   456  }
   457  
   458  func testValidate(t *testing.T, tests []validateTest, validate func(str string) error) {
   459  	for _, test := range tests {
   460  		test := test
   461  		t.Run(test.name, func(t *testing.T) {
   462  			err := validate(test.value)
   463  			if test.expectedError {
   464  				require.Error(t, err)
   465  			} else {
   466  				require.Nil(t, err)
   467  			}
   468  		})
   469  	}
   470  }
   471  
   472  func TestValidateDuration(t *testing.T) {
   473  	testValidate(t,
   474  		[]validateTest{
   475  			{
   476  				name:          "1s_no_error",
   477  				value:         "1s",
   478  				expectedError: false,
   479  			},
   480  			{
   481  				name:          "1m_no_error",
   482  				value:         "1m",
   483  				expectedError: false,
   484  			},
   485  			{
   486  				name:          "empty_error",
   487  				value:         "",
   488  				expectedError: true,
   489  			},
   490  			{
   491  				name:          "bad_input_0",
   492  				value:         "-",
   493  				expectedError: true,
   494  			},
   495  			{
   496  				name:          "bad_input_1",
   497  				value:         "asdafaf",
   498  				expectedError: true,
   499  			},
   500  			{
   501  				name:          "bad_unit",
   502  				value:         "1sad",
   503  				expectedError: true,
   504  			},
   505  		},
   506  		ValidateDuration,
   507  	)
   508  }
   509  
   510  func TestValidateIP(t *testing.T) {
   511  	testValidate(t,
   512  		[]validateTest{
   513  			{
   514  				name:          "IPv4_no_error",
   515  				value:         "127.0.0.1",
   516  				expectedError: false,
   517  			},
   518  			{
   519  				name:          "IPv6_no_error",
   520  				value:         "::1",
   521  				expectedError: false,
   522  			},
   523  			{
   524  				name:          "empty_no_error",
   525  				value:         "",
   526  				expectedError: false,
   527  			},
   528  			{
   529  				name:          "bad_input_0",
   530  				value:         "-",
   531  				expectedError: true,
   532  			},
   533  			{
   534  				name:          "bad_input_1",
   535  				value:         "foo",
   536  				expectedError: true,
   537  			},
   538  		},
   539  		ValidateIP,
   540  	)
   541  }