Add the wrongCaseFailure, and scads more fixtures

This commit is contained in:
sam boyer 2017-09-02 03:13:30 -04:00
Родитель 6592101eeb
Коммит 3d369c50a9
5 изменённых файлов: 122 добавлений и 22 удалений

Просмотреть файл

@ -239,6 +239,32 @@ func (s *solver) checkRootCaseConflicts(a atomWithPackages, cdep completeDep) er
s.fail(d.depender.id) s.fail(d.depender.id)
} }
// If a project has multiple packages that import each other, we treat that
// as establishing a canonical case variant for the ProjectRoot. It's possible,
// however, that that canonical variant is not the same one that others
// imported it under. If that's the situation, then we'll have arrived here
// when visiting the project, not its dependers, having misclassified its
// internal imports as external. That means the atomWithPackages will
// be the wrong case variant induced by the importers, and the cdep will be
// a link pointing back at the canonical case variant.
//
// If this is the case, use a special failure, wrongCaseFailure, that
// makes a stronger statement as to the correctness of case variants.
//
// TODO(sdboyer) This approach to marking failure is less than great, as
// this will mark the current atom as failed, as well, causing the
// backtracker to work through it. While that could prove fruitful, it's
// quite likely just to be wasted effort. Addressing this - if that's a good
// idea - would entail creating another path back out of checking to enable
// backjumping directly to the incorrect importers.
if current == a.a.id.ProjectRoot {
return &wrongCaseFailure{
correct: pr,
goal: dependency{depender: a.a, dep: cdep},
badcase: deps,
}
}
return &caseMismatchFailure{ return &caseMismatchFailure{
goal: dependency{depender: a.a, dep: cdep}, goal: dependency{depender: a.a, dep: cdep},
current: current, current: current,

Просмотреть файл

@ -399,6 +399,9 @@ type basicFixture struct {
changeall bool changeall bool
// individual projects to change // individual projects to change
changelist []ProjectRoot changelist []ProjectRoot
// if the fixture is currently broken/expected to fail, this has a message
// recording why
broken string
} }
func (f basicFixture) name() string { func (f basicFixture) name() string {

Просмотреть файл

@ -683,7 +683,7 @@ var bimodalFixtures = map[string]bimodalFixture{
"a 1.0.0", "a 1.0.0",
), ),
}, },
"simple case-only variations": { "simple case-only differences": {
ds: []depspec{ ds: []depspec{
dsp(mkDepspec("root 0.0.0"), dsp(mkDepspec("root 0.0.0"),
pkg("root", "foo", "bar")), pkg("root", "foo", "bar")),
@ -706,6 +706,23 @@ var bimodalFixtures = map[string]bimodalFixture{
}, },
}, },
}, },
"case variations acceptable with agreement": {
ds: []depspec{
dsp(mkDepspec("root 0.0.0"),
pkg("root", "foo")),
dsp(mkDepspec("foo 1.0.0"),
pkg("foo", "Bar", "baz")),
dsp(mkDepspec("baz 1.0.0"),
pkg("baz", "Bar")),
dsp(mkDepspec("bar 1.0.0"),
pkg("bar")),
},
r: mksolution(
"foo 1.0.0",
"Bar 1.0.0",
"baz 1.0.0",
),
},
"case variations within root": { "case variations within root": {
ds: []depspec{ ds: []depspec{
dsp(mkDepspec("root 0.0.0"), dsp(mkDepspec("root 0.0.0"),
@ -714,8 +731,6 @@ var bimodalFixtures = map[string]bimodalFixture{
pkg("foo")), pkg("foo")),
dsp(mkDepspec("bar 1.0.0"), dsp(mkDepspec("bar 1.0.0"),
pkg("bar")), pkg("bar")),
dsp(mkDepspec("Bar 1.0.0"),
pkg("Bar")),
}, },
fail: &noVersionError{ fail: &noVersionError{
pn: mkPI("foo"), pn: mkPI("foo"),
@ -730,6 +745,7 @@ var bimodalFixtures = map[string]bimodalFixture{
}, },
}, },
}, },
broken: "need to implement checking for import case variations *within* the root",
}, },
"case variations within single dep": { "case variations within single dep": {
ds: []depspec{ ds: []depspec{
@ -739,8 +755,6 @@ var bimodalFixtures = map[string]bimodalFixture{
pkg("foo", "bar", "Bar")), pkg("foo", "bar", "Bar")),
dsp(mkDepspec("bar 1.0.0"), dsp(mkDepspec("bar 1.0.0"),
pkg("bar")), pkg("bar")),
dsp(mkDepspec("Bar 1.0.0"),
pkg("Bar")),
}, },
fail: &noVersionError{ fail: &noVersionError{
pn: mkPI("foo"), pn: mkPI("foo"),
@ -755,8 +769,9 @@ var bimodalFixtures = map[string]bimodalFixture{
}, },
}, },
}, },
broken: "need to implement checking for import case variations *within* a single project",
}, },
"case variations within multiple deps": { "case variations across multiple deps": {
ds: []depspec{ ds: []depspec{
dsp(mkDepspec("root 0.0.0"), dsp(mkDepspec("root 0.0.0"),
pkg("root", "foo", "bar")), pkg("root", "foo", "bar")),
@ -766,8 +781,6 @@ var bimodalFixtures = map[string]bimodalFixture{
pkg("baz", "Bar")), pkg("baz", "Bar")),
dsp(mkDepspec("bar 1.0.0"), dsp(mkDepspec("bar 1.0.0"),
pkg("bar")), pkg("bar")),
dsp(mkDepspec("Bar 1.0.0"),
pkg("Bar")),
}, },
fail: &noVersionError{ fail: &noVersionError{
pn: mkPI("baz"), pn: mkPI("baz"),
@ -787,37 +800,86 @@ var bimodalFixtures = map[string]bimodalFixture{
}, },
}, },
// This isn't actually as crazy as it might seem, as the root is defined by // This isn't actually as crazy as it might seem, as the root is defined by
// the addresser, not the addressee. It would occur if, e.g. something // the addresser, not the addressee. It would occur (to provide a
// imports github.com/Sirupsen/logrus, as the contained subpackage at // real-as-of-this-writing example) if something imports
// github.com/Sirupsen/logrus, as the contained subpackage at
// github.com/Sirupsen/logrus/hooks/syslog imports // github.com/Sirupsen/logrus/hooks/syslog imports
// github.com/sirupsen/logrus. The only reason that doesn't blow up all the // github.com/sirupsen/logrus. The only reason that doesn't blow up all the
// time is that most people only import the root package, not the syslog // time is that most people only import the root package, not the syslog
// subpackage. // subpackage.
"case variations from self": { "canonical case is established by mutual self-imports": {
ds: []depspec{ ds: []depspec{
dsp(mkDepspec("root 0.0.0"), dsp(mkDepspec("root 0.0.0"),
pkg("root", "foo")), pkg("root", "foo")),
dsp(mkDepspec("foo 1.0.0"), dsp(mkDepspec("foo 1.0.0"),
pkg("foo", "bar")), pkg("foo", "Bar")),
dsp(mkDepspec("bar 1.0.0"), dsp(mkDepspec("bar 1.0.0"),
pkg("bar", "Bar")), pkg("bar", "bar/subpkg"),
dsp(mkDepspec("Bar 1.0.0"), pkg("bar/subpkg")),
pkg("Bar")),
}, },
fail: &noVersionError{ fail: &noVersionError{
pn: mkPI("foo"), pn: mkPI("Bar"),
fails: []failedVersion{ fails: []failedVersion{
{ {
v: NewVersion("1.0.0"), v: NewVersion("1.0.0"),
f: &caseMismatchFailure{ f: &wrongCaseFailure{
goal: mkDep("foo 1.0.0", "Bar 1.0.0", "Bar"), correct: ProjectRoot("bar"),
current: ProjectRoot("bar"), goal: mkDep("Bar 1.0.0", "bar 1.0.0", "bar"),
failsib: []dependency{mkDep("root", "foo 1.0.0", "foo")}, badcase: []dependency{mkDep("foo 1.0.0", "Bar 1.0.0", "Bar/subpkg")},
}, },
}, },
}, },
}, },
}, },
"canonical case only applies if relevant imports are activated": {
ds: []depspec{
dsp(mkDepspec("root 0.0.0"),
pkg("root", "foo")),
dsp(mkDepspec("foo 1.0.0"),
pkg("foo", "Bar/subpkg")),
dsp(mkDepspec("bar 1.0.0"),
pkg("bar", "bar/subpkg"),
pkg("bar/subpkg")),
},
r: mksolution(
"foo 1.0.0",
mklp("Bar 1.0.0", "subpkg"),
),
},
"simple case-only variations plus source variance": {
// COPYPASTA BELOW, FIX IT
ds: []depspec{
dsp(mkDepspec("root 0.0.0"),
pkg("root", "foo", "Bar")), // TODO align the froms
dsp(mkDepspec("foo 1.0.0", "Bar from quux 1.0.0"),
pkg("foo", "Bar")),
dsp(mkDepspec("bar 1.0.0"),
pkg("bar")),
dsp(mkDepspec("quux 1.0.0"),
pkg("bar")),
},
r: mksolution(
"foo 1.0.0",
"Bar from quux 1.0.0",
),
},
"case-only variations plus source variance with internal canonicality": {
// COPYPASTA BELOW, FIX IT
ds: []depspec{
dsp(mkDepspec("root 0.0.0"),
pkg("root", "foo", "Bar")),
dsp(mkDepspec("foo 1.0.0", "Bar from quux 1.0.0"),
pkg("foo", "Bar")),
dsp(mkDepspec("bar 1.0.0"),
pkg("bar")),
dsp(mkDepspec("quux 1.0.0"),
pkg("bar")),
},
r: mksolution(
"foo 1.0.0",
"Bar from quux 1.0.0",
),
},
"alternate net address": { "alternate net address": {
ds: []depspec{ ds: []depspec{
dsp(mkDepspec("root 1.0.0", "foo from bar 2.0.0"), dsp(mkDepspec("root 1.0.0", "foo from bar 2.0.0"),
@ -1240,6 +1302,9 @@ type bimodalFixture struct {
ignore []string ignore []string
// pkgs to require // pkgs to require
require []string require []string
// if the fixture is currently broken/expected to fail, this has a message
// recording why
broken string
} }
func (f bimodalFixture) name() string { func (f bimodalFixture) name() string {

Просмотреть файл

@ -132,13 +132,13 @@ type wrongCaseFailure struct {
func (e *wrongCaseFailure) Error() string { func (e *wrongCaseFailure) Error() string {
if len(e.badcase) == 1 { if len(e.badcase) == 1 {
str := "Could not introduce %s; its packages import each other using %q, establishing that as correct, but %s tried to import it as %q" str := "Could not introduce %s; mutual imports by its packages establish %q as the canonical casing for root, but %s tried to import it as %q"
return fmt.Sprintf(str, a2vs(e.goal.depender), e.correct, a2vs(e.badcase[0].depender), e.badcase[0].dep.Ident.ProjectRoot) return fmt.Sprintf(str, a2vs(e.goal.depender), e.correct, a2vs(e.badcase[0].depender), e.badcase[0].dep.Ident.ProjectRoot)
} }
var buf bytes.Buffer var buf bytes.Buffer
str := "Could not introduce %s; its packages import each other using %q, establishing that as correct, but the following projects tried to import it as %q" str := "Could not introduce %s; mutual imports by its packages establish %q as the canonical casing for root, but the following projects tried to import it as %q"
fmt.Fprintf(&buf, str, a2vs(e.goal.depender), e.correct, e.badcase[0].dep.Ident.ProjectRoot) fmt.Fprintf(&buf, str, a2vs(e.goal.depender), e.correct, e.badcase[0].dep.Ident.ProjectRoot)
for _, c := range e.badcase { for _, c := range e.badcase {

Просмотреть файл

@ -60,6 +60,9 @@ func TestBasicSolves(t *testing.T) {
func solveBasicsAndCheck(fix basicFixture, t *testing.T) (res Solution, err error) { func solveBasicsAndCheck(fix basicFixture, t *testing.T) (res Solution, err error) {
sm := newdepspecSM(fix.ds, nil) sm := newdepspecSM(fix.ds, nil)
if fix.broken != "" {
t.Skip(fix.broken)
}
params := SolveParameters{ params := SolveParameters{
RootDir: string(fix.ds[0].n), RootDir: string(fix.ds[0].n),
@ -103,6 +106,9 @@ func TestBimodalSolves(t *testing.T) {
func solveBimodalAndCheck(fix bimodalFixture, t *testing.T) (res Solution, err error) { func solveBimodalAndCheck(fix bimodalFixture, t *testing.T) (res Solution, err error) {
sm := newbmSM(fix) sm := newbmSM(fix)
if fix.broken != "" {
t.Skip(fix.broken)
}
params := SolveParameters{ params := SolveParameters{
RootDir: string(fix.ds[0].n), RootDir: string(fix.ds[0].n),