detached 388d3be

heartbeat_test.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package web
4
5import (
6	"strconv"
7	"strings"
8	"testing"
9
10	"github.com/stretchr/testify/assert"
11	"github.com/stretchr/testify/require"
12)
13
14func TestHeartbeat(t *testing.T) {
15	t.Parallel()
16	assert.Nil(t, heartbeatOf("x", nil, false), "no data, no curve")
17
18	days := make([]int, 90)
19	days[10], days[60], days[88] = 30, 4, 2
20	h := heartbeatOf("proj", days, false)
21	require.NotNil(t, h)
22	assert.True(t, strings.HasPrefix(h.Line, "M0 "), h.Line)
23	assert.Equal(t, 45, strings.Count(h.Line, " C"), "a point every two days, and today")
24	assert.Less(t, len(h.Line)+len(h.Area), 4000, "light enough for every live update")
25	assert.True(t, strings.HasPrefix(h.Area, h.Line) && strings.HasSuffix(h.Area, " Z"))
26	assert.Equal(t, "hb-proj", h.GradID)
27	assert.Equal(t, "Activity: 36 commits in the last 90 days", h.Label)
28	assert.True(t, h.Live, "commits in the last week")
29	assert.Equal(t, num(heartbeatEndX), h.X)
30
31	// Every point stays inside the box: no overshoot below the base line or
32	// above the top.
33	for _, f := range strings.FieldsFunc(h.Line, func(r rune) bool { return r == 'M' || r == 'C' || r == ' ' }) {
34		v, err := strconv.ParseFloat(f, 64)
35		require.NoError(t, err, f)
36		assert.GreaterOrEqual(t, v, 0.0)
37		assert.LessOrEqual(t, v, heartbeatW)
38	}
39
40	quiet := heartbeatOf("q", make([]int, 90), false)
41	require.NotNil(t, quiet)
42	assert.False(t, quiet.Live)
43	assert.Equal(t, num(heartbeatH-heartbeatPad), quiet.Y, "a flat line on the base")
44	assert.Equal(t, 1, strings.Count(quiet.Line, " C"), "two points")
45	assert.Equal(t, "Activity: 0 commits in the last 90 days", quiet.Label)
46
47	assert.Equal(t, "Activity: at least 36 commits in the last 90 days", heartbeatOf("proj", days, true).Label)
48}
49
50func TestPulseCache(t *testing.T) {
51	t.Parallel()
52	var c pulseCache
53	days := make([]int, 90)
54	days[80] = 3
55	a := c.get("proj", days, false)
56	require.NotNil(t, a)
57	assert.Same(t, a, c.get("proj", days, false), "same figures, same curve")
58	assert.Equal(t, heartbeatOf("proj", days, false), a)
59
60	assert.NotSame(t, a, c.get("other", days, false), "per repository: the gradient id differs")
61	assert.NotSame(t, a, c.get("proj", days, true), "partial changes the label")
62	days[89] = 1
63	b := c.get("proj", days, false)
64	assert.NotSame(t, a, b, "new figures, new curve")
65	assert.True(t, b.Live)
66	assert.Nil(t, c.get("proj", nil, false))
67}
68
69func BenchmarkPulseCache(b *testing.B) {
70	var c pulseCache
71	days := make([]int, 90)
72	for i := range days {
73		days[i] = i * 7 % 11
74	}
75	b.ReportAllocs()
76	for b.Loop() {
77		c.get("neferwl", days, false)
78	}
79}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 4

Tags 45

↑↓ moveenter openesc close