Artifact [c1547ecce7]
Not logged in

Artifact c1547ecce7f03726989f1acc241ebbc3bacee5ecfb85aff8d8860e8a9ba285fa:


package web

import (
	"regexp"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/oltp"
)

// The tab comment that held the strip at two set its own acceptance
// test: "a tab that opens onto an empty page teaches a reader the forge
// is broken rather than that the feature is unbuilt." So the Teams tab
// appears only when the forge has one.
func TestTheTeamsTabAppearsOnlyOnceATeamExists(t *testing.T) {
	var none, some strings.Builder
	if err := peoplePage.ExecuteTemplate(&none, "content",
		pageData{Explore: "people", FleetTotal: 20, PeopleTotal: 3}); err != nil {
		t.Fatal(err)
	}
	if strings.Contains(none.String(), `href="/teams"`) {
		t.Error("FAIL: a forge with no teams draws the Teams tab")
	}
	if err := peoplePage.ExecuteTemplate(&some, "content",
		pageData{Explore: "people", FleetTotal: 20, PeopleTotal: 3, TeamsTotal: 2}); err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(some.String(), `href="/teams"`) {
		t.Error("FAIL: a forge with teams does not draw the Teams tab")
	}
	// And the other two are still there, in order.
	body := some.String()
	repos, people, teams := strings.Index(body, `href="/?view=explore"`),
		strings.Index(body, `href="/people"`), strings.Index(body, `href="/teams"`)
	if !(repos < people && people < teams) {
		t.Errorf("FAIL: tab order is repos %d, people %d, teams %d", repos, people, teams)
	}
}

// A team is shown by its title where it has one, and never by both —
// "Craft Design Group (craft-design-group)" is the same fact twice and
// the handle is already in the URL.
func TestATeamIsLabelledOnceNotTwice(t *testing.T) {
	named := teamRow{Name: "craft-design-group", Title: "Craft Design Group"}
	if got := named.Label(); got != "Craft Design Group" {
		t.Errorf("FAIL: label = %q", got)
	}
	if !named.Named() {
		t.Error("FAIL: a titled team does not read as named")
	}
	bare := teamRow{Name: "core"}
	if got := bare.Label(); got != "core" {
		t.Errorf("FAIL: an untitled team labels as %q", got)
	}
	if bare.Named() {
		t.Error("FAIL: an untitled team would print its handle twice")
	}
	// A title that merely repeats the handle is not a second fact.
	if (teamRow{Name: "core", Title: "core"}).Named() {
		t.Error("FAIL: a title equal to the handle reads as named")
	}
}

// The directory says where a team's substance is, and a team with no
// repositories is a real row rather than one that reads as broken.
func TestTheDirectoryNamesAnEmptyTeamHonestly(t *testing.T) {
	var buf strings.Builder
	if err := teamsPage.ExecuteTemplate(&buf, "content", pageData{
		Explore: "teams", TeamsTotal: 2,
		Teams: []teamRow{
			{Name: "craft-design-group", Title: "Craft Design Group",
				Descr: "quarry and zit", Members: 1, Repos: 0},
			{Name: "firestorm-dataworks", Title: "FireStorm DataWorks", Members: 4, Repos: 3},
		},
	}); err != nil {
		t.Fatal(err)
	}
	body := buf.String()
	for _, want := range []string{
		`href="/t/craft-design-group"`, "Craft Design Group", "quarry and zit",
		"no repositories yet", "3 repositories", "1 member", "4 members",
	} {
		if !strings.Contains(body, want) {
			t.Errorf("FAIL: the directory is missing %q", want)
		}
	}
	// A count of zero must not render as a bare "0 repositories".
	if strings.Contains(body, "0 repositor") {
		t.Error("FAIL: an empty team reads as a zero rather than as a sentence")
	}
}

// An empty forge says what a team is for, rather than showing an empty
// list — the same rule the tab comment states.
func TestAnEmptyDirectorySaysWhatATeamIs(t *testing.T) {
	var buf strings.Builder
	if err := teamsPage.ExecuteTemplate(&buf, "content", pageData{Explore: "teams"}); err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(buf.String(), "No teams yet") {
		t.Error("FAIL: an empty directory renders an empty list")
	}
}

// A member's standing is named in the words the People editor uses: the
// preset where the string matches one, the letters where it does not.
func TestAMembersRoleReadsAsARoleWhereItIsOne(t *testing.T) {
	for _, tc := range []struct {
		caps, want string
	}{
		{"", "by membership"}, // RFC 0018's third route, named
		{oltp.Maintain.Caps(), "Maintainer"},
		{"a", "Admin"},
		{"2i", "2i"}, // no preset covers it; the letters stand
	} {
		if got := (teamMember{Caps: tc.caps}).Role(); got != tc.want {
			t.Errorf("FAIL: Role(%q) = %q, want %q", tc.caps, got, tc.want)
		}
	}
}

// One team's page: the repositories under it, the members, and the
// owner marked. An unlisted member reaching a manager is marked as
// such, so the manager can see why the public page differs.
func TestTheTeamPageShowsReposMembersAndWhoOwnsIt(t *testing.T) {
	var buf strings.Builder
	td := teamDetail{
		Team: teamRow{Name: "craft-design-group", Title: "Craft Design Group",
			Descr: "quarry and zit", Members: 2, Repos: 2},
		Repos: []teamRepo{
			{Repo: "quarry", Added: "2026-09-12T00:00:00Z"},
			{Repo: "zit", Added: "2026-09-12T00:00:00Z"},
		},
		Members: []teamMember{
			{Account: "dmestas", Owner: true, Listed: true},
			{Account: "lou", Caps: oltp.Maintain.Caps(), Listed: false},
		},
		CanManage: true,
	}
	if err := teamPage.ExecuteTemplate(&buf, "content",
		pageData{Title: "Craft Design Group", OwnH1: true, Team: &td}); err != nil {
		t.Fatal(err)
	}
	body := buf.String()
	for _, want := range []string{
		"Craft Design Group", "quarry and zit",
		`href="/r/quarry"`, `href="/r/zit"`,
		`href="/people/dmestas"`, "owner", "Maintainer", "unlisted",
	} {
		if !strings.Contains(body, want) {
			t.Errorf("FAIL: the team page is missing %q", want)
		}
	}
}

// A team holding nothing says so on its own page too, in a sentence
// that tells a reader how a repository gets there.
func TestAnEmptyTeamPageExplainsItself(t *testing.T) {
	var buf strings.Builder
	td := teamDetail{Team: teamRow{Name: "core", Members: 1}}
	if err := teamPage.ExecuteTemplate(&buf, "content", pageData{Team: &td}); err != nil {
		t.Fatal(err)
	}
	body := buf.String()
	if !strings.Contains(body, "somebody who administers it") {
		t.Error("FAIL: an empty team does not say how a repository joins")
	}
	if regexp.MustCompile(`0 repositor`).MatchString(body) {
		t.Error("FAIL: renders a zero instead of a sentence")
	}
}