github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/version/version_test.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package version 18 19 import ( 20 "fmt" 21 "reflect" 22 "testing" 23 ) 24 25 type testItem struct { 26 version string 27 unparsed string 28 equalsPrev bool 29 } 30 31 func testOne(v *Version, item, prev testItem) error { 32 str := v.String() 33 if item.unparsed == "" { 34 if str != item.version { 35 return fmt.Errorf("bad round-trip: %q -> %q", item.version, str) 36 } 37 } else { 38 if str != item.unparsed { 39 return fmt.Errorf("bad unparse: %q -> %q, expected %q", item.version, str, item.unparsed) 40 } 41 } 42 43 if prev.version != "" { 44 cmp, err := v.Compare(prev.version) 45 if err != nil { 46 return fmt.Errorf("unexpected parse error: %v", err) 47 } 48 rv, err := parse(prev.version, v.semver) 49 if err != nil { 50 return fmt.Errorf("unexpected parse error: %v", err) 51 } 52 rcmp, err := rv.Compare(item.version) 53 if err != nil { 54 return fmt.Errorf("unexpected parse error: %v", err) 55 } 56 57 switch { 58 case cmp == -1: 59 return fmt.Errorf("unexpected ordering %q < %q", item.version, prev.version) 60 case cmp == 0 && !item.equalsPrev: 61 return fmt.Errorf("unexpected comparison %q == %q", item.version, prev.version) 62 case cmp == 1 && item.equalsPrev: 63 return fmt.Errorf("unexpected comparison %q != %q", item.version, prev.version) 64 case cmp != -rcmp: 65 return fmt.Errorf("unexpected reverse comparison %q <=> %q %v %v %v %v", item.version, prev.version, cmp, rcmp, v.Components(), rv.Components()) 66 } 67 } 68 69 return nil 70 } 71 72 func TestSemanticVersions(t *testing.T) { 73 tests := []testItem{ 74 // This is every version string that appears in the 2.0 semver spec, 75 // sorted in strictly increasing order except as noted. 76 {version: "0.1.0"}, 77 {version: "1.0.0-0.3.7"}, 78 {version: "1.0.0-alpha"}, 79 {version: "1.0.0-alpha+001", equalsPrev: true}, 80 {version: "1.0.0-alpha.1"}, 81 {version: "1.0.0-alpha.beta"}, 82 {version: "1.0.0-beta"}, 83 {version: "1.0.0-beta+exp.sha.5114f85", equalsPrev: true}, 84 {version: "1.0.0-beta.2"}, 85 {version: "1.0.0-beta.11"}, 86 {version: "1.0.0-rc.1"}, 87 {version: "1.0.0-x.7.z.92"}, 88 {version: "1.0.0"}, 89 {version: "1.0.0+20130313144700", equalsPrev: true}, 90 {version: "1.8.0-alpha.3"}, 91 {version: "1.8.0-alpha.3.673+73326ef01d2d7c"}, 92 {version: "1.9.0"}, 93 {version: "1.10.0"}, 94 {version: "1.11.0"}, 95 {version: "2.0.0"}, 96 {version: "2.1.0"}, 97 {version: "2.1.1"}, 98 {version: "42.0.0"}, 99 100 // We also allow whitespace and "v" prefix 101 {version: " 42.0.0", unparsed: "42.0.0", equalsPrev: true}, 102 {version: "\t42.0.0 ", unparsed: "42.0.0", equalsPrev: true}, 103 {version: "43.0.0-1", unparsed: "43.0.0-1"}, 104 {version: "43.0.0-1 ", unparsed: "43.0.0-1", equalsPrev: true}, 105 {version: "v43.0.0-1", unparsed: "43.0.0-1", equalsPrev: true}, 106 {version: " v43.0.0", unparsed: "43.0.0"}, 107 {version: " 43.0.0 ", unparsed: "43.0.0", equalsPrev: true}, 108 } 109 110 var prev testItem 111 for _, item := range tests { 112 v, err := ParseSemantic(item.version) 113 if err != nil { 114 t.Errorf("unexpected parse error: %v", err) 115 continue 116 } 117 err = testOne(v, item, prev) 118 if err != nil { 119 t.Errorf("%v", err) 120 } 121 prev = item 122 } 123 } 124 125 func TestBadSemanticVersions(t *testing.T) { 126 tests := []string{ 127 // "MUST take the form X.Y.Z" 128 "1", 129 "1.2", 130 "1.2.3.4", 131 ".2.3", 132 "1..3", 133 "1.2.", 134 "", 135 "..", 136 // "where X, Y, and Z are non-negative integers" 137 "-1.2.3", 138 "1.-2.3", 139 "1.2.-3", 140 "1a.2.3", 141 "1.2a.3", 142 "1.2.3a", 143 "a1.2.3", 144 "a.b.c", 145 "1 .2.3", 146 "1. 2.3", 147 // "and MUST NOT contain leading zeroes." 148 "01.2.3", 149 "1.02.3", 150 "1.2.03", 151 // "[pre-release] identifiers MUST comprise only ASCII alphanumerics and hyphen" 152 "1.2.3-/", 153 // "[pre-release] identifiers MUST NOT be empty" 154 "1.2.3-", 155 "1.2.3-.", 156 "1.2.3-foo.", 157 "1.2.3-.foo", 158 // "Numeric [pre-release] identifiers MUST NOT include leading zeroes" 159 "1.2.3-01", 160 // "[build metadata] identifiers MUST comprise only ASCII alphanumerics and hyphen" 161 "1.2.3+/", 162 // "[build metadata] identifiers MUST NOT be empty" 163 "1.2.3+", 164 "1.2.3+.", 165 "1.2.3+foo.", 166 "1.2.3+.foo", 167 168 // whitespace/"v"-prefix checks 169 "v 1.2.3", 170 "vv1.2.3", 171 } 172 173 for i := range tests { 174 _, err := ParseSemantic(tests[i]) 175 if err == nil { 176 t.Errorf("unexpected success parsing invalid semver %q", tests[i]) 177 } 178 } 179 } 180 181 func TestGenericVersions(t *testing.T) { 182 tests := []testItem{ 183 // This is all of the strings from TestSemanticVersions, plus some strings 184 // from TestBadSemanticVersions that should parse as generic versions, 185 // plus some additional strings. 186 {version: "0.1.0", unparsed: "0.1.0"}, 187 {version: "1.0.0-0.3.7", unparsed: "1.0.0"}, 188 {version: "1.0.0-alpha", unparsed: "1.0.0", equalsPrev: true}, 189 {version: "1.0.0-alpha+001", unparsed: "1.0.0", equalsPrev: true}, 190 {version: "1.0.0-alpha.1", unparsed: "1.0.0", equalsPrev: true}, 191 {version: "1.0.0-alpha.beta", unparsed: "1.0.0", equalsPrev: true}, 192 {version: "1.0.0.beta", unparsed: "1.0.0", equalsPrev: true}, 193 {version: "1.0.0-beta+exp.sha.5114f85", unparsed: "1.0.0", equalsPrev: true}, 194 {version: "1.0.0.beta.2", unparsed: "1.0.0", equalsPrev: true}, 195 {version: "1.0.0.beta.11", unparsed: "1.0.0", equalsPrev: true}, 196 {version: "1.0.0.rc.1", unparsed: "1.0.0", equalsPrev: true}, 197 {version: "1.0.0-x.7.z.92", unparsed: "1.0.0", equalsPrev: true}, 198 {version: "1.0.0", unparsed: "1.0.0", equalsPrev: true}, 199 {version: "1.0.0+20130313144700", unparsed: "1.0.0", equalsPrev: true}, 200 {version: "1.2", unparsed: "1.2"}, 201 {version: "1.2a.3", unparsed: "1.2", equalsPrev: true}, 202 {version: "1.2.3", unparsed: "1.2.3"}, 203 {version: "1.2.3.0", unparsed: "1.2.3.0", equalsPrev: true}, 204 {version: "1.2.3a", unparsed: "1.2.3", equalsPrev: true}, 205 {version: "1.2.3-foo.", unparsed: "1.2.3", equalsPrev: true}, 206 {version: "1.2.3-.foo", unparsed: "1.2.3", equalsPrev: true}, 207 {version: "1.2.3-01", unparsed: "1.2.3", equalsPrev: true}, 208 {version: "1.2.3+", unparsed: "1.2.3", equalsPrev: true}, 209 {version: "1.2.3+foo.", unparsed: "1.2.3", equalsPrev: true}, 210 {version: "1.2.3+.foo", unparsed: "1.2.3", equalsPrev: true}, 211 {version: "1.02.3", unparsed: "1.2.3", equalsPrev: true}, 212 {version: "1.2.03", unparsed: "1.2.3", equalsPrev: true}, 213 {version: "1.2.003", unparsed: "1.2.3", equalsPrev: true}, 214 {version: "1.2.3.4", unparsed: "1.2.3.4"}, 215 {version: "1.2.3.4b3", unparsed: "1.2.3.4", equalsPrev: true}, 216 {version: "1.2.3.4.5", unparsed: "1.2.3.4.5"}, 217 {version: "1.9.0", unparsed: "1.9.0"}, 218 {version: "1.9.0.0.0.0.0.0", unparsed: "1.9.0.0.0.0.0.0", equalsPrev: true}, 219 {version: "1.10.0", unparsed: "1.10.0"}, 220 {version: "1.11.0", unparsed: "1.11.0"}, 221 {version: "1.11.0.0.5", unparsed: "1.11.0.0.5"}, 222 {version: "2.0.0", unparsed: "2.0.0"}, 223 {version: "2.1.0", unparsed: "2.1.0"}, 224 {version: "2.1.1", unparsed: "2.1.1"}, 225 {version: "42.0.0", unparsed: "42.0.0"}, 226 {version: " 42.0.0", unparsed: "42.0.0", equalsPrev: true}, 227 {version: "\t42.0.0 ", unparsed: "42.0.0", equalsPrev: true}, 228 {version: "42.0.0-1", unparsed: "42.0.0", equalsPrev: true}, 229 {version: "42.0.0-1 ", unparsed: "42.0.0", equalsPrev: true}, 230 {version: "v42.0.0-1", unparsed: "42.0.0", equalsPrev: true}, 231 {version: " v43.0.0", unparsed: "43.0.0"}, 232 {version: " 43.0.0 ", unparsed: "43.0.0", equalsPrev: true}, 233 } 234 235 var prev testItem 236 for _, item := range tests { 237 v, err := ParseGeneric(item.version) 238 if err != nil { 239 t.Errorf("unexpected parse error: %v", err) 240 continue 241 } 242 err = testOne(v, item, prev) 243 if err != nil { 244 t.Errorf("%v", err) 245 } 246 prev = item 247 } 248 } 249 250 func TestBadGenericVersions(t *testing.T) { 251 tests := []string{ 252 "1", 253 "01.2.3", 254 "-1.2.3", 255 "1.-2.3", 256 ".2.3", 257 "1..3", 258 "1a.2.3", 259 "a1.2.3", 260 "1 .2.3", 261 "1. 2.3", 262 "1.bob", 263 "bob", 264 "v 1.2.3", 265 "vv1.2.3", 266 "", 267 ".", 268 } 269 270 for i := range tests { 271 _, err := ParseGeneric(tests[i]) 272 if err == nil { 273 t.Errorf("unexpected success parsing invalid version %q", tests[i]) 274 } 275 } 276 } 277 278 func TestComponents(t *testing.T) { 279 280 var tests = []struct { 281 version string 282 semver bool 283 expectedComponents []uint 284 expectedMajor uint 285 expectedMinor uint 286 expectedPatch uint 287 expectedPreRelease string 288 expectedBuildMetadata string 289 }{ 290 { 291 version: "1.0.2", 292 semver: true, 293 expectedComponents: []uint{1, 0, 2}, 294 expectedMajor: 1, 295 expectedMinor: 0, 296 expectedPatch: 2, 297 }, 298 { 299 version: "1.0.2-alpha+001", 300 semver: true, 301 expectedComponents: []uint{1, 0, 2}, 302 expectedMajor: 1, 303 expectedMinor: 0, 304 expectedPatch: 2, 305 expectedPreRelease: "alpha", 306 expectedBuildMetadata: "001", 307 }, 308 { 309 version: "1.2", 310 semver: false, 311 expectedComponents: []uint{1, 2}, 312 expectedMajor: 1, 313 expectedMinor: 2, 314 }, 315 { 316 version: "1.0.2-beta+exp.sha.5114f85", 317 semver: true, 318 expectedComponents: []uint{1, 0, 2}, 319 expectedMajor: 1, 320 expectedMinor: 0, 321 expectedPatch: 2, 322 expectedPreRelease: "beta", 323 expectedBuildMetadata: "exp.sha.5114f85", 324 }, 325 } 326 327 for _, test := range tests { 328 version, _ := parse(test.version, test.semver) 329 if !reflect.DeepEqual(test.expectedComponents, version.Components()) { 330 t.Error("parse returned un'expected components") 331 } 332 if test.expectedMajor != version.Major() { 333 t.Errorf("parse returned version.Major %d, expected %d", test.expectedMajor, version.Major()) 334 } 335 if test.expectedMinor != version.Minor() { 336 t.Errorf("parse returned version.Minor %d, expected %d", test.expectedMinor, version.Minor()) 337 } 338 if test.expectedPatch != version.Patch() { 339 t.Errorf("parse returned version.Patch %d, expected %d", test.expectedPatch, version.Patch()) 340 } 341 if test.expectedPreRelease != version.PreRelease() { 342 t.Errorf("parse returned version.PreRelease %s, expected %s", test.expectedPreRelease, version.PreRelease()) 343 } 344 if test.expectedBuildMetadata != version.BuildMetadata() { 345 t.Errorf("parse returned version.BuildMetadata %s, expected %s", test.expectedBuildMetadata, version.BuildMetadata()) 346 } 347 } 348 }