diff --git a/gopls/internal/regtest/diagnostics/diagnostics_test.go b/gopls/internal/regtest/diagnostics/diagnostics_test.go index 433b462349..a2707efdb5 100644 --- a/gopls/internal/regtest/diagnostics/diagnostics_test.go +++ b/gopls/internal/regtest/diagnostics/diagnostics_test.go @@ -1650,7 +1650,19 @@ const B = a.B Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.OpenFile("b/b.go") - env.Await(env.DiagnosticAtRegexp("a/a.go", `"mod.test/b"`)) + env.Await( + OnceMet( + env.DoneWithOpen(), + // The Go command sometimes tells us about only one of the import cycle + // errors below. For robustness of this test, succeed if we get either. + // + // TODO(golang/go#52904): we should get *both* of these errors. + AnyOf( + env.DiagnosticAtRegexpWithMessage("a/a.go", `"mod.test/b"`, "import cycle"), + env.DiagnosticAtRegexpWithMessage("b/b.go", `"mod.test/a"`, "import cycle"), + ), + ), + ) env.RegexpReplace("b/b.go", `const B = a\.B`, "") env.SaveBuffer("b/b.go") env.Await( diff --git a/internal/lsp/regtest/env.go b/internal/lsp/regtest/env.go index b6b163a87b..f095c38f28 100644 --- a/internal/lsp/regtest/env.go +++ b/internal/lsp/regtest/env.go @@ -258,7 +258,7 @@ func checkExpectations(s State, expectations []Expectation) (Verdict, string) { if v > finalVerdict { finalVerdict = v } - summary.WriteString(fmt.Sprintf("\t%v: %s\n", v, e.Description())) + summary.WriteString(fmt.Sprintf("%v: %s\n", v, e.Description())) } return finalVerdict, summary.String() } diff --git a/internal/lsp/regtest/expectation.go b/internal/lsp/regtest/expectation.go index 15de33f349..ab808f9e8c 100644 --- a/internal/lsp/regtest/expectation.go +++ b/internal/lsp/regtest/expectation.go @@ -96,13 +96,37 @@ func OnceMet(precondition Expectation, mustMeets ...Expectation) *SimpleExpectat return Unmet } } - var descriptions []string - for _, mustMeet := range mustMeets { - descriptions = append(descriptions, mustMeet.Description()) - } + description := describeExpectations(mustMeets...) return &SimpleExpectation{ check: check, - description: fmt.Sprintf("once %q is met, must have %q", precondition.Description(), strings.Join(descriptions, "\n")), + description: fmt.Sprintf("once %q is met, must have:\n%s", precondition.Description(), description), + } +} + +func describeExpectations(expectations ...Expectation) string { + var descriptions []string + for _, e := range expectations { + descriptions = append(descriptions, e.Description()) + } + return strings.Join(descriptions, "\n") +} + +// AnyOf returns an expectation that is satisfied when any of the given +// expectations is met. +func AnyOf(anyOf ...Expectation) *SimpleExpectation { + check := func(s State) Verdict { + for _, e := range anyOf { + verdict := e.Check(s) + if verdict == Met { + return Met + } + } + return Unmet + } + description := describeExpectations(anyOf...) + return &SimpleExpectation{ + check: check, + description: fmt.Sprintf("Any of:\n%s", description), } }