| // Copyright 2023 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package versions_test | |
| import ( | |
| "go/ast" | |
| "go/parser" | |
| "go/token" | |
| "go/types" | |
| "testing" | |
| "golang.org/x/tools/internal/versions" | |
| ) | |
| func TestIsValid(t *testing.T) { | |
| // valid versions | |
| for _, x := range []string{ | |
| "go1.21", | |
| "go1.21.2", | |
| "go1.21rc", | |
| "go1.21rc2", | |
| "go0.0", // ?? | |
| "go1", | |
| "go2", | |
| "go1.20.0-bigcorp", | |
| } { | |
| if !versions.IsValid(x) { | |
| t.Errorf("expected versions.IsValid(%q) to hold", x) | |
| } | |
| } | |
| // invalid versions | |
| for _, x := range []string{ | |
| "", | |
| "bad", | |
| "1.21", | |
| "v1.21", | |
| "go", | |
| "goAA", | |
| "go2_3", | |
| "go1.BB", | |
| "go1.21.", | |
| "go1.21.2_2", | |
| "go1.21rc_2", | |
| "go1.21rc2_", | |
| "go1.600+auto", | |
| } { | |
| if versions.IsValid(x) { | |
| t.Errorf("expected versions.IsValid(%q) to not hold", x) | |
| } | |
| } | |
| } | |
| func TestVersionComparisons(t *testing.T) { | |
| for _, item := range []struct { | |
| x, y string | |
| want int | |
| }{ | |
| // All comparisons of go2, go1.21.2, go1.21rc2, go1.21rc, go1, go0.0, "", bad | |
| {"go2", "go2", 0}, | |
| {"go2", "go1.21.2", +1}, | |
| {"go2", "go1.21rc2", +1}, | |
| {"go2", "go1.21rc", +1}, | |
| {"go2", "go1.21", +1}, | |
| {"go2", "go1", +1}, | |
| {"go2", "go0.0", +1}, | |
| {"go2", "", +1}, | |
| {"go2", "bad", +1}, | |
| {"go1.21.2", "go1.21.2", 0}, | |
| {"go1.21.2", "go1.21rc2", +1}, | |
| {"go1.21.2", "go1.21rc", +1}, | |
| {"go1.21.2", "go1.21", +1}, | |
| {"go1.21.2", "go1", +1}, | |
| {"go1.21.2", "go0.0", +1}, | |
| {"go1.21.2", "", +1}, | |
| {"go1.21.2", "bad", +1}, | |
| {"go1.21rc2", "go1.21rc2", 0}, | |
| {"go1.21rc2", "go1.21rc", +1}, | |
| {"go1.21rc2", "go1.21", +1}, | |
| {"go1.21rc2", "go1", +1}, | |
| {"go1.21rc2", "go0.0", +1}, | |
| {"go1.21rc2", "", +1}, | |
| {"go1.21rc2", "bad", +1}, | |
| {"go1.21rc", "go1.21rc", 0}, | |
| {"go1.21rc", "go1.21", +1}, | |
| {"go1.21rc", "go1", +1}, | |
| {"go1.21rc", "go0.0", +1}, | |
| {"go1.21rc", "", +1}, | |
| {"go1.21rc", "bad", +1}, | |
| {"go1.21", "go1.21", 0}, | |
| {"go1.21", "go1", +1}, | |
| {"go1.21", "go0.0", +1}, | |
| {"go1.21", "", +1}, | |
| {"go1.21", "bad", +1}, | |
| {"go1", "go1", 0}, | |
| {"go1", "go0.0", +1}, | |
| {"go1", "", +1}, | |
| {"go1", "bad", +1}, | |
| {"go0.0", "go0.0", 0}, | |
| {"go0.0", "", +1}, | |
| {"go0.0", "bad", +1}, | |
| {"", "", 0}, | |
| {"", "bad", 0}, | |
| {"bad", "bad", 0}, | |
| // Other tests. | |
| {"go1.20", "go1.20.0-bigcorp", 0}, | |
| {"go1.21", "go1.21.0-bigcorp", -1}, // Starting in Go 1.21, patch missing is different from explicit .0. | |
| {"go1.21.0", "go1.21.0-bigcorp", 0}, // Starting in Go 1.21, patch missing is different from explicit .0. | |
| {"go1.19rc1", "go1.19", -1}, | |
| } { | |
| got := versions.Compare(item.x, item.y) | |
| if got != item.want { | |
| t.Errorf("versions.Compare(%q, %q)=%d. expected %d", item.x, item.y, got, item.want) | |
| } | |
| reverse := versions.Compare(item.y, item.x) | |
| if reverse != -got { | |
| t.Errorf("versions.Compare(%q, %q)=%d. expected %d", item.y, item.x, reverse, -got) | |
| } | |
| } | |
| } | |
| func TestLang(t *testing.T) { | |
| for _, item := range []struct { | |
| x string | |
| want string | |
| }{ | |
| // valid | |
| {"go1.21rc2", "go1.21"}, | |
| {"go1.21.2", "go1.21"}, | |
| {"go1.21", "go1.21"}, | |
| {"go1", "go1"}, | |
| // invalid | |
| {"bad", ""}, | |
| {"1.21", ""}, | |
| } { | |
| if got := versions.Lang(item.x); got != item.want { | |
| t.Errorf("versions.Lang(%q)=%q. expected %q", item.x, got, item.want) | |
| } | |
| } | |
| } | |
| func TestKnown(t *testing.T) { | |
| for _, v := range [...]string{ | |
| versions.Go1_18, | |
| versions.Go1_19, | |
| versions.Go1_20, | |
| versions.Go1_21, | |
| versions.Go1_22, | |
| } { | |
| if !versions.IsValid(v) { | |
| t.Errorf("Expected known version %q to be valid.", v) | |
| } | |
| if v != versions.Lang(v) { | |
| t.Errorf("Expected known version %q == Lang(%q).", v, versions.Lang(v)) | |
| } | |
| } | |
| } | |
| func TestAtLeast(t *testing.T) { | |
| for _, item := range [...]struct { | |
| v, release string | |
| want bool | |
| }{ | |
| {versions.Future, versions.Go1_22, true}, | |
| {versions.Go1_22, versions.Go1_22, true}, | |
| {"go1.21", versions.Go1_22, false}, | |
| {"invalid", versions.Go1_22, false}, | |
| } { | |
| if got := versions.AtLeast(item.v, item.release); got != item.want { | |
| t.Errorf("AtLeast(%q, %q)=%v. wanted %v", item.v, item.release, got, item.want) | |
| } | |
| } | |
| } | |
| func TestBefore(t *testing.T) { | |
| for _, item := range [...]struct { | |
| v, release string | |
| want bool | |
| }{ | |
| {versions.Future, versions.Go1_22, false}, | |
| {versions.Go1_22, versions.Go1_22, false}, | |
| {"go1.21", versions.Go1_22, true}, | |
| {"invalid", versions.Go1_22, true}, // invalid < Go1_22 | |
| } { | |
| if got := versions.Before(item.v, item.release); got != item.want { | |
| t.Errorf("Before(%q, %q)=%v. wanted %v", item.v, item.release, got, item.want) | |
| } | |
| } | |
| } | |
| func TestFileVersions(t *testing.T) { | |
| const source = ` | |
| package P | |
| ` | |
| fset := token.NewFileSet() | |
| f, err := parser.ParseFile(fset, "hello.go", source, 0) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| for _, conf := range []types.Config{ | |
| {GoVersion: versions.Go1_22}, | |
| {}, // GoVersion is unset. | |
| } { | |
| info := &types.Info{ | |
| FileVersions: make(map[*ast.File]string), | |
| } | |
| _, err = conf.Check("P", fset, []*ast.File{f}, info) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| v := versions.FileVersion(info, f) | |
| if !versions.AtLeast(v, versions.Go1_22) { | |
| t.Errorf("versions.AtLeast(%q, %q) expected to hold", v, versions.Go1_22) | |
| } | |
| if versions.Before(v, versions.Go1_22) { | |
| t.Errorf("versions.AtLeast(%q, %q) expected to be false", v, versions.Go1_22) | |
| } | |
| if conf.GoVersion == "" && v != versions.Future { | |
| t.Error("Expected the FileVersion to be the Future when conf.GoVersion is unset") | |
| } | |
| } | |
| } |