| // Copyright 2026 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 specdoc | |
| import ( | |
| "errors" | |
| "go/token" | |
| "strings" | |
| "testing" | |
| ) | |
| // Verify that all report types implement Finding and Report implements error. | |
| var ( | |
| _ Finding = TypeMismatch{} | |
| _ Finding = NameMismatch{} | |
| _ Finding = DocOrderViolation{} | |
| _ Finding = UnknownDecl{} | |
| _ Finding = UnexpectedDoc{} | |
| _ error = (*Report)(nil) | |
| ) | |
| func TestReportEmpty(t *testing.T) { | |
| var r Report | |
| if !r.Empty() { | |
| t.Errorf("expected empty report") | |
| } | |
| if s := r.Error(); s != "" { | |
| t.Errorf("expected empty string, got: %q", s) | |
| } | |
| } | |
| func TestReportPositionOrder(t *testing.T) { | |
| r := Report{ | |
| UnknownDecls: []UnknownDecl{ | |
| { | |
| D: Decl{ | |
| Pos: token.Position{Filename: "b.go", Line: 20, Column: 1}, | |
| Recv: "T", | |
| Name: "UnknownMethod", | |
| }, | |
| }, | |
| }, | |
| TypeMismatches: []TypeMismatch{ | |
| { | |
| D: Decl{ | |
| Pos: token.Position{Filename: "a.go", Line: 10, Column: 1}, | |
| Recv: "T", | |
| Name: "TypeOp", | |
| }, | |
| DeclSig: "func (T) TypeOp(int)", | |
| SpecSig: "func (T) TypeOp(int32)", | |
| }, | |
| }, | |
| DocOrderViolations: []DocOrderViolation{ | |
| { | |
| D: Decl{ | |
| Pos: token.Position{Filename: "a.go", Line: 5, Column: 1}, | |
| Recv: "T", | |
| Name: "DocOp", | |
| }, | |
| Err: errors.New("comment order violation"), | |
| }, | |
| }, | |
| NameMismatches: []NameMismatch{ | |
| { | |
| D: Decl{ | |
| Pos: token.Position{Filename: "b.go", Line: 10, Column: 1}, | |
| Recv: "T", | |
| Name: "NameOp", | |
| }, | |
| DeclSig: "func (T) NameOp(x int)", | |
| SpecSig: "func (T) NameOp(y int)", | |
| }, | |
| }, | |
| UnexpectedDocs: []UnexpectedDoc{ | |
| { | |
| D: Decl{ | |
| Pos: token.Position{Filename: "b.go", Line: 15, Column: 1}, | |
| Recv: "T", | |
| Name: "UnexpectedDocOp", | |
| }, | |
| }, | |
| }, | |
| } | |
| s := r.Error() | |
| // Should not have any markdown section headers. | |
| if strings.Contains(s, "##") { | |
| t.Errorf("expected no section headers in report, got:\n%s", s) | |
| } | |
| // Should report in position order: | |
| // 1. a.go:5 | |
| // 2. a.go:10 | |
| // 3. b.go:10 | |
| // 4. b.go:15 | |
| // 5. b.go:20 | |
| idxA5 := strings.Index(s, "a.go:5") | |
| idxA10 := strings.Index(s, "a.go:10") | |
| idxB10 := strings.Index(s, "b.go:10") | |
| idxB15 := strings.Index(s, "b.go:15") | |
| idxB20 := strings.Index(s, "b.go:20") | |
| if idxA5 < 0 || idxA10 < 0 || idxB10 < 0 || idxB15 < 0 || idxB20 < 0 { | |
| t.Fatalf("missing expected entries in report:\n%s", s) | |
| } | |
| if !(idxA5 < idxA10 && idxA10 < idxB10 && idxB10 < idxB15 && idxB15 < idxB20) { | |
| t.Errorf("expected positions in order a.go:5 < a.go:10 < b.go:10 < b.go:15 < b.go:20, got indices: a.go:5=%d, a.go:10=%d, b.go:10=%d, b.go:15=%d, b.go:20=%d\nReport:\n%s", | |
| idxA5, idxA10, idxB10, idxB15, idxB20, s) | |
| } | |
| } |