v0.10.0 5e05d65

issue_test.go RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3package api_test
4
5import (
6	"testing"
7
8	"bnema.dev/ermite-api/gen/ermite"
9	"bnema.dev/ermite-api/gen/ermite/ermiteconnect"
10	"google.golang.org/protobuf/proto"
11	"google.golang.org/protobuf/reflect/protoreflect"
12)
13
14func TestIssueProcedures(t *testing.T) {
15	tests := map[string]string{
16		ermiteconnect.IssueServiceCreateIssueProcedure:       "CreateIssue",
17		ermiteconnect.IssueServiceListIssuesProcedure:        "ListIssues",
18		ermiteconnect.IssueServiceGetIssueProcedure:          "GetIssue",
19		ermiteconnect.IssueServiceAddIssueCommentProcedure:   "AddIssueComment",
20		ermiteconnect.IssueServiceCloseIssueProcedure:        "CloseIssue",
21		ermiteconnect.IssueServiceReopenIssueProcedure:       "ReopenIssue",
22		ermiteconnect.IssueServiceListPendingIssuesProcedure: "ListPendingIssues",
23		ermiteconnect.IssueServiceApproveIssueProcedure:      "ApproveIssue",
24		ermiteconnect.IssueServiceRejectIssueProcedure:       "RejectIssue",
25	}
26	for got, name := range tests {
27		if want := "/ermite.IssueService/" + name; got != want {
28			t.Errorf("procedure = %q, want %q", got, want)
29		}
30	}
31}
32
33func TestIssueContract(t *testing.T) {
34	for _, tt := range []struct {
35		msg    proto.Message
36		fields map[string]int
37	}{
38		{&ermite.Issue{}, map[string]int{"repo": 1, "number": 2, "title": 3, "body": 4, "state": 5, "author": 6, "created_at": 7, "updated_at": 8, "comment_count": 9}},
39		{&ermite.IssueComment{}, map[string]int{"id": 1, "author": 2, "text": 3, "created_at": 4}},
40		{&ermite.RepoSettings{}, map[string]int{"issues": 3}},
41		{&ermite.UpdateRepoRequest{}, map[string]int{"issues": 8}},
42		{&ermite.Event{}, map[string]int{"issue_opened": 17, "issue_closed": 18, "issue_reopened": 19, "issue_commented": 20, "issue_submitted": 21}},
43		{&ermite.IssueSubmitted{}, map[string]int{"repo": 1, "id": 2}},
44		{&ermite.PendingIssue{}, map[string]int{"id": 1, "repo": 2, "title": 3, "body": 4, "author": 5, "created_at": 6}},
45		{&ermite.ListPendingIssuesRequest{}, map[string]int{"repo": 1, "page_size": 2, "page_token": 3}},
46		{&ermite.ListPendingIssuesResponse{}, map[string]int{"issues": 1, "next_page_token": 2}},
47		{&ermite.ApproveIssueRequest{}, map[string]int{"repo": 1, "id": 2}},
48		{&ermite.ApproveIssueResponse{}, map[string]int{"issue": 1}},
49		{&ermite.RejectIssueRequest{}, map[string]int{"repo": 1, "id": 2, "ban": 3}},
50	} {
51		md := tt.msg.ProtoReflect().Descriptor()
52		for name, num := range tt.fields {
53			if fd := md.Fields().ByName(protoreflect.Name(name)); fd == nil || int(fd.Number()) != num {
54				t.Errorf("%s.%s = %v, want %d", md.Name(), name, fd, num)
55			}
56		}
57	}
58	if ermite.Scope_SCOPE_ISSUE_WRITE != 11 {
59		t.Fatal("issue:write scope number changed")
60	}
61	for name, want := range map[string]int32{"ISSUE_STATE_UNSPECIFIED": 0, "ISSUE_STATE_OPEN": 1, "ISSUE_STATE_CLOSED": 2, "ISSUE_STATE_PENDING": 3} {
62		if got := ermite.IssueState_value[name]; got != want {
63			t.Errorf("%s = %d, want %d", name, got, want)
64		}
65	}
66	for name, want := range map[string]int32{"ISSUES_MODE_UNSPECIFIED": 0, "ISSUES_MODE_OFF": 1, "ISSUES_MODE_OWNER": 2, "ISSUES_MODE_PUBLIC": 3} {
67		if got := ermite.IssuesMode_value[name]; got != want {
68			t.Errorf("%s = %d, want %d", name, got, want)
69		}
70	}
71	mode := ermite.IssuesMode_ISSUES_MODE_OFF
72	for _, in := range []proto.Message{
73		&ermite.UpdateRepoRequest{Repo: "r", Issues: &mode},
74		&ermite.Event{Kind: &ermite.Event_IssueOpened{IssueOpened: &ermite.IssueOpened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
75		&ermite.Event{Kind: &ermite.Event_IssueClosed{IssueClosed: &ermite.IssueClosed{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
76		&ermite.Event{Kind: &ermite.Event_IssueReopened{IssueReopened: &ermite.IssueReopened{Issue: &ermite.Issue{Repo: "r", Number: 1}}}},
77		&ermite.Event{Kind: &ermite.Event_IssueSubmitted{IssueSubmitted: &ermite.IssueSubmitted{Repo: "r", Id: "p1"}}},
78		&ermite.PendingIssue{Id: "p1", Repo: "r", Title: "t", Author: "anon"},
79		&ermite.RejectIssueRequest{Repo: "r", Id: "p1", Ban: true},
80		&ermite.Event{Kind: &ermite.Event_IssueCommented{IssueCommented: &ermite.IssueCommented{Repo: "r", Number: 1, Comment: &ermite.IssueComment{Id: "c", Text: "hi"}}}},
81	} {
82		b, err := proto.Marshal(in)
83		if err != nil {
84			t.Fatal(err)
85		}
86		out := in.ProtoReflect().New().Interface()
87		if err := proto.Unmarshal(b, out); err != nil {
88			t.Fatal(err)
89		}
90		if !proto.Equal(in, out) {
91			t.Errorf("%T: round trip mismatch", in)
92		}
93	}
94	fd := (&ermite.UpdateRepoRequest{}).ProtoReflect().Descriptor().Fields().ByName("issues")
95	if !fd.HasOptionalKeyword() {
96		t.Fatal("UpdateRepoRequest.issues must be optional")
97	}
98}

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 2

Tags 18

↑↓ moveenter openesc close