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
5package present
6
7import (
8	"fmt"
9	"html/template"
10	"strings"
11	"testing"
12)
13
14func TestParseCode(t *testing.T) {
15	// Enable play but revert the change at the end.
16	defer func(play bool) { PlayEnabled = play }(PlayEnabled)
17	PlayEnabled = true
18
19	helloTest := []byte(`
20package main
21
22import "fmt"
23
24func main() {
25	fmt.Println("hello, test")
26}
27`)
28	helloTestHTML := template.HTML(`
29<pre><span num="2">package main</span>
30<span num="3"></span>
31<span num="4">import &#34;fmt&#34;</span>
32<span num="5"></span>
33<span num="6">func main() {</span>
34<span num="7">    fmt.Println(&#34;hello, test&#34;)</span>
35<span num="8">}</span>
36</pre>
37`)
38	helloTestHL := []byte(`
39package main
40
41import "fmt" // HLimport
42
43func main() { // HLfunc
44	fmt.Println("hello, test") // HL
45}
46`)
47	highlight := func(h template.HTML, s string) template.HTML {
48		return template.HTML(strings.Replace(string(h), s, "<b>"+s+"</b>", -1))
49	}
50	read := func(b []byte, err error) func(string) ([]byte, error) {
51		return func(string) ([]byte, error) { return b, err }
52	}
53
54	tests := []struct {
55		name       string
56		readFile   func(string) ([]byte, error)
57		sourceFile string
58		cmd        string
59		err        string
60		Code
61	}{
62		{
63			name:       "all code, no play",
64			readFile:   read(helloTest, nil),
65			sourceFile: "main.go",
66			cmd:        ".code main.go",
67			Code: Code{
68				Ext:      ".go",
69				FileName: "main.go",
70				Raw:      helloTest,
71				Text:     helloTestHTML,
72			},
73		},
74		{
75			name:       "all code, play",
76			readFile:   read(helloTest, nil),
77			sourceFile: "main.go",
78			cmd:        ".play main.go",
79			Code: Code{
80				Ext:      ".go",
81				FileName: "main.go",
82				Play:     true,
83				Raw:      helloTest,
84				Text:     helloTestHTML,
85			},
86		},
87		{
88			name:       "all code, highlighted",
89			readFile:   read(helloTestHL, nil),
90			sourceFile: "main.go",
91			cmd:        ".code main.go",
92			Code: Code{
93				Ext:      ".go",
94				FileName: "main.go",
95				Raw:      helloTestHL,
96				Text:     highlight(helloTestHTML, "fmt.Println(&#34;hello, test&#34;)"),
97			},
98		},
99		{
100			name:       "highlight only func",
101			readFile:   read(helloTestHL, nil),
102			sourceFile: "main.go",
103			cmd:        ".code main.go HLfunc",
104			Code: Code{
105				Ext:      ".go",
106				FileName: "main.go",
107				Play:     false,
108				Raw:      []byte("package main\n\nimport \"fmt\" // HLimport\n\nfunc main() { // HLfunc\n\tfmt.Println(\"hello, test\") // HL\n}"),
109				Text:     highlight(helloTestHTML, "func main() {"),
110			},
111		},
112		{
113			name:       "bad highlight syntax",
114			readFile:   read(helloTest, nil),
115			sourceFile: "main.go",
116			cmd:        ".code main.go HL",
117			err:        "invalid highlight syntax",
118		},
119		{
120			name:       "error reading file",
121			readFile:   read(nil, fmt.Errorf("nope")),
122			sourceFile: "main.go",
123			cmd:        ".code main.go",
124			err:        "main.go:0: nope",
125		},
126		{
127			name:       "from func main to the end",
128			readFile:   read(helloTest, nil),
129			sourceFile: "main.go",
130			cmd:        ".code main.go /func main/,",
131			Code: Code{
132				Ext:      ".go",
133				FileName: "main.go",
134				Play:     false,
135				Raw:      []byte("func main() {\n\tfmt.Println(\"hello, test\")\n}"),
136				Text:     "<pre><span num=\"6\">func main() {</span>\n<span num=\"7\">    fmt.Println(&#34;hello, test&#34;)</span>\n<span num=\"8\">}</span>\n</pre>",
137			},
138		},
139		{
140			name:       "just func main",
141			readFile:   read(helloTest, nil),
142			sourceFile: "main.go",
143			cmd:        ".code main.go /func main/",
144			Code: Code{
145				Ext:      ".go",
146				FileName: "main.go",
147				Play:     false,
148				Raw:      []byte("func main() {"),
149				Text:     "<pre><span num=\"6\">func main() {</span>\n</pre>",
150			},
151		},
152		{
153			name:       "bad address",
154			readFile:   read(helloTest, nil),
155			sourceFile: "main.go",
156			cmd:        ".code main.go /function main/",
157			err:        "main.go:0: no match for function main",
158		},
159		{
160			name:       "all code with numbers",
161			readFile:   read(helloTest, nil),
162			sourceFile: "main.go",
163			cmd:        ".code -numbers main.go",
164			Code: Code{
165				Ext:      ".go",
166				FileName: "main.go",
167				Raw:      helloTest,
168				// Replacing the first "<pre>"
169				Text: "<pre class=\"numbers\">" + helloTestHTML[6:],
170			},
171		},
172		{
173			name:       "all code editable",
174			readFile:   read(helloTest, nil),
175			sourceFile: "main.go",
176			cmd:        ".code -edit main.go",
177			Code: Code{
178				Ext:      ".go",
179				FileName: "main.go",
180				Raw:      helloTest,
181				Text:     "<pre contenteditable=\"true\" spellcheck=\"false\">" + helloTestHTML[6:],
182			},
183		},
184	}
185
186	trimHTML := func(t template.HTML) string { return strings.TrimSpace(string(t)) }
187	trimBytes := func(b []byte) string { return strings.TrimSpace(string(b)) }
188
189	for _, tt := range tests {
190		ctx := &Context{tt.readFile}
191		e, err := parseCode(ctx, tt.sourceFile, 0, tt.cmd)
192		if err != nil {
193			if tt.err == "" {
194				t.Errorf("%s: unexpected error %v", tt.name, err)
195			} else if !strings.Contains(err.Error(), tt.err) {
196				t.Errorf("%s: expected error %s; got %v", tt.name, tt.err, err)
197			}
198			continue
199		}
200		if tt.err != "" {
201			t.Errorf("%s: expected error %s; but got none", tt.name, tt.err)
202			continue
203		}
204		c, ok := e.(Code)
205		if !ok {
206			t.Errorf("%s: expected a Code value; got %T", tt.name, e)
207			continue
208		}
209		if c.FileName != tt.FileName {
210			t.Errorf("%s: expected FileName %s; got %s", tt.name, tt.FileName, c.FileName)
211		}
212		if c.Ext != tt.Ext {
213			t.Errorf("%s: expected Ext %s; got %s", tt.name, tt.Ext, c.Ext)
214		}
215		if c.Play != tt.Play {
216			t.Errorf("%s: expected Play %v; got %v", tt.name, tt.Play, c.Play)
217		}
218		if got, wants := trimBytes(c.Raw), trimBytes(tt.Raw); got != wants {
219			t.Errorf("%s: expected Raw \n%q\n; got \n%q\n", tt.name, wants, got)
220		}
221		if got, wants := trimHTML(c.Text), trimHTML(tt.Text); got != wants {
222			t.Errorf("%s: expected Text \n%q\n; got \n%q\n", tt.name, wants, got)
223		}
224	}
225}
226