golang.org/x/tools@v0.21.0/present/parse_test.go (about) 1 // Copyright 2020 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 present 6 7 import ( 8 "bytes" 9 "fmt" 10 "html/template" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "runtime" 15 "testing" 16 ) 17 18 func TestTestdata(t *testing.T) { 19 tmpl := template.Must(Template().Parse(testTmpl)) 20 filesP, err := filepath.Glob("testdata/*.p") 21 if err != nil { 22 t.Fatal(err) 23 } 24 filesMD, err := filepath.Glob("testdata/*.md") 25 if err != nil { 26 t.Fatal(err) 27 } 28 files := append(filesP, filesMD...) 29 for _, file := range files { 30 file := file 31 name := filepath.Base(file) 32 if name == "README" { 33 continue 34 } 35 t.Run(name, func(t *testing.T) { 36 data, err := os.ReadFile(file) 37 if err != nil { 38 t.Fatalf("%s: %v", file, err) 39 } 40 marker := []byte("\n---\n") 41 i := bytes.Index(data, marker) 42 if i < 0 { 43 t.Fatalf("%s: cannot find --- marker in input", file) 44 } 45 input, html := data[:i+1], data[i+len(marker):] 46 doc, err := Parse(bytes.NewReader(input), name, 0) 47 if err != nil { 48 t.Fatalf("%s: %v", file, err) 49 } 50 var buf bytes.Buffer 51 if err := doc.Render(&buf, tmpl); err != nil { 52 t.Fatalf("%s: %v", file, err) 53 } 54 if !bytes.Equal(buf.Bytes(), html) { 55 diffText, err := diff("present-test-", "want", html, "have", buf.Bytes()) 56 if err != nil { 57 t.Fatalf("%s: diff: %v", file, err) 58 } 59 t.Errorf("%s: incorrect html:\n%s", file, diffText) 60 } 61 }) 62 } 63 } 64 65 func diff(prefix string, name1 string, b1 []byte, name2 string, b2 []byte) ([]byte, error) { 66 f1, err := writeTempFile(prefix, b1) 67 if err != nil { 68 return nil, err 69 } 70 defer os.Remove(f1) 71 72 f2, err := writeTempFile(prefix, b2) 73 if err != nil { 74 return nil, err 75 } 76 defer os.Remove(f2) 77 78 cmd := "diff" 79 if runtime.GOOS == "plan9" { 80 cmd = "/bin/ape/diff" 81 } 82 83 data, err := exec.Command(cmd, "-u", f1, f2).Output() 84 if len(data) > 0 { 85 // diff exits with a non-zero status when the files don't match. 86 // Ignore that failure as long as we get output. 87 err = nil 88 } else if exit, ok := err.(*exec.ExitError); ok && len(exit.Stderr) > 0 { 89 err = fmt.Errorf("%w\nstderr:\n%s)", err, exit.Stderr) 90 } 91 92 data = bytes.Replace(data, []byte(f1), []byte(name1), -1) 93 data = bytes.Replace(data, []byte(f2), []byte(name2), -1) 94 95 return data, err 96 } 97 98 func writeTempFile(prefix string, data []byte) (string, error) { 99 file, err := os.CreateTemp("", prefix) 100 if err != nil { 101 return "", err 102 } 103 _, err = file.Write(data) 104 if err1 := file.Close(); err == nil { 105 err = err1 106 } 107 if err != nil { 108 os.Remove(file.Name()) 109 return "", err 110 } 111 return file.Name(), nil 112 } 113 114 var testTmpl = ` 115 {{define "root" -}} 116 <h1>{{.Title}}</h1> 117 {{with .Subtitle}}<h2>{{.}}</h2> 118 {{end -}} 119 {{range .Authors}}<author> 120 {{range .Elem}}{{elem $.Template .}}{{end}}</author> 121 {{end -}} 122 {{range .Sections}}<section>{{elem $.Template .}}</section> 123 {{end -}} 124 {{end}} 125 126 {{define "newline"}}{{/* No automatic line break. Paragraphs are free-form. */}} 127 {{end}} 128 129 {{define "section"}} 130 {{if .Title}}<h2 id="TOC_{{.FormattedNumber}}">{{.Title}}</h2> 131 {{end -}} 132 {{range .Elem}}{{elem $.Template .}}{{end}} 133 {{- end}} 134 135 {{define "list" -}} 136 <ul> 137 {{range .Bullet -}} 138 <li>{{style .}}</li> 139 {{end -}} 140 </ul> 141 {{end}} 142 143 {{define "text" -}} 144 {{if .Pre -}} 145 <pre>{{range .Lines}}{{.}}{{end}}</pre> 146 {{else -}} 147 <p>{{range $i, $l := .Lines}}{{if $i}}{{template "newline"}}{{end}}{{style $l}}{{end}}</p> 148 {{end -}} 149 {{end}} 150 151 {{define "code" -}} 152 {{if .Play -}} 153 <div class="playground">{{.Text}}</div> 154 {{else -}} 155 <div class="code">{{.Text}}</div> 156 {{end -}} 157 {{end}} 158 159 {{define "image" -}} 160 <img src="{{.URL}}"{{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}} alt=""> 161 {{end}} 162 163 {{define "caption" -}} 164 <figcaption>{{style .Text}}</figcaption> 165 {{end}} 166 167 {{define "iframe" -}} 168 <iframe src="{{.URL}}"{{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}}></iframe> 169 {{end}} 170 171 {{define "link" -}} 172 <p class="link"><a href="{{.URL}}">{{style .Label}}</a></p> 173 {{end}} 174 175 {{define "html" -}}{{.HTML}}{{end}} 176 `