зеркало из https://github.com/golang/dep.git
419 строки
10 KiB
Go
419 строки
10 KiB
Go
// Copyright 2017 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 gps
|
|
|
|
import (
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/golang/dep/internal/gps/pkgtree"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var testAnalyzerInfo = ProjectAnalyzerInfo{
|
|
Name: "test-analyzer",
|
|
Version: 1,
|
|
}
|
|
|
|
func TestSingleSourceCache(t *testing.T) {
|
|
const root = "example.com/test"
|
|
|
|
t.Run("info", func(t *testing.T) {
|
|
const rev Revision = "revision"
|
|
|
|
c := newMemoryCache()
|
|
|
|
var m Manifest = &cachedManifest{
|
|
constraints: ProjectConstraints{
|
|
ProjectRoot("foo"): ProjectProperties{},
|
|
ProjectRoot("bar"): ProjectProperties{
|
|
Source: "whatever",
|
|
Constraint: testSemverConstraint(t, "> 1.3"),
|
|
},
|
|
},
|
|
overrides: ProjectConstraints{
|
|
ProjectRoot("b"): ProjectProperties{
|
|
Constraint: NewVersion("2.0.0"),
|
|
},
|
|
},
|
|
ignored: map[string]bool{
|
|
"a": true,
|
|
"b": true,
|
|
},
|
|
required: map[string]bool{
|
|
"c": true,
|
|
"d": true,
|
|
},
|
|
}
|
|
var l Lock = &cachedLock{
|
|
inputHash: []byte("test_hash"),
|
|
projects: []LockedProject{
|
|
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), []string{"gps"}),
|
|
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), nil),
|
|
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), []string{"gps", "flugle"}),
|
|
NewLockedProject(mkPI("foo"), NewVersion("nada"), []string{"foo"}),
|
|
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0"), []string{"flugle", "gps"}),
|
|
},
|
|
}
|
|
c.setManifestAndLock(rev, testAnalyzerInfo, m, l)
|
|
|
|
gotM, gotL, ok := c.getManifestAndLock(rev, testAnalyzerInfo)
|
|
if !ok {
|
|
t.Error("no manifest and lock found for revision")
|
|
}
|
|
compareManifests(t, m, gotM)
|
|
if dl := DiffLocks(l, gotL); dl != nil {
|
|
t.Errorf("lock differences:\n\t %#v", dl)
|
|
}
|
|
|
|
m = &cachedManifest{
|
|
constraints: ProjectConstraints{
|
|
ProjectRoot("foo"): ProjectProperties{
|
|
Source: "whatever",
|
|
},
|
|
},
|
|
overrides: ProjectConstraints{
|
|
ProjectRoot("bar"): ProjectProperties{
|
|
Constraint: NewVersion("2.0.0"),
|
|
},
|
|
},
|
|
ignored: map[string]bool{
|
|
"c": true,
|
|
"d": true,
|
|
},
|
|
required: map[string]bool{
|
|
"a": true,
|
|
"b": true,
|
|
},
|
|
}
|
|
l = &cachedLock{
|
|
inputHash: []byte("different_test_hash"),
|
|
projects: []LockedProject{
|
|
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.10.0").Pair("278a227dfc3d595a33a77ff3f841fd8ca1bc8cd0"), []string{"gps"}),
|
|
NewLockedProject(mkPI("github.com/sdboyer/gps"), NewVersion("v0.11.0"), []string{"gps"}),
|
|
NewLockedProject(mkPI("github.com/sdboyer/gps"), Revision("278a227dfc3d595a33a77ff3f841fd8ca1bc8cd0"), []string{"gps"}),
|
|
},
|
|
}
|
|
c.setManifestAndLock(rev, testAnalyzerInfo, m, l)
|
|
|
|
gotM, gotL, ok = c.getManifestAndLock(rev, testAnalyzerInfo)
|
|
if !ok {
|
|
t.Error("no manifest and lock found for revision")
|
|
}
|
|
compareManifests(t, m, gotM)
|
|
if dl := DiffLocks(l, gotL); dl != nil {
|
|
t.Errorf("lock differences:\n\t %#v", dl)
|
|
}
|
|
})
|
|
|
|
t.Run("pkgTree", func(t *testing.T) {
|
|
c := newMemoryCache()
|
|
|
|
const rev Revision = "rev_adsfjkl"
|
|
|
|
if got, ok := c.getPackageTree(rev); ok {
|
|
t.Fatalf("unexpected result before setting package tree: %v", got)
|
|
}
|
|
|
|
pt := pkgtree.PackageTree{
|
|
ImportRoot: root,
|
|
Packages: map[string]pkgtree.PackageOrErr{
|
|
"simple": {
|
|
P: pkgtree.Package{
|
|
ImportPath: "simple",
|
|
CommentPath: "comment",
|
|
Name: "simple",
|
|
Imports: []string{
|
|
"github.com/golang/dep/internal/gps",
|
|
"sort",
|
|
},
|
|
},
|
|
},
|
|
"m1p": {
|
|
P: pkgtree.Package{
|
|
ImportPath: "m1p",
|
|
CommentPath: "",
|
|
Name: "m1p",
|
|
Imports: []string{
|
|
"github.com/golang/dep/internal/gps",
|
|
"os",
|
|
"sort",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
c.setPackageTree(rev, pt)
|
|
|
|
got, ok := c.getPackageTree(rev)
|
|
if !ok {
|
|
t.Errorf("no package tree found:\n\t(WNT): %#v", pt)
|
|
}
|
|
comparePackageTree(t, pt, got)
|
|
|
|
pt = pkgtree.PackageTree{
|
|
ImportRoot: root,
|
|
Packages: map[string]pkgtree.PackageOrErr{
|
|
"test": {
|
|
Err: errors.New("error"),
|
|
},
|
|
},
|
|
}
|
|
c.setPackageTree(rev, pt)
|
|
|
|
got, ok = c.getPackageTree(rev)
|
|
if !ok {
|
|
t.Errorf("no package tree found:\n\t(WNT): %#v", pt)
|
|
}
|
|
comparePackageTree(t, pt, got)
|
|
})
|
|
|
|
t.Run("versions", func(t *testing.T) {
|
|
c := newMemoryCache()
|
|
|
|
const rev1, rev2 = "rev1", "rev2"
|
|
const br, ver = "branch_name", "2.10"
|
|
versions := []PairedVersion{
|
|
NewBranch(br).Pair(rev1),
|
|
NewVersion(ver).Pair(rev2),
|
|
}
|
|
SortPairedForDowngrade(versions)
|
|
c.setVersionMap(versions)
|
|
|
|
t.Run("getAllVersions", func(t *testing.T) {
|
|
got := c.getAllVersions()
|
|
if len(got) != len(versions) {
|
|
t.Errorf("unexpected versions:\n\t(GOT): %#v\n\t(WNT): %#v", got, versions)
|
|
} else {
|
|
SortPairedForDowngrade(got)
|
|
for i := range versions {
|
|
if !versions[i].identical(got[i]) {
|
|
t.Errorf("unexpected versions:\n\t(GOT): %#v\n\t(WNT): %#v", got, versions)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
revToUV := map[Revision]UnpairedVersion{
|
|
rev1: NewBranch(br),
|
|
rev2: NewVersion(ver),
|
|
}
|
|
|
|
t.Run("getVersionsFor", func(t *testing.T) {
|
|
for rev, want := range revToUV {
|
|
rev, want := rev, want
|
|
t.Run(string(rev), func(t *testing.T) {
|
|
uvs, ok := c.getVersionsFor(rev)
|
|
if !ok {
|
|
t.Errorf("no version found:\n\t(WNT) %#v", want)
|
|
} else if len(uvs) != 1 {
|
|
t.Errorf("expected one result but got %d", len(uvs))
|
|
} else {
|
|
uv := uvs[0]
|
|
if uv.Type() != want.Type() {
|
|
t.Errorf("expected version type %d but got %d", want.Type(), uv.Type())
|
|
}
|
|
if uv.String() != want.String() {
|
|
t.Errorf("expected version %q but got %q", want.String(), uv.String())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("getRevisionFor", func(t *testing.T) {
|
|
for want, uv := range revToUV {
|
|
want, uv := want, uv
|
|
t.Run(uv.String(), func(t *testing.T) {
|
|
rev, ok := c.getRevisionFor(uv)
|
|
if !ok {
|
|
t.Errorf("expected revision %q but got none", want)
|
|
} else if rev != want {
|
|
t.Errorf("expected revision %q but got %q", want, rev)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("toRevision", func(t *testing.T) {
|
|
for want, uv := range revToUV {
|
|
want, uv := want, uv
|
|
t.Run(uv.String(), func(t *testing.T) {
|
|
rev, ok := c.toRevision(uv)
|
|
if !ok {
|
|
t.Errorf("expected revision %q but got none", want)
|
|
} else if rev != want {
|
|
t.Errorf("expected revision %q but got %q", want, rev)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("toUnpaired", func(t *testing.T) {
|
|
for rev, want := range revToUV {
|
|
rev, want := rev, want
|
|
t.Run(want.String(), func(t *testing.T) {
|
|
uv, ok := c.toUnpaired(rev)
|
|
if !ok {
|
|
t.Errorf("no UnpairedVersion found:\n\t(WNT): %#v", uv)
|
|
} else if !uv.identical(want) {
|
|
t.Errorf("unexpected UnpairedVersion:\n\t(GOT): %#v\n\t(WNT): %#v", uv, want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// compareManifests compares two manifests and reports differences as test errors.
|
|
func compareManifests(t *testing.T, want, got Manifest) {
|
|
{
|
|
want, got := want.DependencyConstraints(), got.DependencyConstraints()
|
|
if !projectConstraintsEqual(want, got) {
|
|
t.Errorf("unexpected constraints:\n\t(GOT): %#v\n\t(WNT): %#v", got, want)
|
|
}
|
|
}
|
|
|
|
wantRM, wantOK := want.(RootManifest)
|
|
gotRM, gotOK := got.(RootManifest)
|
|
if wantOK && !gotOK {
|
|
t.Errorf("expected RootManifest:\n\t(GOT): %#v", got)
|
|
return
|
|
}
|
|
if gotOK && !wantOK {
|
|
t.Errorf("didn't expected RootManifest:\n\t(GOT): %#v", got)
|
|
return
|
|
}
|
|
|
|
{
|
|
want, got := wantRM.IgnoredPackages(), gotRM.IgnoredPackages()
|
|
if !mapStringBoolEqual(want, got) {
|
|
t.Errorf("unexpected ignored packages:\n\t(GOT): %#v\n\t(WNT): %#v", got, want)
|
|
}
|
|
}
|
|
|
|
{
|
|
want, got := wantRM.Overrides(), gotRM.Overrides()
|
|
if !projectConstraintsEqual(want, got) {
|
|
t.Errorf("unexpected overrides:\n\t(GOT): %#v\n\t(WNT): %#v", got, want)
|
|
}
|
|
}
|
|
|
|
{
|
|
want, got := wantRM.RequiredPackages(), gotRM.RequiredPackages()
|
|
if !mapStringBoolEqual(want, got) {
|
|
t.Errorf("unexpected required packages:\n\t(GOT): %#v\n\t(WNT): %#v", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// comparePackageTree compares two pkgtree.PackageTree and reports differences as test errors.
|
|
func comparePackageTree(t *testing.T, want, got pkgtree.PackageTree) {
|
|
if got.ImportRoot != want.ImportRoot {
|
|
t.Errorf("expected package tree root %q but got %q", want.ImportRoot, got.ImportRoot)
|
|
}
|
|
{
|
|
want, got := want.Packages, got.Packages
|
|
if len(want) != len(got) {
|
|
t.Errorf("unexpected packages:\n\t(GOT): %#v\n\t(WNT): %#v", got, want)
|
|
} else {
|
|
for k, v := range want {
|
|
if v2, ok := got[k]; !ok {
|
|
t.Errorf("key %q: expected %v but got none", k, v)
|
|
} else if !packageOrErrEqual(v, v2) {
|
|
t.Errorf("key %q: expected %v but got %v", k, v, v2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func projectConstraintsEqual(want, got ProjectConstraints) bool {
|
|
loop, check := want, got
|
|
if len(got) > len(want) {
|
|
loop, check = got, want
|
|
}
|
|
for pr, pp := range loop {
|
|
pp2, ok := check[pr]
|
|
if !ok {
|
|
return false
|
|
}
|
|
if pp.Source != pp2.Source {
|
|
return false
|
|
}
|
|
if pp.Constraint == nil || pp2.Constraint == nil {
|
|
if pp.Constraint != nil || pp2.Constraint != nil {
|
|
return false
|
|
}
|
|
} else if !pp.Constraint.identical(pp2.Constraint) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func mapStringBoolEqual(exp, got map[string]bool) bool {
|
|
loop, check := exp, got
|
|
if len(got) > len(exp) {
|
|
loop, check = got, exp
|
|
}
|
|
for k, v := range loop {
|
|
v2, ok := check[k]
|
|
if !ok || v != v2 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func safeError(err error) string {
|
|
if err == nil {
|
|
return ""
|
|
}
|
|
return err.Error()
|
|
}
|
|
|
|
// packageOrErrEqual return true if the pkgtree.PackageOrErrs are equal. Error equality is
|
|
// string based. Imports and TestImports are treated as sets, and will be sorted.
|
|
func packageOrErrEqual(a, b pkgtree.PackageOrErr) bool {
|
|
if safeError(a.Err) != safeError(b.Err) {
|
|
return false
|
|
}
|
|
if a.P.Name != b.P.Name {
|
|
return false
|
|
}
|
|
if a.P.ImportPath != b.P.ImportPath {
|
|
return false
|
|
}
|
|
if a.P.CommentPath != b.P.CommentPath {
|
|
return false
|
|
}
|
|
|
|
if len(a.P.Imports) != len(b.P.Imports) {
|
|
return false
|
|
}
|
|
sort.Strings(a.P.Imports)
|
|
sort.Strings(b.P.Imports)
|
|
for i := range a.P.Imports {
|
|
if a.P.Imports[i] != b.P.Imports[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if len(a.P.TestImports) != len(b.P.TestImports) {
|
|
return false
|
|
}
|
|
sort.Strings(a.P.TestImports)
|
|
sort.Strings(b.P.TestImports)
|
|
for i := range a.P.TestImports {
|
|
if a.P.TestImports[i] != b.P.TestImports[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|