github.com/magodo/terraform@v0.11.12-beta1/helper/validation/validation_test.go (about)

     1  package validation
     2  
     3  import (
     4  	"regexp"
     5  	"testing"
     6  
     7  	"github.com/hashicorp/terraform/helper/schema"
     8  )
     9  
    10  type testCase struct {
    11  	val         interface{}
    12  	f           schema.SchemaValidateFunc
    13  	expectedErr *regexp.Regexp
    14  }
    15  
    16  func TestValidationIntBetween(t *testing.T) {
    17  	runTestCases(t, []testCase{
    18  		{
    19  			val: 1,
    20  			f:   IntBetween(1, 1),
    21  		},
    22  		{
    23  			val: 1,
    24  			f:   IntBetween(0, 2),
    25  		},
    26  		{
    27  			val:         1,
    28  			f:           IntBetween(2, 3),
    29  			expectedErr: regexp.MustCompile("expected [\\w]+ to be in the range \\(2 - 3\\), got 1"),
    30  		},
    31  		{
    32  			val:         "1",
    33  			f:           IntBetween(2, 3),
    34  			expectedErr: regexp.MustCompile("expected type of [\\w]+ to be int"),
    35  		},
    36  	})
    37  }
    38  
    39  func TestValidationIntAtLeast(t *testing.T) {
    40  	runTestCases(t, []testCase{
    41  		{
    42  			val: 1,
    43  			f:   IntAtLeast(1),
    44  		},
    45  		{
    46  			val: 1,
    47  			f:   IntAtLeast(0),
    48  		},
    49  		{
    50  			val:         1,
    51  			f:           IntAtLeast(2),
    52  			expectedErr: regexp.MustCompile("expected [\\w]+ to be at least \\(2\\), got 1"),
    53  		},
    54  		{
    55  			val:         "1",
    56  			f:           IntAtLeast(2),
    57  			expectedErr: regexp.MustCompile("expected type of [\\w]+ to be int"),
    58  		},
    59  	})
    60  }
    61  
    62  func TestValidationIntAtMost(t *testing.T) {
    63  	runTestCases(t, []testCase{
    64  		{
    65  			val: 1,
    66  			f:   IntAtMost(1),
    67  		},
    68  		{
    69  			val: 1,
    70  			f:   IntAtMost(2),
    71  		},
    72  		{
    73  			val:         1,
    74  			f:           IntAtMost(0),
    75  			expectedErr: regexp.MustCompile("expected [\\w]+ to be at most \\(0\\), got 1"),
    76  		},
    77  		{
    78  			val:         "1",
    79  			f:           IntAtMost(0),
    80  			expectedErr: regexp.MustCompile("expected type of [\\w]+ to be int"),
    81  		},
    82  	})
    83  }
    84  
    85  func TestValidationStringInSlice(t *testing.T) {
    86  	runTestCases(t, []testCase{
    87  		{
    88  			val: "ValidValue",
    89  			f:   StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false),
    90  		},
    91  		// ignore case
    92  		{
    93  			val: "VALIDVALUE",
    94  			f:   StringInSlice([]string{"ValidValue", "AnotherValidValue"}, true),
    95  		},
    96  		{
    97  			val:         "VALIDVALUE",
    98  			f:           StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false),
    99  			expectedErr: regexp.MustCompile("expected [\\w]+ to be one of \\[ValidValue AnotherValidValue\\], got VALIDVALUE"),
   100  		},
   101  		{
   102  			val:         "InvalidValue",
   103  			f:           StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false),
   104  			expectedErr: regexp.MustCompile("expected [\\w]+ to be one of \\[ValidValue AnotherValidValue\\], got InvalidValue"),
   105  		},
   106  		{
   107  			val:         1,
   108  			f:           StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false),
   109  			expectedErr: regexp.MustCompile("expected type of [\\w]+ to be string"),
   110  		},
   111  	})
   112  }
   113  
   114  func TestValidationStringMatch(t *testing.T) {
   115  	runTestCases(t, []testCase{
   116  		{
   117  			val: "foobar",
   118  			f:   StringMatch(regexp.MustCompile(".*foo.*"), ""),
   119  		},
   120  		{
   121  			val:         "bar",
   122  			f:           StringMatch(regexp.MustCompile(".*foo.*"), ""),
   123  			expectedErr: regexp.MustCompile("expected value of [\\w]+ to match regular expression " + regexp.QuoteMeta(`".*foo.*"`)),
   124  		},
   125  		{
   126  			val:         "bar",
   127  			f:           StringMatch(regexp.MustCompile(".*foo.*"), "value must contain foo"),
   128  			expectedErr: regexp.MustCompile("invalid value for [\\w]+ \\(value must contain foo\\)"),
   129  		},
   130  	})
   131  }
   132  
   133  func TestValidationRegexp(t *testing.T) {
   134  	runTestCases(t, []testCase{
   135  		{
   136  			val: ".*foo.*",
   137  			f:   ValidateRegexp,
   138  		},
   139  		{
   140  			val:         "foo(bar",
   141  			f:           ValidateRegexp,
   142  			expectedErr: regexp.MustCompile(regexp.QuoteMeta("error parsing regexp: missing closing ): `foo(bar`")),
   143  		},
   144  	})
   145  }
   146  
   147  func TestValidationSingleIP(t *testing.T) {
   148  	runTestCases(t, []testCase{
   149  		{
   150  			val: "172.10.10.10",
   151  			f:   SingleIP(),
   152  		},
   153  		{
   154  			val:         "1.1.1",
   155  			f:           SingleIP(),
   156  			expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")),
   157  		},
   158  		{
   159  			val:         "1.1.1.0/20",
   160  			f:           SingleIP(),
   161  			expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")),
   162  		},
   163  		{
   164  			val:         "256.1.1.1",
   165  			f:           SingleIP(),
   166  			expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")),
   167  		},
   168  	})
   169  }
   170  
   171  func TestValidationIPRange(t *testing.T) {
   172  	runTestCases(t, []testCase{
   173  		{
   174  			val: "172.10.10.10-172.10.10.12",
   175  			f:   IPRange(),
   176  		},
   177  		{
   178  			val:         "172.10.10.20",
   179  			f:           IPRange(),
   180  			expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP range, got:")),
   181  		},
   182  		{
   183  			val:         "172.10.10.20-172.10.10.12",
   184  			f:           IPRange(),
   185  			expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP range, got:")),
   186  		},
   187  	})
   188  }
   189  
   190  func TestValidateRFC3339TimeString(t *testing.T) {
   191  	runTestCases(t, []testCase{
   192  		{
   193  			val: "2018-03-01T00:00:00Z",
   194  			f:   ValidateRFC3339TimeString,
   195  		},
   196  		{
   197  			val: "2018-03-01T00:00:00-05:00",
   198  			f:   ValidateRFC3339TimeString,
   199  		},
   200  		{
   201  			val: "2018-03-01T00:00:00+05:00",
   202  			f:   ValidateRFC3339TimeString,
   203  		},
   204  		{
   205  			val:         "03/01/2018",
   206  			f:           ValidateRFC3339TimeString,
   207  			expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)),
   208  		},
   209  		{
   210  			val:         "03-01-2018",
   211  			f:           ValidateRFC3339TimeString,
   212  			expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)),
   213  		},
   214  		{
   215  			val:         "2018-03-01",
   216  			f:           ValidateRFC3339TimeString,
   217  			expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)),
   218  		},
   219  		{
   220  			val:         "2018-03-01T",
   221  			f:           ValidateRFC3339TimeString,
   222  			expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)),
   223  		},
   224  		{
   225  			val:         "2018-03-01T00:00:00",
   226  			f:           ValidateRFC3339TimeString,
   227  			expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)),
   228  		},
   229  		{
   230  			val:         "2018-03-01T00:00:00Z05:00",
   231  			f:           ValidateRFC3339TimeString,
   232  			expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)),
   233  		},
   234  		{
   235  			val:         "2018-03-01T00:00:00Z-05:00",
   236  			f:           ValidateRFC3339TimeString,
   237  			expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)),
   238  		},
   239  	})
   240  }
   241  
   242  func TestValidateJsonString(t *testing.T) {
   243  	type testCases struct {
   244  		Value    string
   245  		ErrCount int
   246  	}
   247  
   248  	invalidCases := []testCases{
   249  		{
   250  			Value:    `{0:"1"}`,
   251  			ErrCount: 1,
   252  		},
   253  		{
   254  			Value:    `{'abc':1}`,
   255  			ErrCount: 1,
   256  		},
   257  		{
   258  			Value:    `{"def":}`,
   259  			ErrCount: 1,
   260  		},
   261  		{
   262  			Value:    `{"xyz":[}}`,
   263  			ErrCount: 1,
   264  		},
   265  	}
   266  
   267  	for _, tc := range invalidCases {
   268  		_, errors := ValidateJsonString(tc.Value, "json")
   269  		if len(errors) != tc.ErrCount {
   270  			t.Fatalf("Expected %q to trigger a validation error.", tc.Value)
   271  		}
   272  	}
   273  
   274  	validCases := []testCases{
   275  		{
   276  			Value:    ``,
   277  			ErrCount: 0,
   278  		},
   279  		{
   280  			Value:    `{}`,
   281  			ErrCount: 0,
   282  		},
   283  		{
   284  			Value:    `{"abc":["1","2"]}`,
   285  			ErrCount: 0,
   286  		},
   287  	}
   288  
   289  	for _, tc := range validCases {
   290  		_, errors := ValidateJsonString(tc.Value, "json")
   291  		if len(errors) != tc.ErrCount {
   292  			t.Fatalf("Expected %q not to trigger a validation error.", tc.Value)
   293  		}
   294  	}
   295  }
   296  
   297  func TestValidateListUniqueStrings(t *testing.T) {
   298  	runTestCases(t, []testCase{
   299  		{
   300  			val: []interface{}{"foo", "bar"},
   301  			f:   ValidateListUniqueStrings,
   302  		},
   303  		{
   304  			val:         []interface{}{"foo", "bar", "foo"},
   305  			f:           ValidateListUniqueStrings,
   306  			expectedErr: regexp.MustCompile("duplicate entry - foo"),
   307  		},
   308  		{
   309  			val:         []interface{}{"foo", "bar", "foo", "baz", "bar"},
   310  			f:           ValidateListUniqueStrings,
   311  			expectedErr: regexp.MustCompile("duplicate entry - (?:foo|bar)"),
   312  		},
   313  	})
   314  }
   315  
   316  func TestValidationNoZeroValues(t *testing.T) {
   317  	runTestCases(t, []testCase{
   318  		{
   319  			val: "foo",
   320  			f:   NoZeroValues,
   321  		},
   322  		{
   323  			val: 1,
   324  			f:   NoZeroValues,
   325  		},
   326  		{
   327  			val: float64(1),
   328  			f:   NoZeroValues,
   329  		},
   330  		{
   331  			val:         "",
   332  			f:           NoZeroValues,
   333  			expectedErr: regexp.MustCompile("must not be empty"),
   334  		},
   335  		{
   336  			val:         0,
   337  			f:           NoZeroValues,
   338  			expectedErr: regexp.MustCompile("must not be zero"),
   339  		},
   340  		{
   341  			val:         float64(0),
   342  			f:           NoZeroValues,
   343  			expectedErr: regexp.MustCompile("must not be zero"),
   344  		},
   345  	})
   346  }
   347  
   348  func runTestCases(t *testing.T, cases []testCase) {
   349  	matchErr := func(errs []error, r *regexp.Regexp) bool {
   350  		// err must match one provided
   351  		for _, err := range errs {
   352  			if r.MatchString(err.Error()) {
   353  				return true
   354  			}
   355  		}
   356  
   357  		return false
   358  	}
   359  
   360  	for i, tc := range cases {
   361  		_, errs := tc.f(tc.val, "test_property")
   362  
   363  		if len(errs) == 0 && tc.expectedErr == nil {
   364  			continue
   365  		}
   366  
   367  		if len(errs) != 0 && tc.expectedErr == nil {
   368  			t.Fatalf("expected test case %d to produce no errors, got %v", i, errs)
   369  		}
   370  
   371  		if !matchErr(errs, tc.expectedErr) {
   372  			t.Fatalf("expected test case %d to produce error matching \"%s\", got %v", i, tc.expectedErr, errs)
   373  		}
   374  	}
   375  }