github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/cli/opts/opts_test.go (about) 1 package opts 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "gotest.tools/v3/assert" 9 ) 10 11 func TestValidateIPAddress(t *testing.T) { 12 if ret, err := ValidateIPAddress(`1.2.3.4`); err != nil || ret == "" { 13 t.Fatalf("ValidateIPAddress(`1.2.3.4`) got %s %s", ret, err) 14 } 15 16 if ret, err := ValidateIPAddress(`127.0.0.1`); err != nil || ret == "" { 17 t.Fatalf("ValidateIPAddress(`127.0.0.1`) got %s %s", ret, err) 18 } 19 20 if ret, err := ValidateIPAddress(`::1`); err != nil || ret == "" { 21 t.Fatalf("ValidateIPAddress(`::1`) got %s %s", ret, err) 22 } 23 24 if ret, err := ValidateIPAddress(`127`); err == nil || ret != "" { 25 t.Fatalf("ValidateIPAddress(`127`) got %s %s", ret, err) 26 } 27 28 if ret, err := ValidateIPAddress(`random invalid string`); err == nil || ret != "" { 29 t.Fatalf("ValidateIPAddress(`random invalid string`) got %s %s", ret, err) 30 } 31 32 } 33 34 func TestMapOpts(t *testing.T) { 35 tmpMap := make(map[string]string) 36 o := NewMapOpts(tmpMap, logOptsValidator) 37 o.Set("max-size=1") 38 if o.String() != "map[max-size:1]" { 39 t.Errorf("%s != [map[max-size:1]", o.String()) 40 } 41 42 o.Set("max-file=2") 43 if len(tmpMap) != 2 { 44 t.Errorf("map length %d != 2", len(tmpMap)) 45 } 46 47 if tmpMap["max-file"] != "2" { 48 t.Errorf("max-file = %s != 2", tmpMap["max-file"]) 49 } 50 51 if tmpMap["max-size"] != "1" { 52 t.Errorf("max-size = %s != 1", tmpMap["max-size"]) 53 } 54 if o.Set("dummy-val=3") == nil { 55 t.Error("validator is not being called") 56 } 57 } 58 59 func TestListOptsWithoutValidator(t *testing.T) { 60 o := NewListOpts(nil) 61 o.Set("foo") 62 if o.String() != "[foo]" { 63 t.Errorf("%s != [foo]", o.String()) 64 } 65 o.Set("bar") 66 if o.Len() != 2 { 67 t.Errorf("%d != 2", o.Len()) 68 } 69 o.Set("bar") 70 if o.Len() != 3 { 71 t.Errorf("%d != 3", o.Len()) 72 } 73 if !o.Get("bar") { 74 t.Error("o.Get(\"bar\") == false") 75 } 76 if o.Get("baz") { 77 t.Error("o.Get(\"baz\") == true") 78 } 79 o.Delete("foo") 80 if o.String() != "[bar bar]" { 81 t.Errorf("%s != [bar bar]", o.String()) 82 } 83 listOpts := o.GetAll() 84 if len(listOpts) != 2 || listOpts[0] != "bar" || listOpts[1] != "bar" { 85 t.Errorf("Expected [[bar bar]], got [%v]", listOpts) 86 } 87 mapListOpts := o.GetMap() 88 if len(mapListOpts) != 1 { 89 t.Errorf("Expected [map[bar:{}]], got [%v]", mapListOpts) 90 } 91 92 } 93 94 func TestListOptsWithValidator(t *testing.T) { 95 // Re-using logOptsvalidator (used by MapOpts) 96 o := NewListOpts(logOptsValidator) 97 o.Set("foo") 98 if o.String() != "" { 99 t.Errorf(`%s != ""`, o.String()) 100 } 101 o.Set("foo=bar") 102 if o.String() != "" { 103 t.Errorf(`%s != ""`, o.String()) 104 } 105 o.Set("max-file=2") 106 if o.Len() != 1 { 107 t.Errorf("%d != 1", o.Len()) 108 } 109 if !o.Get("max-file=2") { 110 t.Error("o.Get(\"max-file=2\") == false") 111 } 112 if o.Get("baz") { 113 t.Error("o.Get(\"baz\") == true") 114 } 115 o.Delete("max-file=2") 116 if o.String() != "" { 117 t.Errorf(`%s != ""`, o.String()) 118 } 119 } 120 121 //nolint:lll 122 func TestValidateDNSSearch(t *testing.T) { 123 valid := []string{ 124 `.`, 125 `a`, 126 `a.`, 127 `1.foo`, 128 `17.foo`, 129 `foo.bar`, 130 `foo.bar.baz`, 131 `foo.bar.`, 132 `foo.bar.baz`, 133 `foo1.bar2`, 134 `foo1.bar2.baz`, 135 `1foo.2bar.`, 136 `1foo.2bar.baz`, 137 `foo-1.bar-2`, 138 `foo-1.bar-2.baz`, 139 `foo-1.bar-2.`, 140 `foo-1.bar-2.baz`, 141 `1-foo.2-bar`, 142 `1-foo.2-bar.baz`, 143 `1-foo.2-bar.`, 144 `1-foo.2-bar.baz`, 145 } 146 147 invalid := []string{ 148 ``, 149 ` `, 150 ` `, 151 `17`, 152 `17.`, 153 `.17`, 154 `17-.`, 155 `17-.foo`, 156 `.foo`, 157 `foo-.bar`, 158 `-foo.bar`, 159 `foo.bar-`, 160 `foo.bar-.baz`, 161 `foo.-bar`, 162 `foo.-bar.baz`, 163 `foo.bar.baz.this.should.fail.on.long.name.because.it.is.longer.thanisshouldbethis.should.fail.on.long.name.because.it.is.longer.thanisshouldbethis.should.fail.on.long.name.because.it.is.longer.thanisshouldbethis.should.fail.on.long.name.because.it.is.longer.thanisshouldbe`, 164 } 165 166 for _, domain := range valid { 167 if ret, err := ValidateDNSSearch(domain); err != nil || ret == "" { 168 t.Fatalf("ValidateDNSSearch(`"+domain+"`) got %s %s", ret, err) 169 } 170 } 171 172 for _, domain := range invalid { 173 if ret, err := ValidateDNSSearch(domain); err == nil || ret != "" { 174 t.Fatalf("ValidateDNSSearch(`"+domain+"`) got %s %s", ret, err) 175 } 176 } 177 } 178 179 func TestValidateLabel(t *testing.T) { 180 tests := []struct { 181 name string 182 value string 183 expectedErr string 184 }{ 185 { 186 name: "empty", 187 expectedErr: `invalid label '': empty name`, 188 }, 189 { 190 name: "whitespace only ", 191 value: " ", 192 expectedErr: `invalid label ' ': empty name`, 193 }, 194 { 195 name: "whitespace around equal-sign", 196 value: " = ", 197 expectedErr: `invalid label ' = ': empty name`, 198 }, 199 { 200 name: "leading whitespace", 201 value: " label=value", 202 }, 203 { 204 name: "whitespaces in key without value", 205 value: "this is a label without value", 206 expectedErr: `label 'this is a label without value' contains whitespaces`, 207 }, 208 { 209 name: "whitespaces in key", 210 value: "this is a label=value", 211 expectedErr: `label 'this is a label' contains whitespaces`, 212 }, 213 { 214 name: "whitespaces in value", 215 value: "label=a value that has whitespace", 216 }, 217 { 218 name: "trailing whitespace in value", 219 value: "label=value ", 220 }, 221 { 222 name: "leading whitespace in value", 223 value: "label= value", 224 }, 225 { 226 name: "no value", 227 value: "label", 228 }, 229 { 230 name: "no key", 231 value: "=label", 232 expectedErr: `invalid label '=label': empty name`, 233 }, 234 { 235 name: "empty value", 236 value: "label=", 237 }, 238 { 239 name: "key value", 240 value: "key1=value1", 241 }, 242 { 243 name: "double equal-signs", 244 value: "key1=value1=value2", 245 }, 246 { 247 name: "multiple equal-signs", 248 value: "key1=value1=value2=value", 249 }, 250 { 251 name: "double quotes in key and value", 252 value: `key"with"quotes={"hello"}`, 253 }, 254 { 255 name: "double quotes around key and value", 256 value: `"quoted-label"="quoted value"`, 257 }, 258 { 259 name: "single quotes in key and value", 260 value: `key'with'quotes=hello'with'quotes`, 261 }, 262 { 263 name: "single quotes around key and value", 264 value: `'quoted-label'='quoted value''`, 265 }, 266 } 267 268 for _, tc := range tests { 269 tc := tc 270 t.Run(tc.name, func(t *testing.T) { 271 val, err := ValidateLabel(tc.value) 272 if tc.expectedErr != "" { 273 assert.Error(t, err, tc.expectedErr) 274 return 275 } 276 assert.NilError(t, err) 277 assert.Equal(t, val, tc.value) 278 }) 279 } 280 } 281 282 func logOptsValidator(val string) (string, error) { 283 allowedKeys := map[string]string{"max-size": "1", "max-file": "2"} 284 vals := strings.Split(val, "=") 285 if allowedKeys[vals[0]] != "" { 286 return val, nil 287 } 288 return "", fmt.Errorf("invalid key %s", vals[0]) 289 } 290 291 func TestNamedListOpts(t *testing.T) { 292 var v []string 293 o := NewNamedListOptsRef("foo-name", &v, nil) 294 295 o.Set("foo") 296 if o.String() != "[foo]" { 297 t.Errorf("%s != [foo]", o.String()) 298 } 299 if o.Name() != "foo-name" { 300 t.Errorf("%s != foo-name", o.Name()) 301 } 302 if len(v) != 1 { 303 t.Errorf("expected foo to be in the values, got %v", v) 304 } 305 } 306 307 func TestNamedMapOpts(t *testing.T) { 308 tmpMap := make(map[string]string) 309 o := NewNamedMapOpts("max-name", tmpMap, nil) 310 311 o.Set("max-size=1") 312 if o.String() != "map[max-size:1]" { 313 t.Errorf("%s != [map[max-size:1]", o.String()) 314 } 315 if o.Name() != "max-name" { 316 t.Errorf("%s != max-name", o.Name()) 317 } 318 if _, exist := tmpMap["max-size"]; !exist { 319 t.Errorf("expected map-size to be in the values, got %v", tmpMap) 320 } 321 } 322 323 func TestValidateMACAddress(t *testing.T) { 324 if _, err := ValidateMACAddress(`92:d0:c6:0a:29:33`); err != nil { 325 t.Fatalf("ValidateMACAddress(`92:d0:c6:0a:29:33`) got %s", err) 326 } 327 328 if _, err := ValidateMACAddress(`92:d0:c6:0a:33`); err == nil { 329 t.Fatalf("ValidateMACAddress(`92:d0:c6:0a:33`) succeeded; expected failure on invalid MAC") 330 } 331 332 if _, err := ValidateMACAddress(`random invalid string`); err == nil { 333 t.Fatalf("ValidateMACAddress(`random invalid string`) succeeded; expected failure on invalid MAC") 334 } 335 } 336 337 func TestValidateLink(t *testing.T) { 338 valid := []string{ 339 "name", 340 "dcdfbe62ecd0:alias", 341 "7a67485460b7642516a4ad82ecefe7f57d0c4916f530561b71a50a3f9c4e33da", 342 "angry_torvalds:linus", 343 } 344 invalid := map[string]string{ 345 "": "empty string specified for links", 346 "too:much:of:it": "bad format for links: too:much:of:it", 347 } 348 349 for _, link := range valid { 350 if _, err := ValidateLink(link); err != nil { 351 t.Fatalf("ValidateLink(`%q`) should succeed: error %q", link, err) 352 } 353 } 354 355 for link, expectedError := range invalid { 356 if _, err := ValidateLink(link); err == nil { 357 t.Fatalf("ValidateLink(`%q`) should have failed validation", link) 358 } else { 359 if !strings.Contains(err.Error(), expectedError) { 360 t.Fatalf("ValidateLink(`%q`) error should contain %q", link, expectedError) 361 } 362 } 363 } 364 } 365 366 func TestParseLink(t *testing.T) { 367 name, alias, err := ParseLink("name:alias") 368 if err != nil { 369 t.Fatalf("Expected not to error out on a valid name:alias format but got: %v", err) 370 } 371 if name != "name" { 372 t.Fatalf("Link name should have been name, got %s instead", name) 373 } 374 if alias != "alias" { 375 t.Fatalf("Link alias should have been alias, got %s instead", alias) 376 } 377 // short format definition 378 name, alias, err = ParseLink("name") 379 if err != nil { 380 t.Fatalf("Expected not to error out on a valid name only format but got: %v", err) 381 } 382 if name != "name" { 383 t.Fatalf("Link name should have been name, got %s instead", name) 384 } 385 if alias != "name" { 386 t.Fatalf("Link alias should have been name, got %s instead", alias) 387 } 388 // empty string link definition is not allowed 389 if _, _, err := ParseLink(""); err == nil || !strings.Contains(err.Error(), "empty string specified for links") { 390 t.Fatalf("Expected error 'empty string specified for links' but got: %v", err) 391 } 392 // more than two colons are not allowed 393 if _, _, err := ParseLink("link:alias:wrong"); err == nil || !strings.Contains(err.Error(), "bad format for links: link:alias:wrong") { 394 t.Fatalf("Expected error 'bad format for links: link:alias:wrong' but got: %v", err) 395 } 396 }