| package tests |
| |
| import ( |
| "bytes" |
| "fmt" |
| "sort" |
| "strings" |
| |
| "golang.org/x/tools/internal/lsp/protocol" |
| "golang.org/x/tools/internal/lsp/source" |
| "golang.org/x/tools/internal/span" |
| ) |
| |
| // DiffDiagnostics prints the diff between expected and actual diagnostics test |
| // results. |
| func DiffDiagnostics(want, got []source.Diagnostic) string { |
| sortDiagnostics(want) |
| sortDiagnostics(got) |
| |
| if len(got) != len(want) { |
| return summarizeDiagnostics(-1, want, got, "different lengths got %v want %v", len(got), len(want)) |
| } |
| for i, w := range want { |
| g := got[i] |
| if w.Message != g.Message { |
| return summarizeDiagnostics(i, want, got, "incorrect Message got %v want %v", g.Message, w.Message) |
| } |
| if w.Severity != g.Severity { |
| return summarizeDiagnostics(i, want, got, "incorrect Severity got %v want %v", g.Severity, w.Severity) |
| } |
| if w.Source != g.Source { |
| return summarizeDiagnostics(i, want, got, "incorrect Source got %v want %v", g.Source, w.Source) |
| } |
| // Don't check the range on the badimport test. |
| if strings.Contains(string(g.URI), "badimport") { |
| continue |
| } |
| if protocol.ComparePosition(w.Range.Start, g.Range.Start) != 0 { |
| return summarizeDiagnostics(i, want, got, "incorrect Start got %v want %v", g.Range.Start, w.Range.Start) |
| } |
| if !protocol.IsPoint(g.Range) { // Accept any 'want' range if the diagnostic returns a zero-length range. |
| if protocol.ComparePosition(w.Range.End, g.Range.End) != 0 { |
| return summarizeDiagnostics(i, want, got, "incorrect End got %v want %v", g.Range.End, w.Range.End) |
| } |
| } |
| } |
| return "" |
| } |
| |
| func sortDiagnostics(d []source.Diagnostic) { |
| sort.Slice(d, func(i int, j int) bool { |
| return compareDiagnostic(d[i], d[j]) < 0 |
| }) |
| } |
| |
| func compareDiagnostic(a, b source.Diagnostic) int { |
| if r := span.CompareURI(a.URI, b.URI); r != 0 { |
| return r |
| } |
| if r := protocol.CompareRange(a.Range, b.Range); r != 0 { |
| return r |
| } |
| if a.Message < b.Message { |
| return -1 |
| } |
| if a.Message == b.Message { |
| return 0 |
| } else { |
| return 1 |
| } |
| } |
| |
| func summarizeDiagnostics(i int, want []source.Diagnostic, got []source.Diagnostic, reason string, args ...interface{}) string { |
| msg := &bytes.Buffer{} |
| fmt.Fprint(msg, "diagnostics failed") |
| if i >= 0 { |
| fmt.Fprintf(msg, " at %d", i) |
| } |
| fmt.Fprint(msg, " because of ") |
| fmt.Fprintf(msg, reason, args...) |
| fmt.Fprint(msg, ":\nexpected:\n") |
| for _, d := range want { |
| fmt.Fprintf(msg, " %s:%v: %s\n", d.URI, d.Range, d.Message) |
| } |
| fmt.Fprintf(msg, "got:\n") |
| for _, d := range got { |
| fmt.Fprintf(msg, " %s:%v: %s\n", d.URI, d.Range, d.Message) |
| } |
| return msg.String() |
| } |