Files
gitea-tea/internal/app/repos_test.go
T
bircni 70443acce0 fix: reconcile the repository, platform and admin streams
Share one yesNo helper, drop the unused confirmTyped now that typed
confirmations go through confirmAction, keep Markdown raw in view tests
through the markdown preference, and print doctor latency in whole
milliseconds so fast instances do not show 0s.

Signed-off-by: bircni <bircni@icloud.com>
2026-10-11 23:54:37 +02:00

160 lines
7.5 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package app
import (
"bytes"
"context"
"net/http"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
)
// repoTTYDeps returns serverDeps for a 100-column terminal without color or links, as people read
// tea's output, at a fixed time.
func repoTTYDeps(t *testing.T, serverURL string) (Dependencies, *bytes.Buffer, *bytes.Buffer) {
t.Helper()
deps, out, diagnostics := serverDeps(t, serverURL)
deps.Getenv = serverEnv(serverURL, map[string]string{"TERM": "dumb"})
deps.Streams.OutTTY, deps.Streams.Width = true, 100
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
return deps, out, diagnostics
}
const listedRepositories = `[
{"full_name":"alice/old-stuff","description":"Archived repository","archived":true,"html_url":"https://gitea.test/alice/old-stuff","updated_at":"2026-10-11T18:00:00Z"},
{"full_name":"acme/service","private":true,"fork":true,"html_url":"https://gitea.test/acme/service","updated_at":"2026-10-09T18:00:00Z"}
]`
func TestRepoListShowsColumns(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/api/v1/user/repos", r.URL.Path)
w.Header().Set("X-Total-Count", "2")
_, _ = w.Write([]byte(listedRepositories))
}))
defer server.Close()
deps, out, _ := repoTTYDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "list"}))
require.Equal(t, `Showing 2 of 2 repositories you can access
NAME DESCRIPTION INFO UPDATED
alice/old-stuff Archived repository public, archived about 2 hours ago
acme/service private, fork about 2 days ago
`, out.String())
deps, out, _ = serverDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "list"}))
require.Equal(t, "alice/old-stuff\tArchived repository\tpublic, archived\t2026-10-11T18:00:00Z\thttps://gitea.test/alice/old-stuff\n"+
"acme/service\t\tprivate, fork\t2026-10-09T18:00:00Z\thttps://gitea.test/acme/service\n", out.String())
}
func TestRepoListReportsAnEmptyCollection(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/v1/orgs/acme":
_, _ = w.Write([]byte(`{"id":3,"username":"acme"}`))
default:
_, _ = w.Write([]byte(`[]`))
}
}))
defer server.Close()
deps, out, diagnostics := repoTTYDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "list", "acme", "--type", "fork"}))
require.Empty(t, out.String())
require.Equal(t, "no forks owned by acme\n", diagnostics.String())
}
func TestRepoViewShowsStateAndReadme(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/v1/repos/bob/project":
_, _ = w.Write([]byte(`{"full_name":"bob/project","description":"Demo","fork":true,"archived":true,"default_branch":"main",
"stars_count":1,"forks_count":0,"open_issues_count":2,"open_pr_counter":1,"updated_at":"2026-10-11T19:00:00Z",
"html_url":"https://gitea.test/bob/project","clone_url":"https://gitea.test/bob/project.git",
"parent":{"full_name":"alice/project"}}`))
case "/api/v1/repos/bob/project/contents/":
require.Equal(t, "develop", r.URL.Query().Get("ref"))
_, _ = w.Write([]byte(`[{"name":"docs","type":"dir"},{"name":"README","type":"file"},{"name":"readme.md","type":"file"}]`))
case "/api/v1/repos/bob/project/raw/readme.md":
_, _ = w.Write([]byte("Hello **there**"))
default:
t.Errorf("unexpected request %s", r.URL)
}
}))
defer server.Close()
deps, out, _ := repoTTYDeps(t, server.URL)
deps.Getenv = serverEnv(server.URL, map[string]string{"TERM": "dumb"})
rawMarkdown(t, deps)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "view", "bob/project", "--branch", "develop"}))
require.Equal(t, `bob/project
public • fork • archived (read-only) • ★ 1 · 0 forks · 2 open issues · 1 open pull request · updated about 1 hour ago
Description: Demo
Forked from: alice/project
Default branch: main
Clone: https://gitea.test/bob/project.git
Hello **there**
View this repository on Gitea: https://gitea.test/bob/project
`, out.String())
deps, out, _ = serverDeps(t, server.URL)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "view", "bob/project", "-b", "develop"}))
require.Equal(t, "title:\tbob/project\ndescription:\tDemo\nforked from:\talice/project\nmirror of:\t\ndefault branch:\tmain\nwebsite:\t\ntopics:\t\n"+
"clone:\thttps://gitea.test/bob/project.git\nssh:\t\nurl:\thttps://gitea.test/bob/project\n--\nHello **there**\n", out.String())
}
func TestRepoSetDefaultValidatesTheRepository(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/api/v1/repos/alice/project" {
w.WriteHeader(http.StatusNotFound)
return
}
_, _ = w.Write([]byte(`{"full_name":"alice/project"}`))
}))
defer server.Close()
deps, _, diagnostics := repoTTYDeps(t, server.URL)
saved := "config --local tea.repository " + server.URL + "/alice/project"
runner := &fakeGit{results: map[string]string{"rev-parse --is-inside-work-tree": "true", saved: ""}}
deps.Git = runner
err := Execute(context.Background(), deps, []string{"repo", "set-default", "nobody/none"})
require.Error(t, err)
require.NotContains(t, strings.Join(runner.calls, "\n"), "config --local tea.repository")
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "set-default", "alice/project"}))
require.Contains(t, runner.calls, saved)
require.Equal(t, "✓ Set alice/project as the default repository for this clone\n", diagnostics.String())
}
func TestRepoSetDefaultViewAndUnset(t *testing.T) {
deps, out, diagnostics := repoTTYDeps(t, "http://gitea.test")
runner := &fakeGit{results: map[string]string{
"rev-parse --is-inside-work-tree": "true",
"config --local --get tea.repository": "http://gitea.test/alice/project",
"config --local --unset tea.repository": "",
}}
deps.Git = runner
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "set-default", "--view"}))
require.Equal(t, "http://gitea.test/alice/project\n", out.String())
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "set-default", "-u"}))
require.Equal(t, "✓ Removed the default repository http://gitea.test/alice/project from this clone\n", diagnostics.String())
deps.Git = &fakeGit{}
err := Execute(context.Background(), deps, []string{"repo", "set-default", "-v"})
require.ErrorContains(t, err, "set-default must run inside a Git clone")
}
func TestRepoViewOfAnEmptyRepositorySkipsTheReadme(t *testing.T) {
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/api/v1/repos/alice/empty", r.URL.Path)
_, _ = w.Write([]byte(`{"full_name":"alice/empty","private":true,"empty":true,"html_url":"https://gitea.test/alice/empty"}`))
}))
defer server.Close()
deps, out, _ := repoTTYDeps(t, server.URL)
deps.Getenv = serverEnv(server.URL, map[string]string{"TERM": "dumb"})
rawMarkdown(t, deps)
require.NoError(t, Execute(context.Background(), deps, []string{"repo", "view", "alice/empty"}))
require.Contains(t, out.String(), "private • empty • ★ 0")
require.Contains(t, out.String(), "_This repository is empty._")
}