Source file src/go/doc/comment/testdata_test.go

     1  // Copyright 2022 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 comment
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/json"
    10  	"fmt"
    11  	"internal/diff"
    12  	"internal/txtar"
    13  	"path/filepath"
    14  	"strings"
    15  	"testing"
    16  )
    17  
    18  func TestTestdata(t *testing.T) {
    19  	files, _ := filepath.Glob("testdata/*.txt")
    20  	if len(files) == 0 {
    21  		t.Fatalf("no testdata")
    22  	}
    23  	var p Parser
    24  	p.Words = map[string]string{
    25  		"italicword": "",
    26  		"linkedword": "https://example.com/linkedword",
    27  	}
    28  	p.LookupPackage = func(name string) (importPath string, ok bool) {
    29  		if name == "comment" {
    30  			return "go/doc/comment", true
    31  		}
    32  		return DefaultLookupPackage(name)
    33  	}
    34  	p.LookupSym = func(recv, name string) (ok bool) {
    35  		if recv == "Parser" && name == "Parse" ||
    36  			recv == "" && name == "Doc" ||
    37  			recv == "" && name == "NoURL" {
    38  			return true
    39  		}
    40  		return false
    41  	}
    42  
    43  	stripDollars := func(b []byte) []byte {
    44  		// Remove trailing $ on lines.
    45  		// They make it easier to see lines with trailing spaces,
    46  		// as well as turning them into lines without trailing spaces,
    47  		// in case editors remove trailing spaces.
    48  		return bytes.ReplaceAll(b, []byte("$\n"), []byte("\n"))
    49  	}
    50  	for _, file := range files {
    51  		t.Run(filepath.Base(file), func(t *testing.T) {
    52  			var pr Printer
    53  			a, err := txtar.ParseFile(file)
    54  			if err != nil {
    55  				t.Fatal(err)
    56  			}
    57  			if len(a.Comment) > 0 {
    58  				err := json.Unmarshal(a.Comment, &pr)
    59  				if err != nil {
    60  					t.Fatalf("unmarshalling top json: %v", err)
    61  				}
    62  			}
    63  			if len(a.Files) < 1 || a.Files[0].Name != "input" {
    64  				t.Fatalf("first file is not %q", "input")
    65  			}
    66  			d := p.Parse(string(stripDollars(a.Files[0].Data)))
    67  			for _, f := range a.Files[1:] {
    68  				want := stripDollars(f.Data)
    69  				for len(want) >= 2 && want[len(want)-1] == '\n' && want[len(want)-2] == '\n' {
    70  					want = want[:len(want)-1]
    71  				}
    72  				var out []byte
    73  				switch f.Name {
    74  				default:
    75  					t.Fatalf("unknown output file %q", f.Name)
    76  				case "dump":
    77  					out = dump(d)
    78  				case "gofmt":
    79  					out = pr.Comment(d)
    80  				case "html":
    81  					out = pr.HTML(d)
    82  				case "markdown":
    83  					out = pr.Markdown(d)
    84  				case "text":
    85  					out = pr.Text(d)
    86  				}
    87  				if string(out) != string(want) {
    88  					t.Errorf("%s: %s", file, diff.Diff(f.Name, want, "have", out))
    89  				}
    90  			}
    91  		})
    92  	}
    93  }
    94  
    95  func dump(d *Doc) []byte {
    96  	var out bytes.Buffer
    97  	dumpTo(&out, 0, d)
    98  	return out.Bytes()
    99  }
   100  
   101  func dumpTo(out *bytes.Buffer, indent int, x any) {
   102  	switch x := x.(type) {
   103  	default:
   104  		fmt.Fprintf(out, "?%T", x)
   105  
   106  	case *Doc:
   107  		fmt.Fprintf(out, "Doc")
   108  		dumpTo(out, indent+1, x.Content)
   109  		if len(x.Links) > 0 {
   110  			dumpNL(out, indent+1)
   111  			fmt.Fprintf(out, "Links")
   112  			dumpTo(out, indent+2, x.Links)
   113  		}
   114  		fmt.Fprintf(out, "\n")
   115  
   116  	case []*LinkDef:
   117  		for _, def := range x {
   118  			dumpNL(out, indent)
   119  			dumpTo(out, indent, def)
   120  		}
   121  
   122  	case *LinkDef:
   123  		fmt.Fprintf(out, "LinkDef Used:%v Text:%q URL:%s", x.Used, x.Text, x.URL)
   124  
   125  	case []Block:
   126  		for _, blk := range x {
   127  			dumpNL(out, indent)
   128  			dumpTo(out, indent, blk)
   129  		}
   130  
   131  	case *Heading:
   132  		fmt.Fprintf(out, "Heading")
   133  		dumpTo(out, indent+1, x.Text)
   134  
   135  	case *List:
   136  		fmt.Fprintf(out, "List ForceBlankBefore=%v ForceBlankBetween=%v", x.ForceBlankBefore, x.ForceBlankBetween)
   137  		dumpTo(out, indent+1, x.Items)
   138  
   139  	case []*ListItem:
   140  		for _, item := range x {
   141  			dumpNL(out, indent)
   142  			dumpTo(out, indent, item)
   143  		}
   144  
   145  	case *ListItem:
   146  		fmt.Fprintf(out, "Item Number=%q", x.Number)
   147  		dumpTo(out, indent+1, x.Content)
   148  
   149  	case *Paragraph:
   150  		fmt.Fprintf(out, "Paragraph")
   151  		dumpTo(out, indent+1, x.Text)
   152  
   153  	case *Code:
   154  		fmt.Fprintf(out, "Code")
   155  		dumpTo(out, indent+1, x.Text)
   156  
   157  	case []Text:
   158  		for _, t := range x {
   159  			dumpNL(out, indent)
   160  			dumpTo(out, indent, t)
   161  		}
   162  
   163  	case Plain:
   164  		if !strings.Contains(string(x), "\n") {
   165  			fmt.Fprintf(out, "Plain %q", string(x))
   166  		} else {
   167  			fmt.Fprintf(out, "Plain")
   168  			dumpTo(out, indent+1, string(x))
   169  		}
   170  
   171  	case Italic:
   172  		if !strings.Contains(string(x), "\n") {
   173  			fmt.Fprintf(out, "Italic %q", string(x))
   174  		} else {
   175  			fmt.Fprintf(out, "Italic")
   176  			dumpTo(out, indent+1, string(x))
   177  		}
   178  
   179  	case string:
   180  		for _, line := range strings.SplitAfter(x, "\n") {
   181  			if line != "" {
   182  				dumpNL(out, indent)
   183  				fmt.Fprintf(out, "%q", line)
   184  			}
   185  		}
   186  
   187  	case *Link:
   188  		fmt.Fprintf(out, "Link %q", x.URL)
   189  		dumpTo(out, indent+1, x.Text)
   190  
   191  	case *DocLink:
   192  		fmt.Fprintf(out, "DocLink pkg:%q, recv:%q, name:%q", x.ImportPath, x.Recv, x.Name)
   193  		dumpTo(out, indent+1, x.Text)
   194  	}
   195  }
   196  
   197  func dumpNL(out *bytes.Buffer, n int) {
   198  	out.WriteByte('\n')
   199  	for i := 0; i < n; i++ {
   200  		out.WriteByte('\t')
   201  	}
   202  }
   203  

View as plain text