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
5package present
6
7import (
8	"bytes"
9	"html/template"
10	"io/ioutil"
11	"os"
12	"os/exec"
13	"path/filepath"
14	"runtime"
15	"testing"
16)
17
18func 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
65func 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
96func 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
112var 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