v3.1.0 d676137

json_test.go RawHistoryFolder

1package cli
2
3import (
4	"bytes"
5	"encoding/json"
6	"testing"
7	"time"
8
9	"github.com/stretchr/testify/assert"
10	"github.com/stretchr/testify/require"
11
12	"github.com/bnema/gordon/internal/adapters/dto"
13	"github.com/bnema/gordon/internal/domain"
14)
15
16func TestImagesList_JSONFlag_Accepted(t *testing.T) {
17	cmd := newImagesListCmd()
18	f := cmd.Flags().Lookup("json")
19	assert.NotNil(t, f)
20	if f != nil {
21		assert.Equal(t, "false", f.DefValue)
22	}
23}
24
25func TestBackupList_JSONFlag_Accepted(t *testing.T) {
26	cmd := newBackupListCmd()
27	f := cmd.Flags().Lookup("json")
28	assert.NotNil(t, f)
29	if f != nil {
30		assert.Equal(t, "false", f.DefValue)
31	}
32}
33
34func TestTokenList_JSONFlag_Accepted(t *testing.T) {
35	cmd := newTokenListCmd()
36	f := cmd.Flags().Lookup("json")
37	assert.NotNil(t, f)
38	if f != nil {
39		assert.Equal(t, "false", f.DefValue)
40	}
41}
42
43func TestRemotesList_JSONFlag_Accepted(t *testing.T) {
44	cmd := newRemotesListCmd()
45	f := cmd.Flags().Lookup("json")
46	assert.NotNil(t, f)
47	if f != nil {
48		assert.Equal(t, "false", f.DefValue)
49	}
50}
51
52func TestImagesList_JSONShape_RoundTripsDTO(t *testing.T) {
53	createdAt := time.Date(2026, 2, 8, 12, 0, 0, 0, time.UTC)
54	images := []dto.Image{{Repository: "registry.example.com/app", Tag: "latest", Size: 12_000_000, Created: createdAt, ID: "sha256:1111", Dangling: false}}
55
56	payload, err := json.Marshal(images)
57	require.NoError(t, err)
58
59	var got []dto.Image
60	require.NoError(t, json.Unmarshal(payload, &got))
61	require.Len(t, got, 1)
62	assert.Equal(t, images[0].Repository, got[0].Repository)
63	assert.Equal(t, images[0].Tag, got[0].Tag)
64	assert.Equal(t, images[0].ID, got[0].ID)
65}
66
67func TestPinList_JSONShape_RoundTripsTags(t *testing.T) {
68	tags := []string{"v1.2.0", "v1.1.0"}
69	payload, err := json.Marshal(tags)
70	require.NoError(t, err)
71
72	var got []string
73	require.NoError(t, json.Unmarshal(payload, &got))
74	assert.Equal(t, tags, got)
75}
76
77func TestBackupList_JSONShape_RoundTripsJobs(t *testing.T) {
78	startedAt := time.Date(2026, 3, 1, 10, 0, 0, 0, time.UTC)
79	jobs := []domain.BackupJob{{ID: "b1", App: "shop", Service: "api", DBName: "orders", Status: domain.BackupStatusCompleted, StartedAt: startedAt}}
80
81	payload, err := json.Marshal(jobs)
82	require.NoError(t, err)
83
84	var got []domain.BackupJob
85	require.NoError(t, json.Unmarshal(payload, &got))
86	require.Len(t, got, 1)
87	assert.Equal(t, "b1", got[0].ID)
88	assert.Equal(t, "shop", got[0].App)
89	assert.Equal(t, "api", got[0].Service)
90	assert.Equal(t, "orders", got[0].DBName)
91}
92
93func TestTokenList_JSONShape_RoundTripsTokens(t *testing.T) {
94	tokens := []domain.Token{{
95		ID:        "tok-1",
96		Subject:   "deploy",
97		Scopes:    []string{"admin:*:*"},
98		IssuedAt:  time.Date(2026, 3, 1, 10, 0, 0, 0, time.UTC),
99		ExpiresAt: time.Date(2026, 4, 1, 10, 0, 0, 0, time.UTC),
100	}}
101
102	payload, err := json.Marshal(tokens)
103	require.NoError(t, err)
104
105	var got []domain.Token
106	require.NoError(t, json.Unmarshal(payload, &got))
107	require.Len(t, got, 1)
108	assert.Equal(t, tokens[0].ID, got[0].ID)
109	assert.Equal(t, tokens[0].Subject, got[0].Subject)
110	assert.Equal(t, tokens[0].Scopes, got[0].Scopes)
111}
112
113func TestRemotesList_JSONShape_RoundTripsRemoteObjects(t *testing.T) {
114	items := []struct {
115		Name        string `json:"name"`
116		URL         string `json:"url"`
117		Active      bool   `json:"active"`
118		InsecureTLS bool   `json:"insecure_tls"`
119	}{
120		{Name: "prod", URL: "https://prod.example.com", Active: true, InsecureTLS: true},
121	}
122
123	payload, err := json.Marshal(items)
124	require.NoError(t, err)
125
126	var got []struct {
127		Name        string `json:"name"`
128		URL         string `json:"url"`
129		Active      bool   `json:"active"`
130		InsecureTLS bool   `json:"insecure_tls"`
131	}
132	require.NoError(t, json.Unmarshal(payload, &got))
133	require.Len(t, got, 1)
134	assert.Equal(t, "prod", got[0].Name)
135	assert.Equal(t, "https://prod.example.com", got[0].URL)
136	assert.True(t, got[0].Active)
137	assert.True(t, got[0].InsecureTLS)
138}
139
140func TestWriteJSON_ProducesValidIndentedJSON(t *testing.T) {
141	var out bytes.Buffer
142	err := writeJSON(&out, map[string]any{"ok": true})
143	require.NoError(t, err)
144
145	var got map[string]any
146	require.NoError(t, json.Unmarshal(out.Bytes(), &got))
147	assert.Equal(t, true, got["ok"])
148	assert.Contains(t, out.String(), "\n")
149}

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 7

Tags 106

↑↓ moveenter openesc close