File view with blame information shown in the left gutter beside each line.

barerepo / server / internal/httpd/view_test.go
1012 lines · 33kb · 133728eaa05486504991b230f9d4c7e986b7defc
log files threads runs releases config jump to file t
133728e barerepo 1mo
1
package httpd
133728e barerepo 1mo
2
133728e barerepo 1mo
3
import (
133728e barerepo 1mo
4
"fmt"
133728e barerepo 1mo
5
"strings"
133728e barerepo 1mo
6
"testing"
133728e barerepo 1mo
7
"time"
133728e barerepo 1mo
8
133728e barerepo 1mo
9
"github.com/barerepo/server/internal/gitread"
133728e barerepo 1mo
10
"github.com/barerepo/server/internal/run"
133728e barerepo 1mo
11
"github.com/barerepo/server/internal/thread"
133728e barerepo 1mo
12
"html/template"
133728e barerepo 1mo
13
)
133728e barerepo 1mo
14
133728e barerepo 1mo
15
// renderCase is one template and what its page must say, shared by the render and field checks.
133728e barerepo 1mo
16
type renderCase struct {
133728e barerepo 1mo
17
data any
133728e barerepo 1mo
18
want []string
133728e barerepo 1mo
19
}
133728e barerepo 1mo
20
133728e barerepo 1mo
21
// Every template runs here, because a typo otherwise fails when a user asks for the page.
133728e barerepo 1mo
22
func TestTemplatesRender(t *testing.T) {
133728e barerepo 1mo
23
for name, c := range renderCases() {
133728e barerepo 1mo
24
tpl, ok := pages[name]
133728e barerepo 1mo
25
if !ok {
133728e barerepo 1mo
26
t.Errorf("no template named %q", name)
133728e barerepo 1mo
27
continue
133728e barerepo 1mo
28
}
133728e barerepo 1mo
29
var out strings.Builder
133728e barerepo 1mo
30
if err := tpl.ExecuteTemplate(&out, "layout", c.data); err != nil {
133728e barerepo 1mo
31
t.Errorf("%s: %v", name, err)
133728e barerepo 1mo
32
continue
133728e barerepo 1mo
33
}
133728e barerepo 1mo
34
got := out.String()
133728e barerepo 1mo
35
if !strings.HasPrefix(got, "<!doctype html>") || !strings.Contains(got, "</html>") {
133728e barerepo 1mo
36
t.Errorf("%s: not a whole document", name)
133728e barerepo 1mo
37
}
133728e barerepo 1mo
38
for _, want := range c.want {
133728e barerepo 1mo
39
if !strings.Contains(got, want) {
133728e barerepo 1mo
40
t.Errorf("%s: missing %q", name, want)
133728e barerepo 1mo
41
}
133728e barerepo 1mo
42
}
133728e barerepo 1mo
43
}
133728e barerepo 1mo
44
// Every template, not only the ones somebody remembered, or a new page ships untested.
133728e barerepo 1mo
45
for name := range pages {
133728e barerepo 1mo
46
if _, ok := renderCases()[name]; !ok {
133728e barerepo 1mo
47
t.Errorf("template %q has no case here, so nothing renders it before a user asks", name)
133728e barerepo 1mo
48
}
133728e barerepo 1mo
49
}
133728e barerepo 1mo
50
}
133728e barerepo 1mo
51
133728e barerepo 1mo
52
func renderCases() map[string]renderCase {
133728e barerepo 1mo
53
page := repoPage{
133728e barerepo 1mo
54
chrome: newChrome("barerepo · john/johnbot", "a summary"),
133728e barerepo 1mo
55
Owner: "john",
133728e barerepo 1mo
56
Name: "johnbot",
133728e barerepo 1mo
57
Branch: "master",
133728e barerepo 1mo
58
CloneURL: "git@barerepo:john/johnbot",
133728e barerepo 1mo
59
Tabs: repoTabs("john", "johnbot", "log", "master", 3),
133728e barerepo 1mo
60
}
133728e barerepo 1mo
61
commits := viewCommits("john", "johnbot", []gitread.Commit{{
133728e barerepo 1mo
62
SHA: "a3f9c2d", Short: "a3f9c2", Author: "lisa",
133728e barerepo 1mo
63
When: time.Now().Add(-2 * time.Hour), Subject: "fix panic when config is empty",
133728e barerepo 1mo
64
Add: 4, Del: 1,
133728e barerepo 1mo
65
Files: []gitread.FileDiff{{Path: "config.go", Add: 4, Del: 1, Hunks: []gitread.Hunk{{
133728e barerepo 1mo
66
Header: "@@ -41,7 +41,10 @@ func Load",
133728e barerepo 1mo
67
Lines: []gitread.Line{
133728e barerepo 1mo
68
{Kind: ' ', Text: "f, err := os.Open(path)"},
133728e barerepo 1mo
69
{Kind: '-', Text: "return cfg"},
133728e barerepo 1mo
70
{Kind: '+', Text: "if len(raw) == 0 {"},
133728e barerepo 1mo
71
},
133728e barerepo 1mo
72
}}}},
133728e barerepo 1mo
73
}})
133728e barerepo 1mo
74
133728e barerepo 1mo
75
return map[string]renderCase{
133728e barerepo 1mo
76
"repo-log": {
133728e barerepo 1mo
77
struct {
133728e barerepo 1mo
78
repoPage
133728e barerepo 1mo
79
Commits []commitView
133728e barerepo 1mo
80
ReadmeHref string
133728e barerepo 1mo
81
OnlyPath string
133728e barerepo 1mo
82
FileHref string
133728e barerepo 1mo
83
}{page, commits, "/john/johnbot/file/a3f9c2/README.md", "", ""},
133728e barerepo 1mo
84
[]string{"john / ", "johnbot", "a3f9c2", "fix panic", "barerepo 0.1.0"},
133728e barerepo 1mo
85
},
133728e barerepo 1mo
86
"push-rejected": {
133728e barerepo 1mo
87
struct {
133728e barerepo 1mo
88
repoPage
133728e barerepo 1mo
89
Ref string
133728e barerepo 1mo
90
Head string
133728e barerepo 1mo
91
Push string
133728e barerepo 1mo
92
You string
133728e barerepo 1mo
93
MayPush bool
133728e barerepo 1mo
94
}{page, "refs/heads/master", "a3f9c2 · 2h", `["john", "lisa"]`, "mark", false},
133728e barerepo 1mo
95
// html/template writes a quote as &#34; in text, so the assertion says what a reader sees.
133728e barerepo 1mo
96
[]string{"you pushed to refs/heads/master", "&#34;john&#34;, &#34;lisa&#34;", "you are mark",
133728e barerepo 1mo
97
"git push origin HEAD:refs/proposals/new", "printed in your terminal"},
133728e barerepo 1mo
98
},
133728e barerepo 1mo
99
"repo-empty": {
133728e barerepo 1mo
100
struct {
133728e barerepo 1mo
101
repoPage
133728e barerepo 1mo
102
Public bool
133728e barerepo 1mo
103
Description string
133728e barerepo 1mo
104
Visibility string
133728e barerepo 1mo
105
}{page, false, "", "private"},
133728e barerepo 1mo
106
[]string{"git init", "git@barerepo:john/johnbot", ".barerepo/config", "visibility"},
133728e barerepo 1mo
107
},
133728e barerepo 1mo
108
"repo-files": {
133728e barerepo 1mo
109
struct {
133728e barerepo 1mo
110
repoPage
133728e barerepo 1mo
111
Path string
133728e barerepo 1mo
112
Up string
133728e barerepo 1mo
113
Entries []entryView
133728e barerepo 1mo
114
More string
133728e barerepo 1mo
115
}{page, "", "", viewEntries("john", "johnbot", "master", []gitread.Entry{
133728e barerepo 1mo
116
{Name: "irc", Path: "irc", Dir: true, Author: "john", Subject: "split the daemon out"},
133728e barerepo 1mo
117
{Name: "config.go", Path: "config.go", Author: "lisa", Subject: "fix panic when config is empty"},
133728e barerepo 1mo
118
}), ""},
133728e barerepo 1mo
119
[]string{"irc/", "config.go", "split the daemon out", "/john/johnbot/files/master/irc"},
133728e barerepo 1mo
120
},
133728e barerepo 1mo
121
"repo-file": {
133728e barerepo 1mo
122
struct {
133728e barerepo 1mo
123
repoPage
133728e barerepo 1mo
124
Path string
133728e barerepo 1mo
125
File *gitread.File
133728e barerepo 1mo
126
Lines []fileLineView
133728e barerepo 1mo
127
Meta string
133728e barerepo 1mo
128
SizeText string
133728e barerepo 1mo
129
RawHref string
133728e barerepo 1mo
130
HistoryHref string
133728e barerepo 1mo
131
Shown int
133728e barerepo 1mo
132
Truncated bool
133728e barerepo 1mo
133
RenderedHref string
133728e barerepo 1mo
134
}{page, "config.go", &gitread.File{Path: "config.go", Size: 1400},
133728e barerepo 1mo
135
viewFileLines([]gitread.FileLine{{Number: 41, Text: "f, err := os.Open(path)",
133728e barerepo 1mo
136
Short: "a3f9c2", Author: "lisa", When: time.Now().Add(-2 * time.Hour)}}),
133728e barerepo 1mo
137
"61 lines · 1.4kb · master", "1.4kb", "/john/johnbot/raw/master/config.go",
133728e barerepo 1mo
138
"/john/johnbot?path=config.go", 0, false, ""},
133728e barerepo 1mo
139
[]string{"config.go", "a3f9c2 lisa 2h", "class=\"num\"", "os.Open(path)", "raw", "history"},
133728e barerepo 1mo
140
},
133728e barerepo 1mo
141
"repo-commit": {
133728e barerepo 1mo
142
struct {
133728e barerepo 1mo
143
repoPage
133728e barerepo 1mo
144
Commit commitView
133728e barerepo 1mo
145
FileCount string
133728e barerepo 1mo
146
Reachable bool
133728e barerepo 1mo
147
Parent string
133728e barerepo 1mo
148
ParentHref string
133728e barerepo 1mo
149
FilesHref string
133728e barerepo 1mo
150
Signature string
133728e barerepo 1mo
151
SigBad bool
133728e barerepo 1mo
152
SignerHref string
133728e barerepo 1mo
153
Signer string
133728e barerepo 1mo
154
Verify string
133728e barerepo 1mo
155
}{page, commits[0], "1 file", true, "8b1d44",
133728e barerepo 1mo
156
"/john/johnbot/commit/8b1d44", "/john/johnbot/file/a3f9c2/",
133728e barerepo 1mo
157
"signed by lisa", false, "/lisa", "lisa", "git verify-commit a3f9c2d"},
133728e barerepo 1mo
158
[]string{"a3f9c2", "fix panic", "reachable from", `href="/lisa">lisa`,
133728e barerepo 1mo
159
`href="/john/johnbot">master`, `href="/john/johnbot/commit/8b1d44">8b1d44`,
133728e barerepo 1mo
160
`href="/john/johnbot/file/a3f9c2/config.go"`},
133728e barerepo 1mo
161
},
133728e barerepo 1mo
162
"repo-compare": {
133728e barerepo 1mo
163
struct {
133728e barerepo 1mo
164
repoPage
133728e barerepo 1mo
165
Comparison *gitread.Comparison
133728e barerepo 1mo
166
Files []fileView
133728e barerepo 1mo
167
Stats string
133728e barerepo 1mo
168
Action string
133728e barerepo 1mo
169
FilesHref string
133728e barerepo 1mo
170
Refs []refLink
133728e barerepo 1mo
171
}{page, &gitread.Comparison{A: "master", B: "refs/proposals/47"},
133728e barerepo 1mo
172
viewFiles(commits[0].Commit.Files, nil),
133728e barerepo 1mo
173
"3 commits · 2 files · +81 -12 · no conflicts", "/john/johnbot/compare",
133728e barerepo 1mo
174
"/john/johnbot/file/refs/proposals/47/",
133728e barerepo 1mo
175
[]refLink{{Name: "topic", Kind: "branch", Href: "/john/johnbot/compare/master...topic"}}},
133728e barerepo 1mo
176
[]string{"master", "refs/proposals/47", "no conflicts", "class=\"rev\"",
133728e barerepo 1mo
177
`href="/john/johnbot/file/refs/proposals/47/config.go"`,
133728e barerepo 1mo
178
`href="/john/johnbot/compare/master...topic"`},
133728e barerepo 1mo
179
},
133728e barerepo 1mo
180
"404": {
133728e barerepo 1mo
181
struct {
133728e barerepo 1mo
182
chrome
133728e barerepo 1mo
183
Path string
133728e barerepo 1mo
184
Near string
133728e barerepo 1mo
185
Href string
133728e barerepo 1mo
186
Missing string
133728e barerepo 1mo
187
}{newChrome("barerepo · not found", "s"), "/john/johnbot/nope", "john/johnbot", "/john/johnbot", ""},
133728e barerepo 1mo
188
[]string{"404", "john/johnbot", "exists. that path in it does not."},
133728e barerepo 1mo
189
},
133728e barerepo 1mo
190
"readme": {
133728e barerepo 1mo
191
struct {
133728e barerepo 1mo
192
repoPage
133728e barerepo 1mo
193
Path string
133728e barerepo 1mo
194
HTML template.HTML
133728e barerepo 1mo
195
SourceHref string
133728e barerepo 1mo
196
RawHref string
133728e barerepo 1mo
197
}{page, "README.md", template.HTML("<h1>barerepo</h1>"),
133728e barerepo 1mo
198
"/john/johnbot/file/a3f9c2/README.md", "/john/johnbot/raw/a3f9c2/README.md"},
133728e barerepo 1mo
199
[]string{"README.md", "<h1>barerepo</h1>", "rendered",
133728e barerepo 1mo
200
`href="/john/johnbot/file/a3f9c2/README.md"`, ">source<",
133728e barerepo 1mo
201
`href="/john/johnbot/raw/a3f9c2/README.md"`},
133728e barerepo 1mo
202
},
133728e barerepo 1mo
203
"threads": {
133728e barerepo 1mo
204
struct {
133728e barerepo 1mo
205
repoPage
133728e barerepo 1mo
206
Threads []threadRow
133728e barerepo 1mo
207
Counts string
133728e barerepo 1mo
208
Viewer string
133728e barerepo 1mo
209
Empty string
133728e barerepo 1mo
210
}{page, []threadRow{{N: 47, Title: "panic when config file is empty",
133728e barerepo 1mo
211
Author: "lisa", AuthorHref: "/lisa", Ago: "2h",
133728e barerepo 1mo
212
Href: "/john/johnbot/thread/47",
133728e barerepo 1mo
213
Detail: []bit{plain("has proposal"), {Text: "+81 -12", Href: "/john/johnbot/compare"},
133728e barerepo 1mo
214
{Text: "build failed", Danger: true}, plain("2 replies")}}},
214 of 1012 lines · the whole file
history · rawbarerepo 0.1.0