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 | "html/template" |
10 | "io/ioutil" |
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 := ioutil.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).CombinedOutput() |
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 | } |
89 | |
90 | data = bytes.Replace(data, []byte(f1), []byte(name1), -1) |
91 | data = bytes.Replace(data, []byte(f2), []byte(name2), -1) |
92 | |
93 | return data, err |
94 | } |
95 | |
96 | func writeTempFile(prefix string, data []byte) (string, error) { |
97 | file, err := ioutil.TempFile("", prefix) |
98 | if err != nil { |
99 | return "", err |
100 | } |
101 | _, err = file.Write(data) |
102 | if err1 := file.Close(); err == nil { |
103 | err = err1 |
104 | } |
105 | if err != nil { |
106 | os.Remove(file.Name()) |
107 | return "", err |
108 | } |
109 | return file.Name(), nil |
110 | } |
111 | |
112 | var testTmpl = ` |
113 | {{define "root" -}} |
114 | <h1>{{.Title}}</h1> |
115 | {{with .Subtitle}}<h2>{{.}}</h2> |
116 | {{end -}} |
117 | {{range .Authors}}<author> |
118 | {{range .Elem}}{{elem $.Template .}}{{end}}</author> |
119 | {{end -}} |
120 | {{range .Sections}}<section>{{elem $.Template .}}</section> |
121 | {{end -}} |
122 | {{end}} |
123 | |
124 | {{define "newline"}}{{/* No automatic line break. Paragraphs are free-form. */}} |
125 | {{end}} |
126 | |
127 | {{define "section"}} |
128 | {{if .Title}}<h2 id="TOC_{{.FormattedNumber}}">{{.Title}}</h2> |
129 | {{end -}} |
130 | {{range .Elem}}{{elem $.Template .}}{{end}} |
131 | {{- end}} |
132 | |
133 | {{define "list" -}} |
134 | <ul> |
135 | {{range .Bullet -}} |
136 | <li>{{style .}}</li> |
137 | {{end -}} |
138 | </ul> |
139 | {{end}} |
140 | |
141 | {{define "text" -}} |
142 | {{if .Pre -}} |
143 | <pre>{{range .Lines}}{{.}}{{end}}</pre> |
144 | {{else -}} |
145 | <p>{{range $i, $l := .Lines}}{{if $i}}{{template "newline"}}{{end}}{{style $l}}{{end}}</p> |
146 | {{end -}} |
147 | {{end}} |
148 | |
149 | {{define "code" -}} |
150 | {{if .Play -}} |
151 | <div class="playground">{{.Text}}</div> |
152 | {{else -}} |
153 | <div class="code">{{.Text}}</div> |
154 | {{end -}} |
155 | {{end}} |
156 | |
157 | {{define "image" -}} |
158 | <img src="{{.URL}}"{{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}} alt=""> |
159 | {{end}} |
160 | |
161 | {{define "caption" -}} |
162 | <figcaption>{{style .Text}}</figcaption> |
163 | {{end}} |
164 | |
165 | {{define "iframe" -}} |
166 | <iframe src="{{.URL}}"{{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}}></iframe> |
167 | {{end}} |
168 | |
169 | {{define "link" -}} |
170 | <p class="link"><a href="{{.URL}}">{{style .Label}}</a></p> |
171 | {{end}} |
172 | |
173 | {{define "html" -}}{{.HTML}}{{end}} |
174 | ` |
175 |
Members