package web
import (
"strings"
"testing"
)
// The page a person opens to ask about themselves could not answer the
// question they came with. /me listed no repositories, no roles and no
// teams; the dashboard drew a Reader repository and an Admin one
// identically; and account.explain refused you your own letters. This
// is the last of those three (ticket f44e0c66).
func TestMeSaysWhatYouMayReach(t *testing.T) {
me := meView{Name: "jva", Created: "2026-06-01T00:00:00Z",
Access: []meAccessRow{
{Repo: "quarry", Role: "Reader"},
{Repo: "dantest-sandbox", Role: "Admin"},
},
Teams: []string{"dantest-crew"},
Notify: &prefsView{},
}
var b strings.Builder
if err := noHooks.template(mePageTmpl).ExecuteTemplate(&b, "content",
pageData{Title: "jva", User: "jva", Me: &me}); err != nil {
t.Fatal(err)
}
got := b.String()
for what, want := range map[string]string{
"names the repository": "dantest-sandbox",
"says the role on it": "Admin",
"distinguishes the other": "Reader",
"lists the team": "dantest-crew",
"is reachable from the rail": `href="#access"`,
} {
if !strings.Contains(got, want) {
t.Errorf("FAIL: /me no longer %s (%q)", what, want)
} else {
t.Logf("ok: /me %s", what)
}
}
// Somebody with no grants is told so plainly, and told what they can
// still do — an empty table would read as a bug.
var none strings.Builder
if err := noHooks.template(mePageTmpl).ExecuteTemplate(&none, "content",
pageData{Title: "jan", User: "jan", Me: &meView{Name: "jan", Notify: &prefsView{}}}); err != nil {
t.Fatal(err)
}
if !strings.Contains(none.String(), "No repository has given you a role") {
t.Error("FAIL: an account with no grants is shown an empty table and no explanation")
} else {
t.Log("ok: no role is stated rather than left blank")
}
// A site admin reaches what the table says and no more (#318), so
// nothing on the page may tell them otherwise.
var admin strings.Builder
if err := noHooks.template(mePageTmpl).ExecuteTemplate(&admin, "content",
pageData{Title: "dmestas", User: "dmestas", Me: &meView{Name: "dmestas", Admin: true, Notify: &prefsView{}}}); err != nil {
t.Fatal(err)
}
if !strings.Contains(admin.String(), `data-hook="me-site-admin"`) {
t.Error("FAIL: a site admin is not told the flag gives them no repository")
}
if strings.Contains(admin.String(), "reach every repository") {
t.Error("FAIL: a site admin is told they reach every repository")
}
}
// A ROLE NAME ALONE UNDERSTATES A GRANT THAT HOLDS MORE.
//
// jan held Reader plus the check-in letter; the page drew the bare word
// "reader", and the account concluded it could not push. It could. The
// table now qualifies the name and renders what the difference IS.
//
// Asserted on the data hooks rather than on the words, per this repo's
// rule for page tests: the hook says the difference REACHED the page,
// which is the claim. What it reads like is a judgement no assertion
// makes, and that is what the browser pass is for.
func TestTheAccessTableSaysWhenARoleHoldsMore(t *testing.T) {
me := meView{Name: "jan",
Access: []meAccessRow{{
Repo: "dantest-pushmatrix", Role: "Reader", Exact: false,
Plus: []string{"check in and push"},
}},
Notify: &prefsView{},
}
var b strings.Builder
if err := noHooks.template(mePageTmpl).ExecuteTemplate(&b, "content",
pageData{Title: "jan", User: "jan", Me: &me}); err != nil {
t.Fatal(err)
}
got := b.String()
if !strings.Contains(got, `data-hook="access-role"`) {
t.Error("FAIL: the role cell carries no hook, so nothing can tell it apart from the repository cell")
} else {
t.Log("ok: the role is a marked cell")
}
if !strings.Contains(got, `data-hook="access-plus"`) {
t.Error("FAIL: a grant holding more than its name reports no extras — " +
"this is the understatement that made a client conclude the account could not push")
} else {
t.Log("ok: what the role does not say reached the page")
}
if !strings.Contains(got, "check in and push") {
t.Error("FAIL: the extra is counted but not named, so the reader still cannot tell whether they may push")
} else {
t.Log("ok: the extra is named")
}
}
// The "+" is the qualifier for a reader who takes in the role column and
// nothing else. It appears only when there is more to say, so an exact
// grant is not permanently hedged.
func TestARoleIsOnlyQualifiedWhenItUnderstates(t *testing.T) {
if got := (meAccessRow{Role: "Reader", Plus: []string{"check in and push"}}).Qualified(); got != "Reader+" {
t.Errorf("Qualified() = %q, want Reader+ — a reader taking only this column is told they are a plain Reader", got)
}
if got := (meAccessRow{Role: "Reader", Exact: true}).Qualified(); got != "Reader" {
t.Errorf("Qualified() = %q for an exact grant, want Reader — the qualifier is for the inexact case only", got)
}
if got := (meAccessRow{Role: ""}).Qualified(); got != "" {
t.Errorf("Qualified() = %q for no role, want empty", got)
}
}