...

Source file src/go/doc/doc_test.go

Documentation: go/doc

		 1  // Copyright 2012 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package doc
		 6  
		 7  import (
		 8  	"bytes"
		 9  	"flag"
		10  	"fmt"
		11  	"go/ast"
		12  	"go/parser"
		13  	"go/printer"
		14  	"go/token"
		15  	"io/fs"
		16  	"os"
		17  	"path/filepath"
		18  	"regexp"
		19  	"strings"
		20  	"testing"
		21  	"text/template"
		22  )
		23  
		24  var update = flag.Bool("update", false, "update golden (.out) files")
		25  var files = flag.String("files", "", "consider only Go test files matching this regular expression")
		26  
		27  const dataDir = "testdata"
		28  
		29  var templateTxt = readTemplate("template.txt")
		30  
		31  func readTemplate(filename string) *template.Template {
		32  	t := template.New(filename)
		33  	t.Funcs(template.FuncMap{
		34  		"node":		 nodeFmt,
		35  		"synopsis": synopsisFmt,
		36  		"indent":	 indentFmt,
		37  	})
		38  	return template.Must(t.ParseFiles(filepath.Join(dataDir, filename)))
		39  }
		40  
		41  func nodeFmt(node interface{}, fset *token.FileSet) string {
		42  	var buf bytes.Buffer
		43  	printer.Fprint(&buf, fset, node)
		44  	return strings.ReplaceAll(strings.TrimSpace(buf.String()), "\n", "\n\t")
		45  }
		46  
		47  func synopsisFmt(s string) string {
		48  	const n = 64
		49  	if len(s) > n {
		50  		// cut off excess text and go back to a word boundary
		51  		s = s[0:n]
		52  		if i := strings.LastIndexAny(s, "\t\n "); i >= 0 {
		53  			s = s[0:i]
		54  		}
		55  		s = strings.TrimSpace(s) + " ..."
		56  	}
		57  	return "// " + strings.ReplaceAll(s, "\n", " ")
		58  }
		59  
		60  func indentFmt(indent, s string) string {
		61  	end := ""
		62  	if strings.HasSuffix(s, "\n") {
		63  		end = "\n"
		64  		s = s[:len(s)-1]
		65  	}
		66  	return indent + strings.ReplaceAll(s, "\n", "\n"+indent) + end
		67  }
		68  
		69  func isGoFile(fi fs.FileInfo) bool {
		70  	name := fi.Name()
		71  	return !fi.IsDir() &&
		72  		len(name) > 0 && name[0] != '.' && // ignore .files
		73  		filepath.Ext(name) == ".go"
		74  }
		75  
		76  type bundle struct {
		77  	*Package
		78  	FSet *token.FileSet
		79  }
		80  
		81  func test(t *testing.T, mode Mode) {
		82  	// determine file filter
		83  	filter := isGoFile
		84  	if *files != "" {
		85  		rx, err := regexp.Compile(*files)
		86  		if err != nil {
		87  			t.Fatal(err)
		88  		}
		89  		filter = func(fi fs.FileInfo) bool {
		90  			return isGoFile(fi) && rx.MatchString(fi.Name())
		91  		}
		92  	}
		93  
		94  	// get packages
		95  	fset := token.NewFileSet()
		96  	pkgs, err := parser.ParseDir(fset, dataDir, filter, parser.ParseComments)
		97  	if err != nil {
		98  		t.Fatal(err)
		99  	}
	 100  
	 101  	// test packages
	 102  	for _, pkg := range pkgs {
	 103  		importPath := dataDir + "/" + pkg.Name
	 104  		var files []*ast.File
	 105  		for _, f := range pkg.Files {
	 106  			files = append(files, f)
	 107  		}
	 108  		doc, err := NewFromFiles(fset, files, importPath, mode)
	 109  		if err != nil {
	 110  			t.Error(err)
	 111  			continue
	 112  		}
	 113  
	 114  		// golden files always use / in filenames - canonicalize them
	 115  		for i, filename := range doc.Filenames {
	 116  			doc.Filenames[i] = filepath.ToSlash(filename)
	 117  		}
	 118  
	 119  		// print documentation
	 120  		var buf bytes.Buffer
	 121  		if err := templateTxt.Execute(&buf, bundle{doc, fset}); err != nil {
	 122  			t.Error(err)
	 123  			continue
	 124  		}
	 125  		got := buf.Bytes()
	 126  
	 127  		// update golden file if necessary
	 128  		golden := filepath.Join(dataDir, fmt.Sprintf("%s.%d.golden", pkg.Name, mode))
	 129  		if *update {
	 130  			err := os.WriteFile(golden, got, 0644)
	 131  			if err != nil {
	 132  				t.Error(err)
	 133  			}
	 134  			continue
	 135  		}
	 136  
	 137  		// get golden file
	 138  		want, err := os.ReadFile(golden)
	 139  		if err != nil {
	 140  			t.Error(err)
	 141  			continue
	 142  		}
	 143  
	 144  		// compare
	 145  		if !bytes.Equal(got, want) {
	 146  			t.Errorf("package %s\n\tgot:\n%s\n\twant:\n%s", pkg.Name, got, want)
	 147  		}
	 148  	}
	 149  }
	 150  
	 151  func Test(t *testing.T) {
	 152  	test(t, 0)
	 153  	test(t, AllDecls)
	 154  	test(t, AllMethods)
	 155  }
	 156  
	 157  func TestAnchorID(t *testing.T) {
	 158  	const in = "Important Things 2 Know & Stuff"
	 159  	const want = "hdr-Important_Things_2_Know___Stuff"
	 160  	got := anchorID(in)
	 161  	if got != want {
	 162  		t.Errorf("anchorID(%q) = %q; want %q", in, got, want)
	 163  	}
	 164  }
	 165  

View as plain text