diff options
Diffstat (limited to 'src/go/doc/doc_test.go')
-rw-r--r-- | src/go/doc/doc_test.go | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/go/doc/doc_test.go b/src/go/doc/doc_test.go new file mode 100644 index 0000000..cbdca62 --- /dev/null +++ b/src/go/doc/doc_test.go @@ -0,0 +1,164 @@ +// Copyright 2012 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 doc + +import ( + "bytes" + "flag" + "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" + "testing" + "text/template" +) + +var update = flag.Bool("update", false, "update golden (.out) files") +var files = flag.String("files", "", "consider only Go test files matching this regular expression") + +const dataDir = "testdata" + +var templateTxt = readTemplate("template.txt") + +func readTemplate(filename string) *template.Template { + t := template.New(filename) + t.Funcs(template.FuncMap{ + "node": nodeFmt, + "synopsis": synopsisFmt, + "indent": indentFmt, + }) + return template.Must(t.ParseFiles(filepath.Join(dataDir, filename))) +} + +func nodeFmt(node interface{}, fset *token.FileSet) string { + var buf bytes.Buffer + printer.Fprint(&buf, fset, node) + return strings.ReplaceAll(strings.TrimSpace(buf.String()), "\n", "\n\t") +} + +func synopsisFmt(s string) string { + const n = 64 + if len(s) > n { + // cut off excess text and go back to a word boundary + s = s[0:n] + if i := strings.LastIndexAny(s, "\t\n "); i >= 0 { + s = s[0:i] + } + s = strings.TrimSpace(s) + " ..." + } + return "// " + strings.ReplaceAll(s, "\n", " ") +} + +func indentFmt(indent, s string) string { + end := "" + if strings.HasSuffix(s, "\n") { + end = "\n" + s = s[:len(s)-1] + } + return indent + strings.ReplaceAll(s, "\n", "\n"+indent) + end +} + +func isGoFile(fi fs.FileInfo) bool { + name := fi.Name() + return !fi.IsDir() && + len(name) > 0 && name[0] != '.' && // ignore .files + filepath.Ext(name) == ".go" +} + +type bundle struct { + *Package + FSet *token.FileSet +} + +func test(t *testing.T, mode Mode) { + // determine file filter + filter := isGoFile + if *files != "" { + rx, err := regexp.Compile(*files) + if err != nil { + t.Fatal(err) + } + filter = func(fi fs.FileInfo) bool { + return isGoFile(fi) && rx.MatchString(fi.Name()) + } + } + + // get packages + fset := token.NewFileSet() + pkgs, err := parser.ParseDir(fset, dataDir, filter, parser.ParseComments) + if err != nil { + t.Fatal(err) + } + + // test packages + for _, pkg := range pkgs { + importPath := dataDir + "/" + pkg.Name + var files []*ast.File + for _, f := range pkg.Files { + files = append(files, f) + } + doc, err := NewFromFiles(fset, files, importPath, mode) + if err != nil { + t.Error(err) + continue + } + + // golden files always use / in filenames - canonicalize them + for i, filename := range doc.Filenames { + doc.Filenames[i] = filepath.ToSlash(filename) + } + + // print documentation + var buf bytes.Buffer + if err := templateTxt.Execute(&buf, bundle{doc, fset}); err != nil { + t.Error(err) + continue + } + got := buf.Bytes() + + // update golden file if necessary + golden := filepath.Join(dataDir, fmt.Sprintf("%s.%d.golden", pkg.Name, mode)) + if *update { + err := os.WriteFile(golden, got, 0644) + if err != nil { + t.Error(err) + } + continue + } + + // get golden file + want, err := os.ReadFile(golden) + if err != nil { + t.Error(err) + continue + } + + // compare + if !bytes.Equal(got, want) { + t.Errorf("package %s\n\tgot:\n%s\n\twant:\n%s", pkg.Name, got, want) + } + } +} + +func Test(t *testing.T) { + test(t, 0) + test(t, AllDecls) + test(t, AllMethods) +} + +func TestAnchorID(t *testing.T) { + const in = "Important Things 2 Know & Stuff" + const want = "hdr-Important_Things_2_Know___Stuff" + got := anchorID(in) + if got != want { + t.Errorf("anchorID(%q) = %q; want %q", in, got, want) + } +} |