Skip to content

Commit 366fea2

Browse files
committed
Add rootdata-specific tests
1 parent 85a0fc3 commit 366fea2

File tree

4 files changed

+225
-13
lines changed

4 files changed

+225
-13
lines changed

lock.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func (sl safeLock) Projects() []LockedProject {
212212
// while the solver is in-flight.
213213
//
214214
// This is achieved by copying the lock's data into a new safeLock.
215-
func prepLock(l Lock) Lock {
215+
func prepLock(l Lock) safeLock {
216216
pl := l.Projects()
217217

218218
rl := safeLock{

manifest.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func (m simpleRootManifest) dup() simpleRootManifest {
139139
// ProjectProperties.
140140
//
141141
// This is achieved by copying the manifest's data into a new SimpleManifest.
142-
func prepManifest(m Manifest) Manifest {
142+
func prepManifest(m Manifest) SimpleManifest {
143143
if m == nil {
144144
return SimpleManifest{}
145145
}

rootdata.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ type rootdata struct {
3232
// A map of the project names listed in the root's lock.
3333
rlm map[ProjectRoot]LockedProject
3434

35-
// A defensively-copied instance of the root manifest.
36-
rm Manifest
35+
// A defensively copied instance of the root manifest.
36+
rm SimpleManifest
3737

38-
// A defensively-copied instance of the root lock.
39-
rl Lock
38+
// A defensively copied instance of the root lock.
39+
rl safeLock
4040

41-
// A defensively-copied instance of params.RootPackageTree
41+
// A defensively copied instance of params.RootPackageTree
4242
rpt PackageTree
4343
}
4444

@@ -55,10 +55,8 @@ func (rd rootdata) externalImportList() []string {
5555

5656
// If there are any requires, slide them into the reach list, as well.
5757
if len(rd.req) > 0 {
58-
// Make a map of both imported and required pkgs to skip, to avoid
59-
// duplication. Technically, a slice would probably be faster (given
60-
// small size and bounds check elimination), but this is a one-time op,
61-
// so it doesn't matter.
58+
// Make a map of imports that are both in the import path list and the
59+
// required list to avoid duplication.
6260
skip := make(map[string]bool, len(rd.req))
6361
for _, r := range reach {
6462
if rd.req[r] {
@@ -143,10 +141,10 @@ func (rd rootdata) combineConstraints() []workingConstraint {
143141

144142
// needVersionListFor indicates whether we need a version list for a given
145143
// project root, based solely on general solver inputs (no constraint checking
146-
// required). This will be true if:
144+
// required). This will be true if any of the following conditions hold:
147145
//
148146
// - ChangeAll is on
149-
// - The project is not in the lock at all
147+
// - The project is not in the lock
150148
// - The project is in the lock, but is also in the list of projects to change
151149
func (rd rootdata) needVersionsFor(pr ProjectRoot) bool {
152150
if rd.chngall {

rootdata_test.go

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
package gps
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestRootdataExternalImports(t *testing.T) {
9+
fix := basicFixtures["shared dependency with overlapping constraints"]
10+
11+
params := SolveParameters{
12+
RootDir: string(fix.ds[0].n),
13+
RootPackageTree: fix.rootTree(),
14+
Manifest: fix.rootmanifest(),
15+
}
16+
17+
is, err := Prepare(params, newdepspecSM(fix.ds, nil))
18+
if err != nil {
19+
t.Errorf("Unexpected error while prepping solver: %s", err)
20+
t.FailNow()
21+
}
22+
rd := is.(*solver).rd
23+
24+
want := []string{"a", "b"}
25+
got := rd.externalImportList()
26+
if !reflect.DeepEqual(want, got) {
27+
t.Errorf("Unexpected return from rootdata.externalImportList:\n\t(GOT): %s\n\t(WNT): %s", got, want)
28+
}
29+
30+
// Add a require
31+
rd.req["c"] = true
32+
33+
want = []string{"a", "b", "c"}
34+
got = rd.externalImportList()
35+
if !reflect.DeepEqual(want, got) {
36+
t.Errorf("Unexpected return from rootdata.externalImportList:\n\t(GOT): %s\n\t(WNT): %s", got, want)
37+
}
38+
39+
// Add same path as import
40+
poe := rd.rpt.Packages["root"]
41+
poe.P.Imports = []string{"a", "b", "c"}
42+
rd.rpt.Packages["root"] = poe
43+
44+
// should still be the same
45+
got = rd.externalImportList()
46+
if !reflect.DeepEqual(want, got) {
47+
t.Errorf("Unexpected return from rootdata.externalImportList:\n\t(GOT): %s\n\t(WNT): %s", got, want)
48+
}
49+
50+
// Add an ignore, but not on the required path (Prepare makes that
51+
// combination impossible)
52+
53+
rd.ig["b"] = true
54+
want = []string{"a", "c"}
55+
got = rd.externalImportList()
56+
if !reflect.DeepEqual(want, got) {
57+
t.Errorf("Unexpected return from rootdata.externalImportList:\n\t(GOT): %s\n\t(WNT): %s", got, want)
58+
}
59+
}
60+
61+
func TestGetApplicableConstraints(t *testing.T) {
62+
fix := basicFixtures["shared dependency with overlapping constraints"]
63+
64+
params := SolveParameters{
65+
RootDir: string(fix.ds[0].n),
66+
RootPackageTree: fix.rootTree(),
67+
Manifest: fix.rootmanifest(),
68+
}
69+
70+
is, err := Prepare(params, newdepspecSM(fix.ds, nil))
71+
if err != nil {
72+
t.Errorf("Unexpected error while prepping solver: %s", err)
73+
t.FailNow()
74+
}
75+
rd := is.(*solver).rd
76+
77+
table := []struct {
78+
name string
79+
mut func()
80+
result []workingConstraint
81+
}{
82+
{
83+
name: "base case, two constraints",
84+
mut: func() {},
85+
result: []workingConstraint{
86+
{
87+
Ident: mkPI("a"),
88+
Constraint: mkSVC("1.0.0"),
89+
},
90+
{
91+
Ident: mkPI("b"),
92+
Constraint: mkSVC("1.0.0"),
93+
},
94+
},
95+
},
96+
{
97+
name: "with unconstrained require",
98+
mut: func() {
99+
// No constraint means it doesn't show up
100+
rd.req["c"] = true
101+
},
102+
result: []workingConstraint{
103+
{
104+
Ident: mkPI("a"),
105+
Constraint: mkSVC("1.0.0"),
106+
},
107+
{
108+
Ident: mkPI("b"),
109+
Constraint: mkSVC("1.0.0"),
110+
},
111+
},
112+
},
113+
{
114+
name: "with unconstrained import",
115+
mut: func() {
116+
// Again, no constraint means it doesn't show up
117+
poe := rd.rpt.Packages["root"]
118+
poe.P.Imports = []string{"a", "b", "d"}
119+
rd.rpt.Packages["root"] = poe
120+
},
121+
result: []workingConstraint{
122+
{
123+
Ident: mkPI("a"),
124+
Constraint: mkSVC("1.0.0"),
125+
},
126+
{
127+
Ident: mkPI("b"),
128+
Constraint: mkSVC("1.0.0"),
129+
},
130+
},
131+
},
132+
{
133+
name: "constraint on required",
134+
mut: func() {
135+
rd.rm.Deps["c"] = ProjectProperties{
136+
Constraint: NewBranch("foo"),
137+
}
138+
},
139+
result: []workingConstraint{
140+
{
141+
Ident: mkPI("a"),
142+
Constraint: mkSVC("1.0.0"),
143+
},
144+
{
145+
Ident: mkPI("b"),
146+
Constraint: mkSVC("1.0.0"),
147+
},
148+
{
149+
Ident: mkPI("c"),
150+
Constraint: NewBranch("foo"),
151+
},
152+
},
153+
},
154+
{
155+
name: "override on imported",
156+
mut: func() {
157+
rd.ovr["d"] = ProjectProperties{
158+
Constraint: NewBranch("bar"),
159+
}
160+
},
161+
result: []workingConstraint{
162+
{
163+
Ident: mkPI("a"),
164+
Constraint: mkSVC("1.0.0"),
165+
},
166+
{
167+
Ident: mkPI("b"),
168+
Constraint: mkSVC("1.0.0"),
169+
},
170+
{
171+
Ident: mkPI("c"),
172+
Constraint: NewBranch("foo"),
173+
},
174+
{
175+
Ident: mkPI("d"),
176+
Constraint: NewBranch("bar"),
177+
overrConstraint: true,
178+
},
179+
},
180+
},
181+
{
182+
// It is certainly the simplest and most rule-abiding solution to
183+
// drop the constraint in this case, but is there a chance it would
184+
// violate the principle of least surprise?
185+
name: "ignore imported and overridden pkg",
186+
mut: func() {
187+
rd.ig["d"] = true
188+
},
189+
result: []workingConstraint{
190+
{
191+
Ident: mkPI("a"),
192+
Constraint: mkSVC("1.0.0"),
193+
},
194+
{
195+
Ident: mkPI("b"),
196+
Constraint: mkSVC("1.0.0"),
197+
},
198+
{
199+
Ident: mkPI("c"),
200+
Constraint: NewBranch("foo"),
201+
},
202+
},
203+
},
204+
}
205+
206+
for _, fix := range table {
207+
fix.mut()
208+
209+
got := rd.getApplicableConstraints()
210+
if !reflect.DeepEqual(fix.result, got) {
211+
t.Errorf("(fix: %q) unexpected applicable constraint set:\n\t(GOT): %+v\n\t(WNT): %+v", fix.name, got, fix.result)
212+
}
213+
}
214+
}

0 commit comments

Comments
 (0)