Black Lives Matter. Support the Equal Justice Initiative.

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