package oltp
import "testing"
// RFC 0018's one screen asks "who reaches these repositories", so a
// non-member holding a string on one of them belongs on it. An answer
// that listed only members would be answering a different question.
func TestTeamPeopleIncludesNonMembersWhoReachIt(t *testing.T) {
db := teamDB(t)
if err := db.AddTeam("core", "", "", "dan"); err != nil {
t.Fatal(err)
}
if err := db.SetTeamRepo("core", "quarry", "dan"); err != nil {
t.Fatal(err)
}
if err := db.SetTeamRepo("core", "zit", "dan"); err != nil {
t.Fatal(err)
}
// lou is a member with the floor alone.
if err := db.SetTeamMember("core", "lou", "", false, true); err != nil {
t.Fatal(err)
}
// ann is in no team but holds a string on one of the repositories.
if err := db.SetCaps("ann", "zit", "a"); err != nil {
t.Fatal(err)
}
// And a grant on a repository the team does NOT hold must not pull
// somebody onto this screen.
if err := db.SetCaps("ann", "elsewhere", "a"); err != nil {
t.Fatal(err)
}
people, err := db.TeamPeople("core")
if err != nil {
t.Fatal(err)
}
got := map[string]TeamPerson{}
for _, p := range people {
got[p.Account] = p
}
if len(people) != 3 {
t.Fatalf("FAIL: %d people, want dan, lou and ann: %+v", len(people), people)
}
if !got["dan"].Owner {
t.Error("FAIL: the creator does not read as owner")
}
if !got["lou"].Member || got["lou"].Caps != "" {
t.Errorf("FAIL: lou = %+v, want a member holding the floor alone", got["lou"])
}
ann := got["ann"]
if ann.Member {
t.Error("FAIL: ann reads as a member of a team she is not in")
}
if len(ann.Direct) != 1 || ann.Direct[0].Repo != "zit" {
t.Errorf("FAIL: ann's direct grants = %+v, want zit only — elsewhere is not this team's", ann.Direct)
}
if !ann.Reaches() {
t.Error("FAIL: ann does not read as reaching anything")
}
}
// Owners first, then members, then everybody else, each by name: the
// order somebody scanning for "who runs this" needs.
func TestTeamPeopleAreOrderedByStanding(t *testing.T) {
db := teamDB(t)
if err := db.AddTeam("core", "", "", "lou"); err != nil {
t.Fatal(err)
}
if err := db.SetTeamRepo("core", "quarry", "lou"); err != nil {
t.Fatal(err)
}
if err := db.SetTeamMember("core", "ann", "", false, true); err != nil {
t.Fatal(err)
}
if err := db.SetCaps("dan", "quarry", "a"); err != nil {
t.Fatal(err)
}
people, err := db.TeamPeople("core")
if err != nil {
t.Fatal(err)
}
var order []string
for _, p := range people {
order = append(order, p.Account)
}
// lou owns it, ann is a member, dan only holds a direct grant.
want := []string{"lou", "ann", "dan"}
for i := range want {
if i >= len(order) || order[i] != want[i] {
t.Fatalf("FAIL: order = %v, want %v", order, want)
}
}
}
// A team holding no repositories has members and nobody reaching
// anything, which the screen says rather than listing people against
// nothing.
func TestATeamWithNoReposStillListsItsMembers(t *testing.T) {
db := teamDB(t)
if err := db.AddTeam("core", "", "", "dan"); err != nil {
t.Fatal(err)
}
people, err := db.TeamPeople("core")
if err != nil {
t.Fatal(err)
}
if len(people) != 1 || people[0].Account != "dan" {
t.Fatalf("FAIL: people = %+v", people)
}
if len(people[0].Direct) != 0 {
t.Errorf("FAIL: direct grants on a team holding nothing: %+v", people[0].Direct)
}
}
// Somebody who is both a member and holds a string of their own shows
// both routes, because the page has to be able to say which is which.
func TestBothRoutesAppearOnOnePerson(t *testing.T) {
db := teamDB(t)
if err := db.AddTeam("core", "", "", "dan"); err != nil {
t.Fatal(err)
}
if err := db.SetTeamRepo("core", "quarry", "dan"); err != nil {
t.Fatal(err)
}
if err := db.SetTeamMember("core", "lou", "i", false, true); err != nil {
t.Fatal(err)
}
if err := db.SetCaps("lou", "quarry", "a"); err != nil {
t.Fatal(err)
}
people, err := db.TeamPeople("core")
if err != nil {
t.Fatal(err)
}
for _, p := range people {
if p.Account != "lou" {
continue
}
if !p.Member || p.Caps != "i" {
t.Errorf("FAIL: the team route is missing: %+v", p)
}
if len(p.Direct) != 1 || p.Direct[0].Caps != "a" {
t.Errorf("FAIL: the direct route is missing: %+v", p.Direct)
}
return
}
t.Fatal("FAIL: lou is not on the screen at all")
}